<> <> <> <> <> <> <<>> 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 OPEN MakePLA; 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. Error: PUBLIC ERROR[ec: ErrorCode, msg: Rope.ROPE] ~ CODE; PLADescription: TYPE = REF PLADescriptionRec; PLADescriptionRec: TYPE = RECORD [ context: Parquet.Context _ NIL, inputNames, outputNames: LIST OF Rope.ROPE _ NIL, -- every input and output MUST be named, ReadParameters and ReadTileSetOnly guarentee this truthTable: BoolOps.TruthTable _ NIL, extraRows, extraAndColumns, extraOrColumns: CARDINAL _ CARDINAL.LAST-100, -- SPACING (in number of minterms) between extra ground rows and columns optimize: BOOL _ TRUE, printRows: CARDINAL _ 25, -- If the PLA has more than this many rows, then list them out on the screen as we assemble them. dumpFile: Rope.ROPE _ NIL -- if non-NIL then truth table (after optimization, if any) will be dumped to this file. ]; Create: PUBLIC PROC [context: Parquet.Context] 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; ourTruthTable: BoolOps.TruthTable; desc: PLADescription; <<-- 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; DumpTruthTable: PROC [tt: BoolOps.TruthTable, ttFile: Rope.ROPE] = BEGIN <<-- dump truth table to file>> 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 ERROR Error[NoDump, Rope.Cat["Could not create truth table dump file '", ttFile, "'.\n"]]; BoolOps.TTToStream[tt, ttStream ! BoolOps.Error => {message _ msg; CONTINUE}]; IF message # NIL THEN ERROR Error[NoDump, Rope.Cat["Could not dump truth table to file '", ttFile, "', error was: ", message, "\n"]]; END; LoadTiles: PROC[context: Parquet.Context] = BEGIN anyTilesNotFound: BOOL _ FALSE; anyErrorsMessages: Rope.ROPE _ NIL; anyErrors: BOOL _ FALSE; GetTile: PROC[name1, name2, name3: Rope.ROPE _ NIL, required: BOOL] RETURNS [Parquet.Tile] = BEGIN tile: Parquet.Tile _ NIL; tile _ Parquet.InstantiateTile[context, name1]; IF name2 # NIL AND tile = NIL THEN { tile _ Parquet.InstantiateTile[context, name2]; IF name3 # NIL AND tile = NIL THEN { tile _ Parquet.InstantiateTile[context, name3]; }; }; IF required AND tile = NIL THEN { anyErrors _ TRUE; anyErrorsMessages _ Rope.Cat[anyErrorsMessages, "MakePLA could not find tile '", name1]; IF name2 # NIL THEN { IF name3 # NIL THEN anyErrorsMessages _ Rope.Cat[anyErrorsMessages, " nor its alternates '", name2, "' and '", name3] ELSE anyErrorsMessages _ Rope.Cat[" nor its alternate '", name2]; }; anyErrorsMessages _ Rope.Cat[anyErrorsMessages, "'.\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 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 { anyErrorsMessages _ Rope.Cat[anyErrorsMessages, "Set of tiles must have all of the extra horizontal tiles or none of them.\n"]; anyErrors _ TRUE; } ELSE haveHorizontalExtras _ FALSE; }; IF AUV = NIL OR ADV = NIL THEN { IF AUV # NIL OR ADV # NIL THEN { anyErrorsMessages _ Rope.Cat[anyErrorsMessages, "Set of tiles must have all of the extra vertical AND plane tiles or none of them.\n"]; anyErrors _ TRUE; } ELSE haveVerticalAndExtras _ FALSE; }; IF OUV = NIL OR ODV = NIL THEN { IF OUV # NIL OR ODV # NIL THEN { anyErrorsMessages _ Rope.Cat[anyErrorsMessages, "Set of tiles must have all of the extra vertical OR plane tiles or none of them.\n"]; anyErrors _ TRUE; } ELSE haveVerticalOrExtras _ FALSE; }; IF haveHorizontalExtras THEN { IF haveVerticalAndExtras AND AHV = NIL THEN { anyErrorsMessages _ Rope.Cat[anyErrorsMessages, "Tile 'AHV' is missing.\n"]; anyErrors _ TRUE; }; IF haveVerticalOrExtras AND OHV = NIL THEN { anyErrorsMessages _ Rope.Cat[anyErrorsMessages, "Tile 'OHV' is missing.\n"]; anyErrors _ TRUE; }; }; IF Aul # NIL AND AUleft = NIL THEN { anyErrorsMessages _ Rope.Cat[anyErrorsMessages, "Tile 'Aul' exists but it connects to AUleft which is missing.\n"]; anyErrors _ TRUE; }; IF All # NIL AND (AUleft = NIL OR ADleft = NIL) THEN { anyErrorsMessages _ Rope.Cat[anyErrorsMessages, "Tile 'All' exists but it connects to AUleft or ADleft which is missing.\n"]; anyErrors _ TRUE; }; IF Our # NIL AND OUright = NIL THEN { anyErrorsMessages _ Rope.Cat[anyErrorsMessages, "Tile 'Our' exists but it connects to OUright which is missing.\n"]; anyErrors _ TRUE; }; IF Olr # NIL AND (OUright = NIL OR ODright = NIL) THEN { anyErrorsMessages _ Rope.Cat[anyErrorsMessages, "Tile 'Olr' exists but it connects to OUright or ODright which is missing.\n"]; anyErrors _ TRUE; }; IF anyErrors THEN ERROR Error[TileSet, anyErrorsMessages]; 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]][ourTruthTable.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]][ourTruthTable.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; <<-- start of main body of module generator -->> IF context = NIL THEN ERROR Error[NoDescription, "No description was specified!"]; <<-- store parameters for tiles>> { ourParams: SymTab.Ref _ SymTab.Create[]; ExprRead.StoreInt[ourParams, "numInputs", numInputs]; ExprRead.StoreInt[ourParams, "numOutputs", numOutputs]; ExprRead.StoreInt[ourParams, "numProductTerms", numPTerms]; Parquet.CombineParameters[context, ourParams]; }; <<>> <<-- check & create input>> desc _ ReadParameters[context]; IF desc.truthTable = NIL THEN ERROR Error[NoTruthTable, "No truth table was specified!"]; <<>> <<-- optimize>> IF desc.optimize THEN ourTruthTable _ BoolOps.TTOptimize[desc.truthTable] ELSE ourTruthTable _ desc.truthTable; IF desc.dumpFile # NIL THEN DumpTruthTable[ourTruthTable, desc.dumpFile]; <<>> <<-- initialization>> LoadTiles[context]; numInputs _ ourTruthTable.numInputs; numOutputs _ ourTruthTable.numOutputs; numPTerms _ ourTruthTable.numPTerms; [constructedPLA, startOfPreviousRow] _ Parquet.NewModule[context]; <<>> <<-- create the PLA row by row, inserting extra ground rows as needed>> { noisy: BOOL _ (numPTerms > desc.printRows); 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; <<-- get the truth table from a description>> FetchTT: PUBLIC PROC [context: Parquet.Context] RETURNS [inputNames, outputNames: LIST OF Rope.ROPE, truthTable: BoolOps.TruthTable] = BEGIN 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, reversedEqnTrees: LIST OF BoolOps.Tree _ NIL; message: Rope.ROPE; allErrorMessages: Rope.ROPE _ NIL; IF inNames = NIL OR outNames = NIL THEN ERROR Error[ParameterErrors, "Both 'Inputs' and 'Outputs' must be specified."]; <<-- 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 _ NIL; t: BoolOps.Tree _ NIL; eqn _ ExprRead.FetchRope[context.parameters, outs.first, TRUE].val; IF eqn = NIL THEN { problems _ TRUE; allErrorMessages _ Rope.Cat[allErrorMessages, "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; allErrorMessages _ Rope.Cat[allErrorMessages, "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; allErrorMessages _ Rope.Cat[allErrorMessages, "Could not translate output '", outs.first, "' to sum-of-products form, error was: ", message, "\n"]; } ELSE { reversedEqnTrees _ CONS[t, reversedEqnTrees]; }; }; ENDLOOP; IF problems THEN ERROR Error[ParameterErrors, allErrorMessages]; <<-- reverse our list of equations since it is backwards>> FOR trees: LIST OF BoolOps.Tree _ reversedEqnTrees, trees.rest WHILE trees # NIL DO eqnTrees _ CONS[trees.first, eqnTrees]; ENDLOOP; <<-- create a list of atoms from the input names>> 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; <<-- make a truth table>> message _ NIL; tt _ BoolOps.SOPToTT[inAtoms, eqnTrees ! BoolOps.Error => {message _ msg; CONTINUE}]; IF message # NIL THEN ERROR Error[ParameterErrors, Rope.Cat["Could not translate equations to truth table form, error was: ", message, "\n"]]; RETURN[tt]; END; GetTTFile: PROC[] RETURNS[BoolOps.TruthTable] = BEGIN tt: BoolOps.TruthTable; ttFile: Rope.ROPE; ttStream: IO.STREAM; explanation: Rope.ROPE; ttFile _ ExprRead.FetchRope[context.parameters, "TruthTableFile", TRUE].val; IF ttFile = NIL THEN RETURN[NIL]; ttStream _ FS.StreamOpen[ttFile ! FS.Error => IF error.group = user THEN {ttStream _ NIL; CONTINUE}]; IF ttStream = NIL THEN ERROR Error[ParameterErrors, Rope.Cat["Could not open truth table file '", ttFile, "'.\n"]]; tt _ BoolOps.StreamToTT[ttStream ! BoolOps.Error => {explanation _ msg; CONTINUE}]; IF explanation # NIL THEN ERROR Error[ParameterErrors, Rope.Cat["Error in reading truth table: ", explanation, "\n"]]; RETURN[tt]; END; GetTT: PROC[] RETURNS[BoolOps.TruthTable] = BEGIN ref: REF ANY; ref _ ExprRead.FetchRefAny[context.parameters, "TruthTable", TRUE].val; IF ref = NIL THEN RETURN[NIL]; IF ~ISTYPE[ref, BoolOps.TruthTable] THEN ERROR Error[ParameterErrors, Rope.Cat["TruthTable option is not of type BoolOps.TruthTable!"]]; RETURN[NARROW[ref]]; END; EnsureSize: PROC [list: LIST OF Rope.ROPE, quantity: INT, defaultName: Rope.ROPE] RETURNS [LIST OF Rope.ROPE] = BEGIN forward, backward: LIST OF Rope.ROPE _ NIL; FOR i: INT IN [1..quantity] DO IF list # NIL THEN { backward _ CONS[list.first, backward]; list _ list.rest; } ELSE { backward _ CONS[Rope.Concat[defaultName, Convert.RopeFromInt[from: i, showRadix: FALSE]], backward]; }; ENDLOOP; FOR i: INT IN [1..quantity] DO forward _ CONS[backward.first, forward]; backward _ backward.rest; ENDLOOP; RETURN[forward]; END; <<-- get names of inputs and outputs>> inputNames _ ExprRead.FetchListOfRope[context.parameters, "Inputs", TRUE].val; outputNames _ ExprRead.FetchListOfRope[context.parameters, "Outputs", TRUE].val; <<-- get a truth table>> SELECT TRUE FROM ExprRead.FetchRope[context.parameters, "TruthTableFile", TRUE].found => truthTable _ GetTTFile[]; ExprRead.FetchRefAny[context.parameters, "TruthTable", TRUE].found => truthTable _ GetTT[]; TRUE => truthTable _ GetEQN[inputNames, outputNames]; ENDCASE; inputNames _ EnsureSize[inputNames, truthTable.numInputs, "input"]; outputNames _ EnsureSize[outputNames, truthTable.numOutputs, "output"]; END; ReadParameters: PROC [context: Parquet.Context] RETURNS [options: PLADescription] = BEGIN GetOptions: PROC[context: Parquet.Context] RETURNS[PLADescription] = BEGIN opt: PLADescription _ NEW[PLADescriptionRec]; bool: BOOL; card: CARDINAL; found: BOOL; <<-- get equations and names>> [opt.inputNames, opt.outputNames, opt.truthTable] _ FetchTT[context]; <<-- optimize?>> [found, bool] _ ExprRead.FetchBool[context.parameters, "Optimize", TRUE]; IF found THEN opt.optimize _ bool; <<-- get the number of extra rows and columns>> [found, card] _ ExprRead.FetchCardinal[context.parameters, "Extras", TRUE]; IF found THEN opt.extraRows _ opt.extraAndColumns _ opt.extraOrColumns _ card; [found, card] _ ExprRead.FetchCardinal[context.parameters, "ExtraRows", TRUE]; IF found THEN opt.extraRows _ card; [found, card] _ ExprRead.FetchCardinal[context.parameters, "ExtraColumns", TRUE]; IF found THEN opt.extraAndColumns _ opt.extraOrColumns _ card; [found, card] _ ExprRead.FetchCardinal[context.parameters, "ExtraAndColumns", TRUE]; IF found THEN opt.extraAndColumns _ card; [found, card] _ ExprRead.FetchCardinal[context.parameters, "ExtraOrColumns", TRUE]; IF found THEN opt.extraOrColumns _ card; <<-- print rows>> [found, card] _ ExprRead.FetchCardinal[context.parameters, "PrintRows", TRUE]; IF found THEN opt.printRows _ card; <<-- dump file>> opt.dumpFile _ ExprRead.FetchRope[context.parameters, "TruthTableDumpFile", TRUE].val; RETURN[opt]; END; <<>> <<-- get parameters>> options _ GetOptions[context]; IF options = NIL THEN ERROR; IF options.truthTable = NIL THEN ERROR; options.context _ context; RETURN[options]; END; MakePLAProc: Parquet.ModuleGeneratorProc = BEGIN <<-- PROC[context: Context] RETURNS [Module]>> m: Parquet.Module; errMsg: Rope.ROPE _ NIL; m _ Create[context ! Error => {errMsg _ msg; CONTINUE}]; IF errMsg # NIL THEN { TerminalIO.WriteRope[errMsg]; RETURN[NIL]; }; RETURN[m]; 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.