IFUPWLatch.mesa,
Copyright c 1985 by Xerox Corporation. All rights reserved.
RemoveButton CD; CreateButton L Compile Latch; Run Latch
Last Edited by Curry, April 12, 1985 8:54:55 am PST
DIRECTORY
Basics,
CD,
CDCells USING [CreateEmptyCell, SetInterestRect],
CDDirectory,
CDRects USING [CreateRect],
CMos,
CMosContacts,
CMosTransistors,
IFUPW,
IO,
PW,
PWBasics,
Rope;
IFUPWLatch: CEDAR PROGRAM
IMPORTS
CD, CDCells, CDRects, CMosContacts, CMosTransistors, CMos, IO, IFUPW, PW, PWBasics, Rope
EXPORTS IFUPW =
BEGIN OPEN IFUPW;
IFULatchRow: PUBLIC PROC [
design: CD.Design,
enable: PW.ROPE,
top:  LIST OF REF,
in:   LIST OF REF,
out:  LIST OF REF,
bot:  LIST OF REF,
seq:  BOOLFALSE ]
RETURNS [cell: PW.ObjName] = {
cells: LIST OF PW.ObjName;
FOR ii: INT DECREASING IN [0..rngByte*rngBit) DO
index: INT ← IF seq THEN ii MOD rngBit ELSE ii / rngByte;
byte: INT ← IF seq THEN ii / rngBit ELSE ii MOD rngByte;
cells ← CONS[ Latch[
design: design,
enable: enable,
top:  AddGV[ExpandList[byte, index, top]],
in:   ExpandList[byte, index, in],
out:  ExpandList[byte, index, out],
bot:  AddGV[ExpandList[byte, index, bot]]], cells];
ENDLOOP;
RETURN[PW.AbutListX[cells]]};
Latch: PROC [
design: CD.Design,
enable: PW.ROPE,
disable: PW.ROPE ← "VBB",
top:  List,
in:   List,
out:  List,
bot:  List]
RETURNS [PW.ObjName] = {
topTail:  INT  = 4;
botTail:  INT  = 2;
pitch:   Size  = [mPitch, pBigPitch];
cell:   CD.ObPtr ← CDCells.CreateEmptyCell[];
rangeX:  INT  ← nofVWires;
inN:   PW.ROPE ← IF in=NILTHEN NIL ELSE in.first;
outN:   PW.ROPE ← IF out=NILTHEN NIL ELSE out.first;
Metal wires
FOR i: INT IN [0..nofVWires) DO
Add: PROC[bindex, tindex, toptail, bottail: INT] = {
loc.y ← bindex*pitch.y - bottail;
size.y ← (tindex-bindex)*pitch.y + toptail + bottail;
IF size.y>0 THEN AddRet[cell:cell, size:size, loc:loc, level: CMos.met]};
size: Size  ← [6, 0];
loc: Location ← [i*pitch.x, 0];
tIO: PW.ROPE ← ListIndexItem[top,  i];
bIO: PW.ROPE ← ListIndexItem[bot,  i];
IF tIO#NIL THEN SELECT TRUE FROM
Rope.Equal[tIO,  bIO] => {Add[0, 4, 4+topTail, botTail]};
Rope.Equal[outN, tIO] => {Add[2, 4, 4+topTail, 0]};
Rope.Equal[inN,  tIO] => {Add[3, 4, 4+topTail, 0]};
ENDCASE     => ERROR; -- top not connected anywhere ABORT;
IF bIO#NIL THEN SELECT TRUE FROM
Rope.Equal[bIO, tIO] => LOOP;
Rope.Equal[inN, bIO] => {Add[0, 3, 0, botTail]};
Rope.Equal[outN, bIO] => {Add[0, 2, 0, botTail]};
ENDCASE     => ERROR; -- bottom not connected anywhere ABORT
ENDLOOP;
Insert Metal Pins
FOR i: INT IN [0..nofVWires) DO
tName: PW.ROPE ← ListIndexItem[top, i];
bName: PW.ROPE ← ListIndexItem[bot, i];
size: Size  ← [6, 6];
loc: Location ← [i*pitch.x, 4*pitch.y+4+topTail-size.y];
IF tName #NIL THEN PutPin [cell, size, loc,    CMos.met, tName];
IF bName #NIL THEN PutPin [cell, size, [loc.x, -botTail], CMos.met, bName];
ENDLOOP;
Enables and power Wires
AddRet[cell:cell, size:[cellWidth, 4], loc:[-leftTail, 68],  level: CMos.pol];
AddRet[cell:cell, size:[cellWidth,20], loc:[-leftTail, 48],  level: CMos.met2];
AddRet[cell:cell, size:[cellWidth,20], loc:[-leftTail, 0],  level: CMos.met2];
AddRet[cell:cell, size:[cellWidth, 4], loc:[-leftTail, 0],  level: CMos.pol];
Insert Enable and power Pins
PutPin [cell, [4, 4], [-leftTail,     68], CMos.pol,  disable];
PutPin [cell, [4, 4], [cellWidth-leftTail-4, 68], CMos.pol,  disable];
PutPin [cell, [4,20], [-leftTail,     48], CMos.met2, "GND"];
PutPin [cell, [4,20], [cellWidth-leftTail-4, 48], CMos.met2, "GND"];
PutPin [cell, [4,20], [-leftTail,     2],  CMos.met2, "VDD"];
PutPin [cell, [4,20], [cellWidth-leftTail-4, 2],  CMos.met2, "VDD"];
PutPin [cell, [4, 4], [-leftTail,     0],  CMos.pol,  enable];
PutPin [cell, [4, 4], [cellWidth-leftTail-4, 0],  CMos.pol,  enable];
Poly connections
FOR i: INT IN [0..nofVWires) DO
loc: Location ← [i * pitch.x, 0];
ioT: PW.ROPE ← ListIndexItem[top, i];
ioB: PW.ROPE ← ListIndexItem[bot, i];
loc.y ← 2*pitch.y;
IF inN#NIL THEN IF Rope.Equal[inN, ioT] OR Rope.Equal[inN, ioB]
THEN {
[] ← PWBasics.IncludeApplication
[cell, CMosContacts.CreatePolyCon[l: 8], [loc.x, loc.y-2]];
AddRet[cell:cell, size:[(nofVWires-i) * pitch.x, 4], loc:loc, level:CMos.pol]};
loc.y ← 1*pitch.y;
IF outN#NIL THEN IF Rope.Equal[outN, ioT] OR Rope.Equal[outN, ioB]
THEN {
[] ← PWBasics.IncludeApplication
[cell, CMosContacts.CreateMmCon[l: 10], [loc.x, loc.y-4]];
AddRet[cell:cell, size:[(nofVWires-i) * pitch.x, 10], loc:loc, level:CMos.met2]};
ENDLOOP;
Cell
IF inN#NIL THEN {
loc: Location ← [(nofVWires-2)*pitch.x, 0];
[] ← PWBasics.IncludeApplication[
cell:  cell,
subcell: PWBasics.ObjFromName[design, "GVLatch"],
location: loc];
PWBasics.RepositionCell[design, cell];
RETURN[PWBasics.NameFromObj[cell]]};
IFUMuxRow: PUBLIC PROC [
design: CD.Design,
top:  LIST OF REF,
ctl:  List,
in:   LIST OF REF,
out:  LIST OF REF,
bot:  LIST OF REF,
seq:  BOOLFALSE ]
RETURNS [cell: PW.ObjName] = {
cells: LIST OF PW.ObjName;
FOR ii: INT DECREASING IN [0..rngByte*rngBit) DO
index: INT ← IF seq THEN ii MOD rngBit ELSE ii / rngByte;
byte: INT ← IF seq THEN ii / rngBit ELSE ii MOD rngByte;
cells ← CONS[ Mux[
design: design,
ctl:  ctl,
in:   ExpandList[byte, index, in],
top:  ExpandList[byte, index, top],
out:  ExpandList[byte, index, out],
bot:  ExpandList[byte, index, bot]], cells];
ENDLOOP;
RETURN[PW.AbutListX[cells]]};
IFUMuxBytesRow: PUBLIC PROC [ -- Hack to go around compiler limitation
design: CD.Design,
top:  LIST OF REF,
ctl:  List,
in:   LIST OF REF, -- Nesting order changed to Byte, Wd, Bit
out:  LIST OF REF,
bot:  LIST OF REF,
seq:  BOOLFALSE ]
RETURNS [cell: PW.ObjName] = {
cells: LIST OF PW.ObjName;
byteIns:   ARRAY [0..rngByte) OF LIST OF REF;
byteInLengths: ARRAY [0..rngByte) OF INTALL[0];
FOR byte: INT IN [0..rngByte) DO
list: LIST OF REF;
FOR bb: INT IN [0..byte) DO
FOR list ← byteIns[bb], list.rest WHILE list#NIL DO
byteIns[byte]   ← CONS[NIL, byteIns[byte]];
byteInLengths[byte] ← byteInLengths[byte] + 1;
ENDLOOP;
ENDLOOP;
FOR list ← NARROW[LISTIndexItem[in, byte]], list.rest WHILE list#NIL DO
byteIns[byte]   ← CONS[NIL, byteIns[byte]];
byteInLengths[byte] ← byteInLengths[byte] + 1;
ENDLOOP;
ENDLOOP;
FOR byte: INT DECREASING IN [0..rngByte) DO
THROUGH [byteInLengths[byte]..byteInLengths[rngByte-1]) DO
byteIns[byte] ← CONS[NIL, byteIns[byte]];
ENDLOOP;
ENDLOOP;
FOR byte: INT IN [0..rngByte) DO
list: LIST OF REF ← byteIns[byte];
byteIns[byte] ← NIL;
FOR list ← list, list.rest WHILE list#NIL DO
byteIns[byte] ← CONS[list.first, byteIns[byte]];
ENDLOOP;
ENDLOOP;
FOR ii: INT DECREASING IN [0..rngByte*rngBit) DO
index: INT ← IF seq THEN ii MOD rngBit ELSE ii / rngByte;
byte: INT ← IF seq THEN ii / rngBit ELSE ii MOD rngByte;
cells ← CONS[ Mux[
design: design,
ctl:  ctl,
in:   ExpandList[index, 0, byteIns[byte]],
top:  ExpandList[byte, index, top],
out:  ExpandList[byte, index, out],
bot:  ExpandList[byte, index, bot]], cells];
ENDLOOP;
RETURN[PW.AbutListX[cells]]};
Mux: PROC [
design: CD.Design,
top:  List,
ctl:  List,
in:   List,
out:  List,
bot:  List]
RETURNS [PW.ObjName] = {
pitch:   Size  = [mPitch, pBigPitch];
topTail:  INT  = 4;
botTail:  INT  = 2;
muxEvenDn: BOOL  = TRUE;
cell:   CD.ObPtr ← CDCells.CreateEmptyCell[];
range:   Size  ← [MAX[ListLength[top],ListLength[bot]], ListLength[ctl]];
outN:   PW.ROPE ← IF out=NIL THEN NIL ELSE out.first;
iRect:   CD.Rect;
outIndex:  INT ← ListItemIndexMin[top, outN];
outIndexBot: INT ← ListItemIndexMin[bot, outN];
IF outIndex  # ListItemIndexMax[top, outN] OR
outIndexBot  # ListItemIndexMax[bot, outN] OR
(outIndex#-1  AND outIndexBot#-1 AND outIndex#outIndexBot)
THEN ERROR Error[IO.PutFR["Multiple column output %g- ABORT", IO.rope[outN]]];
IF outIndex = -1 THEN outIndex ← outIndexBot;
Metal wires and their pins
FOR i: INT IN [0..range.x) DO
size: Size  ← [6, 0];
loc: Location ← [i*pitch.x, 0];
tIO: PW.ROPE ← ListIndexItem[top, i];
bIO: PW.ROPE ← ListIndexItem[bot, i];
tY:  INTIF tIO=outN THEN ListNonNILIndexMin[in] ELSE ListItemIndexMin[in,tIO];
bY: INTIF bIO=outN THEN ListNonNILIndexMax[in] ELSE ListItemIndexMax[in,bIO];
tY ← tY  + ((tY + (IF (tIO=outN)=muxEvenDn THEN 1 ELSE 2)) MOD 2);
bY ← bY  + ((bY + (IF (bIO=outN)=muxEvenDn THEN 1 ELSE 2)) MOD 2);
IF tY=-1 AND bY=-1 THEN tY𡤋Y𡤀
IF ~Rope.Equal[tIO, bIO] AND tY<=bY AND tIO#NIL AND bIO#NIL
THEN ERROR Error[IO.PutFR
["2 signals (%g, %g) in same channel - ABORT", IO.rope[tIO], IO.rope[bIO]]];
IF tIO#NILTHEN AddRet[cell:cell, level: CMos.met,
size: [6,    (range.y-tY) * pitch.y + 8 + topTail ],
loc: [i*pitch.x,  tY  * pitch.y - 10     ]];
IF bIO#NILTHEN AddRet[cell:cell, level: CMos.met,
size: [6,       bY * pitch.y   + botTail ],
loc: [i*pitch.x,    0 * pitch.y - 10 - botTail ]];
ENDLOOP;
FOR i: INT IN [0..range.x) DO
tName: PW.ROPE ← ListIndexItem[top, i];
bName: PW.ROPE ← ListIndexItem[bot, i];
size: Size  ← [6, 6];
loc: Location ← [i*pitch.x, range.y*pitch.y-2+topTail-size.y];
IF tName #NIL THEN PutPin [cell, size, loc,       CMos.met, tName];
IF bName #NIL THEN PutPin [cell, size, [loc.x, - 10 - botTail], CMos.met, bName];
ENDLOOP;
Poly wires and their pins
FOR i: INT IN [0..range.y) DO
cName: PW.ROPE ← ListIndexItem[ctl, i];
size: Size  ← [cellWidth,  4];
loc: Location ← [-leftTail, i*pitch.y ];
AddRet[cell:cell, size:size, loc:loc, level:CMos.pol];
PutPin [cell, [4, 4], loc,        CMos.pol, cName];
PutPin [cell, [4, 4], [cellWidth-leftTail-4, loc.y], CMos.pol, cName]
ENDLOOP;
Mux connections
FOR ctlIndex: INT IN [0..range.y) DO
AddMux: PROC [index: Location] = {
OPEN PWB: PWBasics;
xstr: CD.ObPtr ← CMosTransistors.CreateTransistor[w: 8, l: 4, difLev: CMos.ndif];
ctct: CD.ObPtr ← CMosContacts.CreateDifCon[l: 8, difLev: CMos.ndif];
dif: CD.ObPtr ← CDRects.CreateRect[[(ABS[outIndex-index.x])*pitch.x+8, 8], CMos.ndif];
half: INT ← IF ((index.y MOD 2)=0)=muxEvenDn THEN pitch.y/2 ELSE -pitch.y/2;
yloc: INT ← index.y*pitch.y-2;
[] ← PWB.IncludeApplication[cell, dif, [MIN[outIndex, index.x]*pitch.x,  yloc+half]];
[] ← PWB.IncludeApplication[cell, ctct, [  outIndex    *pitch.x,  yloc+half]];
[] ← PWB.IncludeApplication[cell, ctct, [     index.x *pitch.x,  yloc-half]];
[] ← PWB.IncludeApplication[cell, xstr, [     index.x *pitch.x-4, yloc-2]]};
ioIndex: INT  ← -1;
ioItem: PW.ROPE ← ListIndexItem[in, ctlIndex];
IF ioItem = NIL THEN LOOP;
IF ioIndex < 0 THEN ioIndex ← ListItemIndexMax[top, ioItem];
IF ioIndex < 0 THEN ioIndex ← ListItemIndexMax[bot, ioItem];
IF ioIndex < 0 THEN LOOP;
AddMux[index: [ioIndex, ctlIndex]];
ENDLOOP;
PWBasics.RepositionCell[design, cell];
iRect ← CD.InterestRect[cell];
IF outIndex=-1 AND bot=NIL OR ListAllNil[bot] THEN iRect.y1 ← iRect.y1-10-botTail;
iRect.y2 ← iRect.y1 + range.y*pitch.y+botTail+8+topTail;
CDCells.SetInterestRect[cell, iRect];
RETURN[PWBasics.NameFromObj[cell]]};
IFUDecoderRow: PUBLIC PROC [
design: CD.Design,
top:  LIST OF REF,
ctl:  List, -- nof names must be 2*nof significant bits - 1st is MSB TRUE
val:  REF ValArray,
out:  LIST OF REF,
bot:  LIST OF REF,
seq:  BOOLFALSE ]
RETURNS [cell: PW.ObjName] = {
cells: LIST OF PW.ObjName;
FOR ii: INT DECREASING IN [0..rngByte*rngBit) DO
index: INT ← IF seq THEN ii MOD rngBit ELSE ii / rngByte;
byte: INT ← IF seq THEN ii / rngBit ELSE ii MOD rngByte;
cells ← CONS[ Decoder[
design: design,
ctl:  ctl,
val:  val[byte][index],
top:  AddGV[ExpandList[byte, index, top]],
out:  ExpandList[byte, index, out],
bot:  AddGV[ExpandList[byte, index, bot]] ], cells];
ENDLOOP;
RETURN[PW.AbutListX[cells]]};
Decoder: PROC [
design: CD.Design,
top:  List,
ctl:  List,
val:  INT,
out:  List,
bot:  List]
RETURNS [PW.ObjName] = {
pitch:   Size  = [mPitch, pBigPitch];
topTail:  INT  = 4;
botTail:  INT  = 2;
cell:   CD.ObPtr ← CDCells.CreateEmptyCell[];
rangeY:  INT  ← ListLength[ctl]+1;
outN:   PW.ROPE ← IF out=NIL THEN NIL ELSE out.first;
iRect:   CD.Rect;
Metal wires and their pins
FOR i: INT IN [0..nofVWires) DO
size: Size  ← [6, 0];
loc: Location ← [i*pitch.x, 0];
tIO: PW.ROPE ← ListIndexItem[top, i];
bIO: PW.ROPE ← ListIndexItem[bot, i];
tY:  INT ← ListItemIndexMin[ctl,tIO] +1;
bY: INT ← ListItemIndexMax[ctl,bIO] +1;
IF tIO=outN     THEN tY𡤀 ELSE IF tY=0 THEN tY←-1;
IF bY=0 AND bIO#outN THEN bY←-1;
IF tY=-1 AND bY=-1 THEN tY𡤋Y𡤀
IF ~Rope.Equal[tIO, bIO] AND tY<=bY AND tIO#NIL AND bIO#NIL
THEN ERROR Error[IO.PutFR
["2 signals (%g, %g) in same channel - ABORT", IO.rope[tIO], IO.rope[bIO]]];
IF tIO#NILTHEN AddRet[cell:cell, level: CMos.met,
size: [6,    (rangeY-tY) * pitch.y + 8 + topTail ],
loc: [i*pitch.x,  tY  * pitch.y - 10     ]];
IF bIO#NILTHEN AddRet[cell:cell, level: CMos.met,
size: [6,       bY * pitch.y   + botTail ],
loc: [i*pitch.x,    0 * pitch.y - 10 - botTail ]];
ENDLOOP;
FOR i: INT IN [0..nofVWires) DO
tName: PW.ROPE ← ListIndexItem[top, i];
bName: PW.ROPE ← ListIndexItem[bot, i];
size: Size  ← [6, 6];
loc: Location ← [i*pitch.x, rangeY*pitch.y-2+topTail-size.y];
IF tName #NIL THEN PutPin [cell, size, loc,      CMos.met, tName];
IF bName #NIL THEN PutPin [cell, size, [loc.x, - 10 - botTail], CMos.met, bName];
ENDLOOP;
Out poly wire
FOR xIndex: INT IN [0..nofVWires-2) DO
loc: Location ← [xIndex*pitch.x, 0 ];
IF Rope.Equal[outN, ListIndexItem[top, xIndex]] OR
Rope.Equal[outN, ListIndexItem[bot, xIndex]] THEN {
AddRet[cell:cell, size:[(nofVWires-2-xIndex)*pitch.x, 4], loc:loc, level:CMos.pol];
[] ← PWBasics.IncludeApplication[cell, CMosContacts.CreatePolyCon[l:8], loc] };
ENDLOOP;
Ctl Poly wires and their pins
FOR cIndex: INT IN (0..rangeY) DO
cName: PW.ROPE ← ListIndexItem[ctl, cIndex-1];
size: Size  ← [cellWidth,  4];
loc: Location ← [-leftTail, cIndex*rangeY ];
AddRet[cell:cell, size:size, loc:loc, level:CMos.pol];
PutPin [cell, [4, 4], loc,        CMos.pol, cName];
PutPin [cell, [4, 4], [cellWidth-leftTail-4, loc.y], CMos.pol, cName];
loc.y ← loc.y-2;
FOR xIndex: INT IN [0..nofVWires-2) DO
loc.x ← xIndex*pitch.x;
IF Rope.Equal[cName, ListIndexItem[top, xIndex]] OR
Rope.Equal[cName, ListIndexItem[bot, xIndex]] THEN
[] ← PWBasics.IncludeApplication[cell, CMosContacts.CreatePolyCon[l:8], loc];
ENDLOOP;
ENDLOOP;
AddRet[cell:cell, level: CMos.met, size:[8, (rangeY-2)*pitch.y], loc: [154, 6]];
AddRet[cell:cell, level: CMos.met, size:[26, (rangeY-1)*pitch.y], loc: [170, 6]];
AddRet[cell:cell, level: CMos.nwel, size:[26, (rangeY+0)*pitch.y+6], loc: [142, -4]];
BEGIN -- Mux connections
Put: PROC[obj: CD.ObPtr, loc: Location] = {[] ← PWBasics.IncludeApplication[cell, obj, loc]};
currIsXstr, lastIsXstr: BOOL ← FALSE;
nXstr: CD.ObPtr ← CMosTransistors.CreateTransistor[w: 32, l: 4, difLev: CMos.ndif];
pXstr: CD.ObPtr ← CMosTransistors.CreateTransistor[w: 24, l: 4, difLev: CMos.pdif];
nCtct: CD.ObPtr ← CMosContacts.CreateDifCon[l: 8, difLev: CMos.ndif];
pCtct: CD.ObPtr ← CMosContacts.CreateDifCon[l: 8, difLev: CMos.pdif];
wCtct: CD.ObPtr ← CMosContacts.CreateDifShortCon[difLev: CMos.ndif];
nDif: CD.ObPtr ← CDRects.CreateRect[[32, 4], CMos.ndif];
pDif: CD.ObPtr ← CDRects.CreateRect[[24, 4], CMos.pdif];
met: CD.ObPtr ← CDRects.CreateRect[[8, 16], CMos.met];
FOR ctlIndex: INT IN (0..rangeY) DO
yloc: INT ← ctlIndex*pitch.y-10;
xloc: INT ← (nofVWires-2)*pitch.x;
currIsXstr ← PW.XthBitOfN[(rangeY+1-ctlIndex)/2, val];
IF (ctlIndex MOD 2) =1 THEN currIsXstr ← NOT currIsXstr;
IF NOT currIsXstr
THEN {
Put[met,   [xloc+28,  yloc  ]];
IF lastIsXstr THEN
Put[nCtct,  [xloc+28,  yloc   ]] }
ELSE {
Put[nDif,   [xloc+4,  yloc+2 ]];
Put[nDif,   [xloc+4,  yloc+2+16]];
Put[nXstr,  [xloc+4,  yloc+4 ]];
IF NOT lastIsXstr THEN
Put[nCtct,  [xloc+28,  yloc   ]];
Put[pDif,   [xloc+62,  yloc+2 ]];
Put[pDif,   [xloc+62,  yloc+2+16]];
Put[pXstr,  [xloc+62,  yloc+4 ]];
Put[wCtct,  [xloc+92,  yloc +16]];
IF (ctlIndex MOD 2) =1 THEN {
Put[pCtct,  [xloc+62,  yloc +16]];
Put[pCtct,  [xloc+78,  yloc   ]] };
};
lastIsXstrcurrIsXstr;
ENDLOOP;
END;
[] ← PWBasics.IncludeApplication[
cell:  cell,
subcell: PWBasics.ObjFromName[design, "DecoderTop"],
location: [0,0]];
[] ← PWBasics.IncludeApplication[
cell:  cell,
subcell: PWBasics.ObjFromName[design, "DecoderBot"],
location: [0,(rangeY-1)*pitch.y-2]];
PWBasics.RepositionCell[design, cell];
iRect ← CD.InterestRect[cell];
IF outIndex=-1 AND bot=NIL OR ListAllNil[bot] THEN iRect.y1 ← iRect.y1-10-botTail;
iRect.y2 ← iRect.y1 + range.y*pitch.y+botTail+8+topTail;
CDCells.SetInterestRect[cell, iRect];
RETURN[PWBasics.NameFromObj[cell]]};
IFUMuxLatchRow: PUBLIC PROC [
design: CD.Design,
enable: PW.ROPE,
top:  LIST OF REF,
ctl:  List,
in:   LIST OF REF,
out:  LIST OF REF,
bot:  LIST OF REF,
seq:  BOOLFALSE ]
RETURNS [cell: PW.ObjName] = {
cells: LIST OF PW.ObjName;
FOR ii: INT DECREASING IN [0..rngByte*rngBit) DO
index: INT ← IF seq THEN ii MOD rngBit ELSE ii / rngByte;
byte: INT ← IF seq THEN ii / rngBit ELSE ii MOD rngByte;
cells ← CONS[ MuxLatch[
design: design,
ctl:  ctl,
in:   ExpandList[byte, index, in],
enable: enable,
top:  ExpandList[byte, index, top],
out:  ExpandList[byte, index, out],
bot:  ExpandList[byte, index, bot]], cells];
ENDLOOP;
RETURN[PW.AbutListX[cells]]};
ioRestRef: List ← LIST["VDD", "GND"];
MuxLatch: PROC [
design: CD.Design,
enable: PW.ROPE,
top:  List,
ctl:  List,
in:   List,
out:  List,
bot:  List]
RETURNS [PW.ObjName] = {
AddMux: PROC [index: Location] = {
patch: CD.ObPtr ← CDRects.CreateRect[[8,8], CMos.ndif];
dif: CD.ObPtr ← CDRects.CreateRect[[(range.x+ioRestLength-index.x)*pitch.x,8], CMos.ndif];
xstr: CD.ObPtr ← CMosTransistors.CreateTransistor[w: 8, l: 4, difLev: CMos.ndif];
ctct: CD.ObPtr ← CMosContacts.CreateDifCon[l: 8, difLev: CMos.ndif];
half: INT  ← IF (index.y MOD 2)=0 THEN pitch.y/2 ELSE -pitch.y/2;
loc: Location ← [index.x*pitch.x, (mIBias+index.y)*pitch.y-2];
IF range.y=1 -- noMux Latch
THEN [] ← PWBasics.IncludeApplication[cell, patch, [loc.x,  loc.y]]
ELSE [] ← PWBasics.IncludeApplication[cell, xstr,  [loc.x-4, loc.y-2]];
[] ← PWBasics.IncludeApplication[cell, dif, [loc.x,  loc.y+half]];
[] ← PWBasics.IncludeApplication[cell, ctct, [loc.x,  loc.y-half]] };
pitch:  Size = [mPitch, pBigPitch];
mIBias: INT = 5;
oIBias: INT = 2;
topTail: INT = 4;
botTail: INT = 2; -- Need tails to prevend pins from appearing on two sides
cell:  CD.ObPtr  ← CDCells.CreateEmptyCell[];
range:  Size ← [MAX[ListLength[top],ListLength[bot]], ListLength[ctl]+mIBias];
ioRest:   List ← ioRestRef;
ioRestLength: CARDINAL ← ListLength[ioRest];
noMux:   BOOL ← range.y=1;
noIORest:   BOOLFALSE;
blank:    BOOL ← in=NIL OR ListAllNil[in];
FOR ioRest ← ioRest, ioRest.rest WHILE ioRest#NIL DO-- are VDD or GND used
IF ListItemIndexMax[in, ioRest.first]#-1 THEN EXIT ENDLOOP;
IF ioRest#NIL
THEN ioRest ← ioRestRef -- at least one is used so do regular case
ELSE noIORest ← TRUE;
IF noIORest THEN {ioRest ← NIL; ioRestLength𡤀}; -- noMux/noIORest latch
Primary Metal wires
FOR i: INT IN [0..range.x) DO
size: Size  ← [6, 0];
loc: Location ← [i*pitch.x, 0];
tIO: PW.ROPE ← ListIndexItem[top, i];
bIO: PW.ROPE ← ListIndexItem[bot, i];
bY: INT ← ListItemIndexMax[in, bIO];
tY:  INT ← ListItemIndexMin[in, tIO];
bY ← IF bY#-1
THEN bY+mIBias ELSE IF ListItemIndexMax[out, bIO]#-1 THEN oIBias ELSE -1;
tY ← IF ListItemIndexMin[out, tIO]#-1
THEN oIBias ELSE IF tY#-1 THEN tY+mIBias ELSE range.y+mIBias;
IF tY >=mIBias THEN tY ← (tY -((tY +1-mIBias) MOD 2));
IF bY >=mIBias THEN bY ← (bY -((bY +1-mIBias) MOD 2));
IF Rope.Equal[tIO, bIO]
THEN tY𡤋Y𡤀
ELSE IF tY<=bY THEN ERROR Error[IO.PutFR
["2 signals (%g, %g) in same channel - ABORT", IO.rope[tIO], IO.rope[bIO]]];
size.y ← (range.y-tY) *pitch.y - pitch.y/2 + topTail;
loc.y ← tY  *pitch.y+6;
IF tIO#NILTHEN AddRet[cell:cell, size:size, loc:loc, level: CMos.met];
size.y ← bY *pitch.y+6 + botTail;
loc.y ← - botTail;
IF bIO#NILTHEN AddRet[cell:cell, size:size, loc:loc, level: CMos.met];
ENDLOOP;
IORest metal wires
IF NOT(noIORest OR blank) THEN
FOR ix: INT IN [0..ioRestLength) DO
bY: INT ← ListItemIndexMax[in, ListIndexItem[ioRest, ix]];
IF bY=-1 THEN LOOP;
AddRet[ cell: cell, level: CMos.met,
loc: [(range.x+ix) * pitch.x, mIBias    * pitch.y - 2],
size: [8,       (bY+(bY MOD 2)) * pitch.y - pitch.y/2 + topTail]];
ENDLOOP;
Collection node metal wire
IF NOT(noMux OR blank) THEN {
bY: INT ← range.y-mIBias-1;
AddRet[ cell: cell, level: CMos.met,
loc: [(range.x+ioRestLength) * pitch.x, (mIBias+1) * pitch.y-2],
size: [8,         (bY-(bY MOD 2)) * pitch.y]]};
Insert Metal Pins
FOR i: INT IN [0..range.x) DO
tName: PW.ROPE ← ListIndexItem[top, i];
bName: PW.ROPE ← ListIndexItem[bot, i];
size: Size  ← [6, 6];
loc: Location ← [i*pitch.x, range.y*pitch.y-2+topTail-size.y];
IF tName #NIL THEN PutPin [cell, size, loc,    CMos.met, tName];
IF bName #NIL THEN PutPin [cell, size, [loc.x, -botTail], CMos.met, bName];
ENDLOOP;
Enable and power Wires
AddRet[cell:cell, size:[cellWidth, 8], loc:[-leftTail, 70],  level: CMos.met2];
AddRet[cell:cell, size:[cellWidth,18], loc:[-leftTail, 42],  level: CMos.met2];
AddRet[cell:cell, size:[cellWidth,20], loc:[-leftTail, 0],  level: CMos.met2];
AddRet[cell:cell, size:[cellWidth, 4], loc:[-leftTail, 0],  level: CMos.pol];
Insert Enable and power Pins
PutPin [cell, [4, 8], [-leftTail,     70], CMos.met2, "VBB"];
PutPin [cell, [4, 8], [cellWidth-leftTail-4, 70], CMos.met2, "VBB"];
PutPin [cell, [4,18], [-leftTail,     42], CMos.met2, "VDD"];
PutPin [cell, [4,18], [cellWidth-leftTail-4, 42], CMos.met2, "VDD"];
PutPin [cell, [4,20], [-leftTail,     0],  CMos.met2, "GND"];
PutPin [cell, [4,20], [cellWidth-leftTail-4, 0],  CMos.met2, "GND"];
PutPin [cell, [4, 4], [-leftTail,     0],  CMos.pol,  enable];
PutPin [cell, [4, 4], [cellWidth-leftTail-4, 0],  CMos.pol,  enable];
Poly wires and latch input node contacts
FOR i: INT IN [0..range.y-mIBias) DO
cName: PW.ROPE ← ListIndexItem[ctl, i];
ctct: CD.ObPtr ← CMosContacts.CreateDifCon[l: 8, difLev: CMos.ndif];
size: Size  ← [cellWidth,     4];
loc: Location ← [-leftTail, (mIBias+i)*pitch.y ];
IF NOT blank AND (i MOD 2)=0 THEN [] ← PWBasics.IncludeApplication
[cell, ctct, [(range.x+ioRestLength)*pitch.x, loc.y+6]];
IF noMux THEN EXIT; -- noMux latch
AddRet[cell:cell, size:size, loc:loc, level:CMos.pol];
Insert Pins
IF cName #NIL THEN {
PutPin [cell, [4, 4], loc,        CMos.pol, cName];
PutPin [cell, [4, 4], [cellWidth-leftTail-4, loc.y], CMos.pol, cName]};
ENDLOOP;
Mux connections
FOR ctlIndex: INT IN [0..range.y-mIBias) DO
ioIndex: INT  ← -1;
ioItem: PW.ROPE ← ListIndexItem[in, ctlIndex];
IF ioItem = NIL THEN LOOP;
IF ioIndex < 0 THEN ioIndex ← ListItemIndexMax[top, ioItem];
IF ioIndex < 0 THEN ioIndex ← ListItemIndexMax[bot, ioItem];
IF ioIndex < 0 THEN {
ioIndex ← ListItemIndexMax[ioRest, ioItem];
IF ioIndex < 0 THEN LOOP;
ioIndex ← ioIndex+range.x};
AddMux[index: [ioIndex, ctlIndex]];
ENDLOOP;
Ouput connections
IF NOT blank THEN FOR i: INT IN [0..range.x) DO
IF ListItemIndexMax[out, ListIndexItem[top, i]]#-1
OR ListItemIndexMax[out, ListIndexItem[bot, i]]#-1
THEN {
loc: Location ← [i*pitch.x, oIBias*pitch.y+4];
size: Size  ← [(range.x-i+(IF noIORest THEN 0 ELSE 1))*pitch.x, 4];
[] ← PWBasics.IncludeApplication[cell, CMosContacts.CreatePolyCon[l: 8], loc];
AddRet[cell:cell, size:size, loc:[loc.x, loc.y+2], level:CMos.pol]};
ENDLOOP;
Latch Cell
IF ~blank THEN [] ← PWBasics.IncludeApplication[
cell:  cell,
subcell: PWBasics.ObjFromName[design, (IF noIORest
THEN "SimLatch"
ELSE "MuxLatch")],
location: [range.x*pitch.x, 0]];
PWBasics.RepositionCell[design, cell];
RETURN[PWBasics.NameFromObj[cell]]};
MuxLatch6x6x6: PW.UserProc = { RETURN[ MuxLatch[
design:  design,
enable: "PhB",
top:  LIST["XB", "Alpa", "Beta", "Pass", "Out",  "In"],
ctl:  LIST["Reset", "Hold",  "Set",   "ASel", "Adv", "RdXBus"],
in:   LIST["GND", "Last",  "VDD",  "Alpa",  "In",  "XB"],
out:  LIST["Out"],
bot:  LIST["XB", "Alpa", "Beta", "Pass", "Out",  "Last"]] ]};
MuxLatch6x7x6: PW.UserProc = {
mux: PW.ObjName ← Mux[
design:  design,
top:  LIST["XB", "Alpa", "Beta", "Pass", "Out",  "In"],
ctl:  LIST["Reset", "Hold",  "Set",   "BSel", "ASel", "Adv", "RdXBus"],
in:   LIST["GND", "Last",  "VDD",  "Beta",  "Alpa",  "In",  "XB"],
out:  LIST["Out"],
bot:  LIST["XB", "Alpa", "Beta", "Pass", "Out",  "Last"] ];
latch: PW.ObjName ← Latch[
design:  design,
enable: "PhB",
top:  LIST["XB", "Alpa", "Beta", "Pass", "Out",  "In"],
in:   LIST["GND", "Last",  "VDD",  "Beta",  "Alpa",  "In",  "XB"],
out:  LIST["Out"],
bot:  LIST["XB", "Alpa", "Beta", "Pass", "Out",  "Last"] ];
RETURN[ PW.AbutY[latch, mux] ]};
Mux6x6: PW.UserProc = { RETURN[ Mux[
design:  design,
top:  LIST["XB", "Alpa", "Beta", "Pass", NIL,  "In",   "Out2"],
ctl:  LIST["Reset", "Hold",  "Set",   "BSel", "ASel", "Adv", "RdXBus"],
in:   LIST["XB", "Alpa",  "Beta",  "Pass", NIL,  "Out2", "In"],
out:  LIST["Out"],
bot:  LIST["XB", "Alpa", "Beta", "Pass", "Out",  NIL,  "Out2"]] ]};
MuxBlank: PW.UserProc = { RETURN[ Mux[
design:  design,
top:  NIL,
ctl:  LIST["Reset", "Hold",  "Set",   "BSel", "ASel", "Adv", "RdXBus"],
in:   NIL,
out:  NIL,
bot:  NIL ] ]};
PW.Register[MuxLatch6x6x6,  "Latch6x6x6"];
PW.Register[MuxLatch6x7x6,  "Latch6x7x6"];
PW.Register[Latch6x6,    "Latch6x6"];
PW.Register[IFULatchRowTest, "IFULatchRowTest"];
PW.Register[IFULatchRows,  "IFULatchRows"];
PW.Register[Latch0,     "Latch0"];
PW.Register[Latch1,     "Latch1"];
PW.Register[Latch2,     "Latch2"];
PW.Register[Latch3,     "Latch3"];
PW.Register[MuxBlank,    "MuxBlank"];
PW.Register[Mux6x6,    "Mux6x6"];
END.