PWPLAStackImpl:
CEDAR
PROGRAM
IMPORTS Basics, CDExpr, PLAOps, PW, REFBit, Rope, TerminalIO, ViewerIO, ViewerOps
EXPORTS PWPLAStack =
BEGIN OPEN PWPLAStack;
CreatePLAFromDesc:
PUBLIC PROC [desc: PLADescription]
RETURNS [plaCell:
CD.Object] = {
BuildConnDescArraysAndReducePLA[desc];
LoadTiles[desc];
DefineRows[desc];
plaCell ← AssembleRows[desc]};
PWPLAStackProc:
PUBLIC
PW.UserProc = {
fileName: ROPE ← TerminalIO.RequestRope["PLA specification file: "];
desc: PLADescription ← ReadParameters[fileName];
desc.design ← design;
RETURN[CreatePLAFromDesc[desc]]};
See InstrDecode.plaSpec for example of a .plaSpec file.
ReadParameters:
PROC [fileName:
ROPE]
RETURNS [desc: PLADescription] = {
ref: REF;
desc ← NEW[PLADescriptionRec ← [plaSpecFile: fileName] ];
desc.symTab ← CDExpr.ReadFile[desc.plaSpecFile]; -- Read xxx.plaSpec
ref ← CDExpr.FetchRef[desc.symTab, "TypedTruthTableFile"].val;
IF ref = NIL OR NOT ISTYPE[ref, REF ROPE] THEN ERROR;
desc.tttFile ← NARROW[ref, REF ROPE]^;
desc.pla ← PLAOps.ReadPLAFile[desc.tttFile !
PLAOps.InvalidTermRope => RESUME ];
desc.pla.iForm ← REFBit.Desc[desc.pla.data].bitForm;
desc.pla.oForm ← REFBit.Desc[desc.pla.out].bitForm;
desc.inputNames ← ListDoubleIns[REFBit.BitNameList[desc.pla.data]];
desc.outputNames ← REFBit.BitNameList[desc.pla.out];
ref ← CDExpr.FetchRef[desc.symTab, "Signals"].val;
IF ref #
NIL
THEN {
IF NOT ISTYPE[ref, LIST OF REF] THEN ERROR;
desc.signalOrder ← ToRopeList[NARROW[ref]]}
ELSE desc.signalOrder ← ListConcat[desc.inputNames, desc.outputNames];
Check for renaming parameters and renamed signals
ref ← CDExpr.FetchRef[desc.symTab, "Params"].val;
IF ref = NIL OR NOT ISTYPE[ref, PLAParams] THEN ERROR;
desc.param ← NARROW[ref];
IF desc.param.tileSet = NIL OR NOT ISTYPE[desc.param.tileSet, ROPE] THEN ERROR};
BuildConnDescArraysAndReducePLA:
PROC [desc: PLADescription ] = {
index: INT ← -1;
maskTerm: PLAOps.Term ← PLAOps.CopyTerm[desc.pla.termList.begin];
actualOutNames: LIST OF ROPE;
PW.Output["Working on connection list . . . "];
desc.connSeq will contain indexes relative to the big (original) PLA
desc.connSeq ← NEW[ConnSeqRec[ListLength[desc.signalOrder]]];
FOR i:
CARDINAL
IN [0..maskTerm.out.wdSize)
DO maskTerm.out[i] ← PLAOps.initOutQrtWz ENDLOOP;
FOR list:
LIST
OF
ROPE ← desc.signalOrder, list.rest
WHILE list#
NIL
DO
pos: INT ← ListItemIndex[desc.inputNames, list.first];
index ← index+1;
IF pos#-1
THEN {
desc.connSeq[index] ← [index: pos/2, isOutput: FALSE, isLeftSide: (pos MOD 2 = 0)];
LOOP};
pos ← ListItemIndex[desc.outputNames, list.first];
IF pos=-1 THEN ERROR; -- Signal name not found;
actualOutNames ← CONS[list.first, actualOutNames];
PLAOps.SetOutQrt[one, maskTerm, desc.pla.oForm[pos].firstBit];
desc.connSeq[index] ← [index: pos, isOutput: TRUE, isLeftSide: FALSE];
ENDLOOP;
desc.smlToBigOut will contain output indexes relative to the big (original) PLA
actualOutNames ← ReverseList[actualOutNames];
desc.smlToBigOut ←
NEW[XsFormSeqRec[ListLength[actualOutNames]]];
FOR i:
CARDINAL
IN [0..desc.smlToBigOut.size)
DO
desc.smlToBigOut[i] ← ListItemIndex[desc.outputNames,ListIndexItem[actualOutNames,i]]
ENDLOOP;
Zero Unused Outputs in the pla
desc.outputNames ← actualOutNames;
FOR term: PLAOps.Term ← desc.pla.termList.begin, term.next
WHILE term#
NIL
DO
FOR i:
CARDINAL
IN [0..maskTerm.out.wdSize)
DO
term.out[i].d ← Basics.BITAND[term.out[i].d, maskTerm.out[i].d] ENDLOOP ENDLOOP;
PW.Output["done\n"];
Compute complete sum for this new pla
IF desc.param.doCompleteSum
THEN {
viewerName: ROPE ← "PWPLAStack Complete Sum Log";
log: IO.STREAM ← ViewerIO.CreateViewerStreams[viewerName].out;
[ ] ← PLAOps.
ConvertTermListToCompleteSum[
list: desc.pla.termList,
addMerges: desc.param.csAddMerges,
addConsensus: desc.param.csAddConsensus,
log: log ];
log.Close[];
ViewerOps.DestroyViewer[ViewerOps.FindViewer[viewerName]]};
Minimize it.
IF desc.param.doMinimization
THEN {
viewerName: ROPE ← "PWPLAStack Minimization Log";
log: IO.STREAM ← ViewerIO.CreateViewerStreams[viewerName].out;
[ ] ← PLAOps.FindAMinimalCover[
list: desc.pla.termList,
time: desc.param.timeOutMinutes,
log: log ];
log.Close[];
ViewerOps.DestroyViewer[ViewerOps.FindViewer[viewerName]]};
desc.nextTerm ← desc.pla.termList.begin };
ToRopeList:
PROC [ refList:
LIST
OF
REF ]
RETURNS [ ropeList: RopeList ] = {
FOR l:
LIST
OF
REF ← refList, l.rest
UNTIL l =
NIL
DO
IF l.first # NIL AND NOT ISTYPE[l.first, ROPE] THEN ERROR;
ENDLOOP;
TRUSTED {ropeList ← LOOPHOLE[refList]} };
LoadTiles:
PROC [desc: PLADescription ] = {
OPEN desc;
tileDefDesign ← PW.OpenDesign[param.tileSet];
IF tileDefDesign=
NIL
THEN
ERROR PW.Error[MissingDesign, "TileSet design not found or empty"];
PW.Output["Setting up tiles\n"];
glueTiles ← NEW[GlueTilesRec];
andTiles ← NEW[NormalTilesRec];
orTiles ← NEW[NormalTilesRec];
glueTiles [header][leftSide] ← PW.Get[source: tileDefDesign, name: "HLeftSide" ];
glueTiles [header][between] ← PW.Get[source: tileDefDesign, name: "HBetween" ];
glueTiles [header][rightSide] ← PW.Get[source: tileDefDesign, name: "HOrEx" ];
andTiles [header][nc] ← PW.Get[source: tileDefDesign, name: "HAnd" ];
andTiles [header][extra] ← PW.Get[source: tileDefDesign, name: "HAndEx" ];
orTiles [header][nc] ← PW.Get[source: tileDefDesign, name: "HOr" ];
orTiles [header][extra] ← PW.Get[source: tileDefDesign, name: "HOrEx" ];
glueTiles [conn][leftSide] ← PW.Get[source: tileDefDesign, name: "CLeftSide" ];
glueTiles [conn][between] ← PW.Get[source: tileDefDesign, name: "CBetween" ];
glueTiles [conn][rightSide] ← PW.Get[source: tileDefDesign, name: "CRightSide" ];
andTiles [conn][left] ← PW.Get[source: tileDefDesign, name: "CAndLt" ];
andTiles [conn][right] ← PW.Get[source: tileDefDesign, name: "CAndRt" ];
andTiles [conn][nc] ← PW.Get[source: tileDefDesign, name: "CAndNC" ];
andTiles [conn][extra] ← PW.Get[source: tileDefDesign, name: "CAndEx" ];
orTiles [conn][left] ← PW.Get[source: tileDefDesign, name: "COr" ];
orTiles [conn][nc] ← PW.Get[source: tileDefDesign, name: "COrNC" ];
orTiles [conn][extra] ← PW.Get[source: tileDefDesign, name: "COrEx" ];
glueTiles [dataUp][leftSide] ← PW.Get[source: tileDefDesign, name: "DLeftSide" ];
glueTiles [dataUp][between] ← PW.Get[source: tileDefDesign, name: "DBetween" ];
glueTiles [dataUp][rightSide] ← PW.Get[source: tileDefDesign, name: "DRightSide" ];
andTiles [dataUp][left] ← PW.Get[source: tileDefDesign, name: "DAndLt" ];
andTiles [dataUp][right] ← PW.Get[source: tileDefDesign, name: "DAndRt" ];
andTiles [dataUp][nc] ← PW.Get[source: tileDefDesign, name: "DAndNC" ];
andTiles [dataUp][extra] ← PW.Get[source: tileDefDesign, name: "DAndEx" ];
orTiles [dataUp][left] ← PW.Get[source: tileDefDesign, name: "DOr" ];
orTiles [dataUp][nc] ← PW.Get[source: tileDefDesign, name: "DOrNC" ];
orTiles [dataUp][extra] ← PW.Get[source: tileDefDesign, name: "DOrEx" ];
glueTiles [dataDn][leftSide] ← glueTiles [dataUp][leftSide];
glueTiles [dataDn][between] ← glueTiles [dataUp][between];
glueTiles [dataDn][rightSide] ← PW.FlipY[tileDefDesign, glueTiles [dataUp][rightSide] ];
andTiles [dataDn][left] ← andTiles [dataUp][left];
andTiles [dataDn][right] ← andTiles [dataUp][right];
andTiles [dataDn][nc] ← andTiles [dataUp][nc];
andTiles [dataDn][extra] ← andTiles [dataUp][extra];
orTiles [dataDn][left] ← PW.FlipY[tileDefDesign, orTiles [dataUp][left] ];
orTiles [dataDn][nc] ← PW.FlipY[tileDefDesign, orTiles [dataUp][nc] ];
orTiles [dataDn][extra] ← PW.FlipY[tileDefDesign, orTiles [dataUp][extra] ];
};
DefineRows:
PROC [desc: PLADescription] = {
index: INT ← 0;
termUp: BOOL ← TRUE;
nofIns: INT ← ListLength[desc.inputNames];
nofOuts: INT ← ListLength[desc.outputNames];
cRowsLeft: INT ← nofIns + nofOuts;
dRowsLeft: INT ← desc.pla.termList.length;
hRowsLeft: INT ← 2 + (dRowsLeft + cRowsLeft -1) / desc.param.rowsPerHeader;
CheckHead:
PROC
RETURNS[ loop:
BOOL ] = {
IF index+1 # desc.nofRows
AND
index MOD (desc.param.rowsPerHeader+1) # 0 THEN RETURN[FALSE];
desc.rows[index] ← NextRow[desc, header];
hRowsLeft ← hRowsLeft - 1;
index ← index + 1;
RETURN[TRUE]};
PW.Output["Assign row types\n"];
desc.nofAndCols ← nofIns/2 + (nofIns/2 -1) / desc.param.insPerExtra;
desc.nofOrCols ← nofOuts + (nofOuts -1) / desc.param.outsPerExtra;
desc.nofRows ← dRowsLeft + cRowsLeft + hRowsLeft;
desc.rows ← NEW[RowsRec[desc.nofRows]];
WHILE index < desc.nofRows
DO
CperD, DperC: INT;
IF CheckHead[] THEN LOOP;
CperD ← MAX[1, (cRowsLeft + dRowsLeft/2)/dRowsLeft];
DperC ← MAX[1, (dRowsLeft + cRowsLeft/2)/cRowsLeft];
WHILE CperD > 0
DO
IF CheckHead[] THEN LOOP;
desc.rows[index] ← NextRow[desc, conn];
index ← index + 1;
cRowsLeft ← cRowsLeft - 1;
CperD ← CperD - 1;
ENDLOOP;
termUp ← TRUE;
WHILE DperC > 0
DO
IF CheckHead[] THEN LOOP;
desc.rows[index] ← NextRow[desc, IF termUp THEN dataUp ELSE dataDn];
index ← index + 1;
dRowsLeft ← dRowsLeft - 1;
DperC ← DperC - 1;
termUp ← NOT termUp;
ENDLOOP;
ENDLOOP };
NextRow:
PROC [desc: PLADescription, type: RowType]
RETURNS[row: RowRef] = {
andIndex, orIndex, index: INT ← 0;
data: PLAOps.Term;
conn: Connection;
SELECT type
FROM
dataUp, dataDn => data ← NextDataTerm[desc];
conn => conn ← NextConnection[desc]; ENDCASE;
row ← NEW[RowRec ← [type: type]];
row.and ← NEW[ColSeqRec[desc.nofAndCols]];
row.or ← NEW[ColSeqRec[desc.nofOrCols]];
FOR index
IN[0..desc.nofAndCols)
DO
IF (index+1)
MOD (desc.param.insPerExtra+1) = 0
THEN row.and[index] ← extra
ELSE {
SELECT type
FROM
dataUp, dataDn =>
SELECT PLAOps.GetInQrt
[data, desc.pla.iForm[andIndex].firstBit]
FROM
zero => row.and[index] ← left;
one => row.and[index] ← right;
ENDCASE => row.and[index] ← nc;
conn =>
IF conn.isOutput
OR conn.index#andIndex
THEN row.and[index] ← nc
ELSE
IF conn.isLeftSide
THEN row.and[index] ← left
ELSE row.and[index] ← right;
ENDCASE => row.and[index] ← nc;
andIndex𡤊ndIndex+1 } ENDLOOP;
FOR index
IN[0..desc.nofOrCols)
DO
IF (index+1)
MOD (desc.param.outsPerExtra+1) = 0
THEN row.or[index] ← extra
ELSE {
SELECT type
FROM
dataUp, dataDn =>
SELECT PLAOps.GetOutQrt
[data, desc.pla.oForm[desc.smlToBigOut[orIndex]].firstBit]
FROM
one => row.or[index] ← left;
ENDCASE => row.or[index] ← nc;
conn =>
IF conn.isOutput
AND conn.index=desc.smlToBigOut[orIndex]
THEN row.or[index] ← left
ELSE row.or[index] ← nc;
ENDCASE => row.or[index] ← nc;
orIndex←orIndex+1 } ENDLOOP};
NextDataTerm:
PROC [desc: PLADescription]
RETURNS[term: PLAOps.Term] = {
term ← desc.nextTerm;
desc.nextTerm ← desc.nextTerm.next};
NextConnection:
PROC [desc: PLADescription]
RETURNS[conn: Connection] = {
conn ← desc.connSeq[desc.nextConn];
desc.nextConn ← desc.nextConn+1};
TestRow: INT ← -1;
AssembleRows:
PROC[desc: PLADescription]
RETURNS[pla:
CD.Object] = {
rowList: PW.ListOb ← NIL;
PW.Output["Assemble row cells\n"];
FOR rowIndex:
INT
IN [0..desc.nofRows)
DO
objects: PW.ListOb ← NIL;
row: RowRef ← desc.rows[rowIndex];
IF TestRow=rowIndex THEN {TestRow←TestRow};
objects ← CONS[desc.glueTiles[row.type][leftSide], objects];
FOR index:
INT
IN [0..row.and.size)
DO
objects ← CONS[desc.andTiles[row.type][row.and[index]], objects] ENDLOOP;
objects ← CONS[desc.glueTiles[row.type][between], objects];
FOR index:
INT
IN [0..row.or.size)
DO
objects ← CONS[desc.orTiles[row.type][row.or[index]], objects] ENDLOOP;
objects ← CONS[desc.glueTiles[row.type][rightSide], objects];
rowList ← CONS[PW.AbutListX[desc.design, PW.Reverse[objects]], rowList]
ENDLOOP;
PW.Output["Assemble PLA\n"];
pla ← PW.AbutListY[desc.design, rowList] };
ReverseList:
PUBLIC
PROC [list:
LIST
OF
ROPE]
RETURNS [new:
LIST
OF
ROPE] =
{FOR list ← list, list.rest WHILE list#NIL DO new ← CONS[list.first, new] ENDLOOP};
ListLength:
PUBLIC
PROC [list:
LIST
OF ROPE]
RETURNS[size:
INT] =
{FOR size ← 0, size+1 WHILE list#NIL DO list←list.rest ENDLOOP};
ListIndexItem:
PUBLIC
PROC [list:
LIST
OF ROPE, index:
INT]
RETURNS[item:
ROPE] = {
FOR index ← index, index-1 WHILE index#0 AND list#NIL DO list←list.rest ENDLOOP;
RETURN[IF list=NIL THEN NIL ELSE list.first]};
ListItemIndex:
PUBLIC
PROC [list:
LIST
OF ROPE, item:
ROPE]
RETURNS[index:
INT] = {
IF item=NIL THEN RETURN[-1];
FOR index ← 0, index+1
WHILE list#
NIL
DO
IF Rope.Equal[list.first, item] THEN RETURN[index];
list←list.rest ENDLOOP;
RETURN[-1]};
ListConcat:
PUBLIC
PROC [list1, list2:
LIST
OF ROPE]
RETURNS[new: LIST OF ROPE] = {
FOR i:
INT
DECREASING
IN [0..ListLength[list2])
DO
new ← CONS[ ListIndexItem[list2, i], new] ENDLOOP;
FOR i:
INT
DECREASING
IN [0..ListLength[list1])
DO
new ← CONS[ ListIndexItem[list1, i], new] ENDLOOP};
ListDoubleIns:
PUBLIC
PROC [list:
LIST
OF ROPE]
RETURNS[new: LIST OF ROPE] = {
FOR i:
INT
DECREASING
IN [0..ListLength[list])
DO
new ← CONS[ ListIndexItem[list, i].Cat["'"], new];
new ← CONS[ ListIndexItem[list, i], new] ENDLOOP};
Random Notes:
Conditionals for pretty wiring is expensive (new object each time).
May want to do wiring directly.
May want to do everything but the header cells directly.
Apply signalNames to pins using PWPins deep enumeration stuff;
Decide on scheme for specifying which side gets wired;
Input contacts on top and bottom;
No output contacts on top and bottom;
Add drivers and buffers to left (right) side;
How about leaving a reference to `MakeDistributedPLA' and (version stamped?) pointers to the .plaSpec, .ttt and .dale files on the CD.object as the property $ReGenerateRef.
Remember to do the reordering and renaming stuff
Using CCxxx cells would save 6*nofInputPairs microns (.24 mm for the big pla) in height but would put the inputs out the left side very closely spaced.
PW.Register [userProc: PWPLAStackProc, name: "PWPLAStack" ];
END.