DIRECTORY CDDirectory, CDViewer, CDSimpleOps, CDOps, CardTable, CCDUtils, CD, CDCells, CDRects, CDSimpleRules, CDSymbolicObjects, Convert, Core, CoreBlock, CoreFrame, CoreGlue, CoreLibrary, CoreName, CoreOps, HashTable, IFUCoreData, IO, PWCLayoutCheckpoint, PW, PWC, PWRoute, Rope, Route; 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]; 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]], mirrorX] ELSE CoreFrame.RotateCellType [ glue.cell[CoreFrame.OppSide[side]], rotate180X]; 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} }; 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]]; TerminalIO.PutF[msg]; TerminalIO.PutF["\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]]; TerminalIO.PutF[msg]; TerminalIO.PutF["\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]}; 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; 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]; 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 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; 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[]; 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; 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 = { 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 {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[]}; log: IO.STREAM _ CoreFrame.GetLog[]; Signal: SIGNAL = CODE; END. VCoreGlueImpl.mesa Copyright c 1985 by Xerox Corporation. All rights reserved. Last Edited by Curry, August 23, 1986 12:35:05 pm PDT Last Edited by: Louis Monier February 10, 1987 7:40:20 pm PST 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]}; ELSE Drop To printout 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]}; left, right, channels etc are all needed to position VDD and GND; Change this; Assign Node Rows IF polyRow THEN Signal[]; Determine Y Size Draw Power extension wires Draw Other extension wires PROC[frameCT: CellType] RETURNS[status: Status] CoreFrame.GetPins[new]; Κ.·˜šœ™Jšœ<™˜>Jšœ?˜?Jšœœ˜—Jšœ+˜+—šœœ œ˜Jšœ3˜3šœ œœ˜šœ˜Jšœœ.˜DJšœœ1˜G———Jšœœ;˜Qšœ.˜0Jšœ$˜(Jšœ8˜<—šœœ˜5Jšœœ˜ Jšœ&˜&Jšœ œ˜!—šœ,œ˜5Jšœ"˜"Jšœ ˜ Jšœ˜$Jšœ-˜-——Jšœ˜Jšœœ"œ œ ˜EJšœœ œœ ˜N——Jšœ˜Jšœ9˜9šœ œœ˜3šœ˜šœ˜Jšœœœ#˜JJšœœœ$˜K—šœ.˜0Jšœ ž œ ˜%—Jšœ ˜—šœ˜Jšœ)œ ˜9Jšœ˜———J™š žœœœ œœ˜4Jšœ œœœ˜%š œœœœœ˜0Jšœ œ%œ˜4Jš œœœœœŸ ˜8Jšœœ˜—Jš œœœœœ˜E—J™šž œœ˜Jš œœœœ œœ˜MJšœœ˜Jšœœœœ˜šœœœ˜,Jšœœ>˜Hšœœœ$˜2JšœO˜SJšœ˜—šœ œ˜Jšœ˜Jšœ1˜1šœ˜Jšœ˜——Jšœ˜—Jšœ,œ˜3Jšœ,œ˜=—J˜šž œœ˜Jšœœœœ œœœœŸ˜oJšœœ ˜Jšœœœ ˜-Jšœœ˜Jšœœ˜Jšœ!˜!šœœœ œœ œœœ˜UJšœ&Ÿ˜DJšœŸ˜A—šœœœ˜,Jšœœ ˜šœœ˜Jšœ$˜$Jšœ˜"—šœ,œœ˜8JšŸ+˜+—šœ˜Jšœœœ œ˜VJšœ œœ œ˜S—Jšœœ<˜FJšœ œ=˜HJšœ3˜3Jšœ*˜*šœ˜Jšœœ(˜DJšœœ(˜A—Jšœ˜—šœœ˜.Jšœ$˜$Jšœ&˜&Jšœ$˜$Jšœ#˜#Jšœœ˜—Jšœ#œ˜)—J™Jšœœ˜#Jšœœ˜#K˜š žœœœœœ ˜OJšœ"˜"Jšœœ(ž œ˜MJšœ˜ Jšœœœœ˜Jšœœ˜Jšœœ˜Jš œœœœœ˜šœ œ˜Jšœ'˜'Jšœ˜%—Jšœ6˜6š œœœœœœ˜8šœœ˜0šœ!˜+šœ˜Jš œœœœœ˜AJšœ˜—šœ˜Jš œœœœœ˜AJšœ˜—Jšœ˜——Jšœ/Ÿ ˜Jšœœœœ˜Jšœ/˜/Jšœ+˜+—Jšœœ ˜:Jšœ!œ˜:Jšœœœ˜@Jšœœœ œ˜MJšœœœœ ˜KJšœ'˜'Jšœ'˜'——J˜š ž œœœœœœ˜3Jš œœœœœ˜+š œœœœœœ˜2šœ˜ Jš œœœœœ˜H——Jšœœœ˜ —J˜š ž œœœœœœ˜4Jš œœœœœ˜+Jš œœœœœœ˜$Jšœœœ œ˜<š œœœœœœ˜7šœ"œ˜)Jšœœœœ˜3——Jšœœ˜—J˜šžœœœ™Jšœœ™Jšœ ™ Jšœœœ™Jšœ™šœœ™Jšœœ ™—Jšœœ™Jšœ/™/Jšœœœœ™Jšœœœ!™4š œœ œœ™/Jšœœ+™6Jšœ œ.™;šœœœ™Jšœœ™4Jšœœ)™2—Jšœ™—Jšœ&™&J™—š ž œœœœœ˜UJšœ?˜?Jšœœ)˜:Jšœ œ ˜Jšœœœ!˜6šœ˜JšœC˜GJšœ/œ ˜B—Jšœ$˜$šœœ ˜Jšœ"œ˜AJšœ"œ˜AJšœœœ ˜#——J™š žœœœœœ˜SJšœ/˜/Jšœ*˜*Jšœ)˜)Jšœ œ&˜2Jšœ œ%˜1Jšœ œ ˜Jšœœœ ˜5JšœL˜LJšœ˜šœœ ˜Jšœœœ˜EJšœœœ˜EJšœœœ ˜#——J™šžœœ˜,Jšœ œœ˜šœ œ˜Jšœœ˜ Jšœœœœ˜Jšœœ˜Jšœœœ˜"JšœC˜CJšœ(ž œ˜CJšœœœ ˜Jšœ-œœ˜9Jšœ œ ˜Jšœ œ˜Jšœ$˜$Jšœ2˜2Jšœ˜Jšœ(ž œ˜CJšœœ ˜*šœ7˜7Jšœ!œž œ˜G—Jšœ˜ ——J˜šž œœœœ˜Dšœœœ˜Jšœ$˜$Jšœ"˜"Jšœœ˜—Jšœœœœ˜L—J˜šž œœœœ˜LJšœ œ#˜1Jšœ œ&˜3Jšœ œ˜"Jšœœ˜&Jšœ œ$˜0Jšœ œ‘ œ˜JšžN™Nšžœœœœ˜1Jšœ œœœ˜ Jš œœœœœ˜Jšœœ)˜6šœœœ˜Jšœœ4œ ˜MJšœ1˜1——šž œ˜'Jšœ œ˜Jš œ œ œœ œœ ˜RJšœœ˜—Jšœœœœ˜šœ˜JšœG˜G—Jšœ1˜1šœœœ˜4Jšœ(˜(Jšœœ˜!Jšœœœœ˜Jšœ œ˜!Jšœ œ˜!Jšœ œœ˜*—Jšœ1˜1šœœœ˜4Jšœ(˜(Jšœœ˜"Jšœœœœ˜Jšœ œ˜!Jšœ œ˜!Jšœ œœ˜*—šœœœ˜Jšœ1˜1šœœœ˜4Jšœ(˜(Jšœœœœ˜Jšœœ˜——šœœœ˜Jšœ1˜1šœœœ˜4Jšœ(˜(Jšœœœœ˜Jšœœ˜——Jšœ-˜-JšœL˜L—J˜šžœ ˜šœGœ˜KJšœ˜—Jšœœ˜Jšœœ œ œ3˜ZJšœœœœ˜Jšœœœœ˜Jšœ œœœ˜Jšœ œ˜'Jšœ ˜ Jšœ0˜0Jšœ™š˜Jšœ œœ˜Jšœ œœ˜š œ œœœ œ˜CJšœ œ%˜2Jš œ œ œ œœ˜4Jšœ œ ™Jšœœœ˜"Jšœ œ˜š œœœ(œœ˜LJšœœœ˜0Jšœ œ˜(Jšœœœ˜'—Jšœ œ˜šœ&˜&Jšœ5˜5—Jšœ˜—Jšœœ œœ˜Jšœœ œ Ÿ ˜*Jšœ˜—Jšœ™Jšœ ˜ š œ œœœ œ˜GJšœ œœ˜4—Jšœœœ ˜3Jšœœœ œ˜=Jšœ ˜ Jšœ™šœœœ˜Jš œœœœœ˜<šœœœ ˜Jšœœ(˜0šœ˜Jš œœœœ œ˜F—šœ˜Jšœœœœ˜@—šœ˜Jš œœ œœœ ˜R—Jšœœ˜——Jšœ™š œ œœœ œœŸ˜KJšœœ˜!Jšœœ˜Jšœœ˜!Jšœœ˜Jšœœœ˜Jš œœ œœœ ˜Bš œœœœœ˜8Jšœ2œ˜OJ˜ —Jšœœœœ˜PJšœœœ˜JJšœ>œ ˜KJšœ˜—Jšœ)˜)Jšœ$˜$Jšœ&˜'Jšœ3˜3Jšœ˜J˜—Jšœ œœ ˜Jšœ œœœ˜3J˜šž œœ/œ˜UJšœœ&˜=šœœœ˜Jšœ œ˜%Jšœ/˜/—šœ˜ Jšœœ œœ˜˜>Jšœ.˜5—Jšœœ˜—Jšœ-˜-—J˜šžœœœœœœœ ˜QJšœœ˜ Jš œœœœœ˜,Jšœ@Ÿ˜XJšœ œ*Ÿ˜Tšœ ˜ Jšœœœ˜Jšœ1œ ˜D——J˜šžœ˜!Jš œ œœœœœ˜GJšœœœ ˜š žœœœœœ˜*Jš œœœœœ ˜L—Jšœ œ˜#šœœœ˜)Jšœœœ˜6—šœœ˜=Jšœœœ˜6—šœœœ˜+Jšœ œ˜šœ œœ ˜Jšœ˜Jšœœ˜&—šœ œœ ˜ Jšœ˜Jšœœœ˜—Jšœœ9˜Lšœœ˜šœœœ˜)Jšœœ˜ Jšœœ˜Jšœ œ˜%Jšœœ˜ Jšœ˜%—šœœœ˜,Jšœœ˜šœœœ˜)Jšœ œ˜%Jšœ˜%—šœœœ˜)Jšœœ˜ Jšœ˜%—Jšœœ˜Jšœ œ˜—šœœœ˜.Jšœœ˜šœœœ˜)Jšœ3˜3Jšœ-˜-Jšœ œ˜—Jšœ8˜8šœœœ˜)Jšœ-˜-Jšœ œ˜—Jšœ œ˜—Jšœ œ˜—Jšœ œ˜"Jšœœœ ˜4Jšœœ˜ —Jšœ˜—J˜š žœœœœœ˜'Jšœœœ˜?—J˜š žœœœœœœ ˜Uš œ œœœ œœŸ ˜RJšœœ˜"Jšœœ˜ Jšœœ˜!Jšœœ˜!Jšœ œ˜'Jšœœœœ ˜$Jšœœ˜Jšœœœ œ œœœœ˜EJšœœ œ˜(šœ˜JšœI˜I—šœ˜JšœL˜L—JšœE˜Eš œ œœœ#œ œ˜OJšœœ˜šœ˜ Jšœœ.œ ˜TJšœœ)œ ˜P—Jš œœœœœ˜XJš œœ œ œœ˜WJšœ˜—š œ œœœ#œ œ˜OJšœœ˜šœ˜ Jšœœ-œ ˜SJšœœ*œ ˜Q—Jšœœœœ˜RJš œœ œ œœ˜WJšœ˜—Jšœ˜ ——J˜Jšœ œœ ˜=J˜šœ œ˜*Jšœœ™/Jšœœ˜(Jšœ˜Jšœ$œ ˜3Jšœ%˜%Jšœ(˜(Jšœ"˜"šœœ œ˜3Jšœœ$˜Dšœœ˜Jšœ)˜)Jšœ˜Jšœ žœ ˜Jšœ žœ˜"šœœ˜Jšœ˜Jšœ žœ˜%Jšœ˜——Jšœ˜Jšœ˜Jšœœ˜7šœ˜Jšœœ˜Jšœœ˜Jšœ œœœ ˜AJšœœœœ ˜CJšœœ˜Jšœœ˜—Jšœ˜—Jšœ˜Jšœ žœ˜%Jšœ ˜ Jšœ™—J™Jšœœœ˜%Jšœœœ˜J˜Jšœ˜—J˜J˜J˜—…—‹tΏ