PLAGenImpl.mesa
Don Curry December 31, 1987 10:29:13 am PST
DIRECTORY
PLAGen, CD, CDIO, CDRects, CDRoutingObjects, CDSimpleRules, CDViewer, CMosB, Core, CoreClasses, CoreCreate, CoreDirectory, CoreGeometry, CoreOps, IO, PLAOps, PWCore, TilingClass, Real, REFBit, Rope, RopeList, Sinix, Sisyph, TerminalIO, ViewerOps, WireIconExtras;
PLAGenImpl: CEDAR PROGRAM
IMPORTS CD, CDIO, CDRects, CDRoutingObjects, CDSimpleRules, CDViewer, CMosB, CoreClasses, CoreCreate, CoreDirectory, CoreGeometry, CoreOps, IO, PLAOps, PWCore, TilingClass, Real, REFBit, Rope, RopeList, Sinix, Sisyph, TerminalIO, ViewerOps, WireIconExtras
EXPORTS PLAGen =
BEGIN
Types, constants and globals
ROPE:    TYPE = Rope.ROPE;
ROPES:   TYPE = LIST OF Rope.ROPE;
CellType:   TYPE = Core.CellType;
Wire:    TYPE = Core.Wire;
Wires:    TYPE = Core.Wires;
DriverTileType: TYPE = {left, in, between, extra, out2, out1, rightHalf};
BodyTileKey: TYPE = RECORD[rt: RowType, tv: TileVariety, tt: TileType, sz: Size ← norm];
RowType:  TYPE = {header, footer, conn, dataUp, dataDn, blank, inCntc};
TileVariety:  TYPE = {glue, and, or};
TileType:   TYPE = {leftSide, between, rightSide, left, right, nc, extra};
Size:    TYPE = {norm, big};
minOutsRp:  ROPE ← "PLAGenOuts";
rowsPerExtraRp: ROPE ← "PLAGenRowsPerExtra";
vddNm:   ROPE ← "Vdd";
gndNm:   ROPE ← "Gnd";
inNm:    ROPE ← "in";
in0Nm:   ROPE ← "in0";
in1Nm:   ROPE ← "in1";
outNm:   ROPE ← "out";
out0Nm:   ROPE ← "out0";
out1Nm:   ROPE ← "out1";
logicInNm:  ROPE ← "logicIn";
logicOutNm:  ROPE ← "logicOut";
rowsPerDr:  INT ← 3; -- not easily changed
outsPerExtra:  INT ← 10; -- can be changed
layRules:   ATOM     ← $cmosB;
Signal:   SIGNAL    = CODE;
Exported Procedures
ExpToPlaCell: PUBLIC PROC[expr: REF, type: ATOMNIL] RETURNS[cell: CellType] = {
pla:   PLAOps.PLA ← PLAOps.ExpressionToPLA[expr];
IF type=NIL THEN type ← $buffered;
SELECT type FROM
$basic   => cell ← PLABodyBasic[pla];
$bufferedBot => cell ← PLABuffered[pla];
$latchedBot => cell ← XXX[pla];
$basicRt  => cell ← PLABodyBasic[pla, TRUE];
$clockedRt => cell ← XXX[pla];
$latchedRt => cell ← XXX[pla];
ENDCASE  => ERROR};
PLABuffered: PROC[pla: PLAOps.PLA] RETURNS[cell: CellType] = {
logic:   CellType ← PLABodyBasic[pla];
bufs:   CellType ← BufferedPLADrivers[pla];
vdd:   Wire  ← CoreOps.CreateWires[0,        vddNm];
gnd:   Wire  ← CoreOps.CreateWires[0,        gndNm];
logicIn:  Wire  ← WireIconExtras.RefWire[pla.data, logicInNm,  TRUE];
logicOut:  Wire  ← WireIconExtras.RefWire[pla.out,  logicOutNm,  FALSE];
in:    Wire  ← WireIconExtras.RefWire[pla.data, inNm,    FALSE];
out:   Wire  ← WireIconExtras.RefWire[pla.out,  outNm,   FALSE];
logicI:   CoreCreate.CellInstance ← CoreCreate.Instance[logic,
[inNm,   logicIn],
[outNm,   logicOut],
[vddNm,   vdd],
[gndNm,   gnd] ];
bufsI:   CoreCreate.CellInstance ← CoreCreate.Instance[bufs,
[inNm,   in],
[outNm,   out],
[logicInNm,  logicIn],
[logicOutNm, logicOut],
[vddNm,   vdd],
[gndNm,   gnd] ];
StripSubWireNames[logicIn];
StripSubWireNames[logicOut];
AddSubWireNamePrefix[to: out, prefix: "Nxt"];
AddSubWireNamePrefixIfDuplicate[ref: in, to: out, prefix: "Nxt"];
cell ← CoreCreate.Cell[
public:  CoreCreate.WireList[LIST[in, out, vdd, gnd]],
onlyInternal: CoreCreate.WireList[LIST[logicIn, logicOut]],
instances:  LIST[bufsI, logicI],
name:   pla.name ];
PWCore.SetAbutY[cell];
RETURN[cell]};
PLAInSB: PUBLIC PROC[cx: PLAGen.Context, tttFile: ROPE] RETURNS[cell: CellType] = {
pla:  PLAOps.PLA ← PLAOps.ReadPLAFile
[tttFile.Cat[".ttt"], TerminalIO.TOS[], TRUE];
rec: CoreClasses.RecordCellType ← NEW[CoreClasses.RecordCellTypeRec[0]];
in:   Wire ← WireIconExtras.RefWire[pla.data, "in",  TRUE];
out:  Wire ← WireIconExtras.RefWire[pla.out,  "out",  FALSE];
public: Wire ← CoreOps.CreateWire[LIST[in]];
internal: Wire ← CoreOps.CreateWire[LIST[in]];
flatIn:  Wire ← CoreOps.CreateWire[Flatten[in]];
flatInOrd: Wire ← CoreOps.CreateWire[Flatten[ReorderWire[in, GetSideNames[cx, right]]]];
insAtTop:  BOOL ← GetSideNames[cx, top]  #NIL;
insAtBot:  BOOL ← GetSideNames[cx, bottom] #NIL AND ~insAtTop;
ins:   NAT ← flatIn.size/2;
nofOrCols: NAT ← NofOrCols[MAX[CoreOps.WireBits[out], GetCxParam[cx, minOutsRp]]];
leftSize:  INT ← 44 * CMosB.lambda;
betweenSize: INT ← 16 * CMosB.lambda;
rightSize:  INT ← 16 * CMosB.lambda;
blankSize: INT ← 8 * CMosB.lambda;
biasX:   INT ← 48 * CMosB.lambda;
biasY:   INT ← 12 * CMosB.lambda;
colAnd:  INT ← 16 * CMosB.lambda;
colOr:   INT ← 8 * CMosB.lambda;
halfColSize: INT ← 8 * CMosB.lambda;
rowSize:  INT ← 24 * CMosB.lambda;
halfRowSize: INT ← 16 * CMosB.lambda;
obj:   CD.Object;
contObj:  CD.Object ← CDSimpleRules.Contact[layRules, CMosB.met, CMosB.met2];
contW:  INT ← CD.InterestSize[contObj].x;
metW:   INT ← CDSimpleRules.MinWidth[layRules, CMosB.met];
met2W:  INT ← CDSimpleRules.MinWidth[layRules, CMosB.met2];
iSizeX:  NAT ← leftSize +ins*colAnd +betweenSize +nofOrCols*colOr +rightSize;
iSizeY:  NAT ← blankSize + ins*rowSize + blankSize;
nodes:   LIST OF CDRoutingObjects.Node;
cell ← CoreClasses.CreateRecordCell[public, internal, NIL, tttFile.Cat["InSB"]];
FOR indexX: INT IN [0..ins) DO
FOR polarity: INT IN [0..2) DO
node:  CDRoutingObjects.Node;
pub:  Wire   ← flatIn[2*indexX + polarity];
name:  ROPE ← CoreOps.GetFullWireName[public, pub];
indexY: INT   ← WireIndex[flatInOrd, pub]/2;
refX:  INT   ← biasX + indexX * colAnd + polarity * halfColSize;
refY:  INT   ← biasY + indexY * rowSize + polarity * halfRowSize;
verYSize: INTSELECT TRUE FROM
insAtTop AND insAtBot => iSizeY,
insAtTop      => iSizeY-refY,
insAtBot      => refY,
ENDCASE      => ERROR;
horSize: CD.Position ← [iSizeX-refX,  metW];
verSize: CD.Position ← [met2W, verYSize];
horPos: CD.Position ← [refX,    refY-metW/2];
verPos: CD.Position ← [refX-met2W/2, (IF insAtBot THEN 0 ELSE refY)];
contPos: CD.Position ← [refX-contW/2, refY-contW/2];
horObj: CD.Object ← CDRects.CreateRect[horSize, CMosB.met];
verObj: CD.Object ← CDRects.CreateRect[verSize, CMosB.met2];
pos: LIST OF CDRoutingObjects.PlacedObject ← NIL;
pins: LIST OF CoreGeometry.Instance ← NIL;
IF name=NIL THEN ERROR;
pos ← CONS[[ horObj, horPos], pos]; --pins ← CONS[[horObj, [horPos]], pins];
pos ← CONS[[ verObj, verPos], pos]; --pins ← CONS[[verObj, [verPos]], pins];
pos ← CONS[[ contObj,  contPos], pos];
CoreGeometry.AddPins[PWCore.extractMode.decoration, pub, pins];
node ← CDRoutingObjects.CreateNode
[pos, LIST[[$SignalName, name], [$InstanceName, name]]];
nodes ← CONS[node, nodes];
ENDLOOP;
ENDLOOP;
obj ← CDRoutingObjects.CreateRoutingObject[nodes, [x1: 0, y1: 0, x2: iSizeX, y2: iSizeY]];
PWCore.SetLayout[cell, $Value, $PWCoreValue, obj]};
PWCore.PutObject[PWCore.extractMode.decoration, cell, obj]};
PLAOutDrHeader: PUBLIC PROC[tttFile: ROPE] RETURNS[cell: CellType] = {
pla:  PLAOps.PLA ← PLAOps.ReadPLAFile[tttFile.Cat[".ttt"], TerminalIO.TOS[], TRUE];
out:  Wire  ← WireIconExtras.RefWire[pla.out,  "out",  FALSE];
outSize: INT  ← CoreOps.WireBits[out];
minSize: NAT  ← (rowsPerDr-1)*outSize;
outFill: INT  ← MAX[pla.termList.length, minSize] - minSize;
header: CellType ← Get[orig, "PLAGen.DrHeader.sch"];
blank:  CellType ← Get[orig, "PLAGen.DrBlank.sch"];
name:  ROPE  ← "DrHeader";
insts:  CoreCreate.CellInstances ← LIST[CoreCreate.Instance[header]];
[]←PWCore.Layout[header];
[]←PWCore.Layout[blank];
IF outFill=0 THEN RETURN[header];
name ← IO.PutFR["%gWith%gBlanks", IO.rope[name], IO.int[outFill]];
FOR i: INT IN [1..outFill] DO insts ← CONS[CoreCreate.Instance[blank], insts]; ENDLOOP;
cell ← CoreCreate.Cell[
public:  CoreOps.CopyWire[header.public],
instances:  insts,
name:   name];
PWCore.SetAbutY[cell]};
PLABody: PUBLIC PROC[cx: PLAGen.Context, tttFile: ROPE] RETURNS[cell: CellType] = {
pla:    PLAOps.PLA ← PLAOps.ReadPLAFile[tttFile, TerminalIO.TOS[], TRUE];
minOuts:   INTGetCxParam[cx, minOutsRp];
rowsPerExtra: INTGetCxParam[cx, rowsPerExtraRp, 1000];
rightNames: ROPES ← GetSideNames[cx, right];
cell ← PLABodyBasic[pla, rightNames#NIL, rightNames, minOuts, rowsPerExtra]};
Domestic Procedures
PLABodyBasic: PROC[
pla:    PLAOps.PLA,
horOuts:   BOOL ← FALSE,
rtNms:   ROPES ← NIL,
minOuts:   INT ← 0,
rowsPerExtra: INT ← 10]
RETURNS[cell: CellType] = {
The type of PLA is implied by where the ouputs are specified in the icon.
output names   on right  => output connections positioned every 3 rows
`out' or output names on bottom => output connections at bottom
`in' or input names may be on top or bottom or both.
vdd:   Wire  ← CoreOps.CreateWires[0,      vddNm];
gnd:   Wire  ← CoreOps.CreateWires[0,      gndNm];
in:    Wire  ← WireIconExtras.RefWire[pla.data, "in",  TRUE];
out:   Wire  ← WireIconExtras.RefWire[pla.out,  "out",  FALSE];
flatIn:   Wire  ← CoreOps.CreateWire[Flatten[in]];
flatOut:  Wire  ← CoreOps.CreateWire[Flatten[out]];
flatOutOrd: Wire  ← CoreOps.CreateWire[Flatten[ReorderWire[out, rtNms]]];
public:  Wire  ← NIL;
baseRows: NAT  ← (IF horOuts
THEN flatOut.size+MAX[flatOut.size*(rowsPerDr-1), pla.termList.length]
ELSE pla.termList.length);
nofRows:  NAT  ← 2 + baseRows + (baseRows-1)/rowsPerExtra;
nofOrCols: NAT  ← NofOrCols[MAX[flatOut.size, minOuts] ];
nofAndCols: NAT  ← flatIn.size/2;
row:   INT  ← 0;
up:   BOOL  ← FALSE;
cRow:   INT  ← 0;
fillLt:   INT  ← 0;
ta:    TilingClass.TileArray ← NEW[TilingClass.TileArrayRec[nofRows]];
terms:   LIST OF PLAOps.Term ← NIL;
data:   PLAOps.Term   ← NIL;
GetRow: PROC[type: RowType] RETURNS[rowRef: TilingClass.TileRow ] = {
AndBit: PROC[index: INT] RETURNS[TileType] = {
RETURN[SELECT type FROM
dataUp, dataDn => SELECT PLAOps.GetInQrt
[data, REFBit.Desc[pla.data].bitForm[index].firstBit] FROM
zero => left, one => right, ENDCASE => nc,
ENDCASE  => nc]};
OrBit: PROC[index: INT] RETURNS[TileType] = {
IF (index+1) MOD (outsPerExtra+1) = 0 THEN RETURN[extra];
index ← index - index/(outsPerExtra+1);
IF index >= flatOut.size THEN RETURN[nc];
SELECT type FROM
conn    => IF flatOutOrd[cRow]=flatOut[index] THEN RETURN[left];
dataUp, dataDn => IF PLAOps.GetOutQrt
[data, REFBit.Desc[pla.out].bitForm[index].firstBit]=one
THEN RETURN[left];
ENDCASE;
RETURN[nc]};
TileIt: PROC[
cell:  CellType,
pubType: {in, out, none} ← none,
index:  INT ← 0,
header: BOOLFALSE ] = {
pas: LIST OF CoreCreate.PANIL;
SELECT pubType FROM
in  => pas ← LIST[[in0Nm, flatIn[2*index+0]], [in1Nm, flatIn[2*index+1]] ];
out => pas ← LIST[[outNm, flatOut[index]]];
ENDCASE;
IF header THEN pas ← CONS[[vddNm, vdd], CONS[[gndNm, gnd], pas]];
rowRef[col] ← NEW[TilingClass.TileRec ← [cell, pas]];
col ← col+1};
col:  INT ← 0;
MainLine GetRow Code
rowRef ← NEW[TilingClass.TileRowRec[1 + nofAndCols + 1 + nofOrCols + 1]];
SELECT type FROM
conn    => {
up    ← FALSE};
dataUp, dataDn => {
IF terms = NIL THEN data ← NIL ELSE {data ← terms.first; terms ← terms.rest};
type ← IF data=NIL THEN blank ELSE IF (up←~up) THEN dataUp ELSE dataDn};
ENDCASE;
IF (type=dataUp OR type=dataDn) AND data#NIL AND
TermLoad[pla, data].load > hotTermThreshold
THEN TileIt[ BodyTile[[type, glue, leftSide, big ]], none, 0]
ELSE TileIt[ BodyTile[[type, glue, leftSide   ]], none, 0];
FOR i: INT IN [0..nofAndCols) DO IF row=0 AND AndBit[i]#extra
THEN {TileIt[BodyTile[[type, and, AndBit[i]]], in, i]}
ELSE {TileIt[BodyTile[[type, and, AndBit[i]]]]}; ENDLOOP;
TileIt[ BodyTile[[type, glue, between]]];
FOR i: INT IN [0..nofOrCols) DO
outI: INT ← i-i/(outsPerExtra+1);
IF row=0 AND OrBit[i]#extra AND outI < flatOut.size
THEN {TileIt[ BodyTile[[type, or, OrBit[i]]], out, outI]}
ELSE {TileIt[ BodyTile[[type, or, OrBit[i]]]]} ENDLOOP;
IF type#conn
THEN {TileIt[BodyTile[[type,glue,rightSide]], none, 0, (type=header OR type=footer)]}
ELSE {TileIt[BodyTile[[type,glue,rightSide]] ]} };
MainLine PLAOut Code
hotTermThreshold: INT ← HotTermThreshold[pla];
TerminalIO.PutRope[Estimates[pla, 2, TRUE, TRUE]];
IF horOuts
THEN terms ← GetHorOutsTermList[pla, flatOut, flatOutOrd]
ELSEFOR term: PLAOps.Term ← pla.termList.end, term.last WHILE term#NIL DO
terms ← CONS[PLAOps.CopyTerm[term], terms] ENDLOOP;
FOR row IN [0..ta.size) DO
extraRow: PROC RETURNS[BOOL] = {RETURN[(row-1+1) MOD (rowsPerExtra+1) = 0]};
SELECT TRUE FROM
row=0     => {ta[row]← GetRow[footer]; fillLt ← rowsPerDr-1};
row+1=nofRows  => {ta[row]← GetRow[header]};
fillLt#0    => {ta[row]← GetRow[dataUp]; fillLt ← fillLt -1};
extraRow[]   => {ta[row]← GetRow[inCntc]};
cRow=flatOut.size => {ta[row]← GetRow[dataUp]};
~horOuts    => {ta[row]← GetRow[dataUp]}; --fillLt not used unless horOuts
ENDCASE    => {ta[row]← GetRow[conn]; fillLt←rowsPerDr-1; cRow𡤌Row+1};
ENDLOOP;
IF terms # NIL THEN ERROR;
AddSubWireNamePrefix[to: out, prefix: "Nxt"];
AddSubWireNamePrefixIfDuplicate[ref: in, to: out, prefix: "Nxt"];
cell ← TilingClass.CreateTiling[
public:   CoreOps.CreateWire[LIST[in, out, vdd, gnd]],
tileArray:   ta,
neighborX:  TilingClass.LayoutNeighborX,
neighborY:  TilingClass.LayoutNeighborY,
name:    pla.name,
props:    NIL ]};
BufferedPLADrivers: PROC[pla: PLAOps.PLA] RETURNS[cell: CellType]={
vdd:   Wire  ← CoreOps.CreateWires[0,        vddNm];
gnd:   Wire  ← CoreOps.CreateWires[0,        gndNm];
lIn:   Wire  ← WireIconExtras.RefWire[pla.data, logicInNm,  TRUE];
lOut:   Wire  ← WireIconExtras.RefWire[pla.out,  logicOutNm,  FALSE];
dIn:   Wire  ← WireIconExtras.RefWire[pla.data, inNm,    FALSE];
dOut:   Wire  ← WireIconExtras.RefWire[pla.out,  outNm,   FALSE];
flatLIn:  Wire  ← CoreOps.CreateWire[Flatten[lIn]];
flatLOut:  Wire  ← CoreOps.CreateWire[Flatten[lOut]];
flatDIn:  Wire  ← CoreOps.CreateWire[Flatten[dIn]];
flatDOut:  Wire  ← CoreOps.CreateWire[Flatten[dOut]];
nofOrCols: NAT  ← NofOrCols[flatDOut.size];
nofOrColExs: NAT  ← nofOrCols/(outsPerExtra+1);
nofOrColOut: NAT  ← nofOrCols - nofOrColExs;
nofAndCols: NAT  ← flatDIn.size;
ta:    TilingClass.TileArray ← NEW[TilingClass.TileArrayRec[1]];
orIndex:  INT ← 0;
extras:   INT ← 0;
col:   INT ← 0;
TileIt: PROC[
cell:  CellType,
pubType: {in, out2, out1, filler} ← filler,
index:  INT ← 0] = {
pas:  LIST OF CoreCreate.PALIST[[vddNm, vdd], [gndNm, gnd]];
SELECT pubType FROM
in  => pas ←
CONS[[inNm,  flatDIn[index]],
CONS[[out0Nm, flatLIn[2*index+0]],
CONS[[out1Nm, flatLIn[2*index+1]], pas]]];
out1  => pas ←
CONS[[in0Nm, flatLOut[index]],
CONS[[out0Nm, flatDOut[index]], pas]];
out2  => pas ←
CONS[[in0Nm, flatLOut[index]],
CONS[[out0Nm, flatDOut[index]],
CONS[[in1Nm, flatLOut[index+1]],
CONS[[out1Nm, flatDOut[index+1]], pas]]]];
ENDCASE;
ta[0][col] ← NEW[TilingClass.TileRec ← [cell, pas]];
col ← col+1};
ta[0] ← NEW[TilingClass.TileRowRec
[1 + nofAndCols + 1 + nofOrColExs + nofOrColOut/2 + 3]];
TileIt[ DriverTile[left], filler];
FOR i: INT IN [0..nofAndCols) DO TileIt[DriverTile[in], in, i] ENDLOOP;
TileIt[ DriverTile[between], filler];
WHILE orIndex < nofOrCols DO
IF ((orIndex+1) MOD (outsPerExtra+1)) = 0
THEN {TileIt[ DriverTile[extra], filler]; orIndex ← orIndex+1; extras ← extras+1; LOOP}
ELSE {IF orIndex+1=nofOrCols
THEN {TileIt[ DriverTile[out1], out1, orIndex-extras]; orIndex ← orIndex+1}
ELSE {TileIt[ DriverTile[out2], out2, orIndex-extras]; orIndex ← orIndex+2}};
ENDLOOP;
TileIt[ DriverTile[rightHalf], filler];
TileIt[ DriverTile[rightHalf], filler];
IF ((nofOrCols-extras) MOD 2)=0
THEN TileIt[ DriverTile[rightHalf], filler];
StripSubWireNames[lIn]; -- to prevent confusion with driver in subWire names
StripSubWireNames[lOut]; -- to prevent confusion with driver out subWire names
MainLine Code
cell ← TilingClass.CreateTiling[
public:   CoreOps.CreateWire[LIST[dIn, dOut, lIn, lOut, vdd, gnd]],
tileArray:   ta,
neighborX:  TilingClass.LayoutNeighborX,
neighborY:  TilingClass.LayoutNeighborY,
name:    pla.name,
props:    NIL ]};
GetCxParam: PROC[cx: Sisyph.Context, param: ROPE, default: INT𡤀]
RETURNS[nofOrCols: INT] = {
RETURN[IF (cx=NIL OR NOT Sisyph.FetchInt[cx, param].found)
THEN default ELSE Sisyph.FetchInt[cx, param].value]};
NofOrCols: PROC[nofOuts: INT] RETURNS[nofOrCols: INT] =
{RETURN[nofOuts+(nofOuts-1)/outsPerExtra]};
StripSubWireNames: PROC[w: Wire] = {
IF w.size=0 THEN RETURN;
FOR i: INT IN [0..w.size) DO
[]𡤌oreOps.SetShortWireName[w[i], NIL]; StripSubWireNames[w[i]]; ENDLOOP};
AddSubWireNamePrefix: PROC[to: Wire, prefix: ROPE] = {
FOR i: INT IN [0..to.size) DO
name1: ROPE ← CoreOps.GetShortWireName[to[i]];
[]𡤌oreOps.SetShortWireName[to[i], Rope.Cat[prefix, name1]] ENDLOOP;};
AddSubWireNamePrefixIfDuplicate: PROC[ref, to: Wire, prefix: ROPE] = {
FOR i: INT IN [0..to.size) DO
name1: ROPE ← CoreOps.GetShortWireName[to[i]];
FOR j: INT IN [0..ref.size) DO
IF CoreOps.GetShortWireName[ref[j]].Equal[name1] THEN EXIT;
REPEAT FINISHED => LOOP ENDLOOP;
[]𡤌oreOps.SetShortWireName[to[i], Rope.Cat[prefix, name1]] ENDLOOP;};
AddSubWireNamePrefixIfClash: PROC[to, ck: Wire, prefix: ROPE] = {
FOR i: INT IN [0..to.size) DO
CkClash: PROC [w: Wire] =
{clash ← clash OR CoreOps.GetShortWireName[w].Equal[name]};
clash: BOOLFALSE;
name: ROPE ← CoreOps.GetShortWireName[to[i]];
IF name.Length[] > 0 THEN [] ← CoreOps.VisitRootAtomics[ck, CkClash];
IF clash THEN []𡤌oreOps.SetShortWireName[to[i], Rope.Cat[prefix, name]];
IF to[i].size>0 THEN AddSubWireNamePrefixIfClash[to[i], ck, prefix]; ENDLOOP};
GetHorOutsTermList: PROC[pla: PLAOps.PLA, flatOut, flatOutOrd: Wire]
RETURNS[terms: LIST OF PLAOps.Term ← NIL] = {
Assumes 3 rows per driver
SeqTermLists:  TYPE = REF SeqTermListsRec;
SeqTermListsRec: TYPE = RECORD[SEQUENCE size: CARDINAL OF LIST OF PLAOps.Term];
TwoTermRecs:  TYPE = RECORD[t1, t2: PLAOps.TermRec];
MoveFromTermsToOuts: PROC[idx: INT] = {
terms ← CONS[NIL, terms];
IF terms=NIL THEN RETURN;
FOR list: LIST OF PLAOps.Term ← terms, list.rest WHILE list.rest#NIL DO
term: PLAOps.Term ← list.rest.first;
IF PLAOps.GetOutQrt[term, idx]#one THEN
{list.rest ← list.rest.rest; terms ← terms.rest; outs[idx] ← CONS[term, outs[idx]]; RETURN};
ENDLOOP;
FOR list: LIST OF PLAOps.Term ← terms, list.rest WHILE list.rest#NIL DO
term: PLAOps.Term ← list.rest.first;
FOR i: INT IN [0..outs.size) DO
IF PLAOps.GetOutQrt[term, i]#one THEN
FOR sub: LIST OF PLAOps.Term ← outs[i], sub.rest WHILE sub#NIL DO
IF PLAOps.GetOutQrt[sub.first, idx]#one THEN {
[term^, sub.first^] ← TwoTermRecs[sub.first^, term^];
list.rest ← list.rest.rest; terms ← terms.rest;
outs[idx] ← CONS[term, outs[idx]]; RETURN}
ENDLOOP;
ENDLOOP;
REPEAT FINISHED => ERROR ENDLOOP};
outForm:  PLAOps.Format ← REFBit.Desc[pla.out].bitForm;
end:   PLAOps.Term;
outs:   SeqTermLists ← NEW[SeqTermListsRec[pla.termList.outBits]];
FOR output: INT IN [pla.termList.length..flatOutOrd.size*2) DO
terms ← CONS[PLAOps.NewTerm[pla.termList.inBits, pla.termList.outBits], terms] ENDLOOP;
FOR term: PLAOps.Term ← pla.termList.end, term.last WHILE term#NIL DO
terms ← CONS[PLAOps.CopyTerm[term], terms] ENDLOOP;
FOR output: INT IN [0..flatOutOrd.size) DO outs[output] ← NIL ENDLOOP;
FOR output: INT IN [0..flatOutOrd.size) DO
FOR index: INT IN [0..flatOut.size) DO
IF flatOutOrd[output] # flatOut[index] THEN LOOP;
MoveFromTermsToOuts[ outForm[index].firstBit ];
MoveFromTermsToOuts[ outForm[index].firstBit ];
EXIT REPEAT FINISHED => ERROR ENDLOOP;
ENDLOOP;
MoveOutsBackToTerms
FOR output: INT DECREASING IN [0..flatOutOrd.size) DO
FOR index: INT IN [0..flatOut.size) DO
IF flatOutOrd[output] # flatOut[index] THEN LOOP;
FOR sub: LIST OF PLAOps.Term ← outs[outForm[index].firstBit], sub.rest
WHILE sub#NIL DO terms ← CONS[sub.first, terms] ENDLOOP;
outs[outForm[index].firstBit] ← NIL; ENDLOOP ENDLOOP;
terms ← ReverseTerms[terms];  -- make last first
UNTIL end#NIL DO end ← terms.first; terms ← terms.rest ENDLOOP; -- remove end term
terms ← ReverseTerms[terms];  -- make first first
terms ← CONS[end, terms]; -- add end term to beginning
FOR list: LIST OF PLAOps.Term ← terms, list.rest WHILE list#NIL DO
FOR i: CARDINAL IN [0..list.first.out.wdSize) DO
IF list.first.out[i].d#0 THEN EXIT;
REPEAT FINISHED => list.first ← NIL ENDLOOP ENDLOOP};
ReverseTerms: PROC[terms: LIST OF PLAOps.Term] RETURNS[new: LIST OF PLAOps.Term] =
{FOR terms ← terms, terms.rest WHILE terms#NIL DO new←CONS[terms.first, new] ENDLOOP};
WireIndex: PROC[big, little: Wire] RETURNS[index: INT ← -1] = {
FOR index: INT IN [0..big.size) DO
IF big[index]=little THEN RETURN[index] ENDLOOP;
RETURN[-1]};
ReorderWire: PROC[wire: Wire, names: ROPES, extras: BOOLFALSE] RETURNS[Wire] = {
wires: Wires ← NIL;
nms: ROPESCONS[NIL, names];
IF names=NIL THEN RETURN[wire];
IF extras THEN FOR nms ← nms, nms.rest WHILE nms.rest#NIL DO
index: INT ← CoreOps.GetWireIndex[wire, nms.rest.first];
IF index=-1 THEN nms.rest ← nms.rest.rest
REPEAT FINISHED => names ← nms.rest ENDLOOP;
FOR names ← names, names.rest WHILE names#NIL DO
index: INT ← CoreOps.GetWireIndex[wire, names.first];
IF index=-1 THEN {
TerminalIO.PutF
["The icon wire name \"%g\" is not an element of the PLA interface.\n",
IO.rope[names.first]];
ERROR};
wires ← CONS[wire[index], wires] ENDLOOP;
RETURN[ CoreOps.CreateWire[ CoreOps.Reverse[wires]]]};
Flatten: PROC[wire: Wire] RETURNS[wires: Wires ← NIL] = {
temp: Wires;
IF wire.size=0 THEN RETURN[LIST[wire]];
FOR ii: INT IN [0..wire.size) DO
FOR temp ← Flatten[wire[ii]], temp.rest WHILE temp#NIL DO
wires ← CONS[temp.first, wires] ENDLOOP ENDLOOP;
temp ← wires; wires ← NIL;
FOR temp ← temp, temp.rest WHILE temp#NIL DO wires ← CONS[temp.first, wires] ENDLOOP};
GetSideNames: PROC[cx: PLAGen.Context, side: CoreGeometry.Side]
RETURNS[names: ROPES] = {
obj: CD.Object ← Sisyph.GetCDObj[cx];
cell: CellType ← NARROW[Sinix.ExtractCell[obj, Sisyph.mode, NIL, cx].result];
eachSortedPin: CoreGeometry.EachSortedPinProc =
{names ← CONS[CoreOps.GetShortWireName[wire], names]};
[]𡤌oreGeometry.EnumerateSortedSides
[Sisyph.mode.decoration, cell, side, eachSortedPin];
names ← RopeList.Reverse[names]};
Tiles
Get: PROC [orientation: {orig, flipY}, name: ROPE] RETURNS [cellType: CellType] ~ {
libraryNm: IO.ROPE = "PLAGen";
library:  CoreDirectory.Library ← CoreDirectory.FetchLibrary[libraryNm];
IF library=NIL THEN
library ← CoreDirectory.RegisterLibrary[CoreDirectory.CreateLibrary[], libraryNm];
cellType  ← CoreDirectory.Fetch[library, name];
IF cellType=NIL THEN {
designName: IO.ROPE  ← name.Substr[0, name.Find["."]];
cellName:  IO.ROPE  ← name.Substr[name.Index[0, "."]+1];
design:  CD.Design ← CDViewer.FindDesign[designName];
cx:    PLAGen.Context;
IF design=NIL THEN {
design ← CDIO.ReadDesign[designName];
IF design=NIL THEN ERROR;
ViewerOps.CloseViewer[CDViewer.CreateViewer[design, FALSE]]}; -- caches the design
cx ← Sisyph.Create[design];
cellType ← Sisyph.ExtractSchematicByName[name: cellName, cx: cx];
[]𡤌oreDirectory.Insert[library, name, cellType]};
IF orientation=flipY THEN {
flipName: IO.ROPE ← Rope.Cat["FlipY.", name];
flipCT: CellType ← CoreDirectory.Fetch[library, flipName];
IF flipCT = NIL THEN {
flipCT ← PWCore.RotateCellType[cellType, $FlipY];
[]𡤌oreDirectory.Insert[library, flipName, flipCT]};
cellType ← flipCT} };
DriverTile: PROC[key: DriverTileType] RETURNS[cell: CellType] = {SELECT key FROM
left   => cell ← Get[orig, "PLAGen.BPlaDrLeftSide.sch"   ];
in    => cell ← Get[orig, "PLAGen.BPlaDrDualIn.sch"   ];
between  => cell ← Get[orig, "PLAGen.BPlaDrBetween.sch"   ];
extra   => cell ← Get[orig, "PLAGen.BPlaDrOrEx.sch"    ];
out2   => cell ← Get[orig, "PLAGen.BPlaDrDualOutInv.sch"  ];
out1   => cell ← Get[orig, "PLAGen.BPlaDrSingOutInv.sch"  ];
rightHalf  => cell ← Get[orig,  "PLAGen.BPlaDrRightSideHalf.sch" ];
ENDCASE};
BodyTile: PROC[key: BodyTileKey] RETURNS[cell: CellType] = {SELECT key FROM
[header, glue, leftSide  ] => cell ← Get[orig,  "PLAGen.HPlaHLeftSide.sch"  ];
[header, glue, between  ] => cell ← Get[orig,  "PLAGen.HPlaHBetween.sch"  ];
[header, glue, rightSide  ] => cell ← Get[orig,  "PLAGen.HPlaHRightSide.sch"  ];
[header, and, nc    ] => cell ← Get[orig,  "PLAGen.HPlaHAnd.sch"   ];
[header, or,  nc    ] => cell ← Get[orig,  "PLAGen.HPlaHOr.sch"    ];
[header, or,  extra   ] => cell ← Get[orig,  "PLAGen.HPlaHOrEx.sch"   ];
[footer, glue, leftSide  ] => cell ← Get[flipY, "PLAGen.HPlaHLeftSide.sch"  ];
[footer, glue, between  ] => cell ← Get[flipY, "PLAGen.HPlaHBetween.sch"  ];
[footer, glue, rightSide  ] => cell ← Get[flipY, "PLAGen.HPlaHRightSide.sch"  ];
[footer, and, nc    ] => cell ← Get[flipY, "PLAGen.HPlaHAnd.sch"   ];
[footer, or,  nc    ] => cell ← Get[flipY, "PLAGen.BPlaHOr.sch"    ];
[footer, or,  extra   ] => cell ← Get[flipY, "PLAGen.HPlaHOrEx.sch"   ];
[blank, glue, leftSide  ] => cell ← Get[orig,  "PLAGen.HPlaBLeftSide.sch"  ];
[blank, glue, between  ] => cell ← Get[orig,  "PLAGen.HPlaBBetween.sch"  ];
[blank, glue, rightSide  ] => cell ← Get[orig,  "PLAGen.HPlaBRightSide.sch"  ];
[blank, and, nc    ] => cell ← Get[orig,  "PLAGen.HPlaBAnd.sch"   ];
[blank, or,  nc    ] => cell ← Get[orig,  "PLAGen.BOr.sch"     ];
[blank, or,  extra   ] => cell ← Get[orig,  "PLAGen.HPlaBOrEx.sch"   ];
[conn, glue, leftSide  ] => cell ← Get[orig,  "PLAGen.HPlaBLeftSide.sch"  ];
[conn, glue, between  ] => cell ← Get[orig,  "PLAGen.HPlaBBetween.sch"  ];
[conn, glue, rightSide  ] => cell ← Get[orig,  "PLAGen.HPlaCRightSide.sch"  ];
[conn, and, nc    ] => cell ← Get[orig,  "PLAGen.HPlaBAnd.sch"   ];
[conn, or,  left   ] => cell ← Get[orig,  "PLAGen.COr.sch"     ];
[conn, or,  nc    ] => cell ← Get[orig,  "PLAGen.COrNC.sch"    ];
[conn, or,  extra   ] => cell ← Get[orig,  "PLAGen.HPlaCOrEx.sch"   ];
[dataUp, glue, leftSide, big ] => cell ← Get[orig,  "PLAGen.HPlaDLeftSideHot.sch" ];
[dataUp, glue, leftSide  ] => cell ← Get[orig,  "PLAGen.HPlaDLeftSide.sch"  ];
[dataUp, glue, between  ] => cell ← Get[orig,  "PLAGen.HPlaDBetween.sch"  ];
[dataUp, glue, rightSide  ] => cell ← Get[orig,  "PLAGen.HPlaDRightSide.sch"  ];
[dataUp, and, left   ] => cell ← Get[orig,  "PLAGen.DAndLt.sch"    ];
[dataUp, and, right   ] => cell ← Get[orig,  "PLAGen.DAndRt.sch"    ];
[dataUp, and, nc    ] => cell ← Get[orig,  "PLAGen.DAnd.sch"    ];
[dataUp, or,  left   ] => cell ← Get[orig,  "PLAGen.DOr.sch"     ];
[dataUp, or,  nc    ] => cell ← Get[orig,  "PLAGen.DOrNC.sch"    ];
[dataUp, or,  extra   ] => cell ← Get[orig,  "PLAGen.HPlaDOrEx.sch"   ];
[dataDn, glue, leftSide, big ] => cell ← Get[orig,  "PLAGen.HPlaDLeftSideHot.sch" ];
[dataDn, glue, leftSide  ] => cell ← Get[orig,  "PLAGen.HPlaDLeftSide.sch"  ];
[dataDn, glue, between  ] => cell ← Get[flipY, "PLAGen.HPlaDBetween.sch"  ];
[dataDn, glue, rightSide  ] => cell ← Get[flipY, "PLAGen.HPlaDRightSide.sch"  ];
[dataDn, and, left   ] => cell ← Get[orig,  "PLAGen.DAndLt.sch"    ];
[dataDn, and, right   ] => cell ← Get[orig,  "PLAGen.DAndRt.sch"    ];
[dataDn, and, nc    ] => cell ← Get[orig,  "PLAGen.DAnd.sch"    ];
[dataDn, or,  left   ] => cell ← Get[flipY, "PLAGen.DOr.sch"     ];
[dataDn, or,  nc    ] => cell ← Get[flipY, "PLAGen.DOrNC.sch"    ];
[dataDn, or,  extra   ] => cell ← Get[flipY, "PLAGen.HPlaDOrEx.sch"   ];
[inCntc, glue, leftSide  ] => cell ← Get[orig,  "PLAGen.HPlaInCntcLeftSide.sch" ];
[inCntc, glue, between  ] => cell ← Get[orig,  "PLAGen.HPlaInCntcBetween.sch" ];
[inCntc, glue, rightSide  ] => cell ← Get[orig,  "PLAGen.HPlaInCntcRightSide.sch" ];
[inCntc, and, nc    ] => cell ← Get[orig,  "PLAGen.HPlaInCntcAnd.sch"  ];
[inCntc, or,  nc    ] => cell ← Get[orig,  "PLAGen.HPlaInCntcOr.sch"  ];
[inCntc, or,  extra   ] => cell ← Get[orig,  "PLAGen.HPlaInCntcOrEx.sch"  ];
ENDCASE};
Performance estimation
nSqRes:   REAL = 18.0;
pSqRes:   REAL = nSqRes*2.5;
InDrRes:   PROC[drSize: INT] RETURNS[REAL] =
{RETURN[nSqRes * .5 / drSize]};
TermPURes: PROC[hot: BOOL] RETURNS[REAL] =
{RETURN[IF hot THEN pSqRes*.75 ELSE pSqRes]};
OutPURes:  PROC RETURNS[REAL] =
{RETURN[pSqRes*.75]};
InCap:   PROC[ldsPerIn, nofTerms: INT] RETURNS[REAL] =
{RETURN[.03     + .0100 * ldsPerIn  + .0015 * nofTerms]};
TermCap:  PROC[ldsPerTerm, nofIns, nofOuts: INT] RETURNS[REAL] =
{RETURN[.0020 * nofIns  + .0100 * ldsPerTerm + .0012 * nofOuts]};
OutCap:   PROC[ldsPerOut, nofTerms, drSize: INT] RETURNS[REAL] =
{RETURN[.0010 * nofTerms + .0100 * ldsPerOut  + .0100 * drSize*3.5]};
Estimates:    PUBLIC PROC[
pla:    PLAOps.PLA,
drSize:   INT ← 0,
useHotTermPU: BOOL ← TRUE,
showOutLoads: BOOL ← TRUE]
RETURNS[rope: IO.ROPE] = {
drSize=1 => pE=10 and nE=4, assume in driver size = out driver size
nofIns:  INT ← REFBit.Desc[pla.data].bitForm.size;
nofOuts:  INT ← REFBit.Desc[pla.out].bitForm.size;
nofTerms: INT ← pla.termList.length;
ldsPerIn:  INT ← MaxLdsPerIn[pla];
ldsPerTerm: INT ← MaxLdsPerTerm[pla].maxLoad;
insPerTerm: INT ← MaxLdsPerTerm[pla].maxIns;
outsPerTerm: INT ← MaxLdsPerTerm[pla].maxOuts;
ldsPerOut: INT ← MaxLdsPerOut[pla];
hotTermT: INT ← IF useHotTermPU THEN HotTermThreshold[pla] ELSE ldsPerTerm;
hotTerms:  INT ← NofHotTerms[pla, hotTermT];
inCap:  REAL ← InCap  [ldsPerIn,  nofTerms];
termCap:  REAL ← TermCap [ldsPerTerm, nofIns, nofOuts];
outCap:  REAL ← OutCap  [ldsPerOut, nofTerms, drSize];
inRest:  REAL ← InDrRes[drSize];
tUpRes:  REAL ← TermPURes[useHotTermPU];
oUpRes:  REAL ← OutPURes[];
tDnRes:  REAL ← (tUpRes * nSqRes/2) / (tUpRes - nSqRes/2);
oDnRes:  REAL ← (oUpRes * nSqRes/2) / (oUpRes - nSqRes/2);
inTime:  REAL ← .7 * inCap  * inRest;
termUpTime: REAL ← .7 * termCap * tUpRes;
termDnTime: REAL ← .7 * termCap * tDnRes;
outUpTime: REAL ← .7 * outCap * oUpRes;
outDnTime: REAL ← .7 * outCap * oDnRes;
onTime:  REAL ← inTime+termUpTime+outDnTime;
offTime:  REAL ← inTime+termDnTime+outUpTime;
ros:   IO.STREAMIO.ROS[];
ros.PutF["\nTiming and power estimates for PLA: %g\n", IO.rope[pla.name]];
ros.PutF[" BufUnits: %3g\n", IO.int[drSize]];
ros.PutF[" HotThld: %3g\n", IO.int[hotTermT]];
ros.PutF[" HotTerms: %3g\n", IO.int[hotTerms]];
ros.PutF[" Ins Terms Outs\n"];
ros.PutF[" Count: %3g %3g %3g\n",
IO.int[nofIns],
IO.int[nofTerms],
IO.int[nofOuts] ];
ros.PutF[" Max Ld: %3g %3g %3g MxTIns: %3g MxTOuts: %3g\n",
IO.int[ldsPerIn],
IO.int[ldsPerTerm],
IO.int[ldsPerOut],
IO.int[insPerTerm],
IO.int[outsPerTerm] ];
ros.PutF[" Max Cap: %6.2f %6.2f %6.2f pF\n",
IO.real[inCap],
IO.real[termCap],
IO.real[outCap]];
ros.PutF[" Time Up: %6.2f %6.2f %6.2f nS\n",
IO.real[inTime],
IO.real[termUpTime],
IO.real[outUpTime]];
ros.PutF[" Time Dn: %6.2f %6.2f %6.2f nS\n",
IO.real[inTime],
IO.real[termDnTime],
IO.real[outDnTime]];
ros.PutF[" Times: Av:%6.2f On:%6.2f Off:%6.2f nS\n",
IO.real[(onTime+offTime)/2],
IO.real[onTime],
IO.real[offTime] ];
ros.PutF[" Power: %6.2f mW\n\n",
IO.real[25.0*(hotTerms/TermPURes[TRUE]+(nofTerms-hotTerms)/TermPURes[FALSE])]];
IF showOutLoads THEN {
bitFormat: PLAOps.Format ← REFBit.Desc[pla.out].bitForm;
ros.PutRope[" Out Lds:\n"];
FOR out: INT IN [0..bitFormat.size) DO
ros.PutF[" %3g: %3g\n", IO.int[out], IO.int[OutLds[pla, out]]]
ENDLOOP};
rope ← IO.RopeFromROS[ros]};
HotTermThreshold: PUBLIC PROC[pla: PLAOps.PLA]
RETURNS[threshold: INTLAST[INT]] = {
nofIns: INT ← REFBit.Desc[pla.data].bitForm.size;
nofOuts: INT ← REFBit.Desc[pla.out].bitForm.size;
max:  INT ← MaxLdsPerTerm[pla].maxLoad;
termCap: REAL ← TermCap [max, nofIns, nofOuts];
biasCap: REAL ← TermCap [0,  nofIns, nofOuts];
factCap: REAL ← (termCap-biasCap)/max;      -- sb .01
rRatio: REAL ← TermPURes[TRUE]/TermPURes[FALSE]; -- sb .75
nReal:  REAL ← rRatio*max - (1 - rRatio)*biasCap/factCap;
threshold   ← Real.Round[nReal]};
TermLoad:    PUBLIC PROC[pla: PLAOps.PLA, term: PLAOps.Term]
RETURNS[load, ins, outs: INT ← 0] = {
inForm: PLAOps.Format ← REFBit.Desc[pla.data].bitForm;
outForm: PLAOps.Format ← REFBit.Desc[pla.out].bitForm;
FOR in: INT IN [0..inForm.size) DO
IF PLAOps.GetInQrt[term, inForm[in].firstBit]#dontcare
THEN ins ← ins+1 ENDLOOP;
FOR out: INT IN [0..outForm.size) DO
IF PLAOps.GetOutQrt[term, outForm[out].firstBit]=one
THEN outs ← outs+1 ENDLOOP;
load ← ins+outs};
MaxLdsPerIn:   PROC[pla: PLAOps.PLA] RETURNS[max: INT ← 0] = {
IntSeq: TYPE = RECORD[SEQUENCE size: NAT OF INT];
inForm: PLAOps.Format ← REFBit.Desc[pla.data].bitForm;
ones:  REF IntSeq  ← NEW[IntSeq[inForm.size]];
zeros:  REF IntSeq  ← NEW[IntSeq[inForm.size]];
FOR in: INT IN [0..inForm.size) DO ones[in] ← zeros[in] ← 0 ENDLOOP;
FOR term: PLAOps.Term ← pla.termList.begin, term.next WHILE term#NIL DO
FOR in: INT IN [0..inForm.size) DO
SELECT PLAOps.GetInQrt[term, inForm[in].firstBit] FROM
one => ones[in] ← ones[in] +1;
zero => zeros[in] ← zeros[in] +1;
ENDCASE ENDLOOP ENDLOOP;
FOR in: INT IN [0..inForm.size) DO max ← MAX[ones[in], zeros[in], max] ENDLOOP};
MaxLdsPerTerm:  PROC[pla: PLAOps.PLA]
RETURNS[maxLoad, maxIns, maxOuts: INT ← 0] = {
load, in, out: INT ← 0;
FOR term: PLAOps.Term ← pla.termList.begin, term.next WHILE term#NIL DO
[load, in, out] ← TermLoad[pla, term];
maxLoad ← MAX[maxLoad, load];
maxIns ← MAX[maxIns,  in];
maxOuts ← MAX[maxOuts, out] ENDLOOP};
NofHotTerms:  PROC[pla: PLAOps.PLA, threshold: INT] RETURNS[cnt: INT ← 0] = {
FOR term: PLAOps.Term ← pla.termList.begin, term.next WHILE term#NIL DO
IF TermLoad[pla, term].load > threshold THEN cnt ← cnt+1 ENDLOOP};
MaxLdsPerOut:  PROC[pla: PLAOps.PLA] RETURNS[max: INT ← 0] = {
bitFormat: PLAOps.Format ← REFBit.Desc[pla.out].bitForm;
FOR out: INT IN [0..bitFormat.size) DO max ← MAX[max, OutLds[pla, out]] ENDLOOP};
OutLds: PROC[pla: PLAOps.PLA, out: INT] RETURNS[cnt: INT ← 0] = {
bitFormat: PLAOps.Format ← REFBit.Desc[pla.out].bitForm;
FOR term: PLAOps.Term ← pla.termList.begin, term.next WHILE term#NIL DO
IF PLAOps.GetOutQrt[term, bitFormat[out].firstBit]=one
THEN cnt ← cnt+1 ENDLOOP};
END.