IFUPWContGlue.mesa
Copyright c 1985 by Xerox Corporation. All rights reserved.
Last Edited by Curry, January 29, 1986 11:03:54 am PST
DIRECTORY
CD,
CDCells,
CDDirectory,
CDExtras,
CDFrame,
CDOps,
CDOrient,
CDPinObjects,
CDProperties,
CDSimpleRules,
CMosB,
IO,
IFUPW,
IFUPWControl,
PW,
PWPins,
PWRoute,
REFBit,
Rope,
Route;
IFUPWContGlue: CEDAR PROGRAM
IMPORTS CD, CDCells, CDDirectory, CDExtras, CDFrame, CDOps, CDOrient, CDPinObjects, CDProperties, CMosB, IFUPW, IFUPWControl, IO, PW, PWPins, PWRoute, REFBit, Rope, Route, CDSimpleRules
EXPORTS IFUPWControl =
BEGIN
Ph:   TYPE = IFUPWControl.Ph;
Frame:  TYPE = IFUPWControl.Frame;
ROPE:   TYPE = IFUPWControl.ROPE;
DriveRec:  TYPE = IFUPWControl.DriveRec;
Side:   TYPE = IFUPWControl.Side;
Status: TYPE = {rejustify, progress, delayed, complete1, complete2};
StatusRope: ARRAY Status OF IO.ROPE
= ["rejustify", "progress", "delayed", "complete1", "complete2"];
chanObjDesign: CD.Design ← CDOps.CreateDesign[IFUPW.cmos];
InstantiateDrivers: PROC[root: Frame, design: CD.Design] = {
MakeDrivers: CDFrame.EnumProc = {
driver: REF DriveRec;
IF frame.data=NIL OR NOT ISTYPE[frame.data, REF DriveRec] THEN RETURN;
driver ← NARROW[frame.data];
frame.data ← IFUPWControl.DriverCell[static, conn, NARROW[frame.data], design];
frame.shell ← CDFrame.ShellFromObject[NARROW[frame.data]]};
CDFrame.EnumFrameBotOnly[root, MakeDrivers]};
CheckExpandedFrame: PROC[root: Frame] = {
CheckFrameProc: CDFrame.EnumProc = {
IF frame.shell.name=NIL OR frame.shell.name.Length[]=0 THEN Signal[];
IF frame.seqSize=0 THEN {
IF frame.data = NIL
THEN Signal[]
ELSE WITH frame.data SELECT FROM
cell: CD.Object     => {};
glue: REF CDFrame.GlueSpec => {};
ENDCASE       => Signal[];
IF frame.shell.size.x<1 OR frame.shell.size.y<1 THEN Signal[]} };
CDFrame.EnumFrameTopFirst[root, CheckFrameProc]};
Instantiate: PROC[frame: Frame, design: CD.Design]
RETURNS[new: Frame, status: Status] = {
IF frame.data#NIL AND ISTYPE[frame.data, CD.Object] THEN RETURN[frame, complete2];
IF frame.data#NIL AND frame.seqSize#0 THEN {Signal[]; frame.data ← NIL};
IF frame.seqSize=0 THEN {
IF frame.data = NIL THEN {Signal[]; RETURN[frame, complete2]};
[new, status] ← InstantiateGlue[frame, design];
IF status=complete2 THEN ERROR;
RETURN[new, status]};
status ← complete2;
new ← frame;
FOR kid: INT IN [0..new.seqSize) WHILE status#rejustify DO
stat: Status;
[new[kid], stat] ← Instantiate[new[kid], design];
status ← MIN[status, stat];
ENDLOOP;
IF status=complete2
THEN {
log.PutF["\n Completed Instantiation of: %g", IO.rope[new.shell.name]];
IF design.technology#CMosB.cmosB THEN ERROR;
new.data ← TempFrameToObject[new, design];
RETURN[new, progress]};
};
TempFrameToObject: PUBLIC PROC[frame: Frame, design: CD.Design, detailed: BOOLTRUE]
RETURNS[cell: CD.Object] = {
IF frame.data#NIL THEN Signal[];
IF frame.seqSize=0
THEN Signal[]
ELSE {
list: PW.ListOb;
FOR i: INT DECREASING IN [0..frame.seqSize) DO
IF frame.seq[i].data=NIL OR NOT ISTYPE[frame.seq[i].data, CD.Object] THEN Signal[];
list ← CONS[ NARROW[frame.seq[i].data], list] ENDLOOP;
IF frame.xory=x
THEN cell ← PW.AbutListX[design, list]
ELSE cell ← PW.AbutListY[design, list];
PW.RenameObject[design, cell, frame.shell.name]} };
InstantiateGlue: PROC[frame: Frame, design: CD.Design]
RETURNS[new: Frame, status: Status] = {
glue: REF CDFrame.GlueSpec ← NARROW[frame.data];
status ← complete1;
FOR side: Side IN Side DO
neighbor: Frame;
SELECT glue.type[side] FROM
chan => {IF glue.obj[side]=NIL THEN Signal[]; LOOP};
sum => LOOP;
diff => LOOP;
cap => LOOP;
ext => {
IF glue.obj[side]#NIL THEN LOOP;
IF glue.obj[CDFrame.OppSide[side]]#NIL
THEN {
IF glue.class=xlt THEN LOOP;
glue.obj[side] ← IF side=left OR side=right
THENPW.FlipX[design, glue.obj[CDFrame.OppSide[side]]]
ELSEPW.FlipY[design, glue.obj[CDFrame.OppSide[side]]];
status ← MIN[status, progress]}
ELSE {
log.PutF["\n Glue %g %g side waiting on %g side.",
IO.rope[frame.shell.name],
IO.rope[CDFrame.SideRope[side]],
IO.rope[CDFrame.SideRope[CDFrame.OppSide[side]]]];
status ← MIN[status, delayed]};
LOOP};
conn, pwr  => {
found: BOOL;
IF glue.obj[side]#NIL THEN LOOP;
[neighbor, found] ← CDFrame.Neighbor[frame, side];
IF ~found
THEN {status ← MIN[status, delayed]; Signal[]} -- Drop To printout
ELSE {
IF neighbor.data#NIL THEN WITH neighbor.data SELECT FROM -- ELSE Drop
cell: CD.Object => {
glue.obj[side] ← NARROW[neighbor.data];
status ← MIN[status, progress];
LOOP};
neighborGlue: REF CDFrame.GlueSpec => {
IF neighborGlue.type[CDFrame.OppSide[side]]=ext
AND neighborGlue.obj[side]#NIL
AND neighborGlue.class#xlt
AND neighborGlue.class#pwr
THEN {
glue.obj[side] ← neighborGlue.obj[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[frame.shell.name],
IO.rope[IF found THEN " " ELSE " (never?) "],
IO.rope[IF neighbor=NIL THEN "???" ELSE neighbor.shell.name],
IO.rope[CDFrame.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[frame, status];
[new, status] ← GlueIt[frame, design]};
GlueIt: PROC[frame: Frame, design: CD.Design] RETURNS[new: Frame, status: Status] = {
msg:   IO.ROPE;
initSize:  CD.Position ← [frame.shell.size.x, frame.shell.size.y];
cell:   CD.Object;
glue:   REF CDFrame.GlueSpec ← NARROW[frame.data];
variable:  BOOLMAX[frame.shell.size.xfree, frame.shell.size.yfree]#fixed;
pwrSide:  Side;
new ← frame;
IF variable AND glue.class IN [fill..xlt] THEN RETURN[new, complete1];
IF glue.class=chan AND ((new.father.xory=y) = (glue.tDir=vertical)) THEN Signal[];
SELECT glue.class FROM
fill   => cell ← CDFrame.BlankCell[design, initSize];
ext, xlt  => {
OPEN glue;
cell ← SELECT TRUE FROM
type[top]  = ext => FillerCell [design, glue, top,  initSize.y],
type[bottom] = ext => FillerCell [design, glue, bottom, initSize.y],
type[left]  = ext => FillerCell [design, glue, left,  initSize.x],
type[right] = ext => FillerCell [design, 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 ← CDFrame.BlankCell[design, initSize]; CONTINUE}};
pwrCell: CD.Object ← NIL;
routeType: PWRoute.RouteType ← IF glue.class=sb THEN switchBox ELSE channel;
sizeSpec: REF CD.Rect ← NEW[CD.Rect ← [0, 0, CDFrame.minSize.x, CDFrame.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 [design, 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 - CD.InterestSize[pwrCell].y]
ELSE sizeSpec.x2 ← MAX[0, sizeSpec.x2 - CD.InterestSize[pwrCell].x] };
IF glue.class=pwr THEN glue.obj[pwrSide] ← pwrCell;
MakeChanDummys[design, glue];
IF glue.class#pwr THEN CheckGlue[design, glue];
IF glue.tDir=horizontal
THEN cell ← PWRoute.MakeChannel[design,
glue.obj[bottom],
glue.obj[top],
glue.obj[left],
glue.obj[right], sizeSpec, glue.params, glue.tDir=vertical, routeType]
ELSE cell ← PWRoute.MakeChannel[design,
glue.obj[left],
glue.obj[right],
glue.obj[bottom],
glue.obj[top], sizeSpec, glue.params, glue.tDir=vertical, routeType];
IF glue.class=pwr THEN cell ← SELECT pwrSide FROM
bottom => PW.AbutY[design, pwrCell, cell],
top  => PW.AbutY[design, cell, pwrCell],
left  => PW.AbutX[design, pwrCell, cell],
right  => PW.AbutX[design, cell, pwrCell], ENDCASE => ERROR;
};
ENDCASE  => Signal[];
IF CellBad[cell] THEN {
temp: CD.Object;
log.PutF["\n ERROR: Substituting Blank cell for: %g", IO.rope[new.shell.name]];
temp ← CDFrame.BlankCell[design, initSize];
Signal[];
cell ← temp};
PW.RenameObject[design, cell, new.shell.name];
new.data ← cell;
new.shell.size ← CDFrame.FixedSize[CD.InterestSize[cell]];
msg ← IO.PutFR["\n Routed %g %g Frame: %g",
IO.rope[IF variable THEN "variable" ELSE "fixed"],
IO.rope[(SELECT glue.class FROM
fill  => "fill",
ext  => "extend",
xlt   => "translate",
chan  => "channel",
pwr  => "power",
sb   => "switchbox",
ENDCASE => " *B*A*D* ")],
IO.rope[new.shell.name] ];
log.PutRope[msg]; PW.Output[msg]; PW.Output["\n"];
IF variable AND (glue.class=chan OR glue.class=pwr)
THEN {
IF glue.tDir=vertical
THEN {IF new.shell.size.y # initSize.y THEN Signal[]}
ELSE {IF new.shell.size.x # initSize.x THEN Signal[]};
new ← AddExtention[
frame:  new,
xory:  (IF glue.tDir=vertical THEN x ELSE y),
glueFirst: glue.type[left]=conn OR glue.type[bottom]=conn ];
RETURN[new, rejustify]}
ELSE {
IF initSize # [new.shell.size.x, new.shell.size.y] THEN Signal[];
RETURN[new, progress] } };
GetPinsLayer: PROC[pins: REF CDFrame.PinSeq]
RETURNS[same: BOOL, layer: CD.Layer] = {
IF pins = NIL OR pins.seqSize=0 THEN RETURN[TRUE, CD.combined];
layer  ← pins[0].layer;
FOR pin: INT IN [1..pins.seqSize) DO
IF pins[pin].layer#layer THEN RETURN[FALSE, CD.combined] ENDLOOP;
RETURN[TRUE, layer]};
CellBad: PROC[cell: CD.Object] RETURNS[bad: BOOL] = {
bad ← cell=NIL OR cell.specificRef=NIL;
IF NOT bad THEN WITH cell.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[cell].x<1 OR CD.InterestSize[cell].y<1]};
AddExtention: PROC[frame: Frame, xory: CDFrame.XorY, glueFirst: BOOL]
RETURNS[new: Frame] = {
glue: Frame ← CDFrame.Glue[
b: (IF xory#y THEN cap ELSE IF glueFirst THEN ext ELSE conn ),
t: (IF xory#y THEN cap ELSE IF glueFirst THEN conn ELSE ext  ),
l: (IF xory#x THEN cap ELSE IF glueFirst THEN ext ELSE conn ),
r: (IF xory#x THEN cap ELSE IF glueFirst THEN conn ELSE ext  ) ];
frame.shell.pos ← [0,0];
new ← CDFrame.NewFrame[2, xory, frame.shell.name.Cat["Ext"]];
new.father ← frame.father;
new[1]  ← IF glueFirst THEN frame ELSE glue;
new[0]  ← IF glueFirst THEN glue ELSE frame;
new[0].father ← new[1].father ← new};
NameSize: TYPE = RECORD[name: IO.ROPE, size: INT];
SideObject: PROC[design: CD.Design, side: Side, layer: CD.Layer, list: LIST OF NameSize]
RETURNS[cell: CD.Object] = {
dim: INT ← 4*IFUPW.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.size, dim]
ENDCASE  => [dim, list.first.size];
pinApl ← PW.IncludeInCell[cell, CDPinObjects.CreatePinOb[size], pos];
CDPinObjects.SetName[pinApl, list.first.name];
CDPinObjects.SetLayer[pinApl, layer];
SELECT side FROM
top, bottom => pos.x ← pos.x + dim + list.first.size;
ENDCASE  => pos.y ← pos.y + dim + list.first.size;
ENDLOOP;
CDCells.SetInterestRect[cell, SELECT side FROM
left   => [-dim, -dim, +dim,  pos.y ],
bottom  => [-dim, -dim, pos.x,  +dim ],
right   => [0,   -dim, 2*dim, pos.y ],
top   => [-dim, 0,  pos.x,  2*dim ],
ENDCASE  => ERROR ]; 
PW.IncludeInDirectory[design, cell, "SideObject"]};
ChanObj: PUBLIC PROC [
layer:  CD.Layer,
side:  Side,
ref:  REF   ← NIL,
ph:  Ph    ← unk,
dim:  INT   ← 0,
design: CD.Design ← NIL ]
RETURNS [cell: CD.Object] ~ {
pos: CD.Position ← [0, 0];
form: REFBit.Format ← REFBit.Desc[ref].bitForm;
list: LIST OF NameSize;
IF design=NIL THEN design ← chanObjDesign;
dim ← MAX[dim, 4*IFUPW.lambda];
FOR i: CARDINAL DECREASING IN [0..form.size) DO
name:  ROPE ← IFUPWControl.BitNameToSigName[form[i].name];
nameInv: ROPE ← IFUPWControl.BitNameToSigName[form[i].nameInv];
list ← CONS[ NameSize[IFUPWControl.SignalName[FALSE, name, nameInv, ph], dim], list];
ENDLOOP;
cell ← SideObject[design, side, layer, list]};
MakeChanDummys: PROC[design: CD.Design, glue: REF CDFrame.GlueSpec] = {
AddIfUnique: PROC[item: NameSize, tlist: LIST OF NameSize]
RETURNS[new: LIST OF NameSize, done: BOOL] = {
IF tlist=NIL THEN RETURN[CONS[item, NIL], TRUE];
new ← tlist;
FOR tlist ← tlist, tlist.rest WHILE tlist#NIL DO
IF Rope.Equal[tlist.first.name, item.name] THEN
{tlist.first.size ← MAX[tlist.first.size, item.size] ; RETURN[new, FALSE]};
ENDLOOP;
RETURN[CONS[item, new], TRUE] };
sum, diff: LIST OF NameSize;
unique: BOOL;
FOR side: Side IN Side
DO IF glue.type[side]=sum OR glue.type[side]=diff THEN EXIT;
REPEAT FINISHED => RETURN ENDLOOP;
FOR side: Side IN Side DO
list: LIST OF NameSize ← NIL;
proc: PWPins.InstanceEnumerator = {
IF PWPins.GetSide[glue.obj[side], inst]=CDFrame.OppSide[side] THEN {
iSize:   CD.Position ← CDOrient.OrientedSize[inst.ob.size, inst.orientation];
nameSize: NameSize ← [
name: CDPinObjects.GetName[inst],
size: SELECT side FROM top, bottom => iSize.x, ENDCASE => iSize.y];
[list, ] ← AddIfUnique[nameSize, list] } };
IF glue.type[side]#conn AND glue.type[side]#chan AND glue.type[side]#pwr THEN LOOP;
[ ] ← PWPins.EnumerateEdgePins[glue.obj[side], proc];
FOR list ← list, list.rest WHILE list#NIL DO
[sum, unique] ← AddIfUnique[list.first, sum];
IF unique
THEN diff ← CONS[list.first, diff]
ELSE IF diff#NIL THEN {
IF Rope.Equal[diff.first.name, list.first.name]
THEN diff ← diff.rest
ELSEFOR tdiff: LIST OF NameSize ← diff, tdiff.rest WHILE tdiff.rest#NIL DO
IF ~Rope.Equal[tdiff.rest.first.name, list.first.name] THEN LOOP;
tdiff.rest ← tdiff.rest.rest; EXIT ENDLOOP};
ENDLOOP;
ENDLOOP;
FOR side: Side IN Side DO
layer: CD.Layer ← CDSimpleRules.GetLayer[design.technology.key,
IF (side=top OR side=bottom) = (glue.tDir=vertical)
THEN glue.params.trunkLayer ELSE glue.params.branchLayer];
IF glue.type[side]=sum THEN glue.obj[side] ← SideObject[design, side, layer, sum];
IF glue.type[side]=diff THEN glue.obj[side] ← SideObject[design, side, layer, diff];
ENDLOOP};
FillerCell: PROC [design: CD.Design, glue: REF CDFrame.GlueSpec, objSide: Side, width: INT]
RETURNS [cell: CD.Object] = {
template:   CD.Object     ← glue.obj[CDFrame.OppSide[objSide]];
templateSize:  CD.Position    ← CD.InterestSize[template];
resultSize:  CD.Position;
deslayer:   CD.Layer ← GlueSideLayer[design, glue, objSide];
deslayerRope: IO.ROPESELECT deslayer FROM
IFUPW.cmosMet => "metal",
IFUPW.cmosMet2 => "metal2",
IFUPW.cmosPoly => "poly",  ENDCASE => ERROR;
IF glue.class=xlt
THEN cell ← IFUPWControl.XferPins[design, template, objSide, deslayerRope, width]
ELSE cell ← IFUPWControl.XferPins[design, template, objSide, NIL,    width];
resultSize ← CD.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 [design: CD.Design, glue: REF CDFrame.GlueSpec, objSide: Side, width: INT]
RETURNS [cell: CD.Object] = {
pinObj:   CD.Object     ← glue.obj[objSide];
pinSide:   Side      ← CDFrame.OppSide[objSide];
vgObj:   CD.Object     ← glue.obj[CDFrame.OppSide[objSide]];
size1:    CD.Position    ← CD.InterestSize[pinObj];
size2:    CD.Position    ← CD.InterestSize[vgObj];
size3:    CD.Position;
deslayer:   CD.Layer ← GlueSideLayer[design, glue, objSide];
deslayerRope: IO.ROPESELECT deslayer FROM
IFUPW.cmosMet => "metal",
IFUPW.cmosMet2 => "metal2",
IFUPW.cmosPoly => "poly",  ENDCASE => ERROR;
cell ← IFUPWControl.MergePwrPins[design, vgObj, pinObj, pinSide, deslayerRope, width];
size3 ← CD.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[]};
GlueSideLayer: PROC[design: CD.Design, glue: REF CDFrame.GlueSpec, side: Side]
RETURNS[layer: CD.Layer] = {
tLayer: BOOLSELECT side FROM
left, right => glue.tDir=horizontal,
top, bottom => glue.tDir=vertical,
ENDCASE => ERROR;
RETURN[CDSimpleRules.GetLayer[design.technology.key,
IF tLayer THEN glue.params.trunkLayer ELSE glue.params.branchLayer]]};
CheckGlue: PROC[design: CD.Design, glue: REF CDFrame.GlueSpec] = {
technology: CD.Technology ← design.technology;
shell:   REF CDFrame.ShellRec ← NEW[CDFrame.ShellRec];
shells:   ARRAY Side OF REF CDFrame.ShellRec;
FOR side: Side IN Side DO IF glue.obj[side]#NIL
THEN shells[side] ← CDFrame.ShellFromObject[glue.obj[side]]
ELSE shells[side] ← NEW[CDFrame.ShellRec]; ENDLOOP;
shell.size.x ← MAX[shells[top].size.x, shells[bottom].size.x];
shell.size.y ← MAX[shells[left].size.y, shells[right].size.y];
FOR side: Side IN Side DO
shell.pins[side] ← shells[side].pins[CDFrame.OppSide[side]] ENDLOOP;
FOR side: Side IN Side DO
IF glue.type[side]#cap THEN {
layer: CD.Layer;
ok: BOOL;
IF (shell.pins[side]=NIL OR shell.pins[side].seqSize=0) THEN {
log.PutF["\n ERROR: No %g side pins.", IO.rope[CDFrame.SideRope[side]]];
Signal[];
LOOP};
[ok, layer] ← GetPinsLayer[shell.pins[side]];
IF NOT ok OR layer # GlueSideLayer[design, glue, side] THEN {
log.PutF["\n ERROR: %g side pin layer mismatch.", IO.rope[CDFrame.SideRope[side]]];
Signal[];
}};
ENDLOOP;
FOR tside: Side IN Side DO
tpins: REF CDFrame.PinSeq ← shell.pins[tside];
IF tpins=NIL THEN LOOP;
FOR tpin: INT IN [0..tpins.seqSize) DO
found: BOOLFALSE;
FOR side: Side IN Side WHILE NOT found DO
pins: REF CDFrame.PinSeq ← shell.pins[side];
IF side=tside THEN LOOP;
IF pins=NIL THEN LOOP;
FOR pin: INT IN [0..pins.seqSize) WHILE NOT found DO
IF Rope.Equal[pins[pin].name,tpins[tpin].name] THEN found ← TRUE;
ENDLOOP;
ENDLOOP;
IF NOT found THEN log.PutF["\n Unique %g side pin: %g",
IO.rope[CDFrame.SideRope[tside]], IO.rope[tpins[tpin].name]];
ENDLOOP;
ENDLOOP};
IFUPW.Show5Objects[glue.obj[bottom], glue.obj[right], glue.obj[top], glue.obj[left], NIL]
IncludeRecursiveInDesign: PUBLIC PROC [design: CD.Design] = {
ExpandAll: CDDirectory.EnumerateObjectsProc = {
new: CD.Object ← CDDirectory.Expand[me, NIL, NIL];
IF new#NIL THEN {
me^ ← new^;
ExpandAll[me, NIL];
RETURN };
CDDirectory.EnumerateChildObjects[me, ExpandAll]};
DeleteOwner: CDDirectory.EnumerateObjectsProc = {
CDProperties.PutPropOnObject[me, $Owner, NIL];
CDDirectory.EnumerateChildObjects[me, DeleteOwner]};
SetOwner: CDDirectory.EnumerateObjectsProc = {
IF CDProperties.GetPropFromObject[me, $Owner]#NIL THEN RETURN;
[] ← CDDirectory.Include[design, me];
CDDirectory.EnumerateChildObjects[me, SetOwner]};
FOR list: LIST OF CD.Instance ← CDOps.InstList[design], list.rest WHILE list#NIL DO
CDDirectory.EnumerateChildObjects[list.first.ob, ExpandAll]; ENDLOOP;
FOR list: LIST OF CD.Instance ← CDOps.InstList[design], list.rest WHILE list#NIL DO
CDDirectory.EnumerateChildObjects[list.first.ob, DeleteOwner]; ENDLOOP;
FOR list: LIST OF CD.Instance ← CDOps.InstList[design], list.rest WHILE list#NIL DO
CDDirectory.EnumerateChildObjects[list.first.ob, SetOwner]; ENDLOOP};
IncludeRecursiveInDesign: PUBLIC PROC [design: CD.Design, ob: CD.Object] = {
ExpandAll: CDDirectory.EnumerateObjectsProc = {
new: CD.Object ← CDDirectory.Expand[me, NIL, NIL];
IF new#NIL THEN {me^ ← new^; ExpandAll[me, NIL]; RETURN };
CDDirectory.EnumerateChildObjects[me, ExpandAll]};
DeleteOwner: CDDirectory.EnumerateObjectsProc = {
CDProperties.PutPropOnObject[me, $Owner, NIL];
CDDirectory.EnumerateChildObjects[me, DeleteOwner]};
SetOwner: CDDirectory.EnumerateObjectsProc = {
IF CDProperties.GetPropFromObject[me, $Owner]#NIL THEN RETURN;
[] ← CDDirectory.Include[design, me];
CDDirectory.EnumerateChildObjects[me, SetOwner]};
FOR list: LIST OF CD.Instance ← CDOps.InstList[design], list.rest WHILE list#NIL DO
ExpandAll[list.first.ob, NIL]; ENDLOOP;
FOR list: LIST OF CD.Instance ← CDOps.InstList[design], list.rest WHILE list#NIL DO
DeleteOwner[list.first.ob, NIL]; ENDLOOP;
FOR list: LIST OF CD.Instance ← CDOps.InstList[design], list.rest WHILE list#NIL DO
SetOwner[list.first.ob, NIL]; ENDLOOP};
IncludeRecursiveInDesign--pfui--: PUBLIC PROC [design: CD.Design] = {
--this procedure violates some ChipNDale requirements
--objects are illegaly removed from library designs
--don't use any of the library designs afterwards, even indirectly
myKey: REF INTNEW[INT];
myVal: REF INTNEW[INT];
DoIt: CDDirectory.EnumerateObjectsProc = {
--uses globals design and myKey
IF me.class.inDirectory AND CDProperties.GetPropFromObject[me, myKey]#x THEN {
CDProperties.PutProp[me, myKey, x];
WHILE ~CDCells.IsCell[me] DO
new: CD.Object ← CDDirectory.Expand[me, NIL, NIL];
IF new=NIL THEN EXIT ELSE me^ ← new^ ENDLOOP; --real dirty--
CDProperties.PutProp[me, $OwnerDesign, NIL];    --real dirty--
[] ← CDDirectory.Include[design, me];
CDDirectory.EnumerateChildObjects[me, DoIt, x]} };
FOR list: LIST OF CD.Instance ← CDOps.InstList[design], list.rest WHILE list#NIL DO
DoIt[list.first.ob, myVal]; ENDLOOP;
At this point, we should attach the holding company (holds all the cached library cells) to the design as a property and flush the caches of all the generator modules.
CDExtras.RemoveProperties[design, myKey] };
BuildFrame: PUBLIC CDFrame.SpecificFrameProc = {
PROC[frame: Frame, name: IO.ROPE, design: CD.Design ← NIL]
RETURNS [new: Frame, done: BOOL];
status:  Status ← rejustify;
IF name=NIL THEN name ← frame.shell.name;
done ← FALSE;
new ← frame;
IF new.shell=NIL OR NOT Rope.Equal[new.shell.name, name] THEN {
FOR index: INT IN [0..new.seqSize) WHILE NOT done DO
[new[index], done] ← BuildFrame[new[index], name, design] ENDLOOP;
RETURN[new, done]};
log.PutF["\n\n Building Frame: %g", IO.rope[name]];
new ← CDFrame.ExpandFrame   [new,  design];
   InstantiateDrivers    [new,  design];
   CDFrame.ReOrient    [new,  design];
   CDFrame.TellKidsAboutDad [new];
   CheckExpandedFrame   [new];
FOR pass: INT ← 1, pass+1 WHILE status<complete2 DO
log.PutF["\n\n Pass %g\n", IO.int[pass]]; log.Flush[];
IF status=rejustify THEN {
log.PutRope[" Rejustify\n"]; log.Flush[];
CDFrame.GetSize  [new];
CDFrame.PutSize  [new];
CDFrame.PutPos   [new, [0,0]];
IF pass<2 THEN {log.PutRope["\n\n"]; CDFrame.LogFrame[new]; log.Flush[]};
};
log.PutRope["\n"];
[new, status] ← Instantiate[new, design];
log.PutF["\n Status: %g", IO.rope[StatusRope[status]]];
SELECT status FROM
rejustify  => {LOOP};
progress  => {LOOP};
delayed  => {IF NOT CDFrame.FixOneSize[new] THEN Signal[]};
complete1  => {IF NOT CDFrame.FixOneSize[new] THEN Signal[]};
complete2  => {EXIT};
ENDCASE  => {ERROR};
ENDLOOP;
log.PutRope["\n\n"]; CDFrame.LogFrame[new]; log.Flush[];
CDFrame.GetPins[new];
RETURN[new, TRUE]};
Signal: SIGNAL = CODE;
log: IO.STREAM ← CDFrame.GetLog[];
END.