<> <> <> 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: BOOL _ TRUE] 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 THEN PW.FlipX[design, glue.obj[CDFrame.OppSide[side]]] ELSE PW.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} }; <> 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: BOOL _ MAX[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 ELSE FOR 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.ROPE _ SELECT 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.ROPE _ SELECT 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: BOOL _ SELECT 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]]]; <> 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]]]; <> }}; 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: BOOL _ FALSE; 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}; <> <> <> <> <> <> <> <> <> <> <> <> <> <> <<[] _ CDDirectory.Include[design, me];>> <> <> <> <> <> <> <> <<>> <> <> <> <> <> <> <> <> <> <> <<[] _ CDDirectory.Include[design, me];>> <> <> <> <> <> <> <> <<>> 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 INT _ NEW[INT]; myVal: REF INT _ NEW[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; <> CDExtras.RemoveProperties[design, myKey] }; BuildFrame: PUBLIC CDFrame.SpecificFrameProc = { <> <> 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 {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.