<> <> <> <> <> DIRECTORY MakePLA, Commander USING [CommandProc, Register], Parquet, ExprRead, BoolOps, TerminalIO, AMTypes, Rope, IO, FS, SymTab, Atom, Convert; MakePLAImpl: CEDAR PROGRAM IMPORTS Commander, Parquet, ExprRead, BoolOps, TerminalIO, Rope, FS, SymTab, Atom, Convert EXPORTS MakePLA = BEGIN maxCellSize: INT ~ 500; -- We will try to keep the second level core cells below this size. maxChunkSize: INT ~ 50; -- We will try to keep the first level core cells below this size. CreateX: PUBLIC PROC [] = BEGIN END; Error: PUBLIC ERROR[ec: ErrorCode, msg: Rope.ROPE] = CODE; ErrorCode: TYPE = {Null, -- never raised NoDescription, -- you must have one NoTruthTable -- you must have one }; PLADescription: TYPE = REF PLADescriptionRec; PLADescriptionRec: TYPE = RECORD [ tileSet: Parquet.Design _ NIL, technology: Parquet.Technology _ NIL, inputNames, outputNames: LIST OF Rope.ROPE _ NIL, truthTable: BoolOps.TruthTable _ NIL, extraRows, extraAndColumns, extraOrColumns: CARDINAL _ CARDINAL.LAST-100 -- SPACING (in number of minterms) between extra ground rows and columns ]; PrivatePLADescription: TYPE = RECORD [ ]; Create: PROC [desc: PLADescription] RETURNS [Parquet.Module] = BEGIN haveHorizontalExtras, haveVerticalOrExtras, haveVerticalAndExtras: BOOL _ TRUE; numInputs, numOutputs, numPTerms: INT; constructedPLA: Parquet.Module _ NIL; startOfPreviousRow: Parquet.PlacedTile; inputNames, outputNames: LIST OF Rope.ROPE _ NIL; <<-- tiles outside of the core of the PLA, and extra tiles in the core>> Aul, AUleft, ADleft, All, ALtop, ARtop, ALbot, ARbot: Parquet.Tile _ NIL; AHleft, ALH, ARH, AHV, AVtop, AUV, ADV, AVbot: Parquet.Tile _ NIL; Btop, BU, BD, BH, Bbot: Parquet.Tile _ NIL; OLtop, ORtop, Our, OUright, ODright, Olr, ORbot, OLbot: Parquet.Tile _ NIL; OVtop, OUV, ODV, OHV, OVbot, OLH, ORH, OHright: Parquet.Tile _ NIL; <<>> <<-- major tiles in the core of the PLA>> AUL1, AUL0, AULx, AUR1, AUR0, AURx: Parquet.Tile _ NIL; ADL1, ADL0, ADLx, ADR1, ADR0, ADRx: Parquet.Tile _ NIL; OUL1, OUL0, OUR1, OUR0: Parquet.Tile _ NIL; ODL1, ODL0, ODR1, ODR0: Parquet.Tile _ NIL; <<-- blocks of the PLA>> AndBlock: Rope.ROPE _ NIL; OrBlock: Rope.ROPE _ NIL; LeftBlock: Rope.ROPE _ "PLA-left"; MidBlock: Rope.ROPE _ "PLA-mid"; RightBlock: Rope.ROPE _ "PLA-right"; TopAndBlock: Rope.ROPE _ "PLA-topAnd"; BotAndBlock: Rope.ROPE _ "PLA-botAnd"; TopOrBlock: Rope.ROPE _ "PLA-topOr"; BotOrBlock: Rope.ROPE _ "PLA-botOr"; ODD: PROC[i: INT] RETURNS[BOOL] = INLINE BEGIN RETURN[(i MOD 2 # 0)] END; EVEN: PROC[i: INT] RETURNS[BOOL] = INLINE BEGIN RETURN[(i MOD 2 = 0)] END; LoadTiles: PROC[] RETURNS[BOOL] = BEGIN anyTilesNotFound: BOOL _ FALSE; everthingIsJustFineAndDandy: BOOL _ TRUE; GetTile: PROC[name1, name2, name3: Rope.ROPE _ NIL, required: BOOL] RETURNS [Parquet.Tile] = BEGIN tile: Parquet.Tile _ NIL; tile _ Parquet.InstantiateTile[desc.tileSet, name1]; IF name2 # NIL AND tile = NIL THEN { tile _ Parquet.InstantiateTile[desc.tileSet, name2]; IF name3 # NIL AND tile = NIL THEN { tile _ Parquet.InstantiateTile[desc.tileSet, name3]; }; }; IF required AND tile = NIL THEN { anyTilesNotFound _ TRUE; TerminalIO.WriteRope[Rope.Cat["MakePLA could not find tile '", name1]]; IF name2 # NIL THEN { IF name3 # NIL THEN TerminalIO.WriteRope[Rope.Cat[" nor its alternates '", name2, "' and '", name3]] ELSE TerminalIO.WriteRope[Rope.Cat[" nor its alternate '", name2]] }; TerminalIO.WriteRope["'.\n"] }; RETURN[tile]; END; RequiredTile: PROC[name1, name2, name3: Rope.ROPE _ NIL] RETURNS [Parquet.Tile] = BEGIN RETURN[GetTile[name1, name2, name3, TRUE]]; END; OptionalTile: PROC[name1, name2, name3: Rope.ROPE _ NIL] RETURNS [Parquet.Tile] = BEGIN RETURN[GetTile[name1, name2, name3, FALSE]]; END; <<-- left side of AND plane>> Aul _ OptionalTile["Aul"]; AUleft _ OptionalTile["AUleft", "Aleft"]; ADleft _ OptionalTile["ADleft", "Aleft"]; AHleft _ OptionalTile["AHleft"]; All _ OptionalTile["All"]; <<>> <<-- top and bottom of AND plane>> ALbot _ OptionalTile["ALbot", "Abot"]; ARbot _ OptionalTile["ARbot", "Abot"]; AVbot _ OptionalTile["AVbot"]; ALtop _ OptionalTile["ALtop", "Atop"]; ARtop _ OptionalTile["ARtop", "Atop"]; AVtop _ OptionalTile["AVtop"]; <<>> <<-- core of AND plane>> AUL0 _ RequiredTile["AUL0", "AL0", "A0"]; ADL0 _ RequiredTile["ADL0", "AL0", "A0"]; AUR0 _ RequiredTile["AUR0", "AR0", "A0"]; ADR0 _ RequiredTile["ADR0", "AR0", "A0"]; AUL1 _ RequiredTile["AUL1", "AL1", "A1"]; ADL1 _ RequiredTile["ADL1", "AL1", "A1"]; AUR1 _ RequiredTile["AUR1", "AR1", "A1"]; ADR1 _ RequiredTile["ADR1", "AR1", "A1"]; AULx _ RequiredTile["AUL-", "AL-", "A-"]; ADLx _ RequiredTile["ADL-", "AL-", "A-"]; AURx _ RequiredTile["AUR-", "AR-", "A-"]; ADRx _ RequiredTile["ADR-", "AR-", "A-"]; ALH _ OptionalTile["ALH", "AH"]; ARH _ OptionalTile["ARH", "AH"]; AUV _ OptionalTile["AUV", "AV"]; ADV _ OptionalTile["ADV", "AV"]; AHV _ OptionalTile["AHV"]; <<>> <<-- area between planes>> Btop _ OptionalTile["Btop"]; BU _ RequiredTile["BU", "B"]; BD _ RequiredTile["BD", "B"]; BH _ OptionalTile["BH"]; Bbot _ OptionalTile["Bbot"]; <<>> <<-- top and bottom of OR plane>> OLtop _ OptionalTile["OLtop", "Otop"]; ORtop _ OptionalTile["ORtop", "Otop"]; OVtop _ OptionalTile["OVtop"]; OLbot _ OptionalTile["OLbot", "Obot"]; ORbot _ OptionalTile["ORbot", "Obot"]; OVbot _ OptionalTile["OVbot"]; <<>> <<-- right side of OR plane>> Olr _ OptionalTile["Olr"]; Our _ OptionalTile["Our"]; OUright _ OptionalTile["OUright", "Oright"]; ODright _ OptionalTile["ODright", "Oright"]; OHright _ OptionalTile["OHright"]; <<-- core of the OR plane>> OUL0 _ RequiredTile["OUL0", "OU0"]; OUR0 _ RequiredTile["OUR0", "OU0"]; ODL0 _ RequiredTile["ODL0", "OD0"]; ODR0 _ RequiredTile["ODR0", "OD0"]; OUL1 _ RequiredTile["OUL1", "OU1"]; OUR1 _ RequiredTile["OUR1", "OU1"]; ODL1 _ RequiredTile["ODL1", "OD1"]; ODR1 _ RequiredTile["ODR1", "OD1"]; OLH _ OptionalTile["OLH", "OH"]; ORH _ OptionalTile["ORH", "OH"]; OUV _ OptionalTile["OUV", "OV"]; ODV _ OptionalTile["ODV", "OV"]; OHV _ OptionalTile["OHV"]; <<>> <<-- now take care of dependencies between tiles>> IF anyTilesNotFound THEN everthingIsJustFineAndDandy _ FALSE; IF ALH = NIL OR ARH = NIL OR BH = NIL OR OLH = NIL OR ORH = NIL THEN { IF ALH # NIL OR ARH # NIL OR BH # NIL OR OLH # NIL OR ORH # NIL THEN { TerminalIO.WriteRope["Set of tiles must have all of the extra horizontal tiles or none of them.\n"]; everthingIsJustFineAndDandy _ FALSE; } ELSE haveHorizontalExtras _ FALSE; }; IF AUV = NIL OR ADV = NIL THEN { IF AUV # NIL OR ADV # NIL THEN { TerminalIO.WriteRope["Set of tiles must have all of the extra vertical AND plane tiles or none of them.\n"]; everthingIsJustFineAndDandy _ FALSE; } ELSE haveVerticalAndExtras _ FALSE; }; IF OUV = NIL OR ODV = NIL THEN { IF OUV # NIL OR ODV # NIL THEN { TerminalIO.WriteRope["Set of tiles must have all of the extra vertical OR plane tiles or none of them.\n"]; everthingIsJustFineAndDandy _ FALSE; } ELSE haveVerticalOrExtras _ FALSE; }; IF haveHorizontalExtras THEN { IF haveVerticalAndExtras AND AHV = NIL THEN { TerminalIO.WriteRope["Tile 'AHV' is missing.\n"]; everthingIsJustFineAndDandy _ FALSE; }; IF haveVerticalOrExtras AND OHV = NIL THEN { TerminalIO.WriteRope["Tile 'OHV' is missing.\n"]; everthingIsJustFineAndDandy _ FALSE; }; }; IF Aul # NIL AND AUleft = NIL THEN { TerminalIO.WriteRope["Tile 'Aul' exists but it connects to AUleft which is missing.\n"]; everthingIsJustFineAndDandy _ FALSE; }; IF All # NIL AND (AUleft = NIL OR ADleft = NIL) THEN { TerminalIO.WriteRope["Tile 'All' exists but it connects to AUleft or ADleft which is missing.\n"]; everthingIsJustFineAndDandy _ FALSE; }; IF Our # NIL AND OUright = NIL THEN { TerminalIO.WriteRope["Tile 'Our' exists but it connects to OUright which is missing.\n"]; everthingIsJustFineAndDandy _ FALSE; }; IF Olr # NIL AND (OUright = NIL OR ODright = NIL) THEN { TerminalIO.WriteRope["Tile 'Olr' exists but it connects to OUright or ODright which is missing.\n"]; everthingIsJustFineAndDandy _ FALSE; }; RETURN[everthingIsJustFineAndDandy]; END; rowTabInitialized: BOOL _ FALSE; rowTab: ARRAY BOOL --and plane-- OF ARRAY BOOL --upper row-- OF ARRAY BOOL -- left col-- OF ARRAY BoolOps.TruthBit --bit-- OF Parquet.Tile; OptAdjTile: PROC [oldTile: Parquet.PlacedTile, newTile: Parquet.Tile, dir: Parquet.Direction, orient: Parquet.Orientation, newBlock: Rope.ROPE] RETURNS[Parquet.PlacedTile] = INLINE BEGIN pt: Parquet.PlacedTile; oldBlock: Rope.ROPE; IF newTile = NIL THEN RETURN[NIL]; oldBlock _ Parquet.GetCurrentBlock[constructedPLA]; Parquet.SwitchBlock[constructedPLA, newBlock]; pt _ Parquet.AdjacentTile[oldTile, newTile, dir, orient]; Parquet.SwitchBlock[constructedPLA, oldBlock]; RETURN[pt]; END; PlaceExtra: PROC[startBelow: Parquet.PlacedTile] RETURNS[Parquet.PlacedTile] = BEGIN prevTile, startRow: Parquet.PlacedTile; tilesSinceExtra: INT; tile: Parquet.Tile; <<-- AND plane>> Parquet.SwitchBlock[constructedPLA, AndBlock]; tilesSinceExtra _ 0; FOR i: INT IN [0 .. numInputs) DO IF tilesSinceExtra+1 >= desc.extraAndColumns AND haveVerticalAndExtras AND EVEN[i] THEN { <<-- do extra vertical columns in AND plane>> prevTile _ Parquet.AdjacentTile[prevTile, AHV, $rightOf, Parquet.IdentityOrient] }; IF i = 0 THEN { <<-- do first tile in core of row, and tiles to its left>> startRow _ prevTile _ Parquet.AdjacentTile[startBelow, ALH, $below, Parquet.IdentityOrient]; [] _ OptAdjTile[prevTile, AHleft, $leftOf, Parquet.IdentityOrient, LeftBlock] } ELSE { <<-- do other tiles in core of AND plane, and tiles above and below>> IF EVEN[i] THEN tile _ ALH ELSE tile _ ARH; prevTile _ Parquet.AdjacentTile[prevTile, tile, $rightOf, Parquet.IdentityOrient]; }; tilesSinceExtra _ tilesSinceExtra + 1; ENDLOOP; <<>> <<-- Between planes>> Parquet.SwitchBlock[constructedPLA, MidBlock]; prevTile _ Parquet.AdjacentTile[prevTile, BH, $rightOf, Parquet.IdentityOrient]; <<-- OR plane>> Parquet.SwitchBlock[constructedPLA, OrBlock]; tilesSinceExtra _ 0; FOR i: INT IN [0 .. numOutputs) DO IF tilesSinceExtra+1 >= desc.extraOrColumns AND haveVerticalOrExtras AND EVEN[i] THEN { <<-- do extra vertical columns in OR plane>> prevTile _ Parquet.AdjacentTile[prevTile, OHV, $rightOf, Parquet.IdentityOrient] }; IF EVEN[i] THEN tile _ OLH ELSE tile _ ORH; prevTile _ Parquet.AdjacentTile[prevTile, tile, $rightOf, Parquet.IdentityOrient]; IF i = numOutputs - 1 THEN { t: Parquet.PlacedTile; <<-- do tiles to the right of the last core tile>> t _ OptAdjTile[prevTile, OHright, $rightOf, Parquet.IdentityOrient, RightBlock]; }; tilesSinceExtra _ tilesSinceExtra + 1; ENDLOOP; <<-- we're done with the row, return the start of it>> RETURN[startRow]; END; PlaceRow: PROC[startBelow: Parquet.PlacedTile, rowNum: INT] RETURNS[Parquet.PlacedTile] = BEGIN topRow: BOOL _ (rowNum = 0); botRow: BOOL _ (rowNum = numPTerms - 1); prevTile, startRow: Parquet.PlacedTile; tilesSinceExtra: INT; tile: Parquet.Tile; IF ~rowTabInitialized THEN { <<-- up (U) rows of AND plane>> rowTab[TRUE][TRUE][TRUE][$One] _ AUL1; rowTab[TRUE][TRUE][TRUE][$Zero] _ AUL0; rowTab[TRUE][TRUE][TRUE][$NC] _ AULx; rowTab[TRUE][TRUE][FALSE][$One] _ AUR1; rowTab[TRUE][TRUE][FALSE][$Zero] _ AUR0; rowTab[TRUE][TRUE][FALSE][$NC] _ AURx; <<-- down (D) rows of AND plane>> rowTab[TRUE][FALSE][TRUE][$One] _ ADL1; rowTab[TRUE][FALSE][TRUE][$Zero] _ ADL0; rowTab[TRUE][FALSE][TRUE][$NC] _ ADLx; rowTab[TRUE][FALSE][FALSE][$One] _ ADR1; rowTab[TRUE][FALSE][FALSE][$Zero] _ ADR0; rowTab[TRUE][FALSE][FALSE][$NC] _ ADRx; <<-- up (U) rows of OR plane>> rowTab[FALSE][TRUE][TRUE][$One] _ OUL1; rowTab[FALSE][TRUE][TRUE][$Zero] _ OUL0; rowTab[FALSE][TRUE][TRUE][$NC] _ OUL0; rowTab[FALSE][TRUE][FALSE][$One] _ OUR1; rowTab[FALSE][TRUE][FALSE][$Zero] _ OUR0; rowTab[FALSE][TRUE][FALSE][$NC] _ OUR0; <<-- down (D) rows of OR plane>> rowTab[FALSE][FALSE][TRUE][$One] _ ODL1; rowTab[FALSE][FALSE][TRUE][$Zero] _ ODL0; rowTab[FALSE][FALSE][TRUE][$NC] _ ODL0; rowTab[FALSE][FALSE][FALSE][$One] _ ODR1; rowTab[FALSE][FALSE][FALSE][$Zero] _ ODR0; rowTab[FALSE][FALSE][FALSE][$NC] _ ODR0; rowTabInitialized _ TRUE; }; <<-- AND plane>> Parquet.SwitchBlock[constructedPLA, AndBlock]; tilesSinceExtra _ 0; FOR i: INT IN [0 .. numInputs) DO tile _ rowTab[TRUE][EVEN[rowNum]][EVEN[i]][desc.truthTable.pterms[rowNum].bits[i]]; IF tilesSinceExtra+1 >= desc.extraAndColumns AND haveVerticalAndExtras AND EVEN[i] THEN { <<-- do extra vertical columns in AND plane>> IF EVEN[rowNum] THEN prevTile _ Parquet.AdjacentTile[prevTile, AUV, $rightOf, Parquet.IdentityOrient] ELSE prevTile _ Parquet.AdjacentTile[prevTile, ADV, $rightOf, Parquet.IdentityOrient]; <<-- upper tile>> IF rowNum = 0 THEN [] _ OptAdjTile[prevTile, AVtop, $above, Parquet.IdentityOrient, TopAndBlock]; <<-- lower tile>> IF rowNum = numPTerms - 1 THEN [] _ OptAdjTile[prevTile, AVbot, $below, Parquet.IdentityOrient, BotAndBlock]; }; IF i = 0 THEN { t: Parquet.PlacedTile; <<-- do first tile in core of row, and tiles to its left>> startRow _ prevTile _ Parquet.AdjacentTile[startBelow, tile, $below, Parquet.IdentityOrient]; IF EVEN[rowNum] THEN t _ OptAdjTile[prevTile, AUleft, $leftOf, Parquet.IdentityOrient, LeftBlock] ELSE t _ OptAdjTile[prevTile, ADleft, $leftOf, Parquet.IdentityOrient, LeftBlock]; <<-- upper left tile>> IF rowNum = 0 THEN [] _ OptAdjTile[t, Aul, $above, Parquet.IdentityOrient, LeftBlock]; <<-- lower left tile>> IF rowNum = numPTerms - 1 THEN [] _ OptAdjTile[t, All, $below, Parquet.IdentityOrient, LeftBlock]; } ELSE { <<-- do other tiles in core of AND plane, and tiles above and below>> prevTile _ Parquet.AdjacentTile[prevTile, tile, $rightOf, Parquet.IdentityOrient]; }; IF rowNum = 0 THEN { <<-- tiles above>> IF EVEN[i] THEN [] _ OptAdjTile[prevTile, ALtop, $above, Parquet.IdentityOrient, TopAndBlock] ELSE [] _ OptAdjTile[prevTile, ARtop, $above, Parquet.IdentityOrient, TopAndBlock]; }; IF rowNum = numPTerms - 1 THEN { <<-- tiles below>> IF EVEN[i] THEN [] _ OptAdjTile[prevTile, ALbot, $below, Parquet.IdentityOrient, BotAndBlock] ELSE [] _ OptAdjTile[prevTile, ARbot, $below, Parquet.IdentityOrient, BotAndBlock]; }; tilesSinceExtra _ tilesSinceExtra + 1; ENDLOOP; <<>> <<-- Between planes>> Parquet.SwitchBlock[constructedPLA, MidBlock]; IF EVEN[rowNum] THEN prevTile _ Parquet.AdjacentTile[prevTile, BU, $rightOf, Parquet.IdentityOrient] ELSE prevTile _ Parquet.AdjacentTile[prevTile, BD, $rightOf, Parquet.IdentityOrient]; <<-- tile above>> IF rowNum = 0 THEN [] _ OptAdjTile[prevTile, Btop, $above, Parquet.IdentityOrient, MidBlock]; <<-- tile below>> IF rowNum = numPTerms - 1 THEN [] _ OptAdjTile[prevTile, Bbot, $below, Parquet.IdentityOrient, MidBlock]; <<-- OR plane>> Parquet.SwitchBlock[constructedPLA, OrBlock]; tilesSinceExtra _ 0; FOR i: INT IN [0 .. numOutputs) DO tile _ rowTab[FALSE][EVEN[rowNum]][EVEN[i]][desc.truthTable.pterms[rowNum].bits[i + numInputs]]; IF tilesSinceExtra+1 >= desc.extraOrColumns AND haveVerticalOrExtras AND EVEN[i] THEN { <<-- do extra vertical columns in OR plane>> IF EVEN[rowNum] THEN prevTile _ Parquet.AdjacentTile[prevTile, OUV, $rightOf, Parquet.IdentityOrient] ELSE prevTile _ Parquet.AdjacentTile[prevTile, ODV, $rightOf, Parquet.IdentityOrient]; <<-- upper tile>> IF rowNum = 0 THEN [] _ OptAdjTile[prevTile, OVtop, $above, Parquet.IdentityOrient, TopOrBlock]; <<-- lower tile>> IF rowNum = numPTerms - 1 THEN [] _ OptAdjTile[prevTile, OVbot, $below, Parquet.IdentityOrient, BotOrBlock]; }; prevTile _ Parquet.AdjacentTile[prevTile, tile, $rightOf, Parquet.IdentityOrient]; IF i = numOutputs - 1 THEN { t: Parquet.PlacedTile; <<-- do tiles to the right of the last core tile>> IF EVEN[rowNum] THEN t _ OptAdjTile[prevTile, OUright, $rightOf, Parquet.IdentityOrient, RightBlock] ELSE t _ OptAdjTile[prevTile, ODright, $rightOf, Parquet.IdentityOrient, RightBlock]; <<-- upper left tile>> IF rowNum = 0 THEN [] _ OptAdjTile[t, Our, $above, Parquet.IdentityOrient, RightBlock]; <<-- lower left tile>> IF rowNum = numPTerms - 1 THEN [] _ OptAdjTile[t, Olr, $below, Parquet.IdentityOrient, RightBlock]; }; IF rowNum = 0 THEN { <<-- tiles above>> IF EVEN[i] THEN [] _ OptAdjTile[prevTile, OLtop, $above, Parquet.IdentityOrient, TopOrBlock] ELSE [] _ OptAdjTile[prevTile, ORtop, $above, Parquet.IdentityOrient, TopOrBlock]; }; IF rowNum = numPTerms - 1 THEN { <<-- tiles below>> IF EVEN[i] THEN [] _ OptAdjTile[prevTile, OLbot, $below, Parquet.IdentityOrient, BotOrBlock] ELSE [] _ OptAdjTile[prevTile, ORbot, $below, Parquet.IdentityOrient, BotOrBlock]; }; tilesSinceExtra _ tilesSinceExtra + 1; ENDLOOP; <<-- we're done with the row, return the start of it>> RETURN[startRow]; END; IF desc = NIL THEN ERROR Error[NoDescription, "No description was specified!"]; IF desc.truthTable = NIL THEN ERROR Error[NoTruthTable, "No truth table was specified!"]; <<-- initialization>> IF ~LoadTiles[] THEN { TerminalIO.WriteRope["MakePLA exitting due to errors while loading tiles.\n"]; RETURN[NIL]; }; numInputs _ desc.truthTable.numInputs; numOutputs _ desc.truthTable.numOutputs; numPTerms _ desc.truthTable.numPTerms; [constructedPLA, startOfPreviousRow] _ Parquet.NewModule[desc.technology]; <<>> <<-- create the PLA row by row>> { noisy: BOOL _ ((numInputs + numOutputs) * numPTerms > 300); rowsSinceExtra: INT _ 0; rowsSinceBlock: INT _ -1; blocksSinceChunk: INT _ -1; blockNumber: INT _ 1; chunkNumber: INT _ 1; rowsPerBlock: INT _ MAX[1, maxCellSize / MAX[numInputs, numOutputs, 1]]; blocksPerChunk: INT _ -1; AndChunk, OrChunk: Rope.ROPE _ NIL; IF numPTerms / rowsPerBlock > 5 THEN blocksPerChunk _ MAX[1, maxChunkSize / rowsPerBlock]; IF noisy THEN TerminalIO.WriteRope["Rows (product terms) placed: "]; FOR row: INT IN [0 .. numPTerms) DO IF (blocksSinceChunk > blocksPerChunk OR blocksSinceChunk < 0) AND blocksPerChunk > 0 THEN { AndChunk _ Rope.Concat["PLA-andBlock", Convert.RopeFromInt[chunkNumber, 10, FALSE]]; OrChunk _ Rope.Concat["PLA-orBlock", Convert.RopeFromInt[chunkNumber, 10, FALSE]]; chunkNumber _ chunkNumber + 1; blocksSinceChunk _ 0; }; IF rowsSinceBlock > rowsPerBlock OR rowsSinceBlock < 0 THEN { AndBlock _ Rope.Concat["PLA-and", Convert.RopeFromInt[blockNumber, 10, FALSE]]; OrBlock _ Rope.Concat["PLA-or", Convert.RopeFromInt[blockNumber, 10, FALSE]]; IF ~Parquet.NestBlock[constructedPLA, AndBlock, AndChunk] THEN ERROR; IF ~Parquet.NestBlock[constructedPLA, OrBlock, OrChunk] THEN ERROR; blockNumber _ blockNumber + 1; blocksSinceChunk _ blocksSinceChunk + 1; rowsSinceBlock _ 0; }; IF rowsSinceExtra+1 >= desc.extraRows AND haveHorizontalExtras AND EVEN[row] THEN { startOfPreviousRow _ PlaceExtra[startBelow: startOfPreviousRow]; rowsSinceExtra _ 0; }; startOfPreviousRow _ PlaceRow[startBelow: startOfPreviousRow, rowNum: row]; IF noisy THEN TerminalIO.WriteInt[row + 1]; rowsSinceExtra _ rowsSinceExtra + 1; rowsSinceBlock _ rowsSinceBlock + 1; ENDLOOP; IF noisy THEN TerminalIO.WriteRope[" . . . that's all.\n"]; }; <<>> <<-- we're done!>> RETURN[constructedPLA]; END; MakePLAProc: Parquet.ModuleGeneratorProc = BEGIN <<-- PROC[parameters: SymTab.Ref] RETURNS [Module]>> FetchRope: PROC [symTab: SymTab.Ref, name: Rope.ROPE] RETURNS [Rope.ROPE] = BEGIN tv: AMTypes.TV; r: Rope.ROPE; [ , tv] _ SymTab.Fetch[symTab, name]; IF tv = NIL THEN RETURN[NIL]; r _ ExprRead.TVToRope[tv]; IF r = NIL THEN { TerminalIO.WriteRope[Rope.Cat["Value for '", name, "' must be a rope.\n"]]; RETURN[NIL]; }; RETURN[r]; END; FetchRopeList: PROC [symTab: SymTab.Ref, name: Rope.ROPE] RETURNS [LIST OF Rope.ROPE] = BEGIN tv: AMTypes.TV; r: LIST OF Rope.ROPE; [ , tv] _ SymTab.Fetch[symTab, name]; IF tv = NIL THEN RETURN[NIL]; r _ ExprRead.TVToListOfRope[tv]; IF r = NIL THEN { TerminalIO.WriteRope[Rope.Cat["Value for '", name, "' must be a list of ropes.\n"]]; RETURN[NIL]; }; RETURN[r]; END; FetchCard: PROC [symTab: SymTab.Ref, name: Rope.ROPE] RETURNS [REF CARDINAL] = BEGIN tv: AMTypes.TV; i: REF CARDINAL; [ , tv] _ SymTab.Fetch[symTab, name]; IF tv = NIL THEN RETURN[NIL]; i _ ExprRead.TVToCardinal[tv]; IF i = NIL THEN { TerminalIO.WriteRope[Rope.Cat["Value for '", name, "' must be a cardinal.\n"]]; RETURN[NIL]; }; RETURN[i]; END; GetEQN: PROC[inNames, outNames: LIST OF Rope.ROPE] RETURNS[BoolOps.TruthTable] = BEGIN tt: BoolOps.TruthTable; problems: BOOL _ FALSE; inAtoms, reverseAtoms: LIST OF ATOM _ NIL; eqnTrees: LIST OF BoolOps.Tree _ NIL; message: Rope.ROPE; IF inNames = NIL OR outNames = NIL THEN { TerminalIO.WriteRope["Both 'Inputs' and 'Outputs' must be specified.\n"]; RETURN[NIL]; }; <<-- read equations one at a time, converting to sum-of-products as we go>> FOR outs: LIST OF Rope.ROPE _ outNames, outs.rest WHILE outs # NIL DO eqn: Rope.ROPE; t: BoolOps.Tree _ NIL; eqn _ FetchRope[parameters, outs.first]; IF eqn = NIL THEN { problems _ TRUE; TerminalIO.WriteRope[Rope.Cat["Equation for output '", outs.first, "' is missing.\n"]]; }; FOR i: INT DECREASING IN [0 .. Rope.Length[eqn]) DO -- remove trailing semicolon ch: CHAR _ Rope.Fetch[eqn, i]; IF ch # ' AND ch # '\t AND ch # '\n THEN { IF ch = '; AND i > 0 THEN eqn _ Rope.Substr[eqn, 0, i]; EXIT; }; ENDLOOP; message _ NIL; t _ BoolOps.RopeToTree[eqn ! BoolOps.Error => {message _ msg; CONTINUE}]; IF message # NIL THEN { problems _ TRUE; TerminalIO.WriteRope[Rope.Cat["Could not translate equation for output '", outs.first, "', error was: ", message, "\n"]]; } ELSE { message _ NIL; t _ BoolOps.TreeToSOP[t ! BoolOps.Error => {message _ msg; CONTINUE}]; IF message # NIL THEN { problems _ TRUE; TerminalIO.WriteRope[Rope.Cat["Could not translate output '", outs.first, "' to sum-of-products form, error was: ", message, "\n"]]; } ELSE { eqnTrees _ CONS[t, eqnTrees]; }; }; ENDLOOP; IF problems THEN RETURN[NIL]; FOR ins: LIST OF Rope.ROPE _ inNames, ins.rest WHILE ins # NIL DO reverseAtoms _ CONS[Atom.MakeAtom[ins.first], reverseAtoms]; ENDLOOP; FOR ins: LIST OF ATOM _ reverseAtoms, ins.rest WHILE ins # NIL DO inAtoms _ CONS[ins.first, inAtoms]; ENDLOOP; message _ NIL; tt _ BoolOps.SOPToTT[inAtoms, eqnTrees ! BoolOps.Error => {message _ msg; CONTINUE}]; IF message # NIL THEN { TerminalIO.WriteRope[Rope.Cat["Could not translate equations to truth table form, error was: ", message, "\n"]]; RETURN[NIL]; }; RETURN[tt]; END; GetTT: PROC[] RETURNS[BoolOps.TruthTable] = BEGIN tt: BoolOps.TruthTable; ttFile: Rope.ROPE; ttStream: IO.STREAM; explanation: Rope.ROPE; ttFile _ FetchRope[parameters, "TruthTableFile"]; IF ttFile = NIL THEN RETURN[NIL]; ttStream _ FS.StreamOpen[ttFile ! FS.Error => IF error.group = user THEN {ttStream _ NIL; CONTINUE}]; IF ttStream = NIL THEN { TerminalIO.WriteRope[Rope.Cat["Could not open truth table file '", ttFile, "'.\n"]]; RETURN[NIL]; }; tt _ BoolOps.StreamToTT[ttStream ! BoolOps.Error => {explanation _ msg; CONTINUE}]; IF explanation # NIL THEN { TerminalIO.WriteRope[Rope.Cat["Error in reading truth table: ", explanation, "\n"]]; RETURN[NIL]; }; RETURN[tt]; END; InteractiveInput: PROC[] RETURNS[PLADescription] = BEGIN TerminalIO.WriteRope["Sorry, no interactive input for MakePLA, use a description file.\n"]; RETURN[NIL]; END; GetOptions: PROC[params: SymTab.Ref] RETURNS[PLADescription] = BEGIN opt: PLADescription _ NEW[PLADescriptionRec]; card: REF CARDINAL; <<-- get names of inputs and outputs>> opt.inputNames _ FetchRopeList[params, "Inputs"]; opt.outputNames _ FetchRopeList[params, "Outputs"]; <<-- get the number of extra rows and columns>> card _ FetchCard[params, "Extras"]; IF card # NIL THEN opt.extraRows _ opt.extraAndColumns _ opt.extraOrColumns _ card^; card _ FetchCard[params, "ExtraRows"]; IF card # NIL THEN opt.extraRows _ card^; card _ FetchCard[params, "ExtraColumns"]; IF card # NIL THEN opt.extraAndColumns _ opt.extraOrColumns _ card^; card _ FetchCard[params, "ExtraAndColumns"]; IF card # NIL THEN opt.extraAndColumns _ card^; card _ FetchCard[params, "ExtraOrColumns"]; IF card # NIL THEN opt.extraOrColumns _ card^; <<-- get a truth table>> IF FetchRope[parameters, "TruthTableFile"] # NIL THEN opt.truthTable _ GetTT[] ELSE opt.truthTable _ GetEQN[options.inputNames, options.outputNames]; RETURN[opt]; END; DumpTruthTable: PROC [tt: BoolOps.TruthTable] = BEGIN <<-- dump truth table to file>> ttFile: Rope.ROPE _ FetchRope[parameters, "TruthTableDumpFile"]; IF ttFile # NIL THEN { ttStream: IO.STREAM; message: Rope.ROPE _ NIL; ttStream _ FS.StreamOpen[ttFile, $create ! FS.Error => IF error.group = user THEN {ttStream _ NIL; CONTINUE}]; IF ttStream = NIL THEN { TerminalIO.WriteRope[Rope.Cat["Could not create truth table dump file '", ttFile, "'.\n"]]; }; BoolOps.TTToStream[tt, ttStream ! BoolOps.Error => {message _ msg; CONTINUE}]; IF message # NIL THEN { TerminalIO.WriteRope[Rope.Cat["Could not dump truth table to file '", ttFile, "', error was: ", message, "\n"]]; }; }; RETURN; END; PLA: Parquet.Module; options: PLADescription; <<-- get parameters>> IF parameters = NIL THEN { options _ InteractiveInput[]; } ELSE { options _ GetOptions[parameters]; }; IF options = NIL THEN RETURN[NIL]; IF options.truthTable = NIL THEN RETURN[NIL]; <<-- load tiles>> { fileName: Rope.ROPE; fileName _ FetchRope[parameters, "TileSet"]; IF fileName = NIL THEN { TerminalIO.WriteRope["No 'TileSet' was specified in the input file.\n"]; RETURN[NIL]; }; [options.tileSet, options.technology, ] _ Parquet.ReadDesign[fileName]; IF options.tileSet = NIL THEN { TerminalIO.WriteRope[Rope.Cat["Could not load tiles from file '", fileName, "'.\n"]]; RETURN[NIL]; }; }; <<-- create stuff>> DumpTruthTable[options.truthTable]; PLA _ Create[options]; RETURN[PLA]; END; NoOp: Commander.CommandProc = BEGIN END; <<-- register this generator with Parquet>> [] _ Parquet.RegisterGenerator["MakePLA", MakePLAProc]; <<-- register a command so that we won't get ".load file failed to register command">> Commander.Register[key: "MakePLA", proc: NoOp, doc: "Does nothing"]; END.