<> <> <> DIRECTORY CD, CDBasics, CDInstances, CDProperties, CDRects, CDRoutingObjects, CDSimpleRules, CMosB, Core, CoreClasses, CoreCreate, CoreGeometry, CoreOps, CoreProperties, CoreRoute, IO, PW, PWCore, Rope, Route, Sisyph, SymTab, TerminalIO; CoreRouteExtend: CEDAR PROGRAM IMPORTS CD, CDBasics, CDInstances, CDProperties, CDRects, CDRoutingObjects, CDSimpleRules, CMosB, CoreGeometry, CoreOps, CoreProperties, CoreRoute, IO, PW, PWCore, Rope, Sisyph, SymTab, TerminalIO = BEGIN <> ExtendForm: TYPE = REF ExtendFormAry; ExtendFormAry: TYPE = RECORD[ vert: CD.Layer _ CD.commentLayer, sameLayers: BOOL _ TRUE, ary: ARRAY Side OF ExtendFormRec ]; ExtendFormRec: TYPE = RECORD[ pins: WirePins _ NIL, min: INT _ LAST[INT], max: INT _ FIRST[INT], width: INT _ 0, wires: Wires _ NIL, buses: Wires _ NIL, busLo: Wires _ NIL, busHi: Wires _ NIL]; BusRec: TYPE = RECORD[ loc: INT _ 0, width: INT _ 0, min: INT _ LAST[INT], max: INT _ FIRST[INT]]; Wires: TYPE = Core.Wires; WirePin: TYPE = CoreRoute.WirePin; WirePins: TYPE = CoreRoute.WirePins; Side: TYPE = CoreGeometry.Side; extendFormProp: ATOM = $ExtendForm; verticalMetalProp: ATOM = $VerticalMetal; changeLayersProp: ATOM = $ChangeLayers; wireWidthProp: ATOM = $w; technologyKey: ATOM = $cmosB; lambda: INT _ CDSimpleRules.GetTechnology[technologyKey].lambda; L4: INT _ 4*lambda; layDeco: CoreGeometry.Decoration _ PWCore.extractMode.decoration; schDeco: CoreGeometry.Decoration _ Sisyph.mode.decoration; sideProp: ARRAY Side OF ATOM _ [bottom: $Bottom, top: $Top, left: $Left, right: $Right]; sizeProp: ARRAY Side OF ATOM _ [bottom: $SizeY, top: $SizeY, left: $SizeX, right: $SizeX]; <> Attribute: PWCore.AttributesProc = { SchSideWires: PROC[side: Side, min: INT _ FIRST[INT], max: INT _ LAST[INT]] RETURNS [wires: Core.Wires] = {RETURN[CoreRoute.OrderedAtomicSchWires[cellType, side, min, max]]}; AddTopOrBottomEnds: PROC[topBot, ltRt: Side] = { buses: Wires _ IF topBot=top THEN form.ary[ltRt].busHi ELSE form.ary[ltRt].busLo; IF form.ary[topBot].width=0 THEN RETURN; FOR buses _ buses, buses.rest WHILE buses#NIL DO rec: REF BusRec _ EnsureBusSideRec[buses.first, ltRt]; loc: INT _ IF ltRt=left THEN 0 - rec.width - rec.loc ELSE subSize.x + rec.loc; pin: WirePin _ [buses.first, loc, loc+rec.width, form.vert]; form.ary[topBot].pins _ CONS[pin, form.ary[topBot].pins]; ENDLOOP}; data: CoreClasses.RecordCellType _ NARROW[cellType.data]; name: IO.ROPE _ CoreOps.GetCellTypeName[cellType]; form: ExtendForm _ NEW[ExtendFormAry _[vert:CD.commentLayer]]; subInst: CoreCreate.CellInstance _ data[0]; subObj: CD.Object _ PWCore.Layout[subInst.type]; subSize: CD.Position _ CD.InterestSize[subObj]; globals: Wires _ CoreRoute.GlobalWires[cellType]; pIR: CD.Rect _ CD.InterestRect[CoreGeometry.GetObject[schDeco, cellType]]; cIR: CD.Rect _ CoreRoute.SchMappedIR[subInst]; form.ary[left].busLo _ SchSideWires[bottom, , cIR.x1-pIR.x1 ]; form.ary[left].busHi _ SchSideWires[top, , cIR.x1-pIR.x1 ]; form.ary[right].busLo _ SchSideWires[bottom, cIR.x2-pIR.x1, ]; form.ary[right].busHi _ SchSideWires[top, cIR.x2-pIR.x1, ]; form.ary[bottom].busLo _ SchSideWires[left, , cIR.y1-pIR.y1 ]; form.ary[bottom].busHi _ SchSideWires[right, , cIR.y1-pIR.y1 ]; form.ary[top].busLo _ SchSideWires[left, cIR.y2-pIR.y1, ]; form.ary[top].busHi _ SchSideWires[right, cIR.y2-pIR.y1, ]; form.vert _ CoreRoute.GetCellTypePropLayer[cellType, verticalMetalProp].layer; form.sameLayers _ CoreProperties.GetCellTypeProp[cellType, changeLayersProp]=NIL; FOR side: Side IN Side DO min: INT _ IF LeftRight[side] THEN cIR.y1-pIR.y1 ELSE cIR.x1-pIR.x1; max: INT _ IF LeftRight[side] THEN cIR.y2-pIR.y1 ELSE cIR.x2-pIR.x1; wires: Wires _ CoreRoute.OrderedAtomicSchWires[cellType, side, min, max]; form.ary[side].wires _ wires; form.ary[side].buses _ MergeOrderedWires[form.ary[side].busLo, form.ary[side].busHi]; FOR buses: Wires _ form.ary[side].buses, buses.rest WHILE buses#NIL DO rec: REF BusRec _ EnsureBusSideRec[buses.first, side]; wires _ CONS[buses.first, wires] ENDLOOP; form.ary[side].pins _ CoreRoute.FilteredInstanceLayoutPins[subInst, side]; form.ary[side].pins _ CoreRoute.FilterPins[form.ary[side].pins, wires, globals]; IF ~form.sameLayers AND form.ary[side].buses#NIL AND form.ary[side].buses.rest#NIL THEN ERROR; <> ENDLOOP; <> FOR side: Side IN Side DO VertLayer: PROC[sideLayer: CD.Layer] RETURNS[vertLayer: CD.Layer] = {RETURN [IF LeftRight[side] # form.sameLayers THEN sideLayer ELSE OtherLayer[sideLayer]]}; w: INT _ GetSideExtention[cellType, side]; strangeLayerFound: BOOL _ FALSE; IF w=0 AND form.sameLayers THEN LOOP; IF ~form.sameLayers THEN AdjustPins345[form.ary[side].pins]; -- 3, 4, 5 => 4 lambda FOR pins: WirePins _ form.ary[side].pins, pins.rest WHILE pins#NIL DO pin: WirePin _ pins.first; sideLayer: CD.Layer _ pin.layer; busRec: REF BusRec _ ExistingBusSideRec[pin.wire, side]; IF NOT MetLayer[sideLayer] THEN { IF NOT strangeLayerFound THEN TerminalIO.PutF["*** %g side of %g has strange pin layer.\n", IO.rope[SideNm[side]], IO.rope[CoreOps.GetCellTypeName[cellType]]]; strangeLayerFound _ TRUE} ELSE { IF form.vert=CD.commentLayer OR form.vert=VertLayer[sideLayer] THEN form.vert _ VertLayer[sideLayer] ELSE TerminalIO.PutF["*** %g side of %g has inconsistent pin layer.\n", IO.rope[SideNm[side]], IO.rope[CoreOps.GetCellTypeName[cellType]]]; IF busRec#NIL THEN busRec.width _ MAX[busRec.width, pin.max-pin.min]}; ENDLOOP ENDLOOP; IF NOT MetLayer[form.vert] THEN ERROR; <> FOR side: Side IN Side DO FOR buses: Wires _ form.ary[side].buses, buses.rest WHILE buses#NIL DO w: REF INT _ NARROW[CoreProperties.GetWireProp[buses.first, wireWidthProp]]; rec: REF BusRec _ EnsureBusSideRec[buses.first, side]; rec.width _ IF w#NIL THEN w^*lambda ELSE 4*lambda ENDLOOP ENDLOOP; <> FOR side: Side IN Side DO w: INT _ GetSideExtention[cellType, side]; buses: Wires _ form.ary[side].buses; IF side=left OR side=bottom THEN buses _ CoreOps.Reverse[buses]; form.ary[side].width _ IF ~form.sameLayers THEN 3*L4 ELSE IF form.ary[side].buses=NIL THEN 0 ELSE L4; FOR buses _ buses, buses.rest WHILE buses#NIL DO rec: REF BusRec _ EnsureBusSideRec[buses.first, side]; rec.loc _ form.ary[side].width; form.ary[side].width _ form.ary[side].width + rec.width + L4 ENDLOOP; IF w#0 THEN { size: INT _ w*lambda; IF size < form.ary[side].width THEN TerminalIO.PutF["*** Warning: %g side Extend of %g Needs %g but was specified as %g.", IO.rope[SideNm[side]], IO.rope[name], IO.int[form.ary[side].width/lambda], IO.int[w]] ELSE form.ary[side].width_size}; form.ary[side].min _ 0; form.ary[side].max _ IF LeftRight[side] THEN subSize.y ELSE subSize.x; ENDLOOP; <> IF form.ary[top].width#0 THEN { form.ary[top].min _ form.ary[top].min - form.ary[left].width; form.ary[top].max _ form.ary[top].max + form.ary[right].width}; IF form.ary[bottom].width#0 THEN { form.ary[bottom].min _ form.ary[bottom].min - form.ary[left].width; form.ary[bottom].max _ form.ary[bottom].max + form.ary[right].width}; <> AddTopOrBottomEnds[top, left]; AddTopOrBottomEnds[top, right]; AddTopOrBottomEnds[bottom, left]; AddTopOrBottomEnds[bottom, right]; <> FOR side: Side IN Side DO IF form.ary[side].width=0 THEN LOOP; FOR pins: WirePins _ form.ary[side].pins, pins.rest WHILE pins#NIL DO pin: WirePin _ pins.first; busRec: REF BusRec _ ExistingBusSideRec[pin.wire, side]; IF NOT MetLayer[pin.layer] THEN LOOP; IF busRec#NIL THEN { busRec.min _ MIN[busRec.min, pin.min]; busRec.max _ MAX[busRec.max, pin.max]} ENDLOOP ENDLOOP; <> FOR side: Side IN Side DO FOR buses: Wires _ form.ary[side].busLo, buses.rest WHILE buses#NIL DO EnsureBusSideRec[buses.first, side].min _ form.ary[side].min ENDLOOP; FOR buses: Wires _ form.ary[side].busHi, buses.rest WHILE buses#NIL DO EnsureBusSideRec[buses.first, side].max _ form.ary[side].max ENDLOOP ENDLOOP; CoreRoute.FlushSchPinCache[subInst.type]; CoreRoute.FlushLayPinCache[subInst.type]; CoreProperties.PutCellTypeProp[cellType, extendFormProp, form]; ShowExtendForm[cellType]}; Layout: PWCore.LayoutProc = { name: IO.ROPE _ CoreOps.GetCellTypeName[cellType]; data: CoreClasses.RecordCellType _ NARROW[cellType.data]; form: ExtendForm _ NARROW[ CoreProperties.GetCellTypeProp[cellType, extendFormProp]]; resultIR: CD.Rect; subObj: CD.Object _ PWCore.Layout[data[0].type]; subSize: CD.Position _ CD.InterestSize[subObj]; cdInstances: CD.InstanceList _ LIST [CDInstances.NewInst[ ob: subObj, trans: [CDBasics.NegOffset[CD.InterestBase[subObj]]] ]]; <> FOR side: Side IN Side DO AddRect: PROC [wire: Core.Wire, size: CD.Position, lay: CD.Layer, off, min: INT] = { rect: CD.Object; IF ~LeftRight[side] THEN size _ [size.y, size.x]; rect _ CDRects.CreateRect[size, lay]; AddPositionedObject[wire, rect, off, min]}; AddVias: PROC [wire: Core.Wire, size: CD.Position, off, min: INT] = { vias: CD.Object _ IF LeftRight[side] THEN Vias[size.x, size.y] ELSE Vias[size.y, size.x]; AddPositionedObject[wire, vias, off, min]}; AddPositionedObject: PROC[wire: Core.Wire, obj: CD.Object, off, min: INT] = { label: Route.Label _ CoreRoute.LabelInternal[data.internal, wire]; pos: REF LIST OF CDRoutingObjects.PlacedObject _ NARROW[SymTab.Fetch[nodes, label].val]; szX: INT _ CD.InterestSize[obj].x; szY: INT _ CD.InterestSize[obj].y; po: CDRoutingObjects.PlacedObject _ SELECT side FROM top => [obj, [min, off ]], bottom => [obj, [min, width-off-szY ]], right => [obj, [off, min ]], left => [obj, [width-off-szX, min ]] ENDCASE=>ERROR; IF pos=NIL THEN { pos _ NEW[LIST OF CDRoutingObjects.PlacedObject _ NIL]; []_SymTab.Store[nodes, label, pos]}; pos^ _ CONS[po, pos^]}; nodes: SymTab.Ref _ SymTab.Create[]; width: INT _ form.ary[side].width; fMin: INT _ form.ary[side].min; fMax: INT _ form.ary[side].max; routingIR: CD.Rect _ SELECT side FROM left => [0, fMin, width, fMax], right => [0, fMin, width, fMax], top => [fMin, 0, fMax, width], bottom => [fMin, 0, fMax, width], ENDCASE => ERROR; routingPos: CD.Position _ SELECT side FROM left => [-width, 0], right => [subSize.x, 0], top => [0, subSize.y], bottom => [0, -width], ENDCASE => ERROR; trunk: CD.Layer _ IF LeftRight[side] THEN form.vert ELSE OtherLayer[form.vert]; branch: CD.Layer _ OtherLayer[trunk]; srcLay: CD.Layer _ IF form.sameLayers THEN branch ELSE trunk; oneBus: BOOL _ NOT form.sameLayers; -- later we can count SELECT side FROM left => resultIR.x1 _ routingPos.x; right => resultIR.x2 _ routingPos.x + width; top => resultIR.y2 _ routingPos.y + width; bottom => resultIR.y1 _ routingPos.y; ENDCASE => ERROR; IF width=0 OR form.ary[side].pins=NIL THEN LOOP; FOR pins: WirePins _ form.ary[side].pins, pins.rest WHILE pins#NIL DO pin: WirePin _ pins.first; size: INT _ pin.max - pin.min; busRec: REF BusRec _ ExistingBusSideRec[pin.wire, side]; corner: BOOL _ ~LeftRight[side] AND (pin.min < 0 OR pin.max > subSize.x); extend: BOOL _ CoreOps.Member[form.ary[side].wires, pin.wire]; IF NOT MetLayer[pin.layer] THEN LOOP; IF corner THEN { AddRect[pin.wire, [width, size], branch, 0, pin.min]; IF busRec#NIL THEN AddVias[pin.wire,[busRec.width, size], busRec.loc, pin.min]} ELSE IF busRec=NIL THEN SELECT TRUE FROM pin.layer=branch => AddRect[pin.wire, [width, size], pin.layer, 0, pin.min]; NOT form.sameLayers => { AddRect[pin.wire, [2*L4, size], pin.layer, 0, pin.min]; AddVias[pin.wire, [L4, size], L4, pin.min]; AddRect[pin.wire, [width-L4, size], branch, L4, pin.min]}; ENDCASE -- skip pin ELSE IF oneBus OR pin.layer=branch THEN { AddRect[pin.wire, [busRec.loc, size], pin.layer, 0, pin.min]; IF pin.layer#trunk OR extend THEN AddVias[pin.wire, [busRec.width, size], busRec.loc, pin.min]; IF extend THEN AddRect[pin.wire, [width - busRec.loc, size], branch, busRec.loc, pin.min]}; ENDLOOP; <> FOR buses: Wires _ form.ary[side].buses, buses.rest WHILE buses#NIL DO rec: REF BusRec _ EnsureBusSideRec[buses.first, side]; size: CD.Position _ [rec.width, rec.max-rec.min]; AddRect[buses.first, size, trunk, rec.loc, rec.min] ENDLOOP; cdInstances _ CONS [ CDInstances.NewInst[ ob: CDRoutingObjects.CreateRoutingObject[ nodes: CDRoutingObjects.CreateNodes[nodes], ir: routingIR], trans: [routingPos]], cdInstances]; ENDLOOP; obj _ PW.CreateCell[instances: cdInstances, ir: resultIR, name: name.Cat[".mask"] ]}; Decorate: PWCore.DecorateProc = { WireToLabels: PROC [wire: Core.Wire] RETURNS [labels: LIST OF Route.Label _ NIL] = {RETURN[LIST [CoreRoute.LabelInternal[data.internal, wire]]]}; data: CoreClasses.RecordCellType _ NARROW [cellType.data]; CoreRoute.DecorateRoutedArea[cellType: cellType, obj: obj, wireToLabels: WireToLabels]}; <> EnsureBusSideRec: PROC[wire: Core.Wire, side: Side] RETURNS[busRec: REF BusRec] = { busRec _ ExistingBusSideRec[wire, side]; IF busRec=NIL THEN { busRec _ NEW[BusRec _ [0, 0, LAST[INT], FIRST[INT]]]; []_CoreProperties.PutWireProp[wire, sideProp[side], busRec]}}; ExistingBusSideRec: PROC[wire: Core.Wire, side: Side] RETURNS[busRec: REF BusRec] = {RETURN[NARROW[CoreProperties.GetWireProp[wire, sideProp[side]]]]}; GetSideExtention: PROC[cellType: Core.CellType, side: Side] RETURNS[extention: INT] = { LoSize: PROC[dif: INT] RETURNS[INT] = {RETURN[dif/2]}; HiSize: PROC[dif: INT] RETURNS[INT] = {RETURN[dif - LoSize[dif]]}; data: CoreClasses.RecordCellType _ NARROW[cellType.data]; inSize: CD.Position _ CD.InterestSize[PWCore.Layout[data[0].type]]; sizeProp: ATOM _ SELECT side FROM left, right => $XSize, ENDCASE => $YSize; sizeRef: REF INT _ NARROW[CoreProperties.GetCellTypeProp[cellType, sizeProp]]; sideRef: REF INT _ NARROW[CoreProperties.GetCellTypeProp[cellType, sideProp[side]]]; extention _ IF sideRef#NIL THEN sideRef^ ELSE IF sizeRef=NIL THEN 0 ELSE SELECT side FROM left => LoSize[MAX[0, sizeRef^ - inSize.x/lambda]], right => HiSize[MAX[0, sizeRef^ - inSize.x/lambda]], top => HiSize[MAX[0, sizeRef^ - inSize.y/lambda]], bottom => LoSize[MAX[0, sizeRef^ - inSize.y/lambda]], ENDCASE => ERROR}; Adjust345: PROC[min, max: INT] RETURNS[minn, maxx: INT] = { minn _ min; maxx _ max; IF max-min IN (0..5*lambda] THEN { minn _ (min+max)/2 - 2*lambda; maxx _ (min+max)/2 + 2*lambda} }; AdjustPins345: PROC[pins: WirePins] = { FOR pins _ pins, pins.rest WHILE pins#NIL DO [pins.first.min, pins.first.max] _ Adjust345[pins.first.min, pins.first.max] ENDLOOP}; LeftRight: PROC[side: Side] RETURNS[leftRight: BOOL] = {RETURN[side=left OR side=right]}; MergeOrderedWires: PROC[a, b: Core.Wires] RETURNS[merge: Core.Wires] = { DO SELECT TRUE FROM a=NIL AND b=NIL => EXIT; a=NIL => {merge_CONS[b.first, merge]; b_b.rest}; b=NIL => {merge_CONS[a.first, merge]; a_a.rest}; a.first=b.first => {merge_CONS[a.first, merge]; a_a.rest; b_b.rest}; CoreOps.Member[b, a.first] => {merge_CONS[b.first, merge]; b_b.rest}; ENDCASE => {merge_CONS[a.first, merge]; a_a.rest}; ENDLOOP; RETURN[CoreOps.Reverse[merge]]}; OtherLayer: PROC[lay: CD.Layer] RETURNS[CD.Layer] = {RETURN[IF lay=CMosB.met THEN CMosB.met2 ELSE CMosB.met]}; MetLayer: PROC[layer: CD.Layer] RETURNS[isMetal1or2: BOOL] = {RETURN[layer=CMosB.met OR layer=CMosB.met2]}; ShowExtendForm: PROC[cellType: Core.CellType] = { name: IO.ROPE _ CoreOps.GetCellTypeName[cellType]; form: ExtendForm _ NARROW[CoreProperties.GetCellTypeProp[cellType, extendFormProp]]; tos: IO.STREAM _ TerminalIO.TOS[]; tos.PutF["Extend Layout: %g\n", IO.rope[name] ]; tos.PutF[" Left: %g\n", IO.int[form.ary[left].width]]; tos.PutF[" Right: %g\n", IO.int[form.ary[right].width]]; tos.PutF[" Top: %g\n", IO.int[form.ary[top].width]]; tos.PutF[" Bottom: %g\n", IO.int[form.ary[bottom].width]]}; SideNm: ARRAY Side OF IO.ROPE _ [bottom: "Bottom", top: "Top", left: "Left", right: "Right"]; Vias: PROC[sizex, sizey: INT] RETURNS[obj: CD.Object] = { Bias: PROC[s: INT] RETURNS[bias:INT] = {RETURN[(s+d-((s+d)/(3*d))*3*d)/2]}; node: IO.ROPE _ "node"; insts: CD.InstanceList _ NIL; name: IO.ROPE _ IO.PutFR["Vias%gx%gy", IO.int[sizex], IO.int[sizey]]; via: CD.Object _ CDSimpleRules.Contact[technologyKey, CMosB.met, CMosB.met2]; d: INT _ L4/2; FOR x: INT _ Bias[sizex], x + 3*d WHILE x <= sizex-(2*d) DO FOR y: INT _ Bias[sizey], y + 3*d WHILE y <= sizey-(2*d) DO insts _ CONS[NEW[CD.InstanceRep _ [via, [[x, y]]]], insts]; CDProperties.PutProp[insts.first, $SignalName, node] ENDLOOP ENDLOOP; IF insts=NIL THEN ERROR; insts _ CONS[NEW[CD.InstanceRep _ [CDRects.CreateRect[[sizex, sizey], CMosB.met]]], insts]; CDProperties.PutProp[insts.first, $SignalName, node]; insts _ CONS[NEW[CD.InstanceRep _ [CDRects.CreateRect[[sizex, sizey], CMosB.met2]]],insts]; CDProperties.PutProp[insts.first, $SignalName, node]; obj _ PW.CreateCell[instances: insts, name: Rope.Cat["Adj.mask"], ir: [0, 0, sizex, sizey]]}; <> [] _ PWCore.RegisterLayoutAtom[$ExtendX, Layout, Decorate, Attribute]; END.