CoreGlueImpl:
CEDAR
PROGRAM
IMPORTS CDDirectory, CDViewer, CDSimpleOps, CDOps, CardTable, CCDUtils, CD, CDCells, CDRects, CDSimpleRules, CDSymbolicObjects, Convert, CoreBlock, CoreFrame, CoreGlue, CoreLibrary, CoreName, CoreOps, HashTable, IFUCoreData, IO, PWCLayoutCheckpoint, PW, PWC, 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 = PWC.NWMML;
FCT: PROC[ct: CellType] RETURNS[Frame] = {RETURN[CoreFrame.FCT[ct]]};
StatusRope:
ARRAY Status
OF
ROPE
= ["rejustify", "progress", "delayed", "complete1", "complete2"];
RouteCheckPointWritten: PUBLIC SIGNAL[name: ROPE] = CODE;
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 INT ← ALL[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#NIL THEN RETURN;
IF frame.data=NIL THEN {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;
mainNm: ROPE ← name;
msg: IO.ROPE;
initSize: CD.Position ← [frame.size.x, frame.size.y];
cell: CellType ← NIL;
glue: Glue ← NARROW[frame.data];
channels: INT ← IF 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];
IF Rope.Equal[Rope.Substr[name, 0, 3], "IFU"]
AND CoreFrame.CellCached[name]
THEN
{cell ← PWCLayoutCheckpoint.Retrieve[name]};
IF cell#
NIL
THEN log.PutF["\nRead routing checkpoint: %g",
IO.rope[name]]
ELSE {
msg ←
IO.PutFR["Routing %g, %g %g Frame: %g",
IO.time[],
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.PutF["\n%g", IO.rope[msg]]; PW.WriteF[msg]; PW.WriteF["\n"];
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 ← 0;
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 - PWC.InterestSize[pwrCell].y]
ELSE sizeSpec.x2 ← MAX[0, sizeSpec.x2 - PWC.InterestSize[pwrCell].x] };
IF glue.class=pwr THEN {mainNm ← name.Cat["Main"]; glue.cell[pwrSide] ← pwrCell};
IF glue.subClass = CoreName.RopeNm["ThreeLevel"]
THEN cell ← ThreeLevel [glue, channels]
ELSE cell ← MakeChannel [glue, mainNm, sizeSpec, routeType];
IF glue.class=pwr
THEN cell ← CoreBlock.AbutCellList[
name: NIL,
first: CoreFrame.SideSides[pwrSide],
cellTypes: LIST[pwrCell, cell] ];
IF Rope.Equal[Rope.Substr[name, 0, 3], "IFU"]
THEN {
[ ] ← CoreName.CellNm[cell, name];
PWCLayoutCheckpoint.Store[cell];
SIGNAL RouteCheckPointWritten[name];
cell ← PWCLayoutCheckpoint.Retrieve[name]} };
ENDCASE => Signal[];
msg ← IO.PutFR["Routing %g, %g complete", IO.rope[name], IO.time[] ];
log.PutF["\n%g", IO.rope[msg]]; PW.WriteF[msg]; PW.WriteF["\n"] };
frame.cell ← cell;
frame.size ← CoreFrame.FixedSize[PWC.InterestSize[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};
IF glue.subClass # CoreName.RopeNm["ThreeLevel"]
THEN CoreFrame.AddExtention[frameCT];
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, 0, FALSE];
cell ← CoreLibrary.ObjCell[object, CoreName.ID["ChanSide"]]};
SideObject:
PUBLIC
PROC
[side: Side, list: LIST OF NWMML, layer: CD.Layer, length: INT ← 0, sameLayerOnly: BOOL ← FALSE] -- 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[];
IF list#
NIL
AND list.rest=
NIL
AND length=0
AND list.first.min=0
THEN
SELECT side
FROM
top, bottom => {pos.x ← pos.x + dim}; -- keep single pin off one end
ENDCASE => {pos.y ← pos.y + dim}; -- keep single pin off one end
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];
IF sameLayerOnly AND (layer#list.first.layer)
THEN
LOOP;
-- to filter contacts (pins on diff layers)
SELECT side
FROM
top, bottom => pos.x ← IF list.first.min < pos.x THEN pos.x+dim*4 ELSE list.first.min;
ENDCASE => pos.y ← IF list.first.min < pos.y THEN pos.y+dim*4 ELSE 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]};
ENDCASE => {length ← MAX[length, pos.y ← pos.y+list.first.max]};
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]};
GND: ROPE ← CoreName.RopeNm["GND"];
VDD: ROPE ← CoreName.RopeNm["VDD"];
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;
vddIdx: INT ← 0;
gndIdx: INT ← 0;
IF cell=NIL THEN RETURN[NIL];
length ←
SELECT side
FROM
top, bottom => PWC.InterestSize[cell].x
ENDCASE => PWC.InterestSize[cell].y;
list ← CCD.SidePinList[cell, CoreFrame.OppSide[side]];
FOR lst:
LIST
OF
NWMML ← list, lst.rest
WHILE lst#
NIL
DO
IF lst.first.layer=layer
AND glue.class=pwr
THEN
SELECT CoreName.RopeNm[lst.first.name]
FROM
GND => {
lst.first.name ← IO.PutFR["%g-%g", IO.rope[GND], IO.int[gndIdx]];
gndIdx ← gndIdx +1};
VDD => {
lst.first.name ← IO.PutFR["%g-%g", IO.rope[VDD], IO.int[vddIdx]];
vddIdx ← vddIdx +1};
ENDCASE;
lst.first.max ← lst.first.max - lst.first.min; -- max ← size
ENDLOOP;
obj ← SideObject[side, list, layer, length, TRUE]};
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, 0, FALSE];
IF glue.type[side]=diff THEN objs[side] ← SideObject[side, diff, layer, 0, FALSE];
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];
TraceChannelRoute[name, objs, obj];
IF glue.class=pwr
THEN {
insts: CD.InstanceList ← NARROW [obj.specificRef, CD.CellPtr].contents;
FOR insts ← insts, insts.rest
WHILE insts #
NIL
DO
name: ROPE;
IF NOT CDSymbolicObjects.IsPin[insts.first.ob] THEN LOOP;
name ← CDSymbolicObjects.GetName[insts.first];
name ← CoreName.RopeNm[name.Substr[0, 3]];
SELECT name
FROM
VDD, GND => CDSymbolicObjects.SetName[insts.first, name]; ENDCASE;
ENDLOOP};
cell ← CoreLibrary.ObjCell[name: name, obj: obj]};
TraceChannelRouteOn: BOOL ← FALSE;
TraceChannelRoute:
PROC[name:
ROPE, objs:
ARRAY Side
OF
CD.Object, obj:
CD.Object] = {
IF TraceChannelRouteOn
THEN {
design: CD.Design ← CDOps.CreateDesign[CD.FetchTechnology[$cmosB]];
OS:
PROC[object:
CD.Object, xory: {x, y}]
RETURNS[
INT] = {
RETURN[
IF object=
NIL
THEN 0
ELSE
IF xory=x
THEN CCDUtils.ObjSize[object].x
ELSE CCDUtils.ObjSize[object].y]};
Add:
PROC[object:
CD.Object, name:
ROPE, pos:
CD.Position] = {
IF object=NIL THEN RETURN;
[] ← CDDirectory.Include[design, object, name];
CDOps.IncludeObjectI[design, object, pos]};
Add[objs[bottom], "B", [OS[objs[left],x], 0 ]];
Add[objs[left], "L", [0, OS[objs[bottom],y] ]];
Add[obj, "M", [OS[objs[left],x], OS[objs[bottom],y] ]];
Add[objs[right], "R", [OS[objs[left],x]+OS[obj,x], OS[objs[bottom],y] ]];
Add[objs[top], "T", [OS[objs[left],x], OS[objs[bottom],y]+OS[obj,y] ]];
CDSimpleOps.RenameDesign[design, name];
[ ] ← CDViewer.CreateViewer[design] }};
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 ← PWC.InterestSize[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 ← PWC.InterestSize[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 ← PWC.InterestSize[pinCell];
size2: CD.Position ← PWC.InterestSize[vgCell];
size3: CD.Position;
deslayerRope: IO.ROPE ← GlueSideLayer[glue, objSide];
cell ← CoreGlue.MergePwrPins[vgCell, pinCell, pinSide, deslayerRope, width];
size3 ← PWC.InterestSize[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: BOOL ← FALSE;
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 nwmmls=NIL THEN Signal[];
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:
BOOL ←
SELECT 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 ← PWC.InterestSize[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: BOOL ← FALSE;
workToDo: BOOL ← FALSE;
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
THEN RETURN[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
ELSE LAST[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.