IFUPWContPLA.mesa
Copyright c 1985 by Xerox Corporation. All rights resersed.
The tile set used by this module was derived from
/IVY/McCreight/IFUDataCells/SelfTimedPLATiles2.dale
Last Edited by: Curry, January 28, 1986 4:48:30 pm PST
Example specification file:
InstrDecode.plaSpec => InstrDecode.ttt
DIRECTORY
Basics,
CD,
CDFrame,
CDPinObjects,
IO,
PLAOps,
PW,
IFUPW,
IFUPWControl,
REFBit,
Rope,
SymTab,
ViewerClasses;
IFUPWContPLA: CEDAR PROGRAM
IMPORTS Basics, CD, CDFrame, CDPinObjects, IFUPW, IFUPWControl, IO, PLAOps, PW, REFBit, Rope
EXPORTS IFUPWControl =
BEGIN OPEN IFUPWControl;
MakePLA: PUBLIC PROC [
name:  ROPE,   plaType: PLAType, drIn, drInClk, plaIn, drOutClk, drOut: Ph←unk,
design: CD.Design, orCols: INT𡤀,  termCols: INT𡤁,
fullWidthTerms: BOOLFALSE, termsPerHeader: INT ← 1000]
RETURNS[new: Frame] = {
fileName: ROPE ← Rope.Cat["IFUPLA", name, ".ttt"];
desc: IFUPWControl.PLADescription;
plaFm, outFm, inFm: Frame;
pla:  PLAOps.PLA ← PLAOps.ReadPLAFile[fileName, log];
IF plaType = precharged AND termsPerHeader=1000 THEN termsPerHeader�
outFm ← DrPLA[name, pla, plaType, plaIn, drOutClk, drOut];
desc  ← NARROW[outFm.data];
plaFm ← DrivenPLA[ outFm, design, orCols, termCols, fullWidthTerms, termsPerHeader];
inFm  ← RefToDriverFrame[name: name.Cat["InDrs"], xory: y, data: NIL,
unordered: FALSE, refRec: pla.data,
initial: [drDir: in, dualOut: TRUE, in:[pos, drIn], ref:[pos, drInClk], out:[pos, plaIn] ] ];
IF plaType # precharged THEN DeleteUnusedStaticInDrs[desc, inFm];
new ← IFUPW.NFS[name, x, LIST[
CDFrame.Glue[l: ext, r: conn],
IFUPW.NFS[name.Cat["Main"], y, LIST[
plaFm,
IFUPW.NFS[name.Cat["InputsSBDr"], x, LIST[
CDFrame.Glue[t: conn, r: conn],
inFm ] ] ] ] ] ] };
DrPLA: PUBLIC PROC
[name: ROPE, pla: PLAOps.PLA, plaType: PLAType, plaIn, plaOut, drOut: Ph←unk]
RETURNS[new: Frame] = {
desc:  REF PLADescriptionRec ← NEW[PLADescriptionRec];
inForm:  REFBit.Format    ← REFBit.Desc[pla.data].bitForm;
outForm:  REFBit.Format    ← REFBit.Desc[pla.out].bitForm;
new ← IFUPWControl.RefToDriverFrame[
name: name, xory: y, data: desc, unordered: TRUE, refRec: pla.out,
initial: [drDir: out, in: [neg, plaOut], ref: [pos, plaOut], out: [pos, drOut] ] ];
new ← new[1]; -- throw away xheader and xfooter frames
desc.ttt  ← pla;
desc.name ← name;
desc.plaType ← plaType;
desc.drFrame ← new; -- can change
FOR i: CARDINAL DECREASING IN [0..inForm.size) DO
namePos: ROPE ← BitNameToSigName[inForm[i].name];
nameInv: ROPE ← BitNameToSigName[inForm[i].nameInv];
desc.plaInNames ← CONS[ SignalName[TRUE, namePos, nameInv, plaIn], desc.plaInNames];
desc.plaInNames ← CONS[ SignalName[FALSE, namePos, nameInv, plaIn], desc.plaInNames];
ENDLOOP;
FOR i: CARDINAL DECREASING IN [0..outForm.size) DO
namePos: ROPE ← BitNameToSigName[outForm[i].name];
nameInv: ROPE ← BitNameToSigName[outForm[i].nameInv];
desc.plaOutNames ←
CONS[ SignalName[FALSE, namePos, nameInv, plaOut], desc.plaOutNames];
ENDLOOP};
DrivenPLA: PUBLIC PROC [
drFrame: Frame,  design: CD.Design,
orCols: INT𡤀,  termCols: INT𡤁,
fullWidthTerms: BOOLFALSE, termsPerHeader: INT ← 1000]
RETURNS [new: Frame] = {
desc: REF PLADescriptionRec ← NARROW[drFrame.data];
log.PutRope["\n"];
desc.design    ← design;
desc.drFrame    ← drFrame;
desc.nofOrCols   ← MAX[orCols,    desc.nofOrCols];
desc.nofTermCols  ← MAX[termCols,   desc.nofTermCols];
desc.termsPerHeader  ← MIN[termsPerHeader,  desc.termsPerHeader];
desc.fullWidthTerms ← fullWidthTerms OR desc.fullWidthTerms;
BuildSignalOrderListFromDrFrame[desc];
BuildConnTranslationArray[desc];
SELECT desc.plaType FROM
precharged => MakePreChargedPLA[desc];
ENDCASE  => MakeStaticPLASection[desc];
new   ← CDFrame.NewFrame[2, x, desc.name.Cat["-PlaDr"] ];
new[0]  ← CDFrame.NewObjectFrame[desc.cell];
new[1]  ← desc.drFrame;
log.PutRope["\n"]};
CheckSize: PROC[obj1, obj2: CD.Object, xory: CDFrame.XorY, design: CD.Design] = {
size1: CD.Position ← CD.InterestSize[obj1];
size2: CD.Position ← CD.InterestSize[obj2];
IF (IF xory=x THEN size1.x#size2.x ELSE size1.y#size2.y) THEN {
viewer: ViewerClasses.Viewer;
log.PutRope["\n Checksize error \n"];
viewer ← CDViewer.CreateViewer[design];
CDOps.SetInstList[design, NIL];
CDOps.AddAnObject[design, obj1, [0, 0]];
CDOps.AddAnObject[design, obj2, 
[(IF xory=y THEN size1.x ELSE 0), (IF xory=x THEN size1.y ELSE 0)]];
CDViewer.ShowAndScale[viewer, CDExtras.BoundingBox[design]];
ERROR} };
BuildSignalOrderListFromDrFrame: PUBLIC PROC[desc: REF PLADescriptionRec] = {
proc: CDFrame.EnumProc = {
rec:  REF DriveRec ← NARROW[frame.data];
name:  ROPE ← BitNameToSigName[rec.name];
nameInv: ROPE ← BitNameToSigName[rec.nameInv];
desc.drSignalOrder ←
CONS[ SignalName[FALSE, name, nameInv, rec.in.ph], desc.drSignalOrder]};
CDFrame.EnumFrameBotOnly[desc.drFrame, proc];
desc.drSignalOrder ← ReverseList[desc.drSignalOrder]};
CreatePLAFromDesc: PUBLIC PROC [desc: PLADescription]
RETURNS [drives, pla: CD.Object] = {
log.PutRope["\n"];
CheckSufficientDesc[desc];
BuildConnTranslationArray[desc];
[pla, drives] ← SELECT desc.plaType FROM
static   => MakeStaticPLASection[desc],
precharged => MakePreChargedPLA[desc],
ENDCASE  => ERROR;
log.PutRope["\n"]};
IFUPWControlProc: PUBLIC PW.UserProc = {
drives, pla: CD.Object;
fileName: ROPE    ← TerminalIO.RequestRope["PLA specification file: "];
desc:  PLADescription ← ReadParameters[fileName];
CheckSufficientDesc[desc];
desc.design ← design;
[drives, pla] ← CreatePLAFromDesc[desc];
RETURN[PW.AbutX[desc.design, drives, pla]]};
See InstrDecode.plaSpec for example of a .plaSpec file.
ReadParameters: PROC [fileName: ROPE] RETURNS [desc: PLADescription] = {
symTab: SymTab.Ref ← NIL;
ref:  REF;
desc ← NEW[PLADescriptionRec ← [plaSpecFile: fileName] ];
symTab ← CDExpr.ReadFile[desc.plaSpecFile]; -- Read xxx.plaSpec
ref ← CDExpr.FetchRef[symTab, "TypedTruthTableName"].val;
IF ref = NIL OR NOT ISTYPE[ref, REF ROPE] THEN ERROR;
desc.name ← NARROW[ref, REF ROPE]^;
desc.ttt ← PLAOps.ReadPLAFile[desc.name.Cat[".ttt"]];
ref ← CDExpr.FetchRef[symTab, "InputNames"].val;
IF ref # NIL THEN desc.plaInNames ← ToRopeList[NARROW[ref]];
ref ← CDExpr.FetchRef[symTab, "OutputNames"].val;
IF ref # NIL THEN desc.plaOutNames ← ToRopeList[NARROW[ref]];
ref ← CDExpr.FetchRef[symTab, "Signals"].val;
IF ref # NIL THEN desc.drSignalOrder ← ToRopeList[NARROW[ref]]};
CheckSufficientDesc: PROC [desc: PLADescription] = {
IF desc.drFrame#NIL THEN ERROR;
IF desc.ttt=NIL THEN ERROR;
IF desc.design=NIL THEN ERROR;
IF desc.plaInNames=NIL THEN {
desc.plaInNames ← REFBit.BitNameList[ref: desc.ttt.data, both: TRUE];
FOR list: LIST OF ROPE ← desc.plaInNames, list.rest WHILE list#NIL DO
list.first ← BitNameToSigName[list.first] ENDLOOP};
IF desc.plaOutNames=NIL THEN {
desc.plaOutNames ← REFBit.BitNameList[ref: desc.ttt.out, both: FALSE];
FOR list: LIST OF ROPE ← desc.plaOutNames, list.rest WHILE list#NIL DO
list.first ← BitNameToSigName[list.first] ENDLOOP};
IF desc.drSignalOrder=NIL
THEN desc.drSignalOrder ← ListConcat[desc.plaInNames, desc.plaOutNames];
IF desc.design=NIL THEN ERROR};
BuildConnTranslationArray: PROC [desc: PLADescription ] = {
index: INT ← -1;
smlOutNames: LIST OF ROPE;
log.PutRope["\n Building pla translation array"];
desc.connSeq will contain indexes relative to the big (original) PLA
desc.connSeq ← NEW[ConnSeq[ListLength[desc.drSignalOrder]]];
FOR list: LIST OF ROPE ← desc.drSignalOrder, list.rest WHILE list#NIL DO
pos: INT ← ListItemIndex[desc.plaInNames, 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.plaOutNames, list.first];
IF pos=-1 THEN ERROR; -- Signal name not found;
smlOutNames ← CONS[list.first, smlOutNames];
desc.connSeq[index] ← [index: pos, isOutput: TRUE, isLeftSide: FALSE];
ENDLOOP;
smlOutNames  ← ReverseList[smlOutNames];
desc.smlToBigOut ← NEW[XsFormSeqRec[ListLength[smlOutNames]]];
FOR i: CARDINAL IN [0..desc.smlToBigOut.size) DO
desc.smlToBigOut[i] ← ListItemIndex[desc.plaOutNames, ListIndexItem[smlOutNames, i]]
ENDLOOP;
desc.plaOutNames ← smlOutNames;
IF desc.drFrame#NIL THEN {
index: INT ← 0;
proc: CDFrame.EnumProc = {
desc.connSeq[index].dr ← NARROW[frame.data];
index ← index+1};
CDFrame.EnumFrameBotOnly[desc.drFrame, proc]} };
ZeroUnusedTTTOutputs: PROC [desc: PLADescription ] = {
maskTerm: PLAOps.Term ← PLAOps.CopyTerm[desc.ttt.termList.begin];
log.PutRope["\n Zero unused TTT outputs"];
FOR i: CARDINAL IN [0..maskTerm.out.wdSize)
DO maskTerm.out[i] ← PLAOps.initOutQrtWz ENDLOOP;
FOR index: INT IN [0..desc.smlToBigOut.size) DO
pos: INT ← desc.smlToBigOut[index];
PLAOps.SetOutQrt[one, maskTerm, REFBit.Desc[desc.ttt.out].bitForm[pos].firstBit] ENDLOOP;
FOR term: PLAOps.Term ← desc.ttt.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 };
CheckPLACompress: PROC [desc: PLADescription ] = {
IF desc.doCompleteSum THEN {
[ ] ← PLAOps.ConvertTermListToCompleteSum[
list:    desc.ttt.termList,
addMerges:  desc.csAddMerges,
addConsensus: desc.csAddConsensus,
log:    log ]};
IF desc.doMinimization THEN {
[ ] ← PLAOps.FindAMinimalCover[
list:    desc.ttt.termList,
time:    desc.timeOutMinutes,
log:    log ]} };
ToRopeList: PROC [ refList: LIST OF REF ] RETURNS [ ropeList: LIST OF ROPE ] = {
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]} };
MakePreChargedPLA: PROC[desc: PLADescription] = {
ZeroUnusedTTTOutputs [desc];
CheckPLACompress   [desc];
DefinePLARows    [desc];
MakeOutDrs     [desc];
MakePla      [desc]};
PreChargedParams: TYPE = RECORD[
minConnSpace:  INT    ← 2,  -- SPACING rows between driver rows;
insPerExtra:   INT    ← 10,  -- SPACING cols between extra columns;
outsPerExtra:   INT    ← 10,
nextTerm:   PLAOps.Term  ← NIL, -- specific parameter
nextConn:   INT    ← 0,  -- specific parameter
rows:     REF RowsRec ← NIL ]; -- specific parameter
RowsRec:   TYPE = RECORD[SEQUENCE size: CARDINAL OF REF RowRec];
RowRec:    TYPE = RECORD[
dr:     REF DriveRec,
type:    RowType,
and:    ColSeqRef,
or:     ColSeqRef ];
ColSeqRef:   TYPE = REF ColSeqRec;
ColSeqRec:   TYPE = RECORD[SEQUENCE size: CARDINAL OF NormalCellType];
DefinePLARows: PROC [desc: PLADescription] = {
pp:   REF PreChargedParams ←
NEW[PreChargedParams ← [nextTerm: desc.ttt.termList.begin]];
firstRow:  BOOLTRUE;
index:   INT ← 0;
termUp:  BOOLTRUE;
nofOuts:  INTMAX[ListLength[desc.plaOutNames], desc.nofOrCols];
nofIns:  INT ← ListLength[desc.plaInNames];
cRowsLeft: INT ← ListLength[desc.drSignalOrder];
dRowsLeft: INT ← desc.ttt.termList.length;
hRowsLeft: INT;
dRowsLeft ← MAX[dRowsLeft, cRowsLeft*(pp.minConnSpace)];
hRowsLeft ← MAX[1, (dRowsLeft+ desc.termsPerHeader/2)/desc.termsPerHeader];
log.PutRope["\n Assign precharged pla row types"];
desc.data ← pp;
desc.nofAndCols ← nofIns/2 + (nofIns/2 -1) / pp.insPerExtra;
desc.nofOrCols ← nofOuts + (nofOuts -1) / pp.outsPerExtra;
pp.rows   ← NEW[RowsRec[cRowsLeft+dRowsLeft+2*hRowsLeft]];
WHILE hRowsLeft#0 DO-- actually one more header is appended afterwards
RperH: INT ← (cRowsLeft+dRowsLeft+hRowsLeft + hRowsLeft/2)/hRowsLeft;
IF firstRow
THEN firstRow←FALSE
ELSE {pp.rows[index] ← NextRow[desc, xheader]; index←index+1};
pp.rows[index] ← NextRow[desc, header];
index←index+1; RperH←RperH-1; hRowsLeft←hRowsLeft-1;
WHILE RperH > 0 DO
CperD, DperC: INT;
CperD ← MAX[1, (cRowsLeft + dRowsLeft/2)/dRowsLeft];
DperC ← MAX[1, (dRowsLeft + cRowsLeft/2)/cRowsLeft];
IF DperC < pp.minConnSpace OR
(CperD>1) AND (pp.minConnSpace>0) THEN ERROR;
RperH ← RperH - CperD - DperC;
WHILE CperD > 0 DO
pp.rows[index] ← NextRow[desc, conn];
index←index+1; cRowsLeft𡤌RowsLeft-1; CperD𡤌perD-1;
ENDLOOP;
termUp ← TRUE;
WHILE DperC > 0 DO
pp.rows[index] ← NextRow[desc, IF termUp THEN dataUp ELSE dataDn];
index←index+1; dRowsLeft𡤍RowsLeft-1; DperC𡤍perC-1;
termUp ← NOT termUp;
ENDLOOP;
ENDLOOP;
ENDLOOP;
IF index+1#pp.rows.size THEN ERROR;
pp.rows[index] ← NextRow[desc, footer]};
NextRow: PROC [desc: PLADescription, type: RowType] RETURNS[row: REF RowRec] = {
pp: REF PreChargedParams ← NARROW[desc.data];
andIndex, orIndex, index: INT ← 0;
data:  PLAOps.Term;
conn:  Connection;
row  ← NEW[RowRec ← [type: type]];
row.and ← NEW[ColSeqRec[desc.nofAndCols]];
IF desc.nofOrCols#0 THEN row.or ← NEW[ColSeqRec[desc.nofOrCols]];
SELECT type FROM
header   => { };
conn    => {conn ← NextConnection[desc]; row.dr ← conn.dr};
dataUp, dataDn => {
data ← NextDataTerm[desc];
row.dr ← NIL;
IF data=NIL THEN type ← row.type ← blank};
ENDCASE;
FOR index IN[0..desc.nofAndCols) DO
IF (index+1) MOD (pp.insPerExtra+1) = 0
THEN     row.and[index]  ← extra
ELSE {
SELECT type FROM
dataUp, dataDn => SELECT PLAOps.GetInQrt
[data, REFBit.Desc[desc.ttt.data].bitForm[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;
IF desc.nofOrCols#0 THEN FOR index IN[0..desc.nofOrCols) DO
IF (index+1) MOD (pp.outsPerExtra+1) = 0
THEN     row.or[index]   ← extra
ELSE {
row.or[index] ← nc;
IF orIndex < desc.smlToBigOut.size THEN {
IF (type=dataUp OR type=dataDn) AND PLAOps.GetOutQrt
[data, REFBit.Desc[desc.ttt.out].bitForm[desc.smlToBigOut[orIndex]].firstBit]=one
THEN row.or[index] ← left;
IF type=conn AND conn.isOutput AND conn.index=desc.smlToBigOut[orIndex]
THEN row.or[index] ← left };
orIndex←orIndex+1 } ENDLOOP};
NextDataTerm: PROC [desc: PLADescription] RETURNS[term: PLAOps.Term] = {
pp: REF PreChargedParams ← NARROW[desc.data];
term ← pp.nextTerm;
IF term#NIL THEN pp.nextTerm ← pp.nextTerm.next};
NextConnection: PROC [desc: PLADescription] RETURNS[conn: Connection] = {
pp: REF PreChargedParams ← NARROW[desc.data];
conn ← desc.connSeq[pp.nextConn];
pp.nextConn ← pp.nextConn+1};
MakeOutDrs: PROC[desc: PLADescription] = {
pp: REF PreChargedParams ← NARROW[desc.data];
new: Frame;
last: INT ← -1-pp.minConnSpace;
cnt: INT ← 0;
list: LIST OF Frame;
FOR driverIndex: INT IN [0..pp.rows.size) DO
SELECT pp.rows[driverIndex].type FROM
header, xheader, footer => {
IF (driverIndex-last) <= pp.minConnSpace THEN ERROR;
last ← driverIndex-pp.minConnSpace};
blank, dataUp, dataDn  => {
IF (driverIndex-last) <= pp.minConnSpace THEN LOOP};
conn       => {
IF (driverIndex-last) <= pp.minConnSpace THEN ERROR;
last ← driverIndex}
ENDCASE => ERROR;
list ← CONS[CDFrame.NewObjectFrame[ DriverCell
[precharged, pp.rows[driverIndex].type, pp.rows[driverIndex].dr, desc.design]], list];
cnt ← cnt+1;
ENDLOOP;
new ← CDFrame.NewFrame[cnt, y, desc.name.Cat["-OutDr"]];
FOR ii: INT IN [0..cnt) DO new[ii] ← list.first; list ← list.rest ENDLOOP;
desc.drFrame ← new};
MakePla: PROC[desc: PLADescription] = {
tiles: REF TileVarieties ← GetPLATiles[ ];
pp: REF PreChargedParams ← NARROW[desc.data];
refPhase: Ph ← unk;
rowList: PW.ListOb ← NIL;
log.PutRope["\n Assemble precharged pla row cells"];
FOR rowIndex: INT IN [0..pp.rows.size) DO
objects: PW.ListOb ← NIL;
row: REF RowRec ← pp.rows[rowIndex];
IF pp.rows[rowIndex].dr#NIL THEN refPhase ← pp.rows[rowIndex].dr.ref.ph;
objects ← CONS[tiles.glue[row.type][leftSide], objects];
FOR index: INT IN [0..row.and.size) DO
objects ← CONS[tiles.and[row.type][row.and[index]], objects] ENDLOOP;
IF desc.nofOrCols#0 THEN {
objects ← CONS[tiles.glue[row.type][between], objects];
FOR index: INT IN [0..row.or.size) DO
objects ← CONS[tiles.or[row.type][row.or[index]], objects] ENDLOOP;
objects ← CONS[tiles.glue[row.type][rightSide], objects] };
rowList ← CONS[PW.AbutListX[desc.design, PW.Reverse[objects]], rowList]
ENDLOOP;
desc.cell ← PW.AbutListY[desc.design, rowList];
ReNamePLAInputPins[desc]};
ReNamePLAInputPins: PROC[desc: PLADescription] = {
pp: REF PreChargedParams ← NARROW[desc.data];
tiles: REF TileVarieties ← GetPLATiles[ ];
format:  REFBit.Format ← REFBit.Desc[desc.ttt.data].bitForm;
leftSize:  INTCD.InterestSize[tiles.glue[blank][leftSide]].x;
andWidth: INTCD.InterestSize[tiles.and[blank][nc]].x;
extraWidth: INTCD.InterestSize[tiles.and[blank][extra]].x;
renameProc: IFUPW.PinNameProc ~ {
list: LIST OF ROPE ← desc.plaInNames;
index: INT;
oldRope: Rope.ROPE ← CDPinObjects.GetName[pin];
in0: BOOL ← Rope.Equal[oldRope, "in0"];
in1: BOOL ← Rope.Equal[oldRope, "in1"];
IF NOT(in0 OR in1) THEN RETURN[oldRope];
index ← (pin.location.x - leftSize)/(pp.insPerExtra*andWidth+extraWidth);
index ← (pin.location.x - leftSize - extraWidth*index)/andWidth;
WHILE index#0 DO list ← list.rest.rest; index ← index-1 ENDLOOP;
name ← IF in1 THEN list.rest.first ELSE list.first};
desc.cell ← IFUPW.RenameObjAndPins[desc.design, desc.cell, desc.name, renameProc] };
plaTilesDesign: CD.Design;
tileBuffer:  REF TileVarieties;
TileVarieties:  TYPE = RECORD[glue: REF GlueTiles, and, or: REF NormalTiles];
GlueTiles:  TYPE = ARRAY RowType OF ARRAY GlueCellType  OF CD.Object;
GlueCellType: TYPE = {leftSide, between, rightSide};
NormalTiles:  TYPE = ARRAY RowType OF ARRAY NormalCellType OF CD.Object;
NormalCellType: TYPE = {left, right, nc, extra};
GetPLATiles: PROC RETURNS[tiles: REF TileVarieties] = {
tDesign: CD.Design;
IF tileBuffer#NIL THEN RETURN[tileBuffer];
log.PutRope["\n Initialize precharged PLA tiles"];
tDesign ← plaTilesDesign← PW.OpenDesign["IFUPWControl.dale"];
IF tDesign=NIL THEN
ERROR PW.Error[MissingDesign, "TileSet design not found or empty"];
tiles  ← tileBuffer ← NEW[TileVarieties];
tiles.glue ← NEW[GlueTiles];
tiles.and ← NEW[NormalTiles];
tiles.or ← NEW[NormalTiles];
tiles.glue [xheader][leftSide] ← PW.Get[design: tDesign, name: "XLeftSide" ];
tiles.glue [xheader][between] ← PW.Get[design: tDesign, name: "XBetween" ];
tiles.glue [xheader][rightSide] ← PW.Get[design: tDesign, name: "XOrEx" ];
tiles.and [xheader][nc]  ← PW.Get[design: tDesign, name: "XAnd" ];
tiles.and [xheader][extra]  ← PW.Get[design: tDesign, name: "XAndEx" ];
tiles.or [xheader][nc]  ← PW.Get[design: tDesign, name: "XOr" ];
tiles.or [xheader][extra]  ← PW.Get[design: tDesign, name: "XOrEx" ];
tiles.glue [header][leftSide] ← PW.Get[design: tDesign, name: "HLeftSide" ];
tiles.glue [header][between] ← PW.Get[design: tDesign, name: "HBetween" ];
tiles.glue [header][rightSide] ← PW.Get[design: tDesign, name: "HOrEx" ];
tiles.and [header][nc]   ← PW.Get[design: tDesign, name: "HAnd" ];
tiles.and [header][extra]  ← PW.Get[design: tDesign, name: "HAndEx" ];
tiles.or [header][nc]   ← PW.Get[design: tDesign, name: "HOr" ];
tiles.or [header][extra]  ← PW.Get[design: tDesign, name: "HOrEx" ];
tiles.glue [footer][leftSide]  ← PW.FlipY[tDesign, tiles.glue [header][leftSide] ];
tiles.glue [footer][between] ← PW.FlipY[tDesign, tiles.glue [header][between] ];
tiles.glue [footer][rightSide] ← PW.FlipY[tDesign, tiles.glue [header][rightSide] ];
tiles.and [footer][nc]   ← PW.FlipY[tDesign, tiles.and [header][nc]   ];
tiles.and [footer][extra]  ← PW.FlipY[tDesign, tiles.and [header][extra]  ];
tiles.or [footer][nc]   ← PW.FlipY[tDesign, tiles.or [header][nc]   ];
tiles.or [footer][extra]  ← PW.FlipY[tDesign, tiles.or [header][extra]  ];
tiles.glue [blank][leftSide]  ← PW.Get[design: tDesign, name: "BLeftSide" ];
tiles.glue [blank][between] ← PW.Get[design: tDesign, name: "BBetween" ];
tiles.glue [blank][rightSide] ← PW.Get[design: tDesign, name: "BOrEx" ];
tiles.and [blank][nc]   ← PW.Get[design: tDesign, name: "BAnd" ];
tiles.and [blank][extra]  ← PW.Get[design: tDesign, name: "BAndEx" ];
tiles.or [blank][nc]   ← PW.Get[design: tDesign, name: "BOr" ];
tiles.or [blank][extra]  ← PW.Get[design: tDesign, name: "BOrEx" ];
tiles.glue [conn][leftSide]  ← PW.Get[design: tDesign, name: "BLeftSide" ];
tiles.glue [conn][between]  ← PW.Get[design: tDesign, name: "BBetween" ];
tiles.glue [conn][rightSide] ← PW.Get[design: tDesign, name: "CRightSide" ];
tiles.and [conn][left]   ← PW.Get[design: tDesign, name: "CAndLt" ];
tiles.and [conn][right]  ← PW.Get[design: tDesign, name: "CAndRt" ];
tiles.and [conn][nc]   ← PW.Get[design: tDesign, name: "BAnd" ];
tiles.and [conn][extra]   ← PW.Get[design: tDesign, name: "BAndEx" ];
tiles.or [conn][left]   ← PW.Get[design: tDesign, name: "COr" ];
tiles.or [conn][nc]   ← PW.Get[design: tDesign, name: "COrNC" ];
tiles.or [conn][extra]   ← PW.Get[design: tDesign, name: "COrEx" ];
tiles.glue [dataUp][leftSide] ← PW.Get[design: tDesign, name: "DLeftSide" ];
tiles.glue [dataUp][between] ← PW.Get[design: tDesign, name: "DBetween" ];
tiles.glue [dataUp][rightSide] ← PW.Get[design: tDesign, name: "DRightSide" ];
tiles.and [dataUp][left]  ← PW.Get[design: tDesign, name: "DAndLt" ];
tiles.and [dataUp][right]  ← PW.Get[design: tDesign, name: "DAndRt" ];
tiles.and [dataUp][nc]   ← PW.Get[design: tDesign, name: "DAnd" ];
tiles.and [dataUp][extra]  ← PW.Get[design: tDesign, name: "DAndEx" ];
tiles.or [dataUp][left]  ← PW.Get[design: tDesign, name: "DOr" ];
tiles.or [dataUp][nc]   ← PW.Get[design: tDesign, name: "DOrNC" ];
tiles.or [dataUp][extra]  ← PW.Get[design: tDesign, name: "DOrEx" ];
tiles.glue [dataDn][leftSide] ←      tiles.glue [dataUp][leftSide];
tiles.glue [dataDn][between] ←      tiles.glue [dataUp][between];
tiles.glue [dataDn][rightSide] ← PW.FlipY[tDesign, tiles.glue [dataUp][rightSide] ];
tiles.and [dataDn][left]  ←      tiles.and [dataUp][left];
tiles.and [dataDn][right]  ←      tiles.and [dataUp][right];
tiles.and [dataDn][nc]   ←      tiles.and [dataUp][nc];
tiles.and [dataDn][extra]  ←      tiles.and [dataUp][extra];
tiles.or [dataDn][left]  ← PW.FlipY[tDesign, tiles.or [dataUp][left]  ];
tiles.or [dataDn][nc]   ← PW.FlipY[tDesign, tiles.or [dataUp][nc]   ];
tiles.or [dataDn][extra]  ← PW.FlipY[tDesign, tiles.or [dataUp][extra]  ];
RETURN[tiles]};
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, FALSE] 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};
log: IO.STREAM ← CDFrame.GetLog[];
PW.Register[userProc: IFUPWControlProc, name: "IFUPWControl"];
END.