IFUPWMux.mesa,
Copyright c 1985 by Xerox Corporation. All rights reserved.
Last Edited by Curry, January 7, 1986 9:02:12 am PST
DIRECTORY
Basics,
CD,
CDCells USING [CreateEmptyCell, SetInterestRect],
CDDirectory,
CDRects USING [CreateRect],
Convert,
IFUPW,
IO,
PW,
Rope;
IFUPWMux: CEDAR PROGRAM
IMPORTS
CD, CDCells, CDDirectory, CDRects, Convert, IO, IFUPW, PW, Rope
EXPORTS IFUPW =
BEGIN OPEN IFUPW;
gnd: INT ← 6;
vdd: INT ← 7; -- vdd assumed to be gnd+1 below
IFUMuxRow: PUBLIC PROC [
design: CD.Design,
name:  PW.ROPE,
leftCtl: List ← NIL,
rightCtl: List ← NIL,
top:  LIST OF REF,
in:   LIST OF REF,
out:  LIST OF REF,
bot:  LIST OF REF,
rp:   RowParams ← IFUDataColNSeq ]
RETURNS [cell: CD.Object] = {
cells: PW.ListOb;
ctl: List ← IFUPW.ListConcat[leftCtl, rightCtl];
FOR ii: INT DECREASING IN [0..rp.rngByte*rp.rngBit) DO
byte, index: INT;
[byte, index] ← IFUPW.ByteBitFromIndex[ii, rp];
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;
cell ← PW.AbutListX[design, cells];
cell ← IFUPW.RenameObjAndAssignRowPins
[design, cell, name, FALSE, top, bot, leftCtl, rightCtl, rp];
RETURN[cell]};
Mux: PROC [
design: CD.Design,
top:  List,
ctl:  List,
in:   List,
out:  List,
bot:  List]
RETURNS [cell: CD.Object] = {
cellName:  PW.ROPE;
xstrLgth:  INT  ← 8*lambda;
xstrWth:  INT  ← (4+4)*lambda;
tranBiasx:  INT  ← (xstrWth-metW)/2;
xstrHt:  INT  ← xstrLgth + 2*difW;
pFrng:  INT  ← (pwrW-metW)/2;
topExtra:  INT  ← cnctSize/2 + topTail;
botExtra:  INT  ← cnctSize/2 + botTail;
pitch:   Size  = [metPitch, met2Pitch];
found:  BOOL  ← TRUE;
muxEvenDn: BOOL  = TRUE;
range:   Size;
outN:   PW.ROPE ← IF out=NIL THEN NIL ELSE out.first;
iRect:   CD.Rect;
outIndex, outIndexBot:  INT;
top ← FixGVInList[top];
bot ← FixGVInList[bot];
range  ← [MAX[ListLength[top],ListLength[bot]], ListLength[ctl]];
outIndex  ← ListItemIndexMin[top, outN];
outIndexBot ← 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;
cellName ← UniqueCellName["Mux", top, bot, in, out];
[found, cell] ← CDDirectory.Fetch[design, cellName];
IF found THEN RETURN[cell];
log.PutRope["."];
Metal wires and their pins
cell ← CDCells.CreateEmptyCell[];
IF outN#NIL AND ListItemIndexMax[top, outN]=-1 AND ListItemIndexMax[bot, outN]=-1
THEN ERROR Error[IO.PutFR
["Output signal (%g) is not in either top or bot lists - ABORT", IO.rope[outN]]];
IF outN#NIL AND ListItemIndexMax[in, outN]#-1 THEN ERROR Error[IO.PutFR
["Output signal (%g) is also used as input - ABORT", IO.rope[outN]]];
FOR i: INT IN [0..range.x) DO
loc: Location ← [i*pitch.x, 0];
tIO: PW.ROPE ← ListIndexItem[top, i];
bIO: PW.ROPE ← ListIndexItem[bot, i];
topOut: BOOL ← Rope.Equal[tIO,outN];
botOut: BOOL ← Rope.Equal[bIO,outN];
tY:  INTIF topOut THEN ListNonNILIndexMin[in] ELSE ListItemIndexMin[in,tIO];
bY: INTIF botOut THEN ListNonNILIndexMax[in] ELSE ListItemIndexMax[in,bIO];
tY ← tY  + ((tY + (IF topOut=muxEvenDn THEN 1 ELSE 2)) MOD 2);
bY ← bY  + ((bY + (IF botOut=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: cmosMet,
size: [metW, (range.y-tY) * pitch.y + topExtra ],
loc: [i*pitch.x,    tY  * pitch.y          ]];
IF bIO#NILTHEN AddRet[cell:cell, level: cmosMet,
size: [metW,    bY * pitch.y + botExtra ],
loc: [i*pitch.x,     0 * pitch.y - botExtra ]];
ENDLOOP;
FOR vgIndex: INT IN [gnd..vdd] DO AddRet[cell: cell, level: cmosMet,
size: [pwrW, range.y * pitch.y + topExtra + botExtra ],
loc: [vgIndex*pitch.x-pFrng,     - botExtra ]] ENDLOOP;
AddMetalPins
[cell, top, bot, -leftTail, range.y*pitch.y+ topExtra, - botExtra, FALSE];
BEGIN
xstr:  CD.Object ← TransistorObject[size: [xstrWth, xstrLgth], difLayer: cmosNDif];
dcon:  CD.Object ← IFUPW.Contact[cmosNDif];
pcon:  CD.Object ← IFUPW.Contact[cmosPoly];
vcon:  CD.Object ← IFUPW.Contact[cmosMet2];
scon:  CD.Object ← IFUPW.Contact[cmosPWCont];
lstIONotGnd:  BOOL ← TRUE;
lstGndClear:  BOOL ← TRUE;
thsIONotGnd: BOOL ← TRUE;
thsGndClear:  BOOL ← TRUE;
FOR ctlIndex: INT IN [0..range.y) DO
cnctBiasx: INT ← (cnctSize-metW)/2;
Include: PROC[object: CD.Object, location: Location] =
{[] ← PW.IncludeInCell[cell, object, location]};
AddGndContact: PROC[updn: {up, dn}] = {IF updn=up
THEN Include[scon, [gnd*pitch.x-cnctBiasx, (ctlIndex+1)*pitch.y - cnctSize/2 ]]
ELSE Include[scon, [gnd*pitch.x-cnctBiasx, (ctlIndex+0)*pitch.y - cnctSize/2 ]]};
AddMux: PROC [index: Location] = {
ptchOset:  INT ← (xstrLgth+difW)/2; -- for gap between transistor and diff wire
dWL:   INT ← (ABS[outIndex-index.x])*pitch.x+cnctSize;
pWL:   INT ← (range.x-index.x)*pitch.x;
minX:   INT ← MIN[outIndex, index.x];
polX:   INT ← MIN[outIndex, index.x];
pol:   CD.Object ← CDRects.CreateRect[[pWL,  polW], cmosPoly];
dif:   CD.Object ← CDRects.CreateRect[[dWL,  difW], cmosNDif];
dPtch:   CD.Object ← CDRects.CreateRect[[xstrWth, difW], cmosNDif];
dir:   INT ← IF ((index.y MOD 2)=0)=muxEvenDn THEN 1 ELSE -1;
yloc:   INT ← index.y*pitch.y + pitch.y/2;
Include[pcon, [range.x *pitch.x -cnctBiasx, yloc      -cnctSize/2 ]];
Include[vcon, [range.x *pitch.x +cnctSize, yloc      -cnctSize/2 ]];
Include[pol,  [index.x *pitch.x -cnctBiasx, yloc      -polW/2  ]];
Include[dif,  [minX  *pitch.x -cnctBiasx, yloc +dir*pitch.y/2 -difW/2  ]];
Include[dPtch, [index.x *pitch.x -cnctBiasx, yloc +dir*ptchOset -difW/2  ]];
Include[dcon, [outIndex *pitch.x -cnctBiasx, yloc +dir*pitch.y/2 -cnctSize/2 ]];
Include[dcon, [index.x *pitch.x -cnctBiasx, yloc -dir*pitch.y/2 -cnctSize/2 ]];
Include[xstr,  [index.x *pitch.x-tranBiasx, yloc     -xstrLgth/2 ]]};
cName: PW.ROPE ← Convert.RopeFromInt[ctlIndex];
size:  Size  ← [cellWidth,  met2W];
loc:  Location ← [-leftTail, ctlIndex*pitch.y+pitch.y/2-met2W/2];
ioIndex: INT  ← -1;
AddRet[cell:cell, size:size, loc:loc, level:cmosMet2];
PutPin [cell, [met2W, met2W], loc,         cmosMet2, cName];
PutPin [cell, [met2W, met2W], [cellWidth-leftTail-met2W, loc.y], cmosMet2, cName];
IF outN#NIL
THEN {
ioItem: PW.ROPE ← ListIndexItem[in, ctlIndex];
IF ioItem # NIL THEN {
IF ioIndex < 0 THEN ioIndex ← ListItemIndexMax[top, ioItem];
IF ioIndex < 0 THEN ioIndex ← ListItemIndexMax[bot, ioItem];
IF ioIndex >=0 THEN AddMux[index: [ioIndex, ctlIndex]]};
thsIONotGnd ← ioIndex # gnd;
thsGndClear ← thsIONotGnd AND ((ioIndex<gnd)=(outIndex<gnd));
IF ((ctlIndex MOD 2)=0)=muxEvenDn
THEN {IF thsIONotGnd AND lstIONotGnd THEN AddGndContact[dn]}
ELSE {IF thsGndClear  AND lstGndClear THEN AddGndContact[dn]};
IF (ctlIndex+1) = range.y THEN IF ((ctlIndex MOD 2)=0)=muxEvenDn
THEN {IF thsGndClear        THEN AddGndContact[up]}
ELSE {IF thsIONotGnd       THEN AddGndContact[up]};
lstIONotGnd ← thsIONotGnd;
lstGndClear ← thsGndClear}
ELSE AddGndContact[dn];
ENDLOOP;
END;
PW.IncludeInDirectory[design, cell];
iRect ← CD.InterestRect[cell];
IF outIndex=-1 AND bot=NIL OR ListAllNil[bot] THEN iRect.y1 ← iRect.y1 - botExtra;
iRect.y2 ← iRect.y1 + range.y*pitch.y + topExtra + botExtra;
CDCells.SetInterestRect[cell, iRect];
PW.RenameObject[design, cell, cellName];
RETURN[cell]};
IFUDecoderRow: PUBLIC PROC [
design: CD.Design,
name:  PW.ROPE,
ctl:  List,    -- total nof names must be 2*nof significant bits
val:  REF ValArray, -- 1st ctl is MSB TRUE eg. bit0 bit0' bit1 bit1' ...
top:  LIST OF REF,
out:  LIST OF REF,
bot:  LIST OF REF,
rp:   RowParams  ← IFUDataColNSeq ]
RETURNS [cell: CD.Object] = {
cells: PW.ListOb;
FOR ii: INT DECREASING IN [0..rp.rngByte*rp.rngBit) DO
byte, index: INT;
[byte, index] ← ByteBitFromIndex[ii, rp];
cells ← CONS[ Decoder[
design: design,
ctl:  ctl,
val:  val[byte][index],
top:  ExpandList[byte, index, top],
out:  ExpandList[byte, index, out],
bot:  ExpandList[byte, index, bot] ], cells];
ENDLOOP;
cell ← PW.AbutListX[design, cells];
cell ← RenameObjAndAssignRowPins[design, cell, name];
RETURN[cell]};
Decoder: PROC [
design: CD.Design,
top:  List,
ctl:  List,
val:  INT,
out:  List,
bot:  List]
RETURNS [cell: CD.Object] = {ERROR -- not fixed up for variable lambda -- };
Decoder: PROC [
design: CD.Design,
top:  List,
ctl:  List,
val:  INT,
out:  List,
bot:  List]
RETURNS [cell: CD.Object] = {
pitch:   Size  = [metPitch, met2Pitch];
xtraY:   INT  = (pitch.y-polW-difW)/2;
rangeY:  INT  ← ListLength[ctl]+1;
outN:   PW.ROPE ← IF out=NIL THEN NIL ELSE out.first;
cell   ← CDCells.CreateEmptyCell[];
top    ← FixGVInList[top];
bot   ← FixGVInList[bot];
Metal wires and their pins
FOR i: INT IN [0..nofVWires) DO
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: cmosMet,
size: [metW,  (rangeY-tY) * pitch.y + polW/2+met2W/2+topTail ],
loc: [i*pitch.x,  tY  * pitch.y          ]];
IF bIO#NILTHEN AddRet[cell:cell, level: cmosMet,
size: [metW,     bY * pitch.y + botTail ],
loc: [i*pitch.x,    0 * pitch.y - botTail ]];
ENDLOOP;
AddMetalPins
[cell, top, bot, -leftTail, rangeY*pitch.y+polW/2+met2W/2+topTail, -botTail, TRUE];
All the rest
BEGIN
Put: PROC[obj: CD.Object, location: Location] =
{[] ← PW.IncludeInCell[cell, obj, location]};
colGND: INT = (nofVWires-2) *pitch.x;
colLt:  INT = colGND +2  *pitch.x;
colPCnt: INT = colLt  +1  *pitch.x;
colRt:  INT = colPCnt  +2*(4+5+3);
colVDD: INT = colRt  +1  *pitch.x;
colWCnt: INT = colVDD +1  *pitch.x;
currIsXstr, lastIsXstr: BOOLFALSE;
nXstr:  CD.Object ← TransistorObject[size: [32,4], difLayer: cmosNDif];
pXstr:  CD.Object ← TransistorObject[size: [32,4], difLayer: cmosPDif];
nCtct:  CD.Object ← CDSimpleRules.Contact[cmosMet, cmosNDif];
pCtct:  CD.Object ← CDSimpleRules.Contact[cmosMet, cmosPDif];
wCtct:  CD.Object ← CDSimpleRules.Contact[cmosMet, cmosWNDif];
polCtct: CD.Object ← CDSimpleRules.Contact[cmosMet, cmosPoly];
viaCtct: CD.Object ← CDSimpleRules.Contact[cmosMet, cmosMet2];
pol:  CD.Object ← CDRects.CreateRect[[colRt-colLt,  4], cmosPoly];
nDif:  CD.Object ← CDRects.CreateRect[[32,     4], cmosNDif];
pDif:  CD.Object ← CDRects.CreateRect[[22,     4], cmosPDif];
met:  CD.Object ← CDRects.CreateRect[[8,   pitch.y], cmosMet];
AddRet[cell, [8,     (rangeY-1)*pitch.y-2],  [colRt, -2], cmosMet];
AddRet[cell, [1*pitch.x+8,  (rangeY-0)*pitch.y],  [colVDD, -3], cmosMet];
AddRet[cell, [2*pitch.x+8+10, (rangeY+0)*pitch.y+10], [colRt-10, -3], cmosNWell];
Out poly wire
IF outN#NIL THEN {
ioIndex: INT ← -1;
IF ioIndex < 0 THEN ioIndex ← ListItemIndexMin[top, outN];
IF ioIndex < 0 THEN ioIndex ← ListItemIndexMin[bot, outN];
IF ioIndex >= 0 THEN {
loc: Location ← [ioIndex*pitch.x, 0 ];
AddRet[cell:cell, size:[colRt-loc.x, polW], loc:loc, level:cmosPoly];
Put[polCtct, [loc.x, loc.y-2 ]] } };
FOR ctlIndex: INT IN [0..rangeY] DO
ycen: INT ← ctlIndex*pitch.y+polW/2;
ylow: INT ← ctlIndex*pitch.y-xtraY-difW;
cName: PW.ROPESELECT ctlIndex FROM
0   => VDD,
rangeY => GND,
ENDCASE => ListIndexItem[ctl, ctlIndex-1];
ioIndex: INT  ← -1;
size:  Size  ← [cellWidth, met2W];
loc:  Location ← [-leftTail,  ctlIndex*pitch.y+polW/2-met2W/2];
AddRet[cell:cell, size:size, loc:loc, level:cmosMet2];
PutPin [cell, [met2W, met2W], loc,          cmosMet2, cName];
PutPin [cell, [met2W, met2W], [cellWidth-leftTail-met2W, loc.y], cmosMet2, cName];
IF cName = NIL THEN LOOP;
IF ioIndex < 0 THEN ioIndex ← ListItemIndexMin[top, cName];
IF ioIndex < 0 THEN ioIndex ← ListItemIndexMin[bot, cName];
IF ioIndex >= 0 THEN Put[viaCtct, [ioIndex*pitch.x-2, loc.y-1]];
SELECT ctlIndex FROM
0   => {
AddRet[cell:cell, size:[8,6], loc:[colLt, ycen], level:cmosMet];
AddRet[cell:cell, size:[8,6], loc:[colRt, ycen], level:cmosMet];
Put[polCtct,  [colLt,    ycen - 8/2   ]];
Put[polCtct,  [colRt,    ycen - 8/2   ]];
Put[viaCtct,   [colVDD,    ycen - 10/2   ]];
LOOP};
rangeY => {
Put[viaCtct,   [colLt-1,    ycen - 10/2   ]];
Put[wCtct,  [colWCnt,   ylow      ]];
IF lastIsXstr
THEN Put[nCtct, [colLt,    ylow       ]]
ELSE Put[met,  [colLt,    ylow       ]];
LOOP};
ENDCASE;
currIsXstr ← PW.XthBitOfN[(rangeY-1-ctlIndex)/2, val];
IF (ctlIndex MOD 2) = 0 THEN currIsXstr ← NOT currIsXstr;
IF NOT currIsXstr
THEN {
Put[met,   [colLt,  ylow      ]];
Put[wCtct,  [colWCnt, ylow      ]];
IF lastIsXstr THEN
Put[nCtct,  [colLt,   ylow       ]] }
ELSE {
Put[pol,   [colLt,  ycen - polW/2 ]];
Put[polCtct,  [colPCnt,  ycen - 8/2   ]];
Put[viaCtct,   [colPCnt+8, ycen - 10/2   ]];
Put[nDif,   [colGND+4, ycen - pitch.y/2  ]];
Put[nDif,   [colGND+4, ycen + pitch.y/2-4 ]];
Put[nXstr,  [colGND,  ycen - 6    ]];
IF NOT lastIsXstr THEN
Put[nCtct,  [colLt,   ylow       ]];
Put[pDif,   [colRt,  ycen - pitch.y/2  ]];
Put[pDif,   [colRt,  ycen + pitch.y/2-4 ]];
Put[pXstr,  [colRt-4,  ycen - 6    ]];
Put[wCtct,  [colWCnt, ylow      ]];
IF (ctlIndex MOD 2) =1
THEN {
Put[pCtct, [colRt,  ylow + pitch.y  ]];
Put[pCtct, [colVDD,  ylow     ]] }
ELSE {
Put[pCtct, [colRt,  ylow     ]];
Put[pCtct, [colVDD,  ylow + pitch.y  ]] };
};
lastIsXstr ← currIsXstr;
ENDLOOP;
END;
PW.IncludeInDirectory[design, cell];
RETURN[cell]};
DecoderTest: IFUPW.UserProc = { RETURN[ Decoder[
design:  design,
top:  LIST["A1", "A0", NIL],
ctl:  LIST["A0", "A0'", "A1", "A1'", "A2", "A2'", "A3", "A3'", "A4", "A4'", "A5", "A5'"],
val:  33,
out:  LIST["Out"],
bot:  LIST["A1", NIL, "Out" ] ] ] };
MuxTest: IFUPW.UserProc = { RETURN[ Mux[
design:  design,
top:  LIST["XB", "Alpha", "Beta", "Pass", NIL, "In1"],
ctl:  LIST["RdXBus", "Hold",  "Clear", "Set", "Set1", "Set2"],
in:   LIST["XB",  "Alpha",  GND,  VDD, "In1", "In2"],
out:  LIST["Out2"],
bot:  LIST["XB", "Alpha", "Beta", "Pass", "Out2", NIL, GND, VDD, "In2"] ] ]};
MuxTest: IFUPW.UserProc = { RETURN[ Mux[
design:  design,
top:  LIST["XBus.37", NIL, NIL, NIL, NIL, NIL, "GND", "VDD", NIL, NIL, NIL, NIL, NIL],
ctl:  LIST["ARtOSetB", "ARtAlpB", "ARtAlp03B", "ARtAlp47B",
"ARtOp47B", "ARtBetB", "ARtBet03B", "ARtBet47B",
"BRtOSetB", "BRtAlpB", "BRtAlp03B", "BRtAlp47B",
"BRtOp47B", "BRtBetB", "BRtBet03B", "BRtBet47B",
"CRtOSetB", "CRtAlpB", "CRtAlp03B", "CRtAlp47B",
"CRtOp47B", "CRtBetB", "CRtBet03B", "CRtBet47B"],
in:   LIST[NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL],
out:  LIST[NIL],
bot:  LIST["XBus.37", NIL, NIL] ] ]};
PW.Register[DecoderTest,   "DecoderTest"];
PW.Register[MuxTest,    "MuxTest"];
END.