IFUCoreDataMuxImpl.mesa,
Copyright c 1986 by Xerox Corporation. All rights reserved.
Last Edited by Curry, June 11, 1986 12:46:42 pm PDT
DIRECTORY CCDUtils, CD, CDCells, CDRects, CDSatellites, CDTexts, Core, CoreClasses, CoreCreate, CoreFrame, CoreLibrary, CoreName, CoreOps, CoreWire, CoreXform, IFUCoreCells, IFUCoreData, CoreInstCell, IO, Lists, PW, Rope;
IFUCoreDataMuxImpl: CEDAR PROGRAM
IMPORTS CCDUtils, CD, CDCells, CDRects, CDSatellites, CDTexts, CoreCreate, CoreFrame, CoreLibrary, CoreName, CoreOps, CoreWire, CoreXform, IFUCoreCells, IFUCoreData, CoreInstCell, IO, Lists, PW, Rope =
BEGIN OPEN CCDUtils;
ROPE: TYPE = Core.ROPE;
VDD: ROPE ← CoreName.RopeNm["VDD"];
GND: ROPE ← CoreName.RopeNm["GND"];
nil: ROPE ← CoreName.RopeNm["nil"];
Signal: SIGNAL = CODE;
ExpandDataMuxFrameSoft: CoreFrame.ExpandProc = { -- frameCT
nil:  ROPE       ← CoreName.RopeNm["nil"];
data:  IFUCoreData.DpCellData ← NARROW[frameCT.data];
xform:  CoreXform.Xform ← CoreXform.GetXform[data.type];
domain: NAT    ← CoreXform.XformSize[xform];
rowPub: CoreWire.CWire ← [frameCT.public];
rowPwr: CoreWire.CWire ← rowPub.f["pwr"];
rowIn: CoreWire.CWire ← rowPub.f["in"];
rowOut: CoreWire.CWire ← rowPub.f["out"];
rowLeft: CoreWire.CWire ← rowPub.f["left"];
rowRight: CoreWire.CWire ← rowPub.f["right"];
rowTop: CoreWire.CWire ← rowPub.f["top"];
rowBot: CoreWire.CWire ← rowPub.f["bot"];
rowCtl: CoreWire.CWire ← IF rowLeft.w.size#0 THEN rowLeft ELSE rowRight;
frame:  REF CoreFrame.FrameRec ← NEW[CoreFrame.FrameRec ← [first: left]];
frame.seq         ← NEW[CoreFrame.FrameSeq[domain]];
FOR ii: INT DECREASING IN [0..domain) DO
bitPub:  Core.Wires ← NIL;
blank:   BOOL ← rowOut.i[0].x[ii].n[]=nil;
mux:   Core.CellType ← NIL;
instances:  CoreClasses.CellInstances ← NIL;
ctx:   CoreName.Context ← CoreName.NewContext[];
out:   CoreWire.CWire ← rowOut.i[0].x[ii];
FOR index: INT IN [0..rowPwr.w.size) DO
bitPub ← CONS[ CoreName.CtxCopyWire[ctx, rowPwr.i[index].w], bitPub];
ENDLOOP;
IF NOT blank THEN {
bitPub ← CONS[ CoreName.CtxCopyWire[ctx, out.w], bitPub];
FOR index: INT IN [0..rowCtl.w.size) DO
ctl: CoreWire.CWire ← rowCtl.i[index].x[ii];
in:  CoreWire.CWire ← rowIn.i[index].x[ii];
instance: CoreClasses.CellInstance ← CoreCreate.Instance[
CoreCreate.Transistor[ ],
["gate", ctl.w ],
["ch1", in.w ],
["ch2", out.w ] ];
instances ← CONS[ instance, instances];
bitPub ← CONS[ CoreName.CtxCopyWire[ctx, ctl.w], bitPub];
bitPub ← CONS[ CoreName.CtxCopyWire[ctx, in.w], bitPub];
ENDLOOP };
mux ← CoreCreate.Cell[
public:  CoreOps.CreateWire[bitPub],
onlyInternal: NIL,
instances:  instances,
name:   NIL,
props:   NIL];
frame.seq[ii] ← CoreFrame.NewFrameCell[0, NIL, [first: left, cell: mux]];
ctx ← CoreName.KillContext[ctx];
ENDLOOP;
frameCT.class ← CoreFrame.frameCellClass;
frameCT.data  ← frame;
CoreFrame.SetFrameExpandProc[soft, frameCT, NIL]};
ExpandDataMuxFrameHard: CoreFrame.ExpandProc = { -- frameCT
data:  IFUCoreData.DpCellData ← NARROW[frameCT.data];
xform:  CoreXform.Xform ← CoreXform.GetXform[data.type];
domain: NAT    ← CoreXform.XformSize[xform];
rowPub: CoreWire.CWire ← [frameCT.public];
rowPwr: CoreWire.CWire ← rowPub.f["pwr"];
rowIn: CoreWire.CWire ← rowPub.f["in"];
rowOut: CoreWire.CWire ← rowPub.f["out"];
rowLeft: CoreWire.CWire ← rowPub.f["left"];
rowRight: CoreWire.CWire ← rowPub.f["right"];
rowTop: CoreWire.CWire ← rowPub.f["top"];
rowBot: CoreWire.CWire ← rowPub.f["bot"];
rowCtl: CoreWire.CWire ← IF rowLeft.w.size#0 THEN rowLeft ELSE rowRight;
frame:  REF CoreFrame.FrameRec ← NEW[CoreFrame.FrameRec ← [first: left]];
frame.seq         ← NEW[CoreFrame.FrameSeq[domain]];
FOR ii: INT DECREASING IN [0..domain) DO
renameProc: CoreInstCell.RenameProc ~
{new ← code.Decode[letter: old]; IF new=NIL THEN Signal[]; RETURN[new]};
mux:  Core.CellType;
code:  IFUCoreData.NameLetterCode  ← IFUCoreData.CreateNameLetterCode
["Mux", LIST[rowTop, rowCtl, rowIn, rowOut, rowBot], ii];
generic: Core.CellType  ← CoreLibrary.Get[IFUCoreCells.library, code.name];
IF generic=NIL THEN {
GenList: PROC[cwire: CoreWire.CWire] RETURNS[list: LIST OF ROPE ] = {
FOR index: INT DECREASING IN [0..cwire.w.size) DO
letter: ROPE ← NIL;
name: ROPE ← cwire.i[index].x[ii].n;
IF name#NIL THEN letter ← code.Encode[name];
list ← CONS[letter, list] ENDLOOP};
obj: CD.Object ← Mux[
channels:  data.channels,
top: GenList[rowTop ],
ctl: GenList[rowCtl ],
in:  GenList[rowIn ],
out: GenList[rowOut ],
bot: GenList[rowBot ] ];
generic ← CoreLibrary.ObjCell[obj, code.name];
CoreLibrary.Set[IFUCoreCells.library, code.name, generic]};
mux ← CoreInstCell.SpecificGeneric[generic, renameProc];
frame.seq[ii] ← CoreFrame.NewFrameCell[0, NIL, [first: left, cell: mux]];
ENDLOOP;
frameCT.class ← CoreFrame.frameCellClass;
frameCT.data  ← frame;
frame.cell   ← CoreFrame.RecastFrameHard[frameCT];
IFUCoreData.BlockSides[frame.cell, [frameCT.public]];
frame.seq   ← NEW[CoreFrame.FrameSeq[0]]; -- free the children
CoreFrame.SetFrameExpandProc[hard, frameCT, NIL]};
textScale: INT ← 2;
font:  CDTexts.CDFont ← CDTexts.MakeFont["Xerox/TiogaFonts/Helvetica7", textScale];
dwText: CD.Object   ← CDTexts.CreateText["driveWeak", font];
Mux: PROC [
channels: INT,
top:  LIST OF ROPE,
ctl:  LIST OF ROPE,
in:   LIST OF ROPE,
out:  LIST OF ROPE,
bot:  LIST OF ROPE]
RETURNS [cell: CD.Object] = {
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:   CD.Position = [metPitch, met2Pitch];
muxEvenDn: BOOL   = TRUE;
range:   CD.Position;
outN:   ROPE  ← IF out=NIL THEN NIL ELSE out.first;
iRect:   CD.Rect;
vdd:   INT ← channels+1;
gnd:   INT ← channels;
cellWidth: INT ← IFUCoreData.CellWidth[channels];
cnctBiasx: INT ← (cnctSize-metW)/2;
outIndex, outIndexBot:  INT;
top ← FixGVCharInList[channels, top];
bot ← FixGVCharInList[channels, bot];
range  ← [MAX[Lists.ListLength[top],Lists.ListLength[bot]], Lists.ListLength[ctl]];
outIndex  ← Lists.ListItemIndexMin[top, outN];
outIndexBot ← Lists.ListItemIndexMin[bot, outN];
IF outIndex  # Lists.ListItemIndexMax[top, outN] OR
outIndexBot  # Lists.ListItemIndexMax[bot, outN] OR
(outIndex#-1  AND outIndexBot#-1 AND outIndex#outIndexBot)
THEN {
log.PutF["Multiple column output %g- ABORT", IO.rope[outN]];
Signal[]};
IF outIndex = -1 THEN outIndex ← outIndexBot;
log.PutRope["."];
Metal wires and their pins
cell ← CDCells.CreateEmptyCell[];
IF outN#NIL AND Lists.ListItemIndexMax[top, outN]=-1
AND Lists.ListItemIndexMax[bot, outN]=-1 THEN {
log.PutF["\n Output signal (%g) is not in either top or bot lists - ABORT",
IO.rope[outN]];
Signal[]};
IF outN#NIL AND Lists.ListItemIndexMax[in, outN]#-1 THEN{
log.PutF["\n Output signal (%g) is also used as input - ABORT", IO.rope[outN]];
Signal[]};
FOR i: INT IN [0..range.x) DO
loc: CD.Position ← [i*pitch.x, 0];
tIO: ROPE ← Lists.ListIndexItem[top, i];
bIO: ROPE ← Lists.ListIndexItem[bot, i];
topOut: BOOL ← Rope.Equal[tIO,outN];
botOut: BOOL ← Rope.Equal[bIO,outN];
tY:  INTIF topOut THEN Lists.ListNonNILIndexMin[in] ELSE Lists.ListItemIndexMin[in,tIO];
bY: INTIF botOut THEN Lists.ListNonNILIndexMax[in] ELSE Lists.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 {
log.PutF["\n 2 signals (%g, %g) in same channel - ABORT",
IO.rope[tIO], IO.rope[bIO]];
Signal[]};
IF tIO#NILTHEN CCDUtils.AddRet[cell:cell, level: cmosMet,
size: [metW, (range.y-tY) * pitch.y + topExtra ],
loc: [i*pitch.x,       tY  * pitch.y     ]];
IF bIO#NILTHEN CCDUtils.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 CCDUtils.AddRet[cell: cell, level: cmosMet,
size: [pwrW, range.y * pitch.y + topExtra + botExtra ],
loc: [vgIndex*pitch.x-pFrng,     - botExtra ]] ENDLOOP;
AddMetalPins
[cell, top, bot, 0, range.y*pitch.y+ topExtra, - botExtra, TRUE];
BEGIN
xstr:  CD.Object ← TransistorObject[size: [xstrWth, xstrLgth], difLayer: cmosNDif];
dcon:  CD.Object ← Contact[cmosNDif];
pcon:  CD.Object ← Contact[cmosPoly];
vcon:  CD.Object ← Contact[cmosMet2];
scon:  CD.Object ← Contact[cmosPWCont];
pvconn: CD.Object ← CDRects.CreateRect[[2*cnctSize, cnctSize], cmosMet];
lstIONotGnd:  BOOL ← TRUE;
lstGndClear:  BOOL ← TRUE;
thsIONotGnd: BOOL ← TRUE;
thsGndClear:  BOOL ← TRUE;
FOR ctlIndex: INT IN [0..range.y) DO
Include: PROC[object: CD.Object, location: CD.Position] =
{[] ← 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: CD.Position] = {
inst0, inst1: CD.Instance;
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[pvconn, [range.x *pitch.x -cnctBiasx, yloc       -cnctSize/2 ]];
Include[vcon, [range.x *pitch.x -cnctBiasx+cnctSize+lambda, 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 ]];
inst0   ← PW.IncludeInCell[cell, xstr,
     [index.x *pitch.x -tranBiasx, yloc       -xstrLgth/2 ]];
inst1   ← PW.IncludeInCell[cell, dwText,
     [index.x *pitch.x -tranBiasx, yloc   -lambda*textScale/2 ]];
CDSatellites.Associate[inst0, inst1]};
cName: ROPE  ← Lists.ListIndexItem[ctl, ctlIndex];
size:  CD.Position ← [cellWidth,  met2W];
loc:  CD.Position ← [metW/2-leftTail, ctlIndex*pitch.y+pitch.y/2-met2W/2];
ioIndex: INT   ← -1;
CCDUtils.AddRet[cell:cell, size:size, loc:loc, level: cmosMet2];
CCDUtils.PutPin [cell, [met2W, met2W], loc,
cmosMet2, cName];
CCDUtils.PutPin [cell, [met2W, met2W], [metW/2-leftTail+cellWidth-met2W, loc.y],
cmosMet2, cName];
IF outN#NIL
THEN {
ioItem: ROPE ← Lists.ListIndexItem[in, ctlIndex];
IF ioItem # NIL THEN {
IF ioIndex < 0 THEN ioIndex ← Lists.ListItemIndexMax[top, ioItem];
IF ioIndex < 0 THEN ioIndex ← Lists.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;
iRect ← CD.InterestRect[cell];
IF outIndex=-1 AND bot=NIL OR Lists.ListAllNil[bot] THEN iRect.y1 ← iRect.y1 - botExtra;
iRect.y2 ← iRect.y1 + range.y*pitch.y + topExtra + botExtra;
CDCells.SetInterestRect[cell, iRect];
[ ] ← CDCells.RepositionCell[cell, NIL];
RETURN[cell]};
AddMetalPins: PUBLIC PROC
[cell: CD.Object, top, bot: LIST OF ROPE, refX, topY, botY: INT, realNames: BOOL] = {
length: INTMAX[Lists.ListLength[top], Lists.ListLength[bot]];
FOR i: INT IN [0..length) DO
tName: ROPE ← Lists.ListIndexItem[top, i];
bName: ROPE ← Lists.ListIndexItem[bot, i];
size: CD.Position ← [metW, metW];
loc: CD.Position ← [refX+i*metPitch, topY-size.y];
IF tName #NIL THEN CCDUtils.PutPin [cell, size, loc,    cmosMet,
(IF realNames THEN tName ELSE NIL)];
IF bName #NIL THEN CCDUtils.PutPin [cell, size, [loc.x, botY], cmosMet,
(IF realNames THEN bName ELSE NIL)];
ENDLOOP};
FixGVCharInList: PROC [chans: INT, list: LIST OF ROPE]
RETURNS[new: LIST OF ROPE] =
{RETURN[AddGVCharToList[chans, DelGVFromList[list]]]};
DelGVFromList: PROC [list: LIST OF ROPE] RETURNS[new: LIST OF ROPE] = {
nonNilItemAdded: BOOLFALSE;
IF list=NIL THEN RETURN[NIL];
FOR ii: INT DECREASING IN [0..Lists.ListLength[list]) DO
item: ROPE ← Lists.ListIndexItem[list, ii];
item ← SELECT item FROM GND, VDD, plus, minus => NIL, ENDCASE => item;
IF item=NIL AND NOT nonNilItemAdded THEN LOOP;
nonNilItemAdded ← TRUE;
new ← CONS[item, new] ENDLOOP};
AddGVCharToList: PROC [chans: INT, list: LIST OF ROPE]
RETURNS[new: LIST OF ROPE] = {
FOR ii: INT DECREASING IN [0..MAX[chans+2, Lists.ListLength[list]]) DO
item: ROPE ← Lists.ListIndexItem[list, ii];
IF ii=chans+1 THEN item ← plus;
IF ii=chans  THEN item ← minus;
new ← CONS[item, new] ENDLOOP};
plus:  ROPE ← CoreName.RopeNm["+"];
minus: ROPE ← CoreName.RopeNm["-"];
log: IO.STREAM ← CoreFrame.GetLog[];
IFUCoreData.RegisterSubClassExpand [soft, "Mux", ExpandDataMuxFrameSoft];
IFUCoreData.RegisterSubClassExpand [hard, "Mux", ExpandDataMuxFrameHard];
END.