<> <> <> <<>> DIRECTORY CardTable, CCDUtils, CD, CDCells, CDOrient, CDRects, CDSimpleRules, CDSymbolicObjects, Convert, Core, CoreBlock, CoreFrame, CoreGlue, CoreLibrary, CoreName, CoreOps, HashTable, IFUCoreData, IO, PW, PWRoute, Rope, Route, Sinix; CoreGlueImpl: CEDAR PROGRAM IMPORTS CardTable, CCDUtils, CD, CDCells, CDRects, CDSimpleRules, CDSymbolicObjects, Convert, CoreBlock, CoreFrame, CoreGlue, CoreLibrary, CoreName, CoreOps, HashTable, IFUCoreData, IO, PW, PWRoute, Rope, Route EXPORTS CoreGlue = BEGIN OPEN CCD: CCDUtils; ROPE: TYPE = Core.ROPE; GlueClass: TYPE = CoreGlue.GlueClass; GlueSideType: TYPE = CoreGlue.GlueSideType; Glue: TYPE = CoreGlue.Glue; GlueSpec: TYPE = CoreGlue.GlueSpec; Node: TYPE = CoreGlue.Node; NodeRec: TYPE = CoreGlue.NodeRec; CellType: TYPE = Core.CellType; Frame: TYPE = CoreFrame.Frame; FrameRec: TYPE = CoreFrame.FrameRec; FrameSeq: TYPE = CoreFrame.FrameSeq; Side: TYPE = CoreFrame.Side; Status: TYPE = CoreGlue.Status; Ph: TYPE = CoreName.Ph; NWMML: TYPE = CCD.NWMML; FCT: PROC[ct: CellType] RETURNS[Frame] = {RETURN[CoreFrame.FCT[ct]]}; StatusRope: ARRAY Status OF ROPE = ["rejustify", "progress", "delayed", "complete1", "complete2"]; glueCellClass: PUBLIC Core.CellClass _ CoreOps.SetClassPrintProc[ NEW[Core.CellClassRec _ [name: "CoreGlue", recast: NIL]], ClassPrintProc]; ClassPrintProc: CoreOps.PrintClassProc = { glueData: Glue _ NARROW[data]; IO.PutRope[out, "\nGlue: "]; GlueDescription[glueData, out]}; GlueSideTypeRp: ARRAY GlueSideType OF ROPE = [ cap: CoreName.RopeNm["cap"], conn: CoreName.RopeNm["conn"], pwr: CoreName.RopeNm["pwr"], ext: CoreName.RopeNm["ext"], chan: CoreName.RopeNm["chan"], sum: CoreName.RopeNm["sum"], diff: CoreName.RopeNm["diff"] ]; GlueClassRp: ARRAY GlueClass OF ROPE = [ fill: CoreName.RopeNm["Fill-"], ext: CoreName.RopeNm["Ext-"], xlt : CoreName.RopeNm["Xlt-"], chan: CoreName.RopeNm["Chan-"], pwr: CoreName.RopeNm["Pwr-"], sb : CoreName.RopeNm["SBox-"], bad: CoreName.RopeNm["Bad-"] ]; GlueDescription: PROC[glue: Glue, out: IO.STREAM] = { out.PutF[" Subclass: %g b:%g l:%g t:%g r:%g ", IO.rope[ glue.subClass ], IO.rope[ GlueSideTypeRp[ glue.type[bottom] ] ], IO.rope[ GlueSideTypeRp[ glue.type[left] ]] , IO.rope[ GlueSideTypeRp[ glue.type[top] ] ], IO.rope[ GlueSideTypeRp[ glue.type[right] ] ] ] }; defaultOptimization: PWRoute.Optimization _ full; CellProc: PUBLIC PROC[ subClass: ROPE _ NIL, name: ROPE _ NIL, l,r,b,t: GlueSideType _ cap, -- cap conn ext chan sum diff bCell,rCell,tCell,lCell: Core.CellType _ NIL, tDir: PWRoute.HorV _ vertical, -- vertical horizontal tLayer: ROPE _ NIL, -- metal metal2 poly bLayer: ROPE _ NIL, xlate: BOOL _ FALSE, data: REF _ NIL ] -- metal2 poly metal RETURNS [cellType: CellType] = { glue: REF GlueSpec _ NEW[GlueSpec _ [ subClass: CoreName.RopeNm[subClass], tDir: tDir, type: [b,r,t,l], cell: [bCell,rCell,tCell,lCell], data: data, params: NEW[PWRoute.RouterParamsRec _ [ opt: defaultOptimization, trunkLayer: tLayer, branchLayer: bLayer]]]]; met: ROPE _ CoreName.RopeNm["metal"]; met2: ROPE _ CoreName.RopeNm["metal2"]; tLayer _ CoreName.RopeNm[tLayer]; bLayer _ CoreName.RopeNm[bLayer]; SetGlueClass[glue]; glue.params.trunkLayer _ tLayer _ SELECT tLayer FROM NIL => SELECT bLayer FROM NIL => IF tDir=horizontal THEN met ELSE met2, met => met2, met2 => met, ENDCASE => ERROR, ENDCASE => tLayer; glue.params.branchLayer _ bLayer _ SELECT bLayer FROM NIL => SELECT tLayer FROM met => met2, met2 => met, ENDCASE => ERROR, ENDCASE => bLayer; IF xlate THEN IF glue.class#ext THEN Signal[] ELSE glue.class _ xlt; IF name=NIL OR name.Length[]=0 THEN name _ CoreName.ID[ GlueClassRp[glue.class] ]; cellType _ CoreOps.SetCellTypeName[ NEW [ Core.CellTypeRec _ [ class: glueCellClass, public: CoreOps.CreateWires[0], data: glue] ], name]; CoreFrame.SetFrameExpandProc[hard, cellType, NEW[CoreFrame.ExpandProc _ ExpandHard] ]; CoreFrame.SetFrameExpandProc[soft, cellType, NEW[CoreFrame.ExpandProc _ ExpandSoft] ]}; ExpandSoft: CoreFrame.ExpandProc = { frameCT.data _ NEW[FrameRec _ [data: frameCT.data, seq: NEW[FrameSeq[0]] ]]; frameCT.class _ CoreFrame.frameCellClass; CoreFrame.SetFrameExpandProc[soft, frameCT, NIL]}; ExpandHard: CoreFrame.ExpandProc = { frameCT.data _ NEW[FrameRec _ [data: frameCT.data, seq: NEW[FrameSeq[0]] ]]; frameCT.class _ CoreFrame.frameCellClass; CoreFrame.SetFrameExpandProc[hard, frameCT, NIL]}; SetGlueClass: PROC[glue: Glue] = { OPEN glue; Type: PROC[side: CoreFrame.Side] RETURNS[GlueSideType] = { SELECT type[side] FROM pwr => RETURN[conn]; sum, diff => RETURN[chan]; ENDCASE => RETURN[type[side]]}; eqS: BOOL _ (Type[left] = Type[right]) OR (Type[top] = Type[bottom]); cnt: ARRAY GlueSideType OF 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]], 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} }; <> ENDCASE => {Signal[]; LOOP} }; log.PutF["\n Glue %g can not yet%guse %g as %g %g.", IO.rope[name], IO.rope[IF found THEN " " ELSE " (never?) "], IO.rope[IF neighborCT=NIL THEN "???" ELSE CoreName.CellNm[neighborCT].n], IO.rope[CoreFrame.SideRope[side]], IO.rope[IF glue.type[side]=conn THEN "conn" ELSE "pwr"]]; status _ MIN[status, delayed]; LOOP}; ENDCASE => ERROR ENDLOOP; IF status < complete1 THEN RETURN[status]; status _ GlueIt[frameCT]}; <<>> GlueIt: PROC[frameCT: CellType] RETURNS[status: Status] = { frame: Frame _ FCT[frameCT]; name: ROPE _ CoreName.CellNm[frameCT].n; msg: IO.ROPE; initSize: CD.Position _ [frame.size.x, frame.size.y]; cell: CellType; glue: Glue _ NARROW[frame.data]; channels: 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]; SELECT glue.class FROM fill => cell _ FCT[CCD.BlankCell[initSize]].cell; ext, xlt => { cell _ SELECT TRUE FROM glue.type[top] = ext => FillerCell [glue, top, initSize.y], glue.type[bottom] = ext => FillerCell [glue, bottom, initSize.y], glue.type[left] = ext => FillerCell [glue, left, initSize.x], glue.type[right] = ext => FillerCell [glue, right, initSize.x], ENDCASE => ERROR}; chan, pwr, sb => { ENABLE { Route.Signal => {log.PutF["\n Route Signal: %g", IO.rope[explanation]]; RESUME}; Route.Error => {log.PutF["\n Route ERROR: %g", IO.rope[explanation]]; cell _ FCT[CCD.BlankCell[initSize]].cell; CONTINUE}}; pwrCell: CellType _ NIL; routeType: PWRoute.RouteType _ IF glue.class=sb THEN switchBox ELSE channel; sizeSpec: REF CD.Rect _ NEW[CD.Rect _ [0, 0, CoreFrame.minSize.x, CoreFrame.minSize.y]]; IF glue.class=pwr THEN { OPEN glue; width: INT; SELECT TRUE FROM type[bottom] = pwr => {pwrSide _ bottom; width _ sizeSpec.y2}; type[top] = pwr => {pwrSide _ top; width _ sizeSpec.y2}; type[left] = pwr => {pwrSide _ left; width _ sizeSpec.x2}; type[right] = pwr => {pwrSide _ right; width _ sizeSpec.x2}; ENDCASE => ERROR; pwrCell _ MergePwr [glue, pwrSide, width]}; IF NOT variable THEN { sizeSpec.x2 _ initSize.x; sizeSpec.y2 _ initSize.y; IF pwrCell#NIL THEN IF glue.tDir=horizontal THEN sizeSpec.y2 _ MAX[0, sizeSpec.y2 - CCD.CellSize[pwrCell].y] ELSE sizeSpec.x2 _ MAX[0, sizeSpec.x2 - CCD.CellSize[pwrCell].x] }; IF glue.class=pwr THEN glue.cell[pwrSide] _ pwrCell; IF glue.subClass = CoreName.RopeNm["ThreeLevel"] THEN cell _ ThreeLevel [glue, channels] ELSE cell _ MakeChannel [glue, name, sizeSpec, routeType]; IF glue.class=pwr THEN cell _ CoreBlock.AbutCellList[ name: NIL, first: CoreFrame.SideSides[pwrSide], cellTypes: LIST[pwrCell, cell] ] }; ENDCASE => Signal[]; frame.cell _ cell; msg _ IO.PutFR["\n Routed %g %g Frame: %g", IO.rope[IF ~variable THEN "fixed" ELSE IF (glue.class=chan OR glue.class=pwr) THEN "firm" ELSE "variable"], IO.rope[GlueClassRp[glue.class]], IO.rope[name] ]; log.PutRope[msg]; PW.WriteF[msg]; PW.WriteF["\n"]; frame.size _ CoreFrame.FixedSize[CCD.CellSize[cell]]; IF variable AND (glue.class=chan OR glue.class=pwr) THEN { IF glue.tDir=vertical THEN {IF frame.size.y # initSize.y THEN Signal[]; frame.size.xfree _ tame} ELSE {IF frame.size.x # initSize.x THEN Signal[]; frame.size.yfree _ tame}; RETURN[rejustify]} ELSE { IF initSize # [frame.size.x, frame.size.y] THEN Signal[]; RETURN[progress] } }; <<>> CellBad: PROC[obj: CD.Object] RETURNS[bad: BOOL] = { bad _ obj=NIL OR obj.specificRef=NIL; IF NOT bad THEN WITH obj.specificRef SELECT FROM cellPtr: CD.CellPtr => bad _ cellPtr.contents=NIL; list: LIST OF CD.Object => bad _ list=NIL; -- redundant ENDCASE => bad _ TRUE; RETURN[bad OR CD.InterestSize[obj].x<1 OR CD.InterestSize[obj].y<1]}; <<>> ChanSideCell: PUBLIC PROC [side: Side, list: LIST OF ROPE, layer: CD.Layer] RETURNS[cell: CellType] = { object: CD.Object; nwmmls: LIST OF NWMML; FOR list _ list, list.rest WHILE list#NIL DO name: ROPE _ Rope.Substr[list.first, 0, Rope.Index[list.first, 0, "/"]]; size: INT _ IF list.first.Length[] > name.Length[] THEN Convert.IntFromRope[Rope.Substr[list.first, Rope.Index[list.first, 0, "/"]+1]] ELSE 4; nwmmls _ CONS[[ name: CoreName.RopeNm[name], min: CCD.lambda, -- move away from beginning edge max: size*CCD.lambda], nwmmls] ENDLOOP; object _ SideObject[side, nwmmls, layer]; cell _ CoreLibrary.ObjCell[object, CoreName.ID["ChanSide"]]}; SideObject: PUBLIC PROC [side: Side, list: LIST OF NWMML, layer: CD.Layer, length: INT _ 0] -- max => size RETURNS[cell: CD.Object] = { dim: INT _ CD.FetchTechnology[$cmosB].lambda; pos: CD.Position _ [0, 0]; size: CD.Position _ [0, 0]; cell _ CDCells.CreateEmptyCell[]; FOR list _ list, list.rest WHILE list#NIL DO pinApl: CD.Instance; size _ SELECT side FROM top, bottom => [list.first.max, dim] ENDCASE => [dim, list.first.max]; SELECT side FROM top, bottom => pos.x _ MAX[pos.x, list.first.min]; ENDCASE => pos.y _ MAX[pos.y, list.first.min]; [ ] _ PW.IncludeInCell[cell, CDRects.CreateRect[size, layer], pos]; pinApl _ PW.IncludeInCell[cell, CDSymbolicObjects.CreatePin[size], pos]; CDSymbolicObjects.SetName[pinApl, list.first.name]; CDSymbolicObjects.SetLayer[pinApl, layer]; SELECT side FROM top, bottom => {length _ MAX[length, pos.x _ pos.x+list.first.max]; pos.x_pos.x+dim*4}; ENDCASE => {length _ MAX[length, pos.y _ pos.y+list.first.max]; pos.y_pos.y+dim*4}; ENDLOOP; CDCells.SetInterestRect[cell, SELECT side FROM left => [-dim, 0, +dim, length ], bottom => [0, -dim, length, +dim ], right => [0, 0, 2*dim, length ], top => [0, 0, length, 2*dim ], ENDCASE => ERROR ]; [ ] _ CDCells.RepositionCell[cell, NIL]}; <<>> GlueSideObject: PUBLIC PROC[glue: Glue, side: Side] RETURNS[obj: CD.Object] = { cell: CellType _ glue.cell[side]; layer: CD.Layer _ CDSimpleRules.GetLayer[$cmosB, GlueSideLayer[glue, side]]; length: INT; list: LIST OF NWMML; IF cell=NIL THEN RETURN[NIL]; length _ SELECT side FROM top, bottom => CCDUtils.CellSize[cell].x ENDCASE => CCDUtils.CellSize[cell].y; list _ CCD.SidePinList[cell, CoreFrame.OppSide[side]]; FOR lst: LIST OF NWMML _ list, lst.rest WHILE lst#NIL DO lst.first.max _ lst.first.max - lst.first.min; -- max _ size ENDLOOP; obj _ SideObject[side, list, layer, length]}; MakeChannel: PUBLIC PROC [glue: Glue, name: ROPE, sizeSpec: REF CD.Rect, routeType: PWRoute.RouteType] RETURNS [cell: CellType] = { sumDiffType: BOOL _ FALSE; sum, diff: LIST OF NWMML; objs: ARRAY Side OF CD.Object _ [ bottom: GlueSideObject[glue, bottom ], right: GlueSideObject[glue, right ], top: GlueSideObject[glue, top ], left: GlueSideObject[glue, left ] ]; obj: CD.Object; FOR side: Side IN Side WHILE NOT sumDiffType DO IF glue.type[side]=sum OR glue.type[side]=diff THEN sumDiffType _ TRUE ENDLOOP; IF sumDiffType THEN { FOR side: Side IN Side DO nwmmls: LIST OF NWMML; IF glue.type[side]#conn AND glue.type[side]#chan AND glue.type[side]#pwr THEN LOOP; nwmmls _ CCD.SidePinList[glue.cell[side], CoreFrame.OppSide[side]]; FOR list: LIST OF NWMML _ nwmmls, list.rest WHILE list#NIL DO list.first.max _ list.first.max - list.first.min; -- max _ size list.first.min _ 0 ENDLOOP; -- throw away position info for channel sides FOR list: LIST OF NWMML _ nwmmls, list.rest WHILE list#NIL DO unique: BOOL; [sum, unique] _ AddIfUnique[list.first, sum]; IF unique THEN diff _ CONS[list.first, diff] ELSE diff _ DelIfPresent[list.first, diff].new; ENDLOOP; ENDLOOP; FOR side: Side IN Side DO layer: CD.Layer _ CDSimpleRules.GetLayer[$cmosB, GlueSideLayer[glue, side]]; IF glue.type[side]=sum THEN objs[side] _ SideObject[side, sum, layer]; IF glue.type[side]=diff THEN objs[side] _ SideObject[side, diff, layer]; ENDLOOP}; obj _ IF glue.tDir=horizontal THEN PWRoute.MakeChannel[objs[bottom], objs[top], objs[left], objs[right], sizeSpec, glue.params, FALSE, routeType] ELSE PWRoute.MakeChannel[objs[left], objs[right], objs[bottom], objs[top], sizeSpec, glue.params, TRUE, routeType]; cell _ CoreLibrary.ObjCell[name: name, obj: obj]}; AddIfUnique: PROC[item: NWMML, list: LIST OF NWMML] RETURNS[new: LIST OF NWMML, done: BOOL] = { FOR l: LIST OF NWMML _ list, l.rest WHILE l#NIL DO IF item.name = l.first.name THEN {l.first.max _ MAX[l.first.max, item.max]; RETURN[list, FALSE]} ENDLOOP; RETURN[CONS[item, list], TRUE]}; DelIfPresent: PROC[item: NWMML, list: LIST OF NWMML] RETURNS[new: LIST OF NWMML, done: BOOL] = { IF list=NIL THEN RETURN[NIL, FALSE]; IF item.name = list.first.name THEN RETURN[list.rest, TRUE]; FOR l: LIST OF NWMML _ list, l.rest WHILE l.rest#NIL DO IF item.name = list.rest.first.name THEN {l.rest _ l.rest.rest; RETURN[list, TRUE]} ENDLOOP; RETURN[list, FALSE]}; <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <<>> FillerCell: PROC [glue: Glue, objSide: Side, width: INT] RETURNS [cell: CellType] = { templateCT: CellType _ glue.cell[CoreFrame.OppSide[objSide]]; templateSize: CD.Position _ CCD.CellSize[templateCT]; resultSize: CD.Position; deslayerRope: IO.ROPE _ GlueSideLayer[glue, objSide]; IF glue.class=xlt THEN cell _ CoreGlue.XferPins[templateCT, objSide, deslayerRope, width] ELSE cell _ CoreGlue.XferPins[templateCT, objSide, NIL, width]; resultSize _ CCD.CellSize[cell]; IF (SELECT objSide FROM left, right => resultSize.x#width OR resultSize.y#templateSize.y, top, bottom => resultSize.y#width OR resultSize.x#templateSize.x, ENDCASE => ERROR) THEN Signal[] }; <<>> MergePwr: PROC [glue: Glue, objSide: Side, width: INT] RETURNS [cell: CellType] = { pinSide: Side _ CoreFrame.OppSide[objSide]; pinCell: CellType _ glue.cell[objSide]; vgCell: CellType _ glue.cell[pinSide]; size1: CD.Position _ CCD.CellSize[pinCell]; size2: CD.Position _ CCD.CellSize[vgCell]; size3: CD.Position; deslayerRope: IO.ROPE _ GlueSideLayer[glue, objSide]; cell _ CoreGlue.MergePwrPins[vgCell, pinCell, pinSide, deslayerRope, width]; size3 _ CCD.CellSize[cell]; IF (SELECT objSide FROM left, right => size3.y#size1.y OR size3.y#size2.y OR size3.x < width, top, bottom => size3.x#size1.x OR size3.x#size2.x OR size3.y < width, ENDCASE => ERROR) THEN Signal[] }; <<>> AdjustLayerAssignments: PROC[glue: Glue] = { reversed: 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 (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 _ CCD.CellSize[glue.cell[top]].x; range: INT _ rowWidth/cellWidth; left: INT _ CCD.metW/2-CCD.leftTail; right: INT _ CCD.metW/2-CCD.leftTail+rowWidth; polyMax: INT _ rowWidth/8; <> 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.