File: PWPLAImpl.mesa   
Copyright © 1984 by Xerox Corporation. All rights reserved.
Created by: Monier, March 14, 1985 8:57:18 pm PST
Bertrand Serlet May 28, 1986 12:10:24 pm PDT
-- Make a PLA. Borrows more than heavily from Bob Mayo's MakePLA.
General plan: Read our input table and create a description record. Use that record to build a PLA. The PLA is built by producing rows from top to bottom, inserting extra rows as needed. Each row is built left to right, and may have extra columns added as needed.
DIRECTORY
CD, CDIO, CDSymbolicObjects,
CDExpr, PW,
PWPLA, PWPLABasics, BoolOps, TerminalIO, Rope, IO, SymTab;
PWPLAImpl: CEDAR PROGRAM    
IMPORTS BoolOps, CDExpr, CDIO, CDSymbolicObjects, IO, PW, PWPLABasics, Rope, TerminalIO
EXPORTS PWPLA = BEGIN
OPEN PWPLA;
ReadParameters: PROC [fileName: ROPE] RETURNS [desc: PLADescription] =
-- read the options from a file and build a PLADescription
BEGIN
bool, found: BOOL;
int: INT;
symTab: SymTab.Ref;
ref: REF;
desc ← NEW[PLADescriptionRec];
symTab ← CDExpr.ReadFile[fileName, CDIO.GetWorkingDirectory[]]; -- turn a xxx.mg file into a symtab
desc.tileSet ← CDExpr.FetchRope[symTab, "TileSet"].val;
IF desc.tileSet = NIL THEN ERROR PWPLABasics.Error[TileSet, "TileSet not specified"];
[found, bool] ← CDExpr.FetchBool[symTab, "Optimize"];
IF found THEN desc.optimize ← bool;
[found, int] ← CDExpr.FetchInt[symTab, "Extras"];
IF found THEN desc.extraRows ← desc.extraAndColumns ← desc.extraOrColumns ← int;
[found, int] ← CDExpr.FetchInt[symTab, "ExtraRows"];
IF found THEN desc.extraRows ← int;
[found, int] ← CDExpr.FetchInt[symTab, "ExtraColumns"];
IF found THEN desc.extraAndColumns ← desc.extraOrColumns ← int;
[found, int] ← CDExpr.FetchInt[symTab, "ExtraAndColumns"];
IF found THEN desc.extraAndColumns ← int;
[found, int] ← CDExpr.FetchInt[symTab, "ExtraOrColumns"];
IF found THEN desc.extraOrColumns ← int;
[found, int] ← CDExpr.FetchInt[symTab, "PrintRows"];
IF found THEN desc.printRows ← int;
desc.dumpFile ← CDExpr.FetchRope[symTab, "TruthTableDumpFile"].val;
-- Input and Output names
ref ← CDExpr.FetchRef[symTab, "Inputs"].val;
IF ref#NIL THEN desc.inputNames ← PWPLABasics.ListRefAnyToListRope[NARROW[ref, REF LIST OF REF]^];
ref ← CDExpr.FetchRef[symTab, "Outputs"].val;
IF ref#NIL THEN desc.outputNames ← PWPLABasics.ListRefAnyToListRope[NARROW[ref, REF LIST OF REF]^] ;
-- Truth Table: One must provide either the truth table, or the equations
desc.truthTable ← PWPLABasics.FetchTT[symTab];
IF desc.truthTable # NIL THEN
BEGIN
PWPLABasics.EnsureSize[desc.inputNames, desc.truthTable.numInputs];
PWPLABasics.EnsureSize[desc.outputNames, desc.truthTable.numOutputs];
END
ELSE desc.truthTable ← PWPLABasics.GetEQN[symTab, desc.inputNames, desc.outputNames];
IF desc.truthTable = NIL THEN ERROR;
IF desc = NIL THEN ERROR;
END;
LoadTiles: PUBLIC PROC[desc: PLADescription] RETURNS [allTiles: AllTiles]=
BEGIN
whereTilesAre: CD.Design ← CDIO.ReadDesign[from: desc.tileSet, wDir: CDIO.GetWorkingDirectory[]];
-- for now, just checking the technologies
OptionalTile: PROC [name1, name2, name3: ROPENIL] RETURNS [CD.Object] =
{RETURN [PWPLABasics.OptionalTile[whereTilesAre, name1, name2, name3]]};
RequiredTile: PROC [name1, name2, name3: ROPENIL] RETURNS [CD.Object] =
{RETURN [PWPLABasics.RequiredTile[whereTilesAre, name1, name2, name3]]};
RopeList: TYPE = LIST OF ROPE;
IF whereTilesAre=NIL THEN ERROR PWPLABasics.Error[TileSet, "TileSet not found or empty"];
allTiles ← NEW[AllTilesRec ← [rowTab: NEW[ProgTileRec]]];
BEGIN OPEN allTiles;
-- left side of AND plane
Aul ← RequiredTile["Aul"];
AUleft ← OptionalTile["AUleft", "Aleft"];
ADleft ← OptionalTile["ADleft", "Aleft"];
AHleft ← OptionalTile["AHleft"];
All ← RequiredTile["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"];
-- 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;
-- extra horizontal tiles
IF desc.haveHorizontalExtras AND ~PWPLABasics.AllPresent[LIST[ALH, ARH, BH, OLH, ORH]] THEN
{PW.WriteF["Some of the extra horizontal tiles are missing.\n"];
desc.haveHorizontalExtras ← FALSE};
-- extra vertical AND plane tiles
IF desc.haveVerticalAndExtras AND ~PWPLABasics.AllPresent[LIST[AUV, ADV]] THEN
{PW.WriteF["Some of the extra vertical AND plane tiles are missing.\n"];
desc.haveVerticalAndExtras ← FALSE};
-- extra vertical OR plane tiles
IF desc.haveVerticalOrExtras AND ~PWPLABasics.AllPresent[LIST[OUV, ODV]] THEN
{PW.WriteF["Some of the extra vertical OR plane tiles are missing.\n"];
desc.haveVerticalOrExtras ← FALSE};
-- intersections between extras
IF desc.haveHorizontalExtras AND desc.haveVerticalAndExtras AND AHV = NIL
THEN PW.WriteF["Tile 'AHV' is missing.\n"];
IF desc.haveHorizontalExtras AND desc.haveVerticalOrExtras AND OHV = NIL
THEN PW.WriteF["Tile 'OHV' is missing.\n"];
END;  -- of the OPEN
END;
-- Cell assembly procedures
AssembleRows: PROC[desc: PLADescription, allTiles: AllTiles] RETURNS[pla: CD.Object] =
BEGIN
RenamePin: PROC[ob: CD.Object, old, new: ROPE] RETURNS [newOb: CD.Object] =
BEGIN
Rename: CDSymbolicObjects.InstEnumerator = {
IF Rope.Equal[CDSymbolicObjects.GetName[inst], old]
THEN CDSymbolicObjects.SetName[inst, new]};
newOb ← PW.Copy[ob];  -- just a copy
[] ← CDSymbolicObjects.EnumerateSymbolicObs[newOb, Rename];
END;
SpecialRow: PROC[left, andVert, andLeft, andRight, between, orVert, orLeft, orRight, right: CD.Object, namePins: BOOLFALSE] RETURNS [row: CD.Object] =
BEGIN
names: LIST OF ROPE;
cell, newCell: CD.Object;
tilesSinceExtra: INT;
colList: LIST OF CD.Object;
-- left column
colList ← CONS[left, NIL];
-- AND plane
tilesSinceExtra ← 0;
names ← desc.inputNames;
FOR i: INT IN [0 .. desc.truthTable.numInputs) DO
IF tilesSinceExtra+1 >= desc.extraAndColumns AND desc.haveVerticalAndExtras AND PW.EVEN[i]
THEN
{colList ← CONS[andVert, colList]; -- extra column in AND plane
tilesSinceExtra ← 0};
cell ← IF PW.EVEN[i] THEN andLeft ELSE andRight;
IF namePins THEN {
newCell ← RenamePin[cell, "In", names.first];
names ← names.rest}
ELSE newCell ← cell;
colList ← CONS[newCell, colList]; -- normal column
tilesSinceExtra ← tilesSinceExtra + 1;
ENDLOOP;
-- Between planes
colList ← CONS[between, colList];
-- OR plane
tilesSinceExtra ← 0;
names ← desc.outputNames;
FOR i: INT IN [0 .. desc.truthTable.numOutputs) DO
IF tilesSinceExtra+1 >= desc.extraOrColumns AND desc.haveVerticalOrExtras AND PW.EVEN[i]
THEN
{colList ← CONS[orVert, colList]; -- extra column in OR plane
tilesSinceExtra ← 0};
cell ← IF PW.EVEN[i] THEN orLeft ELSE orRight;
IF namePins THEN {
newCell ← RenamePin[cell, "Out", names.first];
names ← names.rest}
ELSE newCell ← cell;
colList ← CONS[newCell, colList]; -- normal
tilesSinceExtra ← tilesSinceExtra + 1;
ENDLOOP;
-- right column
colList ← CONS[right, colList];
row ← PW.AbutListX[PW.Reverse[colList]];
END;
NormalRow: PROC[rowNum: INT, left, andVert, between, orVert, right: CD.Object, rowTab: ProgTile] RETURNS[row: CD.Object] =
BEGIN
colList: LIST OF CD.Object;
tilesSinceExtra: INT;
-- left column
colList ← CONS[left, NIL];
-- AND plane
tilesSinceExtra ← 0;
FOR i: INT IN [0 .. desc.truthTable.numInputs) DO
IF tilesSinceExtra+1 >= desc.extraAndColumns AND desc.haveVerticalAndExtras AND PW.EVEN[i]
THEN
{colList ← CONS[andVert, colList]; -- extra column in AND plane
tilesSinceExtra ← 0};
colList ← CONS[ -- normal cell
rowTab[TRUE][PW.EVEN[rowNum]][PW.EVEN[i]][desc.truthTable.pterms[rowNum].bits[i]],
colList];
tilesSinceExtra ← tilesSinceExtra + 1;
ENDLOOP;
-- Between planes
colList ← CONS[between, colList];
-- OR plane
tilesSinceExtra ← 0;
FOR i: INT IN [0 .. desc.truthTable.numOutputs) DO
IF tilesSinceExtra+1 >= desc.extraOrColumns AND desc.haveVerticalOrExtras AND PW.EVEN[i]
THEN
{colList ← CONS[orVert, colList]; -- extra column in OR plane
tilesSinceExtra ← 0};
colList ← CONS[ -- normal cell
rowTab[FALSE][PW.EVEN[rowNum]][PW.EVEN[i]][desc.truthTable.pterms[rowNum].bits[i + desc.truthTable.numInputs]],
colList];
tilesSinceExtra ← tilesSinceExtra + 1;
ENDLOOP;
-- right column
colList ← CONS[right, colList];
row ← PW.AbutListX[PW.Reverse[colList]];
END;
noisy: BOOL;
rowList: LIST OF CD.Object;
rowsSinceExtra: INT ← 0;
-- create the PLA row by row, inserting extra ground rows as needed
noisy ← (desc.truthTable.numPTerms > desc.printRows);
IF noisy THEN PW.WriteF["Rows (product terms) placed: "];
-- Start with the top row
BEGIN OPEN allTiles;
rowList ← LIST [SpecialRow[Aul, AVtop, ALtop, ARtop, Btop, OVtop, OLtop, ORtop, Our, TRUE]];
-- Now the rows, from top to bottom
FOR rowIndex: INT IN [0 .. desc.truthTable.numPTerms) DO
-- if conditions are right, we add an extra ground row
IF rowsSinceExtra+1 >= desc.extraRows AND desc.haveHorizontalExtras AND PW.EVEN[rowIndex] THEN
BEGIN
rowList ← CONS[
SpecialRow[AHleft, AHV, ALH, ARH, BH, OHV, OLH, ORH, OHright],
rowList];
rowsSinceExtra ← 0;
END;
-- now we add the normal row at the bottom
rowList ← CONS[
IF PW.EVEN[rowIndex] THEN
NormalRow[rowIndex, AUleft, AUV, BU, OUV, OUright, rowTab]
ELSE NormalRow[rowIndex, ADleft, ADV, BD, ODV, ODright, rowTab],
rowList];
IF noisy THEN PW.WriteF["%g", IO.int[rowIndex + 1]];
rowsSinceExtra ← rowsSinceExtra + 1;
ENDLOOP;
-- Finally the bottom row
rowList ← CONS[
SpecialRow[All, AVbot, ALbot, ARbot, Bbot, OVbot, OLbot, ORbot, Olr],
rowList];
END;   -- OPEN allTiles
-- Assemble the cells
pla ← PW.AbutListY[rowList];
IF noisy THEN PW.WriteF[" . . . that's all.\n"];
END;
CreatePLAFromFile: PUBLIC PROC [fileName: ROPE] RETURNS [pla: CD.Object] =
BEGIN
desc: PLADescription ← ReadParameters[fileName];
allTiles: AllTiles ← LoadTiles[desc];
pla ← CreatePLA[desc, allTiles];
END;
CreatePLA: PUBLIC PROC [desc: PLADescription, allTiles: AllTiles] RETURNS [pla: CD.Object] =
BEGIN
-- Gas on
IF desc.optimize THEN
BEGIN
old, new: INT ← desc.truthTable.numPTerms;
desc.truthTable ← BoolOps.TTOptimize[desc.truthTable];
new ← desc.truthTable.numPTerms;
IF old>new
THEN PW.WriteF["The optimizer reduced the number of products terms from %g to %g\n", IO.int[old], IO.int[new]]
ELSE PW.WriteF["The optimizer did not help. \n"];
END;
IF desc.dumpFile#NIL THEN PWPLABasics.DumpTruthTable[desc.truthTable, desc.dumpFile];
-- Mixture rich
desc.haveHorizontalExtras ← desc.extraRows <= desc.truthTable.numPTerms;
desc.haveVerticalAndExtras ← desc.extraAndColumns <= desc.truthTable.numInputs;
desc.haveVerticalOrExtras ← desc.extraOrColumns <= desc.truthTable.numOutputs;
-- Carb heat off
pla ← AssembleRows[desc, allTiles];
END;
MakePLAProc: PW.UserProc =
BEGIN
-- Instrument set and trimmed
fileName: ROPE ← TerminalIO.RequestRope["File describing the PLA: "];
-- Take-off !!!
RETURN [CreatePLAFromFile[fileName]];
END;
-- register this generator with PW
PW.Register[MakePLAProc, "Make PLA"];
END.