PWPLAStackImpl.mesa
Copyright © 1985 by Xerox Corporation. All rights resersed.
Originally: /IVY/McCreight/IFUDataCells/
PWMergedPLAImpl.mesa
SelfTimedPLATiles2.dale
PLAExample3.pla
Last Edited by: Curry, September 3, 1985 8:14:40 am PDT
This module builds self timed PLA's by stacking up rows of one of four types {preChargeHeader, input contact, output contact, or term}. This allows inputs and outputs to be intermixed in any order along one side. The layout format enables PLA's above and below to also use the same set of inputs. Therefore it is not required that each PLA provide input contacts to all the inputs used.
Example specification file:
InstrDecode.plaSpec => InstrDecode.ttt
DIRECTORY
Basics,
CD,
CDExpr,
IO,
PLAOps,
PW,
PWPLAStack,
REFBit,
Rope,
SymTab,
TerminalIO,
ViewerIO,
ViewerOps;
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:  BOOLTRUE;
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
ELSEIF 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.