File: MakePLAImpl.mesa   
Copyright © 1984 by Xerox Corporation. All rights reserved.
Created by: Bob July 30, 1984 11:36:59 am PDT PDT
Last Edited by: Mayo, August 6, 1984 7:19:06 pm PDT
Make a PLA. This module is documented in MakePLATileDoc.sil and in the user's manual.
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.ROPENIL,
truthTable: BoolOps.TruthTable ← NIL,
extraRows, extraAndColumns, extraOrColumns: CARDINALCARDINAL.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: BOOLTRUE;
numInputs, numOutputs, numPTerms: INT;
constructedPLA: Parquet.Module ← NIL;
startOfPreviousRow: Parquet.PlacedTile;
inputNames, outputNames: LIST OF Rope.ROPENIL;
-- 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.ROPENIL;
OrBlock: Rope.ROPENIL;
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: BOOLFALSE;
everthingIsJustFineAndDandy: BOOLTRUE;
GetTile: PROC[name1, name2, name3: Rope.ROPENIL, 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.ROPENIL] RETURNS [Parquet.Tile] = BEGIN
RETURN[GetTile[name1, name2, name3, TRUE]];
END;
OptionalTile: PROC[name1, name2, name3: Rope.ROPENIL] 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: BOOLFALSE;
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: INTMAX[1, maxCellSize / MAX[numInputs, numOutputs, 1]];
blocksPerChunk: INT ← -1;
AndChunk, OrChunk: Rope.ROPENIL;
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: BOOLFALSE;
inAtoms, reverseAtoms: LIST OF ATOMNIL;
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.ROPENIL;
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.