IFUPWContAlps.mesa
Copyright © 1985 by Xerox Corporation. All rights resersed.
Last Edited by: Curry, October 3, 1985 1:44:09 pm PDT
DIRECTORY
Basics,
CD,
CDExpr,
CDPinObjects,
IO,
PLAOps,
PW,
IFUPW,
IFUPWControl,
REFBit,
Rope,
SymTab,
TerminalIO,
ViewerIO;
IFUPWContALPs: CEDAR PROGRAM
IMPORTS Basics, CDExpr, CDPinObjects, IFUPW, IFUPWControl, IO, PLAOps, PW, REFBit, Rope, TerminalIO, ViewerIO
EXPORTS IFUPWControl =
BEGIN OPEN IFUPWControl;
CreateAlpsFromDrivers: PUBLIC PROC [desc: PLADescription, log: IO.STREAM]
RETURNS [drives, pla: CD.Object] = {
CheckSufficientDesc[desc];
BuildConnTranslationArray[desc];
ZeroUnusedTTTOutputs[desc];
CheckPLACompress[desc, log];
LoadPLATiles[desc];
DefinePLARows[desc];
drives  ← AssembleDrivers[desc];
pla  ← AssembleRows[desc] };
IFUPWControlProc: PUBLIC PW.UserProc = {
logName: Rope.ROPE;
log:  IO.STREAM;
drives, pla: CD.Object;
fileName: ROPE    ← TerminalIO.RequestRope["PLA specification file: "];
desc:  PLADescription ← ReadParameters[fileName];
CheckSufficientDesc[desc];
desc.design ← design;
logName ← fileName.Cat[".log"];
log  ← ViewerIO.CreateViewerStreams[logName, NIL, logName].out;
[drives, pla] ← CreatePLAFromDesc[desc, log];
RETURN[PW.AbutX[desc.design, drives, pla]]};
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.ttt ← PLAOps.ReadPLAFile[desc.tttFile];
ref ← CDExpr.FetchRef[desc.symTab, "InputNames"].val;
IF ref # NIL THEN desc.plaInNames ← ToRopeList[NARROW[ref]];
ref ← CDExpr.FetchRef[desc.symTab, "OutputNames"].val;
IF ref # NIL THEN desc.plaOutNames ← ToRopeList[NARROW[ref]];
ref ← CDExpr.FetchRef[desc.symTab, "Signals"].val;
IF ref # NIL THEN desc.drSignalOrder ← ToRopeList[NARROW[ref]];
Check for renaming parameters and renamed signals
ref ← CDExpr.FetchRef[desc.symTab, "PLAParams"].val;
IF ref = NIL OR NOT ISTYPE[ref, PLAParams] THEN ERROR;
desc.plaParams ← NARROW[ref];
IF desc.plaParams.tileFile = NIL OR NOT ISTYPE[desc.plaParams.tileFile, ROPE] THEN ERROR};
CheckSufficientDesc: PROC [desc: PLADescription] = {
IF desc.drivers#NIL
THEN {
drivers: REF DriveSeq ← NARROW[desc.drivers];
plaInputRecordRef: REFNIL;
FOR index: INT DECREASING IN [0..drivers.size) DO
driver: REF DriveRec ← NARROW[drivers[index]];
name: ROPE ← driver.name;
IF name=NIL THEN name ← Rope.Cat["Not",driver.nameInv];
SELECT driver.cellType FROM
pla  => {
IF desc.ttt = NIL THEN desc.ttt ← NARROW[driver.cellData];
IF desc.ttt=NIL THEN ERROR;
IF driver.drDir = out THEN desc.plaOutNames ← CONS[name, desc.plaOutNames];
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}};
alps  => ERROR;
conn  => ERROR;
conn  => {
IF desc.plaInNames=NIL THEN {
desc.plaInNames ← REFBit.BitNameList[ref: driver.refRec, both: TRUE];
FOR list: LIST OF ROPE ← desc.plaInNames, list.rest WHILE list#NIL DO
list.first ← BitNameToSigName[list.first] ENDLOOP} };
ENDCASE => ERROR;
desc.drSignalOrder ← CONS[name, desc.drSignalOrder];
ENDLOOP }
ELSE {
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;
IF desc.plaParams=NIL THEN desc.plaParams ← NEW[PLAParamsRec ← [ ]];
IF desc.plaParams.tileFile=NIL THEN desc.plaParams.tileFile ← "IFUPWControl.dale";
IF desc.drivers#NIL THEN desc.plaParams.minConnSpace ← 2};
BuildConnTranslationArray: PROC [desc: PLADescription ] = {
index: INT ← -1;
smlOutNames: LIST OF ROPE;
PW.Output["Building pla translation array\n"];
desc.connSeq will contain indexes relative to the big (original) PLA
desc.connSeq ← NEW[ConnSeqRec[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.drivers#NIL THEN {
drivers: REF DriveSeq ← NARROW[desc.drivers];
FOR index IN [0..desc.connSeq.size) DO
driver: REF DriveRec ← NARROW[drivers[index]];
IF driver=NIL THEN ERROR;
desc.connSeq[index].dr ← driver ENDLOOP} };
ZeroUnusedTTTOutputs: PROC [desc: PLADescription ] = {
maskTerm: PLAOps.Term ← PLAOps.CopyTerm[desc.ttt.termList.begin];
PW.Output["Zero unused TTT outputs\n"];
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, log: IO.STREAM ] = {
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 ]};
desc.nextTerm ← desc.ttt.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]} };
GlobalTiles: RECORD[glue: REF GlueTiles, and, or: REF NormalTiles];
LoadPLATiles: PROC [desc: PLADescription ] = {
OPEN desc.plaParams;
tileDefDesign: CD.Design;
IF glueTiles#NIL AND andTiles#NIL AND orTiles#NIL THEN RETURN;
glueTiles ← GlobalTiles.glue;
andTiles ← GlobalTiles.and;
orTiles ← GlobalTiles.or;
IF glueTiles#NIL AND andTiles#NIL AND orTiles#NIL THEN RETURN;
PW.Output["Initialize pla tiles\n"];
tileDefDesign ← PW.OpenDesign[tileFile];
IF tileDefDesign=NIL THEN
ERROR PW.Error[MissingDesign, "TileSet design not found or empty"];
glueTiles ← NEW[GlueTileArray];
andTiles ← NEW[NormalTileArray];
orTiles ← NEW[NormalTileArray];
glueTiles [xheader][leftSide] ← PW.Get[design: tileDefDesign, name: "XLeftSide" ];
glueTiles [xheader][between] ← PW.Get[design: tileDefDesign, name: "XBetween" ];
glueTiles [xheader][rightSide] ← PW.Get[design: tileDefDesign, name: "XOrEx" ];
andTiles [xheader][nc]  ← PW.Get[design: tileDefDesign, name: "XAnd" ];
andTiles [xheader][extra]  ← PW.Get[design: tileDefDesign, name: "XAndEx" ];
orTiles [xheader][nc]  ← PW.Get[design: tileDefDesign, name: "XOr" ];
orTiles [xheader][extra]  ← PW.Get[design: tileDefDesign, name: "XOrEx" ];
glueTiles [header][leftSide] ← PW.Get[design: tileDefDesign, name: "HLeftSide" ];
glueTiles [header][between] ← PW.Get[design: tileDefDesign, name: "HBetween" ];
glueTiles [header][rightSide] ← PW.Get[design: tileDefDesign, name: "HOrEx" ];
andTiles [header][nc]   ← PW.Get[design: tileDefDesign, name: "HAnd" ];
andTiles [header][extra]  ← PW.Get[design: tileDefDesign, name: "HAndEx" ];
orTiles [header][nc]   ← PW.Get[design: tileDefDesign, name: "HOr" ];
orTiles [header][extra]  ← PW.Get[design: tileDefDesign, name: "HOrEx" ];
glueTiles [footer][leftSide]  ← PW.FlipY[tileDefDesign, glueTiles [header][leftSide] ];
glueTiles [footer][between] ← PW.FlipY[tileDefDesign, glueTiles [header][between] ];
glueTiles [footer][rightSide] ← PW.FlipY[tileDefDesign, glueTiles [header][rightSide] ];
andTiles [footer][nc]   ← PW.FlipY[tileDefDesign, andTiles [header][nc]   ];
andTiles [footer][extra]  ← PW.FlipY[tileDefDesign, andTiles [header][extra]  ];
orTiles [footer][nc]   ← PW.FlipY[tileDefDesign, orTiles [header][nc]   ];
orTiles [footer][extra]  ← PW.FlipY[tileDefDesign, orTiles [header][extra]  ];
glueTiles [blank][leftSide]  ← PW.Get[design: tileDefDesign, name: "BLeftSide" ];
glueTiles [blank][between] ← PW.Get[design: tileDefDesign, name: "BBetween" ];
glueTiles [blank][rightSide] ← PW.Get[design: tileDefDesign, name: "BRightSide" ];
andTiles [blank][nc]   ← PW.Get[design: tileDefDesign, name: "BAnd" ];
andTiles [blank][extra]  ← PW.Get[design: tileDefDesign, name: "BAndEx" ];
orTiles [blank][nc]   ← PW.Get[design: tileDefDesign, name: "BOr" ];
orTiles [blank][extra]  ← PW.Get[design: tileDefDesign, name: "BOrEx" ];
glueTiles [conn][leftSide]  ← PW.Get[design: tileDefDesign, name: "CLeftSide" ];
glueTiles [conn][between]  ← PW.Get[design: tileDefDesign, name: "CBetween" ];
glueTiles [conn][rightSide] ← PW.Get[design: tileDefDesign, name: "CRightSide" ];
andTiles [conn][left]   ← PW.Get[design: tileDefDesign, name: "CAndLt" ];
andTiles [conn][right]  ← PW.Get[design: tileDefDesign, name: "CAndRt" ];
andTiles [conn][nc]   ← PW.Get[design: tileDefDesign, name: "CAndNC" ];
andTiles [conn][extra]   ← PW.Get[design: tileDefDesign, name: "CAndEx" ];
orTiles [conn][left]   ← PW.Get[design: tileDefDesign, name: "COr" ];
orTiles [conn][nc]   ← PW.Get[design: tileDefDesign, name: "COrNC" ];
orTiles [conn][extra]   ← PW.Get[design: tileDefDesign, name: "COrEx" ];
glueTiles [dataUp][leftSide] ← PW.Get[design: tileDefDesign, name: "DLeftSide" ];
glueTiles [dataUp][between] ← PW.Get[design: tileDefDesign, name: "DBetween" ];
glueTiles [dataUp][rightSide] ← PW.Get[design: tileDefDesign, name: "DRightSide" ];
andTiles [dataUp][left]  ← PW.Get[design: tileDefDesign, name: "DAndLt" ];
andTiles [dataUp][right]  ← PW.Get[design: tileDefDesign, name: "DAndRt" ];
andTiles [dataUp][nc]   ← PW.Get[design: tileDefDesign, name: "DAndNC" ];
andTiles [dataUp][extra]  ← PW.Get[design: tileDefDesign, name: "DAndEx" ];
orTiles [dataUp][left]  ← PW.Get[design: tileDefDesign, name: "DOr" ];
orTiles [dataUp][nc]   ← PW.Get[design: tileDefDesign, name: "DOrNC" ];
orTiles [dataUp][extra]  ← PW.Get[design: 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]  ];
GlobalTiles ← [glueTiles, andTiles, orTiles]};
DefinePLARows: PROC [desc: PLADescription] = {
firstRow:  BOOL ← TRUE;
index:   INT ← 0;
termUp:  BOOLTRUE;
nofIns:  INT ← ListLength[desc.plaInNames];
nofOuts:  INT ← ListLength[desc.plaOutNames];
cRowsLeft: INT ← ListLength[desc.drSignalOrder];
dRowsLeft: INT ← desc.ttt.termList.length;
hRowsLeft: INT;
dRowsLeft ← MAX[dRowsLeft, cRowsLeft*(desc.plaParams.minConnSpace)];
hRowsLeft ← (dRowsLeft+ desc.plaParams.termsPerHeader/2)/desc.plaParams.termsPerHeader;
PW.Output["Assign pla row types\n"];
desc.nofAndCols ← nofIns/2 + (nofIns/2 -1) / desc.plaParams.insPerExtra;
desc.nofOrCols ← nofOuts + (nofOuts -1) / desc.plaParams.outsPerExtra;
desc.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 {desc.rows[index] ← NextRow[desc, xheader]; index←index+1};
desc.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 < desc.plaParams.minConnSpace OR
(CperD>1) AND (desc.plaParams.minConnSpace>0) THEN ERROR;
RperH ← RperH - CperD - DperC;
WHILE CperD > 0 DO
desc.rows[index] ← NextRow[desc, conn];
index←index+1; cRowsLeft𡤌RowsLeft-1; CperD𡤌perD-1;
ENDLOOP;
termUp ← TRUE;
WHILE DperC > 0 DO
desc.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#desc.rows.size THEN ERROR;
desc.rows[index] ← NextRow[desc, footer] };
NextRow: PROC [desc: PLADescription, type: RowType] RETURNS[row: RowRef] = {
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 (desc.plaParams.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 (desc.plaParams.outsPerExtra+1) = 0
THEN     row.or[index]   ← extra
ELSE {
SELECT type FROM
dataUp, dataDn => SELECT PLAOps.GetOutQrt
[data, REFBit.Desc[desc.ttt.out].bitForm[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;
IF term#NIL THEN desc.nextTerm ← desc.nextTerm.next};
NextConnection: PROC [desc: PLADescription] RETURNS[conn: Connection] = {
conn ← desc.connSeq[desc.nextConn];
desc.nextConn ← desc.nextConn+1};
AssembleDrivers: PROC[desc: PLADescription] RETURNS[drivers: CD.Object] = {
driverList: PW.ListOb ← NIL;
FOR driverIndex: INT IN [0..desc.rows.size) DO
driverList ← CONS[DriverCell
[desc.rows[driverIndex].type, desc.rows[driverIndex].dr, desc.design], driverList];
ENDLOOP;
drivers ← PW.AbutListY[desc.design, driverList]};
AssembleRows: PROC[desc: PLADescription] RETURNS[pla: CD.Object] = {
refPhase, inputPh: Ph ← unk;
rowList: PW.ListOb ← NIL;
PW.Output["Assemble pla row cells\n"];
FOR rowIndex: INT IN [0..desc.rows.size) DO
objects: PW.ListOb ← NIL;
row: RowRef ← desc.rows[rowIndex];
IF desc.rows[rowIndex].dr#NIL THEN refPhase ← desc.rows[rowIndex].dr.ref.ph;
objects ← CONS[desc.plaParams.glueTiles[row.type][leftSide], objects];
FOR index: INT IN [0..row.and.size) DO
objects ← CONS[desc.plaParams.andTiles[row.type][row.and[index]], objects] ENDLOOP;
IF desc.nofOrCols#0 THEN {
objects ← CONS[desc.plaParams.glueTiles[row.type][between], objects];
FOR index: INT IN [0..row.or.size) DO
objects ← CONS[desc.plaParams.orTiles[row.type][row.or[index]], objects] ENDLOOP;
objects ← CONS[desc.plaParams.glueTiles[row.type][rightSide], objects] };
rowList ← CONS[PW.AbutListX[desc.design, PW.Reverse[objects]], rowList]
ENDLOOP;
pla ← PW.AbutListY[desc.design, rowList];
inputPh ← SELECT refPhase FROM A=>BA, B=>AB, ENDCASE => ERROR;
pla ← ReNamePLAInputPins[pla, inputPh, desc]};
ReNamePLAInputPins: PROC[pla: CD.Object, inputPh: Ph, desc: PLADescription]
RETURNS[cell: CD.Object] = {
format:  REFBit.Format ← REFBit.Desc[desc.ttt.data].bitForm;
leftSize:  INTPW.IRSize[desc.plaParams.glueTiles[blank][leftSide]].x;
andWidth: INTPW.IRSize[desc.plaParams.andTiles[blank][nc]].x;
extraWidth: INTPW.IRSize[desc.plaParams.andTiles[blank][extra]].x;
renameProc: IFUPW.PinNameProc ~ {
PROC[pin: CD.Instance, side: Side] RETURNS[name: ROPE]
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)/(desc.plaParams.insPerExtra*andWidth+extraWidth);
index ← (pin.location.x - leftSize - extraWidth*index)/andWidth;
name ← SignalName[in1, format[index].name, format[index].nameInv, inputPh]};
cell ← IFUPW.RenameObjAndPins[desc.design, pla, "PLA", renameProc] };
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};
PW.Register[userProc: IFUPWControlProc, name: "IFUPWControl"];
END.