CoreGlueImpl.mesa
Copyright c 1985 by Xerox Corporation. All rights reserved.
Last Edited by Curry, July 24, 1986 10:17:38 am PDT
DIRECTORY CardTable, CCDUtils, CD, CDCells, CDOrient, CDRects, CDSimpleRules, CDSymbolicObjects, Convert, Core, CoreBlock, CoreFrame, CoreGlue, CoreLibrary, CoreName, CoreOps, HashTable, IFUCoreData, IO, PW, PWRoute, Rope, Route, Sinix;
CoreGlueImpl: CEDAR PROGRAM
IMPORTS CardTable, CCDUtils, CD, CDCells, CDRects, CDSimpleRules, CDSymbolicObjects, Convert, CoreBlock, CoreFrame, CoreGlue, CoreLibrary, CoreName, CoreOps, HashTable, IFUCoreData, IO, PW, PWRoute, Rope, Route
EXPORTS CoreGlue =
BEGIN OPEN CCD: CCDUtils;
ROPE:    TYPE = Core.ROPE;
GlueClass:  TYPE = CoreGlue.GlueClass;
GlueSideType: TYPE = CoreGlue.GlueSideType;
Glue:    TYPE = CoreGlue.Glue;
GlueSpec:   TYPE = CoreGlue.GlueSpec;
Node:    TYPE = CoreGlue.Node;
NodeRec:   TYPE = CoreGlue.NodeRec;
CellType:   TYPE = Core.CellType;
Frame:   TYPE = CoreFrame.Frame;
FrameRec:  TYPE = CoreFrame.FrameRec;
FrameSeq:  TYPE = CoreFrame.FrameSeq;
Side:    TYPE = CoreFrame.Side;
Status:    TYPE = CoreGlue.Status;
Ph:     TYPE = CoreName.Ph;
NWMML:    TYPE = CCD.NWMML;
FCT:     PROC[ct: CellType] RETURNS[Frame] = {RETURN[CoreFrame.FCT[ct]]};
StatusRope: ARRAY Status OF ROPE
= ["rejustify", "progress", "delayed", "complete1", "complete2"];
glueCellClass: PUBLIC Core.CellClass ←
CoreOps.SetClassPrintProc[
NEW[Core.CellClassRec ← [name: "CoreGlue", recast: NIL]],
ClassPrintProc];
ClassPrintProc: CoreOps.PrintClassProc = {
glueData: Glue ← NARROW[data];
IO.PutRope[out, "\nGlue: "];
GlueDescription[glueData, out]};
GlueSideTypeRp: ARRAY GlueSideType OF ROPE = [
cap:  CoreName.RopeNm["cap"],
conn: CoreName.RopeNm["conn"],
pwr: CoreName.RopeNm["pwr"],
ext: CoreName.RopeNm["ext"],
chan: CoreName.RopeNm["chan"],
sum: CoreName.RopeNm["sum"],
diff: CoreName.RopeNm["diff"] ];
GlueClassRp: ARRAY GlueClass OF ROPE = [
fill: CoreName.RopeNm["Fill-"],
ext: CoreName.RopeNm["Ext-"],
xlt : CoreName.RopeNm["Xlt-"],
chan: CoreName.RopeNm["Chan-"],
pwr: CoreName.RopeNm["Pwr-"],
sb : CoreName.RopeNm["SBox-"],
bad: CoreName.RopeNm["Bad-"] ];
GlueDescription: PROC[glue: Glue, out: IO.STREAM] = {
out.PutF[" Subclass: %g b:%g l:%g t:%g r:%g ",
IO.rope[ glue.subClass ],
IO.rope[ GlueSideTypeRp[ glue.type[bottom] ] ],
IO.rope[ GlueSideTypeRp[ glue.type[left] ]] ,
IO.rope[ GlueSideTypeRp[ glue.type[top] ] ],
IO.rope[ GlueSideTypeRp[ glue.type[right] ] ] ] };
defaultOptimization: PWRoute.Optimization ← full;
CellProc: PUBLIC PROC[
subClass:     ROPE    ← NIL,
name:      ROPE    ← NIL,
l,r,b,t:      GlueSideType ← cap,  -- cap conn ext chan sum diff
bCell,rCell,tCell,lCell:  Core.CellType ← NIL,
tDir:      PWRoute.HorV ← vertical, -- vertical horizontal
tLayer:     ROPE    ← NIL,  -- metal metal2 poly
bLayer:     ROPE    ← NIL,
xlate:      BOOL    ← FALSE,
data:      REF    ← NIL ] -- metal2 poly metal
RETURNS [cellType: CellType] = {
glue: REF GlueSpec ← NEW[GlueSpec ← [
subClass:CoreName.RopeNm[subClass],
tDir:  tDir,
type:  [b,r,t,l],
cell:  [bCell,rCell,tCell,lCell],
data:  data,
params: NEW[PWRoute.RouterParamsRec ← [
opt:    defaultOptimization,
trunkLayer:  tLayer,
branchLayer: bLayer]]]];
met: ROPE ← CoreName.RopeNm["metal"];
met2: ROPE ← CoreName.RopeNm["metal2"];
tLayer ← CoreName.RopeNm[tLayer];
bLayer ← CoreName.RopeNm[bLayer];
SetGlueClass[glue];
glue.params.trunkLayer ← tLayer ← SELECT tLayer FROM
NIL => SELECT bLayer FROM
NIL  => IF tDir=horizontal THEN met ELSE met2,
met   => met2,
met2  => met,
ENDCASE => ERROR,
ENDCASE => tLayer;
glue.params.branchLayer ← bLayer ← SELECT bLayer FROM
NIL => SELECT tLayer FROM
met   => met2,
met2  => met,
ENDCASE => ERROR,
ENDCASE => bLayer;
IF xlate THEN IF glue.class#ext THEN Signal[] ELSE glue.class ← xlt;
IF name=NIL OR name.Length[]=0 THEN name ← CoreName.ID[ GlueClassRp[glue.class] ];
cellType ← CoreOps.SetCellTypeName[
NEW [ Core.CellTypeRec ← [
class:  glueCellClass,
public: CoreOps.CreateWires[0],
data:  glue] ],
name];
CoreFrame.SetFrameExpandProc[hard, cellType, NEW[CoreFrame.ExpandProc ← ExpandHard] ];
CoreFrame.SetFrameExpandProc[soft, cellType, NEW[CoreFrame.ExpandProc ← ExpandSoft] ]};
ExpandSoft: CoreFrame.ExpandProc = {
frameCT.data  ← NEW[FrameRec ← [data: frameCT.data, seq: NEW[FrameSeq[0]] ]];
frameCT.class ← CoreFrame.frameCellClass;
CoreFrame.SetFrameExpandProc[soft, frameCT, NIL]};
ExpandHard: CoreFrame.ExpandProc = {
frameCT.data  ← NEW[FrameRec ← [data: frameCT.data, seq: NEW[FrameSeq[0]] ]];
frameCT.class ← CoreFrame.frameCellClass;
CoreFrame.SetFrameExpandProc[hard, frameCT, NIL]};
SetGlueClass: PROC[glue: Glue] = {
OPEN glue;
Type: PROC[side: CoreFrame.Side] RETURNS[GlueSideType] = {
SELECT type[side] FROM
pwr  => RETURN[conn];
sum, diff => RETURN[chan];
ENDCASE => RETURN[type[side]]};
eqS: BOOL ← (Type[left] = Type[right]) OR (Type[top] = Type[bottom]);
cnt: ARRAY GlueSideType OF INTALL[0];
FOR side: CoreFrame.Side IN CoreFrame.Side DO
cnt[type[side]] ← cnt[type[side]] +1;
IF type[side]=ext AND type[CoreFrame.OppSide[side]]#conn
THEN {class ← bad; Signal[]; RETURN} ENDLOOP;
IF cnt[pwr]>1 THEN {class ← bad; Signal[]; RETURN};
SELECT
(((cnt[conn]+cnt[pwr]) *10 +
cnt[ext]) *10 +
cnt[cap]) *10 +
cnt[chan] + cnt[sum] + cnt[diff] FROM
4000 => {class ← sb};
3100 => {class ← sb};
3010 => {class ← sb};
2200 => {class ← IF eqS THEN bad ELSE sb};
2110 => {class ← IF eqS THEN bad ELSE sb};
2020 => {class ← IF ~eqS THEN sb ELSE chan};
2011 => {class ← IF ~eqS THEN bad ELSE chan};
2002 => {class ← IF ~eqS THEN bad ELSE chan};
1120 => {class ← IF ~eqS THEN bad ELSE  ext};
1111 => {class ←         chan};
1102 => {class ← IF ~eqS THEN bad ELSE  chan};
1021 => {class ← IF eqS THEN bad ELSE chan};
1012 => {class ← IF ~eqS THEN bad ELSE chan};
0040 => {class ←        fill};
0022 => {class ← IF ~eqS THEN bad ELSE chan}; -- pass through gap
ENDCASE => {class ←       bad};
IF class=chan THEN {
IF Type[left]=conn OR Type[right]=conn OR
Type[top]=chan OR Type[bottom]=chan THEN tDir←vertical ELSE tDir←horizontal;
IF cnt[chan]+cnt[sum]+cnt[diff]=0
THEN {IF (tDir=vertical) = (type[left] = cap AND type[right] = cap) THEN Signal[]}
ELSE {IF (tDir=vertical) = (Type[left] = chan OR Type[right] = chan) THEN Signal[]}};
IF class=chan AND cnt[pwr]#0 THEN class←pwr;
IF class=bad THEN Signal[]};
CheckExpandedFrame: PROC[frameCT: CellType] = {
checkProc: CoreFrame.EnumProc = {
frame: Frame ← FCT[fCT];
name: ROPE ← CoreName.CellNm[fCT].n;
IF frame.seq.size#0 THEN RETURN;
IF frame.cell#NILTHEN RETURN;
IF frame.data=NILTHEN {Signal[]; RETURN};
IF NOT ISTYPE [frame.data, Glue] THEN Signal[];
IF frame.size.x<1 OR frame.size.y<1 THEN Signal[]};
[ ] ← CoreFrame.EnumFrame[frameCT, checkProc]};
Instantiate: PROC[frameCT: CellType] RETURNS[status: Status] = {
frame: Frame ← FCT[frameCT];
name: ROPE ← CoreName.CellNm[frameCT].n;
IF frame.cell#NIL THEN RETURN[complete2];
IF frame.data#NIL AND frame.seq.size#0 THEN {Signal[]; frame.data ← NIL};
IF frame.seq.size=0 THEN {
IF frame.data = NIL THEN {Signal[]; RETURN[complete2]};
status ← InstantiateGlue[frameCT];
IF status=complete2 THEN ERROR;
RETURN[status]};
status ← complete2;
FOR kid: INT IN [0..frame.seq.size) WHILE status#rejustify DO
stat: Status ← Instantiate[frame.seq[kid]];
status ← MIN[status, stat];
ENDLOOP;
IF status=complete2
THEN {
log.PutF["\n Completed: %g %g", IO.rope[name], IO.time[]];
[ ] ← CoreFrame.RecastFrameHard[frameCT];
IF CoreFrame.IsFrameCheckPoint[framCT] THEN {
frame: CoreFrame.Frame ← CoreFrame.FCT[frameCT];
CoreFrame.WriteFrameCheckPoint[frameCT];
frame.seq  ← NEW[CoreFrame.FrameSeq[0]];
frame.data ← NIL;
CoreFrame.ReadFrameCheckPoint[frameCT, shallow]};
RETURN[progress]} };
InstantiateGlue: PROC[frameCT: CellType] RETURNS[status: Status] = {
frame: Frame ← FCT[frameCT];
name: ROPE ← CoreName.CellNm[frameCT].n;
glue: Glue ← NARROW[frame.data];
status ← complete1;
FOR side: Side IN Side DO
SELECT glue.type[side] FROM
chan => {IF glue.cell[side]=NIL THEN Signal[]; LOOP};
sum => LOOP;
diff => LOOP;
cap => LOOP;
ext => {
IF glue.cell[side]#NIL THEN LOOP;
IF glue.cell[CoreFrame.OppSide[side]]#NIL
THEN {
IF glue.class=xlt THEN LOOP;
glue.cell[side] ← IF side=left OR side=right
THEN CoreFrame.RotateCellType
[ glue.cell[CoreFrame.OppSide[side]], CDOrient.mirrorX]
ELSE CoreFrame.RotateCellType
[ glue.cell[CoreFrame.OppSide[side]], CDOrient.mirrorY];
status ← MIN[status, progress]}
ELSE {
log.PutF["\n Glue %g %g side waiting on %g side.",
IO.rope[name],
IO.rope[CoreFrame.SideRope[side]],
IO.rope[CoreFrame.SideRope[CoreFrame.OppSide[side]]]];
status ← MIN[status, delayed]};
LOOP};
conn, pwr  => {
neighborCT: CellType;
found:  BOOL;
IF glue.cell[side]#NIL THEN LOOP;
[neighborCT, found] ← CoreFrame.Neighbor[frameCT, side];
IF ~found
THEN {status ← MIN[status, delayed]; Signal[]} -- Drop To printout
ELSE {
neighbor: Frame ← FCT[neighborCT];
IF neighbor.cell#NIL THEN {
glue.cell[side] ← neighbor.cell;
status ← MIN[status, progress];
LOOP};
IF neighbor.data#NIL THEN WITH neighbor.data SELECT FROM -- ELSE Drop
neighborGlue: Glue => {
IF neighborGlue.type[CoreFrame.OppSide[side]]=ext
AND neighborGlue.cell[side]#NIL
AND neighborGlue.class#xlt
AND neighborGlue.class#pwr
THEN {
glue.cell[side] ← neighborGlue.cell[side];
status ← MIN[status, progress];
LOOP} };
ELSE Drop To printout
ENDCASE => {Signal[]; LOOP} };
log.PutF["\n Glue %g can not yet%guse %g as %g %g.",
IO.rope[name],
IO.rope[IF found THEN " " ELSE " (never?) "],
IO.rope[IF neighborCT=NIL THEN "???" ELSE CoreName.CellNm[neighborCT].n],
IO.rope[CoreFrame.SideRope[side]],
IO.rope[IF glue.type[side]=conn THEN "conn" ELSE "pwr"]];
status ← MIN[status, delayed]; LOOP};
ENDCASE => ERROR ENDLOOP;
IF status < complete1 THEN RETURN[status];
status ← GlueIt[frameCT]};
GlueIt: PROC[frameCT: CellType] RETURNS[status: Status] = {
frame: Frame ← FCT[frameCT];
name: ROPE ← CoreName.CellNm[frameCT].n;
msg:   IO.ROPE;
initSize:  CD.Position ← [frame.size.x, frame.size.y];
cell:   CellType;
glue:   Glue ← NARROW[frame.data];
channels:  INTIF glue.data=NIL THEN 6 ELSE NARROW[glue.data, REF INT]^;
pwrSide:  Side;
variable:  BOOL ← MAX[frame.size.xfree, frame.size.yfree]#fixed;
variable    MAX[frame.size.xfree, frame.size.yfree]#fixed;
IF variable AND glue.class IN [fill..xlt] THEN RETURN[complete1];
IF glue.class=chan
AND ((FCT[frame.father].first=top OR FCT[frame.father].first=bottom) = (glue.tDir=vertical))
THEN Signal[];
AdjustLayerAssignments[glue];
SELECT glue.class FROM
fill   => cell ← FCT[CCD.BlankCell[initSize]].cell;
ext, xlt  => {
cell ← SELECT TRUE FROM
glue.type[top]  = ext => FillerCell [glue, top,  initSize.y],
glue.type[bottom] = ext => FillerCell [glue, bottom, initSize.y],
glue.type[left]  = ext => FillerCell [glue, left,  initSize.x],
glue.type[right]  = ext => FillerCell [glue, right,  initSize.x],
ENDCASE    => ERROR};
chan, pwr, sb  => {
ENABLE {
Route.Signal => {log.PutF["\n Route Signal: %g", IO.rope[explanation]]; RESUME};
Route.Error => {log.PutF["\n Route ERROR: %g", IO.rope[explanation]];
cell ← FCT[CCD.BlankCell[initSize]].cell; CONTINUE}};
pwrCell: CellType ← NIL;
routeType: PWRoute.RouteType ← IF glue.class=sb THEN switchBox ELSE channel;
sizeSpec: REF CD.Rect ← NEW[CD.Rect ←
[0, 0, CoreFrame.minSize.x, CoreFrame.minSize.y]];
IF glue.class=pwr THEN {
OPEN glue;
width: INT;
SELECT TRUE FROM
type[bottom] = pwr => {pwrSide ← bottom; width ← sizeSpec.y2};
type[top]  = pwr => {pwrSide ← top;  width ← sizeSpec.y2};
type[left]  = pwr => {pwrSide ← left;  width ← sizeSpec.x2};
type[right] = pwr => {pwrSide ← right; width ← sizeSpec.x2};
ENDCASE    => ERROR;
pwrCell ← MergePwr [glue, pwrSide, width]};
IF NOT variable THEN {
sizeSpec.x2 ← initSize.x; sizeSpec.y2 ← initSize.y;
IF pwrCell#NIL THEN
IF glue.tDir=horizontal
THEN sizeSpec.y2 ←
MAX[0, sizeSpec.y2 - CCD.CellSize[pwrCell].y]
ELSE sizeSpec.x2 ←
MAX[0, sizeSpec.x2 - CCD.CellSize[pwrCell].x] };
IF glue.class=pwr THEN glue.cell[pwrSide] ← pwrCell;
IF glue.subClass = CoreName.RopeNm["ThreeLevel"]
THEN cell ← ThreeLevel  [glue, channels]
ELSE cell ← MakeChannel [glue, name, sizeSpec, routeType];
IF glue.class=pwr THEN cell ← CoreBlock.AbutCellList[
name:   NIL,
first:   CoreFrame.SideSides[pwrSide],
cellTypes: LIST[pwrCell, cell] ] };
ENDCASE  => Signal[];
frame.cell ← cell;
msg ← IO.PutFR["\n Routed %g %g Frame: %g",
IO.rope[IF ~variable THEN "fixed" ELSE IF (glue.class=chan OR glue.class=pwr)
THEN "firm" ELSE "variable"],
IO.rope[GlueClassRp[glue.class]],
IO.rope[name] ];
log.PutRope[msg]; PW.WriteF[msg]; PW.WriteF["\n"];
frame.size ← CoreFrame.FixedSize[CCD.CellSize[cell]];
IF variable AND (glue.class=chan OR glue.class=pwr)
THEN {
IF glue.tDir=vertical
THEN {IF frame.size.y # initSize.y THEN Signal[]; frame.size.xfree ← tame}
ELSE {IF frame.size.x # initSize.x THEN Signal[]; frame.size.yfree ← tame};
RETURN[rejustify]}
ELSE {
IF initSize # [frame.size.x, frame.size.y] THEN Signal[];
RETURN[progress] } };
CellBad: PROC[obj: CD.Object] RETURNS[bad: BOOL] = {
bad ← obj=NIL OR obj.specificRef=NIL;
IF NOT bad THEN WITH obj.specificRef SELECT FROM
cellPtr: CD.CellPtr   => bad ← cellPtr.contents=NIL;
list:  LIST OF CD.Object => bad ← list=NIL; -- redundant
ENDCASE       => bad ← TRUE;
RETURN[bad OR CD.InterestSize[obj].x<1 OR CD.InterestSize[obj].y<1]};
ChanSideCell: PUBLIC PROC
[side: Side, list: LIST OF ROPE, layer: CD.Layer] RETURNS[cell: CellType] = {
object: CD.Object;
nwmmls: LIST OF NWMML;
FOR list ← list, list.rest WHILE list#NIL DO
name: ROPE ← Rope.Substr[list.first, 0, Rope.Index[list.first, 0, "/"]];
size: INT ← IF list.first.Length[] > name.Length[]
THEN Convert.IntFromRope[Rope.Substr[list.first, Rope.Index[list.first, 0, "/"]+1]]
ELSE 4;
nwmmls ← CONS[[
name: CoreName.RopeNm[name],
min: CCD.lambda, -- move away from beginning edge
max: size*CCD.lambda],
nwmmls]
ENDLOOP;
object ← SideObject[side, nwmmls, layer];
cell ← CoreLibrary.ObjCell[object, CoreName.ID["ChanSide"]]};
SideObject: PUBLIC PROC
[side: Side, list: LIST OF NWMML, layer: CD.Layer, length: INT ← 0] -- max => size
RETURNS[cell: CD.Object] = {
dim: INT ← CD.FetchTechnology[$cmosB].lambda;
pos: CD.Position ← [0, 0];
size: CD.Position ← [0, 0];
cell ← CDCells.CreateEmptyCell[];
FOR list ← list, list.rest WHILE list#NIL DO
pinApl: CD.Instance;
size  ← SELECT side FROM
top, bottom => [list.first.max, dim]
ENDCASE  => [dim, list.first.max];
SELECT side FROM
top, bottom => pos.x ← MAX[pos.x, list.first.min];
ENDCASE  => pos.y ← MAX[pos.y, list.first.min];
[ ]   ← PW.IncludeInCell[cell, CDRects.CreateRect[size, layer],  pos];
pinApl ← PW.IncludeInCell[cell, CDSymbolicObjects.CreatePin[size], pos];
CDSymbolicObjects.SetName[pinApl, list.first.name];
CDSymbolicObjects.SetLayer[pinApl, layer];
SELECT side FROM
top, bottom =>
{length ← MAX[length, pos.x ← pos.x+list.first.max]; pos.x←pos.x+dim*4};
ENDCASE  =>
{length ← MAX[length, pos.y ← pos.y+list.first.max]; pos.y←pos.y+dim*4};
ENDLOOP;
CDCells.SetInterestRect[cell, SELECT side FROM
left   => [-dim, 0, +dim,  length ],
bottom  => [0,  -dim, length, +dim  ],
right   => [0,   0, 2*dim, length ],
top   => [0,   0, length, 2*dim  ],
ENDCASE  => ERROR ];
[ ] ← CDCells.RepositionCell[cell, NIL]};
GlueSideObject: PUBLIC PROC[glue: Glue, side: Side] RETURNS[obj: CD.Object] = {
cell:  CellType ← glue.cell[side];
layer:  CD.Layer ← CDSimpleRules.GetLayer[$cmosB, GlueSideLayer[glue, side]];
length: INT;
list:  LIST OF NWMML;
IF cell=NIL THEN RETURN[NIL];
length ← SELECT side FROM
top, bottom => CCDUtils.CellSize[cell].x
ENDCASE  => CCDUtils.CellSize[cell].y;
list ← CCD.SidePinList[cell, CoreFrame.OppSide[side]];
FOR lst: LIST OF NWMML ← list, lst.rest WHILE lst#NIL DO
lst.first.max ← lst.first.max - lst.first.min; -- max ← size
ENDLOOP;
obj ← SideObject[side, list, layer, length]};
MakeChannel: PUBLIC PROC
[glue: Glue, name: ROPE, sizeSpec: REF CD.Rect, routeType: PWRoute.RouteType]
RETURNS [cell: CellType] = {
sumDiffType: BOOL ← FALSE;
sum, diff: LIST OF NWMML;
objs:  ARRAY Side OF CD.Object ← [
bottom: GlueSideObject[glue, bottom ],
right:  GlueSideObject[glue, right  ],
top:  GlueSideObject[glue, top  ],
left:  GlueSideObject[glue, left  ] ];
obj:  CD.Object; 
FOR side: Side IN Side WHILE NOT sumDiffType
DO IF glue.type[side]=sum OR glue.type[side]=diff THEN sumDiffType ← TRUE ENDLOOP;
IF sumDiffType THEN {
FOR side: Side IN Side DO
nwmmls: LIST OF NWMML;
IF glue.type[side]#conn AND glue.type[side]#chan AND glue.type[side]#pwr THEN LOOP;
nwmmls ← CCD.SidePinList[glue.cell[side], CoreFrame.OppSide[side]];
FOR list: LIST OF NWMML ← nwmmls, list.rest WHILE list#NIL DO
list.first.max ← list.first.max - list.first.min; -- max ← size
list.first.min ← 0 ENDLOOP;   -- throw away position info for channel sides
FOR list: LIST OF NWMML ← nwmmls, list.rest WHILE list#NIL DO
unique: BOOL;
[sum, unique] ← AddIfUnique[list.first, sum];
IF unique
THEN diff ← CONS[list.first, diff]
ELSE diff ← DelIfPresent[list.first, diff].new;
ENDLOOP;
ENDLOOP;
FOR side: Side IN Side DO
layer: CD.Layer ← CDSimpleRules.GetLayer[$cmosB, GlueSideLayer[glue, side]];
IF glue.type[side]=sum THEN objs[side] ← SideObject[side, sum, layer];
IF glue.type[side]=diff THEN objs[side] ← SideObject[side, diff, layer];
ENDLOOP};
obj ← IF glue.tDir=horizontal
THEN PWRoute.MakeChannel[objs[bottom], objs[top], objs[left], objs[right],
sizeSpec, glue.params, FALSE, routeType]
ELSE PWRoute.MakeChannel[objs[left], objs[right], objs[bottom], objs[top],
sizeSpec, glue.params, TRUE, routeType];
cell ← CoreLibrary.ObjCell[name: name, obj: obj]};
AddIfUnique: PROC[item: NWMML, list: LIST OF NWMML]
RETURNS[new: LIST OF NWMML, done: BOOL] = {
FOR l: LIST OF NWMML ← list, l.rest WHILE l#NIL DO
IF item.name = l.first.name THEN
{l.first.max ← MAX[l.first.max, item.max]; RETURN[list, FALSE]} ENDLOOP;
RETURN[CONS[item, list], TRUE]};
DelIfPresent: PROC[item: NWMML, list: LIST OF NWMML]
RETURNS[new: LIST OF NWMML, done: BOOL] = {
IF list=NIL THEN RETURN[NIL, FALSE];
IF item.name = list.first.name THEN RETURN[list.rest, TRUE];
FOR l: LIST OF NWMML ← list, l.rest WHILE l.rest#NIL DO
IF item.name = list.rest.first.name THEN
{l.rest ← l.rest.rest; RETURN[list, TRUE]} ENDLOOP;
RETURN[list, FALSE]};
ChanObj: PUBLIC PROC [
layer:  CD.Layer,
side:  Side,
ref:  REF   ← NIL,
ph:  Ph    ← unk,
dim:  INT   ← 0 ]
RETURNS [cell: CD.Object] ~ {
pos: CD.Position ← [0, 0];
form: REFBit.Format ← REFBit.Desc[ref].bitForm;
list: LIST OF NWMML;
dim ← MAX[dim, 4*CD.FetchTechnology[$cmosB].lambda];
FOR i: CARDINAL DECREASING IN [0..form.size) DO
name:  ROPE ← CoreName.BitRopeToSigRope[form[i].name];
nameInv: ROPE ← CoreName.BitRopeToSigRope[form[i].nameInv];
list ← CONS[ NWMML[
name: CoreName.SignalName[FALSE, name, nameInv, ph],
wire: NIL, min: 0, max: dim, layer: layer], list];
ENDLOOP;
cell ← SideObject[side, list, layer]};
FillerCell: PROC [glue: Glue, objSide: Side, width: INT] RETURNS [cell: CellType] = {
templateCT:  CellType  ← glue.cell[CoreFrame.OppSide[objSide]];
templateSize:  CD.Position ← CCD.CellSize[templateCT];
resultSize:  CD.Position;
deslayerRope: IO.ROPE  ← GlueSideLayer[glue, objSide];
IF glue.class=xlt
THEN cell ← CoreGlue.XferPins[templateCT, objSide, deslayerRope, width]
ELSE cell ← CoreGlue.XferPins[templateCT, objSide, NIL,    width];
resultSize ← CCD.CellSize[cell];
IF (SELECT objSide FROM
left, right => resultSize.x#width OR resultSize.y#templateSize.y,
top, bottom => resultSize.y#width OR resultSize.x#templateSize.x,
ENDCASE  => ERROR) THEN Signal[] };
MergePwr: PROC [glue: Glue, objSide: Side, width: INT] RETURNS [cell: CellType] = {
pinSide:   Side   ← CoreFrame.OppSide[objSide];
pinCell:   CellType  ← glue.cell[objSide];
vgCell:   CellType  ← glue.cell[pinSide];
size1:    CD.Position ← CCD.CellSize[pinCell];
size2:    CD.Position ← CCD.CellSize[vgCell];
size3:    CD.Position;
deslayerRope: IO.ROPE ← GlueSideLayer[glue, objSide];
cell ← CoreGlue.MergePwrPins[vgCell, pinCell, pinSide, deslayerRope, width];
size3 ← CCD.CellSize[cell];
IF (SELECT objSide FROM
left, right => size3.y#size1.y OR size3.y#size2.y OR size3.x < width,
top, bottom => size3.x#size1.x OR size3.x#size2.x OR size3.y < width,
ENDCASE  => ERROR) THEN Signal[] };
AdjustLayerAssignments: PROC[glue: Glue] = {
reversed: BOOLFALSE;
FOR side: Side IN Side DO
temp:  ROPE;
nwmmls: LIST OF NWMML;
layer:  CD.Layer;
IF glue.type[side]#conn THEN LOOP;
nwmmls ← CCD.SidePinList[glue.cell[side], CoreFrame.OppSide[side]];
layer  ← CDSimpleRules.GetLayer[$cmosB, GlueSideLayer[glue, side]];
IF (layer=nwmmls.first.layer)#(glue.class=xlt) THEN LOOP;
IF reversed THEN Signal[];
reversed ← TRUE;
temp       ← glue.params.trunkLayer;
glue.params.trunkLayer  ← glue.params.branchLayer;
glue.params.branchLayer ← temp;
layer  ← CDSimpleRules.GetLayer[$cmosB, GlueSideLayer[glue, side]];
IF layer#nwmmls.first.layer THEN Signal[];
log.PutF["\nAdjusting Glue layers; %g side to be %g ",
IO.rope[CoreFrame.SideRope[side]], IO.rope[GlueSideLayer[glue, side]]];
ENDLOOP};
GlueSideLayer: PROC[glue: Glue, side: Side] RETURNS[layer: ROPE] = {
tLayer: BOOLSELECT side FROM
left, right => glue.tDir=horizontal,
top, bottom => glue.tDir=vertical,
ENDCASE => ERROR;
RETURN[IF tLayer THEN glue.params.trunkLayer ELSE glue.params.branchLayer]};
ThreeLevel: PROC[glue: Glue, channels: INT] RETURNS[cell: Core.CellType] = {
cellWidth: INT ← IFUCoreData.CellWidth[channels];
rowWidth: INT ← CCD.CellSize[glue.cell[top]].x;
range:   INT ← rowWidth/cellWidth;
left:   INT ← CCD.metW/2-CCD.leftTail;
right:   INT ← CCD.metW/2-CCD.leftTail+rowWidth;
polyMax:  INT ← rowWidth/8;
left, right, channels etc are all needed to position VDD and GND; Change this;
GetNode: PROC[name: ROPE] RETURNS[node: Node] = {
IF IsPwr[name] THEN RETURN[NIL];
IF name=NIL THEN RETURN[NIL];
node ← NARROW[HashTable.Fetch[nodeTable, name].value];
IF node=NIL THEN {
node ← NEW[NodeRec ← [name: name, minX: right, maxX: 0, type: CCD.cmosMet2]];
[ ] ← HashTable.Store[nodeTable, name, node] } };
MarkPolys: HashTable.EachPairAction = {
node: Node ← NARROW[value];
node.type ← IF node.maxX-node.minX <= polyMax THEN CCD.cmosPoly ELSE CCD.cmosMet2;
RETURN[FALSE] };
nwmmls: LIST OF NWMML;
nodeTable: HashTable.Table ←
HashTable.Create[equal: HashTable.RopeEqual, hash: HashTable.HashRope];
nwmmls ← CCD.SidePinList[glue.cell[top], bottom];
FOR nwmmls ← nwmmls, nwmmls.rest WHILE nwmmls#NIL DO
node: Node ← GetNode[nwmmls.first.name];
loc: INT ← nwmmls.first.min+left;
IF node=NIL THEN LOOP;
node.top  ← CONS [loc, node.top];
node.minX ← MIN [loc, node.minX];
node.maxX ← MAX [loc, node.maxX] ENDLOOP;
nwmmls ← CCD.SidePinList[glue.cell[bottom], top];
FOR nwmmls ← nwmmls, nwmmls.rest WHILE nwmmls#NIL DO
node: Node ← GetNode[nwmmls.first.name];
loc:  INT ← nwmmls.first.min+left;
IF node=NIL THEN LOOP;
node.bot  ← CONS [loc, node.bot];
node.minX ← MIN [loc, node.minX];
node.maxX ← MAX [loc, node.maxX] ENDLOOP;
IF glue.cell[left]#NIL THEN {
nwmmls ← CCD.SidePinList[glue.cell[left], right];
FOR nwmmls ← nwmmls, nwmmls.rest WHILE nwmmls#NIL DO
node: Node ← GetNode[nwmmls.first.name];
IF node=NIL THEN LOOP;
node.minX ← left ENDLOOP};
IF glue.cell[right]#NIL THEN {
nwmmls ← CCD.SidePinList[glue.cell[right], left];
FOR nwmmls ← nwmmls, nwmmls.rest WHILE nwmmls#NIL DO
node: Node ← GetNode[nwmmls.first.name];
IF node=NIL THEN LOOP;
node.maxX ← right ENDLOOP };
[ ] ← HashTable.Pairs[nodeTable,  MarkPolys];
cell ← ThreeLevelRoute[nodeTable, range, left, right, cellWidth, channels]};
ThreeLevelRoute: PUBLIC PROC
[ nodeTable: HashTable.Table, range, left, right, cellWidth, channels: INT]
RETURNS[cell: CellType] = {
obj: CD.Object;
pitch: CD.Position ← [CCD.metPitch, CCD.met2Pitch/2]; -- y pitch - met2 pol met2 pol . . .
pass:  LIST OF Node ← NIL;
conn:  LIST OF Node ← NIL;
assigned: LIST OF Node ← NIL;
iSize:   CD.Rect ← [left, 0, right, 0];
MarkNodeDependencies[nodeTable];
[pass, conn] ← BuildNodeLists[nodeTable, iSize];
Assign Node Rows
DO
progress:  BOOLFALSE;
workToDo: BOOLFALSE;
FOR nodePtr: LIST OF Node ← conn, nodePtr.rest WHILE nodePtr#NIL DO
polyRow: BOOL ← nodePtr.first.type = CCD.cmosPoly;
rockMax: INT ← pitch.y*(IF polyRow THEN -1 ELSE -2);
IF polyRow THEN Signal[];
IF nodePtr.first.row>-1 THEN LOOP;
workToDo ← TRUE;
FOR rocks: LIST OF Node ← nodePtr.first.rocks, rocks.rest WHILE rocks#NIL DO
IF rocks.first.row=-1 THEN GOTO unAssignedRocks;
rockMax ← MAX[rockMax, rocks.first.row];
REPEAT unAssignedRocks => LOOP ENDLOOP;
progress ← TRUE;
assigned ← AddUnassignedNodeToAssigned
[polyRow, pitch.y, nodePtr.first, assigned, rockMax];
ENDLOOP;
IF NOT workToDo THEN EXIT;
IF NOT progress THEN Signal[]; -- circular
ENDLOOP;
Determine Y Size
iSize.y2 ← 0;
FOR nodePtr: LIST OF Node ← assigned, nodePtr.rest WHILE nodePtr#NIL DO
iSize.y2 ← MAX[iSize.y2, nodePtr.first.row] ENDLOOP;
iSize.y2 ← iSize.y2 + CCD.cnctSize/2 + CCD.topTail;
iSize.y1 ←  0   - CCD.cnctSize/2  - CCD.botTail - CCD.lambda;
obj ← CDCells.CreateEmptyCell[];
Draw Power extension wires
FOR jj: INT IN [0..1] DO
name: ROPE ← CoreName.RopeNm[IF jj=0 THEN "GND" ELSE "VDD"];
FOR ii: INT IN [0..range) DO
xx: INT ← ii*cellWidth + (channels+jj)*pitch.x;
CCD.PutPin[obj,
[CCD.metW, CCD.metW],   [xx, iSize.y2-CCD.metW],   CCD.cmosMet, name];
CCD.PutPin[obj,
[CCD.metW, CCD.metW],   [xx, iSize.y1],      CCD.cmosMet, name];
CCD.AddRet[obj,
[CCD.pwrW, iSize.y2-iSize.y1], [xx-(CCD.pwrW-CCD.metW)/2, iSize.y1], CCD.cmosMet];
ENDLOOP ENDLOOP;
Draw Other extension wires
FOR nodePtr: LIST OF Node ← pass, nodePtr.rest WHILE nodePtr#NIL DO-- pass
name:  ROPE ← nodePtr.first.name;
vgNode: BOOL   ← IsPwr[name];
xx:   INT   ← nodePtr.first.minX;
xxx:  INT   ← xx;
wireW: INT   ← CCD.metW;
IF vgNode THEN {wireW ← CCD.pwrW; xxx ← xx-(CCD.pwrW-CCD.metW)/2};
IF nodePtr.first.top=NIL OR nodePtr.first.bot=NIL THEN {
log.PutF["\nSignal %g is not connected anywhere", IO.rope[nodePtr.first.name]];
Signal[]};
CCD.PutPin [obj, [wireW, CCD.metW], [xx, iSize.y2-CCD.metW], CCD.cmosMet, name];
CCD.PutPin [obj, [wireW, CCD.metW], [xx, iSize.y1],    CCD.cmosMet, name];
CCD.AddRet [obj, [wireW, iSize.y2-iSize.y1], [xxx, iSize.y1], CCD.cmosMet];
ENDLOOP;
DrawAssigndedNodes[obj, assigned, iSize];
CDCells.SetInterestRect[obj, iSize];
[ ] ← CDCells.RepositionCell[obj, NIL];
cell ← CoreLibrary.ObjCell[obj, CoreName.ID["SB"]];
RETURN[cell]};
Branch:  TYPE = REF BranchRec;
BranchRec: TYPE = RECORD[loc: INT, top, bot: Node];
InsertBranch: PROC [branchTab: CardTable.Ref, s: {top,bot}, loc: INT, node: Node] ~ {
branch: Branch ← NARROW[CardTable.Fetch[branchTab, loc].val];
IF branch=NIL THEN {
branch ← NEW[BranchRec ← [loc: loc]];
[ ] ← CardTable.Store[branchTab, loc, branch]};
SELECT s FROM
top => {IF branch.top#NIL THEN Signal[]; branch.top ← node};
bot => {IF branch.bot#NIL THEN Signal[]; branch.bot ← node}; ENDCASE};
MarkNodeDependencies: PROC[nodeTable: HashTable.Table] = {
InsertNodes: HashTable.EachPairAction = {
node: Node ← NARROW[value];
FOR list: LIST OF INT ← node.top, list.rest WHILE list#NIL DO
InsertBranch[branchTab, top, list.first, node] ENDLOOP;
FOR list: LIST OF INT ← node.bot, list.rest WHILE list#NIL DO
InsertBranch[branchTab, bot, list.first, node] ENDLOOP;
RETURN[FALSE] };
MarkNodes: CardTable.EachPairAction = {
branch: Branch ← NARROW[val];
IF branch.top=NIL OR branch.bot=NIL OR branch.top=branch.bot THEN RETURN[FALSE];
FOR list: LIST OF Node ← branch.top.rocks, list.rest WHILE list#NIL DO
IF list.first=branch.bot THEN EXIT;
REPEAT FINISHED => branch.top.rocks ← CONS[branch.bot, branch.top.rocks] ENDLOOP;
FOR list: LIST OF Node ← branch.bot.clouds, list.rest WHILE list#NIL DO
IF list.first=branch.top THEN EXIT;
REPEAT FINISHED => branch.bot.clouds ← CONS[branch.top, branch.bot.clouds] ENDLOOP;
RETURN[FALSE] };
branchTab: CardTable.Ref ← CardTable.Create[];
[ ] ← HashTable.Pairs[nodeTable,  InsertNodes];
[ ] ← CardTable.Pairs[branchTab, MarkNodes]};
BuildNodeLists: PROC[nodeTable: HashTable.Table, iSize: CD.Rect]
RETURNS[pass, conn: LIST OF Node] = {
SortNodes: HashTable.EachPairAction = {
node: Node ← NARROW[value];
SELECT TRUE FROM
node.maxX = node.minX => pass  ← OrderedInsertion[pass, node];
ENDCASE      => conn  ← OrderedInsertion[conn, node];
RETURN[FALSE] };
[ ] ← HashTable.Pairs[nodeTable, SortNodes]};
OrderedInsertion: PROC[list: LIST OF Node, node: Node] RETURNS [LIST OF Node] = {
test: INT;
IF list = NIL THEN RETURN[CONS[node, list]];
test ← (list.first.maxX-list.first.minX)-(node.maxX-node.minX); -- largest segemet first
IF test = 0 THEN test ← (node.minX)-(list.first.minX);    -- smallest position first
IF test < 0  
THENRETURN[CONS[node, list]]
ELSE {list.rest ← OrderedInsertion[list.rest, node]; RETURN[list]}};
AddUnassignedNodeToAssigned: PROC
[oddRow: BOOL, step: INT, node: Node, orig: LIST OF Node, rockMax: INT]
RETURNS [LIST OF Node] = {
Next: PROC[row: INT] RETURNS[next: INT] =
{ next ← row + (IF (((row/step+2) MOD 2)=1)=oddRow THEN 2*step ELSE step) };
minOkRow: INT ← Next[rockMax+step];
IF orig=NIL OR minOkRow < orig.first.row
THEN {node.row ← minOkRow; RETURN[CONS[node, orig] ]};
IF minOkRow = orig.first.row AND node.maxX < orig.first.minX
THEN {node.row ← minOkRow; RETURN[CONS[node, orig] ]};
FOR list: LIST OF Node ← orig, list.rest DO
thisRow: INT  ← list.first.row;
nextRow: INT ← IF list.rest#NIL
THEN list.rest.first.row
ELSE Next[MAX[thisRow, rockMax+step]];
nextMinX: INT ← IF list.rest#NIL
THEN list.rest.first.minX
ELSELAST[INT];
minOkRow ← Next[MAX[thisRow-step, rockMax+step]]; -- thisRow or thisRow+step
SELECT TRUE FROM
thisRow = nextRow     => SELECT TRUE FROM
minOkRow   < thisRow  => ERROR;
minOkRow  > thisRow  => LOOP;
list.first.maxX >= node.minX => LOOP;
node.maxX  >= nextMinX  => LOOP;
ENDCASE        => node.row ← thisRow;
thisRow+step = nextRow   => SELECT TRUE FROM
minOkRow < thisRow    => ERROR;
minOkRow = thisRow    => SELECT TRUE FROM
list.first.maxX >= node.minX => LOOP;
ENDCASE        => node.row ← thisRow;
minOkRow = nextRow    => SELECT TRUE FROM
node.maxX  >= nextMinX  => LOOP;
ENDCASE        => node.row ← nextRow;
minOkRow > thisRow    => LOOP;
ENDCASE        => ERROR;
thisRow+2*step = nextRow   => SELECT TRUE FROM
minOkRow < thisRow    => ERROR;
minOkRow = thisRow    => SELECT TRUE FROM
list.first.maxX < node.minX  => node.row ← thisRow;
node.maxX  < nextMinX  => node.row ← nextRow;
ENDCASE        => LOOP;
minOkRow < nextRow    => node.row ← minOkRow; -- between
minOkRow = nextRow    => SELECT TRUE FROM
node.maxX  < nextMinX  => node.row ← nextRow;
ENDCASE        => LOOP;
ENDCASE        => LOOP;
ENDCASE        => ERROR;
list.rest ← CONS[node, list.rest];
IF oddRow#(((node.row)/step MOD 2)=1) THEN Signal[];
EXIT ENDLOOP;
RETURN[orig]};
IsPwr: PROC[name: ROPE] RETURNS[BOOL] =
{RETURN[Rope.Find[name,"GND"]#-1 OR Rope.Find[name,"VDD"]#-1]};
DrawAssigndedNodes: PROC[cell: CD.Object, assigned: LIST OF Node, iSize: CD.Rect] = {
FOR nodePtr: LIST OF Node ← assigned, nodePtr.rest WHILE nodePtr#NIL DO -- top bot
name:  ROPE  ← nodePtr.first.name;
yMid:  INT  ← nodePtr.first.row;
minX:  INT  ← nodePtr.first.minX;
maxX:  INT  ← nodePtr.first.maxX;
rowType: CD.Layer ← nodePtr.first.type;
pFrng: INT  ← (CCD.pwrW-CCD.metW)/2;
vgNode: BOOL  ← IsPwr[name];
rowWW: INT  ← IF rowType = CCD.cmosPoly THEN CCD.polW ELSE CCD.met2W;
ctct:  CD.Object ← CCD.Contact[rowType];
IF minX=iSize.x1 THEN
CCD.PutPin[cell, [rowWW, rowWW], [minX,    yMid-rowWW/2], rowType, name];
IF maxX=iSize.x2 THEN
CCD.PutPin[cell, [rowWW, rowWW], [maxX-rowWW, yMid-rowWW/2], rowType, name];
CCD.AddRet [cell, [maxX-minX, rowWW], [minX, yMid-rowWW/2], rowType];
FOR nodeTop: LIST OF INT ← nodePtr.first.top, nodeTop.rest WHILE nodeTop#NIL DO
xx:  INT ← nodeTop.first;
IF vgNode
THEN CCD.AddRet[cell, [CCD.pwrW, iSize.y2-yMid],  [xx-pFrng, iSize.y1], CCD.cmosMet]
ELSE CCD.AddRet[cell, [CCD.metW, iSize.y2-yMid],  [xx,     yMid], CCD.cmosMet];
CCD.PutPin [cell, [CCD.metW, CCD.metW],      [xx,iSize.y2-CCD.metW], CCD.cmosMet, name];
[] ← PW.IncludeInCell[cell, ctct, [xx-(CCD.cnctSize-CCD.metW)/2, yMid-CCD.cnctSize/2]];
ENDLOOP;
FOR nodeBot: LIST OF INT ← nodePtr.first.bot, nodeBot.rest WHILE nodeBot#NIL DO
xx:  INT ← nodeBot.first;
IF vgNode
THEN CCD.AddRet[cell, [CCD.pwrW, yMid-iSize.y1], [xx-pFrng, iSize.y1], CCD.cmosMet]
ELSE CCD.AddRet[cell, [CCD.metW, yMid-iSize.y1], [xx,   iSize.y1], CCD.cmosMet];
CCD.PutPin [cell, [CCD.metW, CCD.metW],      [xx,   iSize.y1], CCD.cmosMet, name];
[] ← PW.IncludeInCell[cell, ctct, [xx-(CCD.cnctSize-CCD.metW)/2, yMid-CCD.cnctSize/2]];
ENDLOOP;
ENDLOOP};
RouteSoft: PUBLIC CoreGlue.FrameRouter = {RETURN[complete2]};
RouteHard: PUBLIC CoreGlue.FrameRouter = {
PROC[frameCT: CellType] RETURNS[status: Status]
name: ROPE ← CoreName.CellNm[frameCT].n;
status ← rejustify;
log.PutF["\n\n Building Frame: %g", IO.rope[name]];
   CoreFrame.RotateFrame   [frameCT];
   CoreFrame.TellKidsAboutDad [frameCT];
   CheckExpandedFrame   [frameCT];
FOR pass: INT ← 1, pass+1 WHILE status<complete2 DO
log.PutF["\n\n Pass %g %g\n", IO.int[pass], IO.time[]]; log.Flush[];
IF status=rejustify THEN {
log.PutRope[" Rejustify\n"]; log.Flush[];
CoreFrame.GetSize  [frameCT];
CoreFrame.ReSize  [frameCT];
CoreFrame.RePos  [frameCT, [0,0]];
IF pass<2 THEN {
log.PutRope["\n\n"];
CoreFrame.LogFCT[frameCT, 0, 1, log];
log.Flush[]} };
log.PutRope["\n"];
status ← Instantiate[frameCT];
log.PutF["\n Status: %g", IO.rope[StatusRope[status]]];
SELECT status FROM
rejustify  => {LOOP};
progress  => {LOOP};
delayed  => {IF NOT CoreFrame.FixOneSize[frameCT] THEN Signal[]};
complete1  => {IF NOT CoreFrame.FixOneSize[frameCT] THEN Signal[]};
complete2  => {EXIT};
ENDCASE  => {ERROR};
ENDLOOP;
log.PutRope["\n\n"];
CoreFrame.LogFCT[frameCT, 0, 1, log];
log.Flush[]};
CoreFrame.GetPins[new];
log:  IO.STREAM ← CoreFrame.GetLog[];
Signal: SIGNAL = CODE;
END.