DIRECTORY CD, CDBasics, CDCells, CDProperties, CDRects, CDRoutingObjects, Convert, Core, CoreRouteFlat, CoreRouteFlatProcs, DABasics, D2Orient, GC, GCPrivate, IP, IPCTG, IPTop, RefTab, Rope, Route, RTBasic, SymTab; GCDetailRouteImpl: CEDAR PROGRAM IMPORTS CD, CDBasics, CDCells, CDProperties, CDRects, CDRoutingObjects, Convert, CoreRouteFlat, CoreRouteFlatProcs, GC, GCPrivate, IPCTG, Route, RefTab, Rope, RTBasic, SymTab EXPORTS GCPrivate = BEGIN NetInChan: TYPE = REF NetInChanRec; -- routing description for a net on a channel NetInChanRec: TYPE = RECORD [ segmentCount: INT _ 0, -- count of existing segments segsInNet: LIST OF Segment _ NIL]; -- segments for this net on this channel Segment: TYPE = REF SegmentRec; SegmentRec: TYPE = RECORD[ name, lookUpName: Rope.ROPE _ NIL, trunkSize: INT _ 0, leftOrBottomExit: BOOL _ FALSE, -- used for channels only (not SB's) rightOrTopExit: BOOL _ FALSE, -- used for channels only (not SB's) pinsInSeg: LIST OF Pin _ NIL]; -- pins for this net on this channel Pin: TYPE = REF PinRec; -- pin description for pins in a net on a channel PinRec: TYPE = RECORD[ min: CD.Number _ 0, max: CD.Number _ 0, layer: CD.Layer, side: DABasics.Side]; DoDetailRoute: PUBLIC PROC [context: GC.Context, layoutStyle: GC.LayoutStyle] RETURNS [result: GC.Result] = { MakeChannel: GCPrivate.EachChannelAction ~ { InitNet: SymTab.EachPairAction = {net: CoreRouteFlat.Net _ NARROW[val]; net.any _ NIL}; rulesParameters: Route.DesignRulesParameters _ IF channel.direction = horizontal THEN context.rules.horizParams ELSE context.rules.vertParams; rules: Route.DesignRules _ IF channel.direction = horizontal THEN context.rules.horizRules ELSE context.rules.vertRules; lower, upper: RTBasic.PQPos; channelSize: CD.Position; [] _ SymTab.Pairs[context.structure.nets, InitNet]; GCPrivate.AssignCoordinates[context]; lower _ GCPrivate.LowerChannelPQ[channel]; upper _ GCPrivate.UpperChannelPQ[channel]; SELECT TRUE FROM channel.ch = bottomChannel => { channel.topOrRightShell _ MakeSide[context, rules, channel, top, TRUE, layoutStyle]; channel.bottomOrLeftShell _ MakeSide[context, rules, channel, bottom, FALSE, layoutStyle]}; channel.ch = rightChannel => { channel.bottomOrLeftShell _ MakeSide[context, rules, channel, left, TRUE, layoutStyle]; channel.topOrRightShell _ MakeSide[context, rules, channel, right, FALSE, layoutStyle]}; channel.ch = topChannel => { channel.bottomOrLeftShell _ MakeSide[context, rules, channel, bottom, TRUE, layoutStyle]; channel.topOrRightShell _ MakeSide[context, rules, channel, top, FALSE, layoutStyle]}; channel.ch = leftChannel => { channel.topOrRightShell _ MakeSide[context, rules, channel, right, TRUE, layoutStyle]; channel.bottomOrLeftShell _ MakeSide[context, rules, channel, left, FALSE, layoutStyle]}; ENDCASE => { channel.bottomOrLeftShell _ MakeSide[context, rules, channel, ChanSide[channel, bottom], TRUE, layoutStyle]; channel.topOrRightShell _ MakeSide[context, rules, channel, ChanSide[channel, top], TRUE, layoutStyle]}; MakeEnd[context, rules, channel, ChanSide[channel, left]]; -- lower end of channel MakeEnd[context, rules, channel, ChanSide[channel, right]]; -- upper end of channel channel.intermediateResult _ Route.ChannelRoute[enumerateNets: EnumerateChannelNets, min: lower.p, max: upper.p, rulesParameters: rulesParameters, rules: rules, name: NIL, enumerateObstructions: NIL, channelData: context, optimization: context.parms.opt, signalSinglePinNets: context.parms.signalSinglePinNets]; channel.cdObject _ Route.ChannelRetrieve[intermediateResult: channel.intermediateResult, enumerateNets: EnumerateChannelNets, brokenNets: NIL, channelData: context, retrieveRect: NIL].object; channelSize _ CDBasics.SizeOfRect[channel.intermediateResult.resultData.routingRect]; channel.width _ IF channel.direction = horizontal THEN channelSize.y ELSE channelSize.x; IPCTG.SetWidth[channel.ch, channel.width]}; IncludeChannel: GCPrivate.EachChannelAction ~ { IF channel.cdObject # NIL THEN { chanInst: CD.Instance _ GCPrivate.IncludeOb[cell: object, ob: channel.cdObject, position: channel.position]; CDProperties.PutInstanceProp[chanInst, $InstanceName, Rope.Cat["Channel", channel.name]]}; SELECT TRUE FROM channel.ch = bottomChannel => { IF channel.topOrRightShell # NIL THEN { [] _ GCPrivate.IncludeOb[cell: object, ob: channel.topOrRightShell, position: [channel.position.x, channel.position.y + channel.width]]}}; channel.ch = rightChannel => { IF channel.bottomOrLeftShell # NIL THEN { [] _ GCPrivate.IncludeOb[cell: object, ob: channel.bottomOrLeftShell, position: [channel.position.x - CD.InterestSize[channel.bottomOrLeftShell].x, channel.position.y]]}}; channel.ch = topChannel => { IF channel.bottomOrLeftShell # NIL THEN { [] _ GCPrivate.IncludeOb[cell: object, ob: channel.bottomOrLeftShell, position: [channel.position.x, channel.position.y - CD.InterestSize[channel.bottomOrLeftShell].y]]}}; channel.ch = leftChannel => { IF channel.topOrRightShell # NIL THEN { [] _ GCPrivate.IncludeOb[cell: object, ob: channel.topOrRightShell, position: [channel.position.x + channel.width, channel.position.y]]}}; ENDCASE => { IF channel.topOrRightShell # NIL THEN { topPos: CD.Position _ IF channel.direction = horizontal THEN [channel.position.x, channel.position.y + channel.width] ELSE [channel.position.x + channel.width, channel.position.y]; [] _ GCPrivate.IncludeOb[cell: object, ob: channel.topOrRightShell, position: topPos]}; IF channel.bottomOrLeftShell # NIL THEN { bottomPos: CD.Position _ IF channel.direction = horizontal THEN [channel.position.x, channel.position.y - CD.InterestSize[channel.bottomOrLeftShell].y] ELSE [channel.position.x - CD.InterestSize[channel.bottomOrLeftShell].x, channel.position.y]; [] _ GCPrivate.IncludeOb[cell: object, ob: channel.bottomOrLeftShell, position: bottomPos]}}}; IncludeInstances: CoreRouteFlatProcs.EachInstanceAction ~ { IF instance.layObject # NIL THEN { cdInst: CD.Instance _ GCPrivate.IncludeOb [object, instance.layObject, instance.position, instance.orientation]; CDProperties.PutInstanceProp[cdInst, $InstanceName, instance.name]}; IF instance.layShell # NIL THEN { } }; topology: IPTop.Ref _ NARROW[context.topology]; bottomChannel, rightChannel, topChannel, leftChannel: IPCTG.Channel; object: CD.Object _ CDCells.CreateEmptyCell[]; [bottomChannel, rightChannel, topChannel, leftChannel] _ IPCTG.GetBoundingChannels[topology.ctg]; [] _ GCPrivate.EnumerateChannelsInTopologicalOrder[context, MakeChannel]; GCPrivate.AssignCoordinates[context]; [] _ GCPrivate.EnumerateChannelsInTopologicalOrder[context, IncludeChannel]; [] _ CoreRouteFlatProcs.EnumerateInstances[context.structure, IncludeInstances]; result _ NEW[GC.ResultRec _ [context: context, object: object]]}; MakeSide: PROC [context: GC.Context, rules: Route.DesignRules, channel: GCPrivate.Channel, chanSide: DABasics.Side, internal: BOOLEAN, layoutStyle: GC.LayoutStyle] RETURNS [shell: CD.Object _ NIL] ~ { DoExternalPins: IPCTG.EachComponentAction ~ { IF co # NIL THEN { instance: CoreRouteFlat.Instance _ NARROW[co.any]; sideOfCell: DABasics.Side _ IF internal THEN otherSide ELSE chanSide; FOR nns: LIST OF CoreRouteFlat.NetONode _ instance.netONodes, nns.rest WHILE nns#NIL DO isPowerNet: BOOLEAN _ Rope.Equal[nns.first.net.name, "Vdd"] OR Rope.Equal[nns.first.net.name, "Gnd"]; IF ExternalNet[context.structure, nns.first.net] AND (layoutStyle = ic OR ~isPowerNet) THEN { sidesForExternalNet: DABasics.Sides _ SidesForExternalNet[context.structure, nns.first.net]; FOR pins: LIST OF CoreRouteFlat.Pin _ nns.first.oNode.pins, pins.rest WHILE pins#NIL DO phyPin: GCPrivate.PhyPinDesc _ NEW[GCPrivate.PhyPinDescRec _ [instance, nns.first.oNode, pins.first]]; netDesc: GCPrivate.NetDesc _ NARROW [RefTab.Fetch[channel.connections, nns.first.net].val]; IF pins.first.layer = rules.branchLayer AND ~GCPrivate.PinOnList[netDesc, phyPin] AND sidesForExternalNet[sideOfCell] AND ((pins.first.side = otherSide AND internal) OR (pins.first.side = chanSide AND ~internal)) THEN { tabIndex: Rope.ROPE _ Rope.Cat[nns.first.net.name, "@", instance.name, "@", Convert.RopeFromInt[pins.first.range.min]]; netDat: NetInChan _ IF nns.first.net.any = NIL THEN NEW[NetInChanRec] ELSE NARROW[nns.first.net.any]; range: CoreRouteFlat.Range _ CoreRouteFlat.TranslateRange[instance, pins.first]; AddPin[nns.first.net, netDat, nns.first.net.name, tabIndex, range, rules.branchLayer, chanSide, defaultTrunkWidth]; maxWidth _ MAX[maxWidth, IncludePin[ phyPin: NEW[GCPrivate.PhyPinDescRec _ [instance, nns.first.oNode, pins.first]], name: tabIndex, side: chanSide, lower: lower, upper: upper, nodes: nodes ] ] }; ENDLOOP}; ENDLOOP} }; EachNet: RefTab.EachPairAction ~ { netDesc: GCPrivate.NetDesc _ NARROW[val]; FOR list: LIST OF GCPrivate.PhyPinDesc _ netDesc.pinList, list.rest WHILE list # NIL DO net: CoreRouteFlat.Net _ NARROW[key]; phyPin: GCPrivate.PhyPinDesc _ list.first; netDat: NetInChan _ IF net.any = NIL THEN NEW[NetInChanRec] ELSE NARROW[net.any]; range: CoreRouteFlat.Range _ CoreRouteFlat.TranslateRange[phyPin.instance, phyPin.pPin]; externalNet: BOOLEAN _ IPCTG.IsBoundingChannel[topology.ctg, channel.ch] AND ExternalNet[context.structure, net]; IF phyPin.pPin.layer # rules.branchLayer THEN GC.Signal[programmingError, "Call Maintainer"]; maxWidth _ MAX[maxWidth, IncludePin [list.first, net.name, chanSide, lower, upper, nodes]]; IF phyPin.pPin.side = otherSide THEN AddPin[net, netDat, net.name, net.name, range, rules.branchLayer, chanSide, defaultTrunkWidth]; IF externalNet THEN { sidesForExternalNet: DABasics.Sides _ SidesForExternalNet[context.structure, net]; sideOfCell: DABasics.Side _ IF internal THEN otherSide ELSE chanSide; IF ~internal AND sidesForExternalNet[sideOfCell] AND phyPin.pPin.side = chanSide THEN AddPin[net, netDat, net.name, net.name, range, rules.branchLayer, chanSide, defaultTrunkWidth]}; ENDLOOP}; DoChannelIntersection: IPCTG.EachIntersectionAction ~ { EachExit: PublicEnumerator ~ { net: CoreRouteFlat.Net _ NARROW[SymTab.Fetch[context.structure.nets, name].val]; sidesForExternalNet: DABasics.Sides _ SidesForExternalNet[context.structure, net]; sideOfCell: DABasics.Side _ IF internal THEN otherSide ELSE chanSide; IF (internal AND side = otherSide) OR (~internal AND sidesForExternalNet[sideOfCell] AND side = chanSide) THEN { range: CoreRouteFlat.Range _ SELECT chanSide FROM bottom, top => [otherChannel.position.x + min, otherChannel.position.x + max], left, right => [otherChannel.position.y + min, otherChannel.position.y + max], ENDCASE => GC.Error[programmingError, "Call maintainer"]; netDat: NetInChan _ IF net.any = NIL THEN NEW[NetInChanRec] ELSE NARROW[net.any]; AddPin[net, netDat, name, name, range, rules.branchLayer, chanSide, defaultTrunkWidth]}}; otherChannel: GCPrivate.Channel _ NARROW[i.ch.any]; [] _ EnumerateEdgePins[context, otherChannel, EachExit]}; defaultTrunkWidth: INT _ rules.trunkWidth; rect: CD.Rect; maxWidth: INT _ 0; otherSide: DABasics.Side _ RTBasic.OtherSide[chanSide]; bottomOrLeft: BOOLEAN _ chanSide = bottom OR chanSide = left; topOrRight: BOOLEAN _ ~bottomOrLeft; lower: RTBasic.PQPos _ GCPrivate.LowerChannelPQ[channel]; upper: RTBasic.PQPos _ GCPrivate.UpperChannelPQ[channel]; topology: IPTop.Ref _ NARROW[context.topology]; polarity: IP.PolarityTypes _ IF (internal AND bottomOrLeft) OR (~internal AND topOrRight) THEN neg ELSE pos; nodes: SymTab.Ref _ SymTab.Create[]; IF IPCTG.IsBoundingChannel[topology.ctg, channel.ch] THEN [] _ IPCTG.Components[channel.ch, polarity, DoExternalPins]; [] _ RefTab.Pairs[channel.connections, EachNet]; [] _ IPCTG.Intersections[channel.ch, polarity, DoChannelIntersection]; IF channel.lowerIntType = inverted THEN [] _ DoChannelIntersection[IPCTG.End[channel.ch, neg]]; IF channel.upperIntType = inverted THEN [] _ DoChannelIntersection[IPCTG.End[channel.ch, pos]]; rect _ SELECT chanSide FROM bottom => [lower.p, lower.q - maxWidth, upper.p, lower.q], right => [upper.q, lower.p, upper.q + maxWidth, upper.p], top => [lower.p, upper.q, upper.p, upper.q + maxWidth], left => [lower.q - maxWidth, lower.p, lower.q, upper.p], ENDCASE => GC.Error[programmingError, "Call maintainer"]; IF SymTab.GetSize[nodes] > 0 THEN shell _ CDRoutingObjects.CreateRoutingObject[ nodes: CDRoutingObjects.CreateNodes[nodes], ir: rect] }; MakeEnd: PROC [context: GC.Context, rules: Route.DesignRules, channel: GCPrivate.Channel, side: DABasics.Side] ~ { EachNet: RefTab.EachPairAction ~ { netDesc: GCPrivate.NetDesc _ NARROW[val]; net: CoreRouteFlat.Net _ NARROW[key]; publicNet: BOOLEAN _ CoreRouteFlat.IsPublic[net]; needsExit: BOOLEAN _ (side = bottom OR side = left) AND netDesc.bottomOrLeftExit OR (side = top OR side = right) AND netDesc.topOrRightExit; IF needsExit AND (ordinaryIntersection OR publicNet) THEN { netDat: NetInChan _ IF net.any = NIL THEN NEW[NetInChanRec] ELSE NARROW[net.any]; AddEnd[net, netDat, net.name, net.name, side, defaultTrunkWidth]}}; defaultTrunkWidth: INT _ rules.trunkWidth; ordinaryIntersection: BOOLEAN _ (channel.lowerIntType = normal AND (side = left OR side = bottom)) OR (channel.upperIntType = normal AND (side = right OR side = top)); [] _ RefTab.Pairs[channel.connections, EachNet]}; ChanSide: PROC [channel: GCPrivate.Channel, side: DABasics.Side] RETURNS [sideToUse: DABasics.Side] ~ { sideToUse _ IF channel.direction = horizontal THEN side ELSE SELECT side FROM bottom => left, right => top, top => right, left => bottom, ENDCASE => GC.Error[programmingError, "Call maintainer"]}; ExternalNet: PROC [struc: CoreRouteFlat.Structure, net: CoreRouteFlat.Net] RETURNS [isExternal: BOOLEAN _ FALSE] ~ { TestONode: CoreRouteFlatProcs.EachNetONodeAction ~ { IF net = netONode.net THEN quit _ TRUE}; isExternal _ CoreRouteFlatProcs.EnumerateNetONodes[struc.outerInstance, TestONode]}; SidesForExternalNet: PROC [struc: CoreRouteFlat.Structure, net: CoreRouteFlat.Net] RETURNS [sides: DABasics.Sides _ DABasics.noSide] ~ { TestONode: CoreRouteFlatProcs.EachNetONodeAction ~ { IF net = netONode.net THEN { TestPin: CoreRouteFlatProcs.EachPinAction ~ { sides[pin.side] _ TRUE}; [] _ CoreRouteFlatProcs.EnumeratePins[netONode.oNode, TestPin]}}; [] _ CoreRouteFlatProcs.EnumerateNetONodes[struc.outerInstance, TestONode]}; IncludePin: PROC [phyPin: GCPrivate.PhyPinDesc, name: Rope.ROPE, side: DABasics.Side, lower, upper: RTBasic.PQPos, nodes: SymTab.Ref] RETURNS[width: INT]~ { instance: CoreRouteFlat.Instance _ phyPin.instance; pPin: CoreRouteFlat.Pin _ phyPin.pPin; range: CoreRouteFlat.Range _ CoreRouteFlat.TranslateRange[instance, pPin]; rangeSize: INT _ range.max - range.min; wireLoc: CD.Position; wireSize: CD.Position; SELECT side FROM top => { width _ instance.position.y - upper.q; -- + pPin.depth wireSize _ [rangeSize, width]; wireLoc _ [range.min, upper.q]}; left => { sidePos: INT _ instance.position.x + CD.InterestSize[instance.layObject].x; width _ lower.q - sidePos; -- + pPin.depth; wireSize _ [width, rangeSize]; wireLoc _ [sidePos -- -pPin.depth--, range.min]}; bottom => { sidePos: INT _ instance.position.y + CD.InterestSize[instance.layObject].y; width _ lower.q - sidePos; -- + pPin.depth; wireSize _ [rangeSize, width]; wireLoc _ [range.min, sidePos -- -pPin.depth--]}; right => { width _ instance.position.x - upper.q; -- + pPin.depth; wireSize _ [width, rangeSize]; wireLoc _ [upper.q, range.min]}; ENDCASE; IF width > 0 THEN { wire: CD.Object _ CDRects.CreateRect[wireSize, pPin.layer]; po: CDRoutingObjects.PlacedObject _ [wire, wireLoc]; pos: REF LIST OF CDRoutingObjects.PlacedObject _ NEW[LIST OF CDRoutingObjects.PlacedObject _ NIL]; []_SymTab.Store[nodes, Rope.Cat[name, "-", Convert.RopeFromInt[range.min]], pos]; pos^ _ CONS[po, pos^]}}; EnumerateEdgePins: PROC [context: GC.Context, channel: GCPrivate.Channel, eachEdgeEntity: PublicEnumerator] RETURNS [quit: BOOL _ FALSE] ~ { rp: CDRoutingObjects.RoutingSpecific = NARROW[channel.cdObject.specific]; FOR i: NAT IN [0 .. rp.size) DO node: CDRoutingObjects.Node = rp[i]; FOR j: NAT IN [0 .. node.size) DO pinIR: CD.Rect _ CDBasics.MoveRect[node[j].object.bbox, node[j].position]; IF CDBasics.Intersect[rp.ir, pinIR] THEN { name: Rope.ROPE _ NARROW[CDProperties.GetProp[node.properties, $SignalName]]; sides: DABasics.Sides = PinIRSides[rp.ir, pinIR]; FOR side: DABasics.Side IN DABasics.Side DO min, max: INT _ 0; IF ~sides[side] THEN LOOP; IF side=top OR side=bottom THEN {min _ pinIR.x1; max _ pinIR.x2}; IF side=left OR side=right THEN {min _ pinIR.y1; max _ pinIR.y2}; IF (quit _ eachEdgeEntity[name, min, max, side, node[j].object.layer]) THEN RETURN; ENDLOOP}; ENDLOOP; ENDLOOP}; PinIRSides: PROC [ir, pinIR: CD.Rect] RETURNS [sides: DABasics.Sides _ DABasics.noSide] = { sides[top] _ CDBasics.Intersect[pinIR, [ir.x1, ir.y2-1, ir.x2, ir.y2]]; sides[bottom] _ CDBasics.Intersect[pinIR, [ir.x1, ir.y1, ir.x2, ir.y1+1]]; sides[left] _ CDBasics.Intersect[pinIR, [ir.x1, ir.y1, ir.x1+1, ir.y2]]; sides[right] _ CDBasics.Intersect[pinIR, [ir.x2-1, ir.y1, ir.x2, ir.y2]]}; PublicEnumerator: TYPE = PROC[name: Rope.ROPE, min, max: INT, side: DABasics.Side, layer: CD.Layer] RETURNS [quit: BOOL _ FALSE]; AddPin: PROC [net: CoreRouteFlat.Net, netDat: NetInChan, name, lookUpName: Rope.ROPE, range: CoreRouteFlat.Range, layer: CD.Layer, side: DABasics.Side, trunkWidth: INT] ~ { pin: Pin _ NEW[PinRec _ [min: range.min, max: range.max, --depth: 0,-- layer: layer, side: side]]; segment: Segment _ LookUpSegment[netDat, name, lookUpName]; segment.pinsInSeg _ CONS[pin, segment.pinsInSeg]; segment.trunkSize _ trunkWidth; net.any _ netDat}; AddEnd: PROC [net: CoreRouteFlat.Net, netDat: NetInChan, name, lookUpName: Rope.ROPE, side: DABasics.Side, trunkWidth: INT] ~ { segment: Segment _ LookUpSegment[netDat, name, lookUpName]; SELECT side FROM bottom, left => segment.leftOrBottomExit _ TRUE; right, top => segment.rightOrTopExit _ TRUE; ENDCASE; segment.trunkSize _ trunkWidth; net.any _ netDat}; LookUpSegment: PROC [netDat: NetInChan, name, lookUpName: Rope.ROPE] RETURNS [segment: Segment _ NIL] ~ { FOR segList: LIST OF Segment _ netDat.segsInNet, segList.rest WHILE segList # NIL AND segment = NIL DO IF Rope.Equal[segList.first.lookUpName, lookUpName] THEN segment _ segList.first; ENDLOOP; IF segment = NIL THEN { -- not found, make a NEW one segment _ NEW[SegmentRec _ [name: name, lookUpName: lookUpName]]; netDat.segmentCount _ netDat.segmentCount + 1; netDat.segsInNet _ CONS[segment, netDat.segsInNet]}}; EnumerateChannelNets: Route.EnumerateChannelNetsProc ~ { ChannelNet: SymTab.EachPairAction ~ { net: CoreRouteFlat.Net _ NARROW[val]; IF net.any # NIL THEN { netDat: NetInChan _ NARROW[net.any]; FOR segs: LIST OF Segment _ netDat.segsInNet, segs.rest UNTIL segs = NIL DO seg: Segment _ segs.first; eachNet[name: seg.name, enumeratePins: ChannelSignalPins, exitLeftOrBottom: seg.leftOrBottomExit, exitRightOrTop: seg.rightOrTopExit, trunkSize: seg.trunkSize, channelData: channelData, netData: seg]; ENDLOOP}}; structure: CoreRouteFlat.Structure _ NARROW[channelData, GC.Context].structure; [] _ SymTab.Pairs[structure.nets, ChannelNet]}; ChannelSignalPins: Route.EnumerateChannelPinsProc ~ { seg: Segment _ NARROW[netData]; FOR pins: LIST OF Pin _ seg.pinsInSeg, pins.rest UNTIL pins = NIL DO pin: Pin _ pins.first; bottomOrLeftSide: BOOL _ pin.side = bottom OR pin.side = left; eachPin[bottomOrLeftSide: bottomOrLeftSide, min: pin.min, max: pin.max, --depth: pin.depth,-- layer: pin.layer]; ENDLOOP}; END. GCDetailRouteImpl.mesa Copyright Ó 1986, 1987 by Xerox Corporation. All rights reserved. Bryan Preas, February 19, 1987 9:06:53 pm PST Don Curry January 15, 1988 7:27:49 pm PST Massoud Pedram June 15, 1988 1:48:07 pm PDT Local Types depth: CD.Number _ 0, DetailRoute Determine actual wiring paths. PROC[context: GC.Context, channel: Channel] RETURNS [quit: BOOLEAN _ FALSE]; construct a channel IF layoutStyle = hybrid THEN { add Vdd layer to channel vddLayer: CD.Layer _ CDSimpleRules.GetLayer[context.rules.technology.key, "poly"]; -- a HACK for Vdd layer wire: CD.Object _ CDRects.CreateRect[channelSize, vddLayer]; po: CDRoutingObjects.PlacedObject _ [wire, channel.position]; node: CDRoutingObjects.Node = CDRoutingObjects.CreateNode[LIST[po], LIST [[key: $SignalName, val: "Vdd"]]]; rp: CDRoutingObjects.RoutingSpecific = NARROW[channel.cdObject.specific]; rp.nodes _ CONS[node, rp.nodes]}; PROC[context: GC.Context, channel: Channel] RETURNS [quit: BOOLEAN _ FALSE]; Include a previously routed channel into the object being constructed first the channel next include the cells containing the wires to get from the channel edges to cells PROC [instance: CoreRouteFlat.Instance] RETURNS [quit: BOOLEAN _ FALSE]; cdshell: CD.Instance _ IncludeRoutingOb [object, instance.layShell, instance.position, instance.orientation]; CDProperties.PutInstanceProp[cdshell, $InstanceName, Rope.Cat[instance.name, "Tap.mask"] ] IF layoutStyle = hybrid THEN { -- add Gnd layer to channel gndLayer: CD.Layer _ CDSimpleRules.GetLayer[context.rules.technology.key, "diff"]; -- a HACK for Gnd layer wire: CD.Object _ CDRects.CreateRect[channelSize, width], gndLayer]; po: CDRoutingObjects.PlacedObject _ [wire, channel.position]; node: CDRoutingObjects.Node = CDRoutingObjects.CreateNode[LIST[po], LIST [[key: $SignalName, val: "Gnd"]]]; rp: CDRoutingObjects.RoutingSpecific = NARROW[channel.cdObject.specific]; rp.nodes _ CONS[node, rp.nodes]}; Construction Utilities construct a shell for the chanSide of a channel and insert global routing info for this channel PROC[co: Component] RETURNS[quit: BOOL _ FALSE]; add the external pins accross the channel for boundry channels Gnd and Vdd are on separate planes for hybrids include pin if it is a public pin, on the right layer, not on a global route and on a public side PROC [key: Key, val: Val] RETURNS [quit: BOOL _ FALSE]; add the pins from the nets PROC[i: Intersection] RETURNS[quit: BOOL _ FALSE]; add the pins from the channel intersections [name: Rope.ROPE, min, max: INT, side: DABasics.Side, layer: CD.Layer] RETURNS [quit: BOOL _ FALSE] AddVdd: IPCTG.EachComponentAction ~ { PROC[co: Component] RETURNS[quit: BOOL _ FALSE]; add the vdd connections for hybrids IF co # NIL THEN { instance: CoreRouteFlat.Instance _ NARROW[co.any]; instSize: CD.Position _ CD.InterestSize[instance.layObject]; width: INT _ SELECT side FROM top => instance.position.y - upper.q, left => lower.q - instance.position.x - instSize.x, bottom => lower.q - instance.position.y - instSize.y, right => instance.position.x - upper.q, ENDCASE => GC.Error[programmingError, "Not suppose to happen"]; IF width > 0 THEN { vddLayer: CD.Layer _ CDSimpleRules.GetLayer[context.rules.technology.key, "poly"]; -- a HACK for Vdd layer wire: CD.Object _ SELECT side FROM bottom, top => CDRects.CreateRect[[instSize.x, width], vddLayer], left, right => CDRects.CreateRect[[[width, instSize.y], width], vddLayer], ENDCASE => GC.Error[programmingError, "Not suppose to happen"]; po: CDRoutingObjects.PlacedObject _ SELECT side FROM SELECT side FROM top => [wire, [instance.position.x, upper.q]], left => [wire, [instance.position.x + instSize.x, instance.position.y]], bottom => [wire, [instance.position.x, instance.position.y + instSize.y]], right => [wire, [upper.q, instance.position.y]], ENDCASE => GC.Error[programmingError, "Not suppose to happen"]; pos: REF LIST OF CDRoutingObjects.PlacedObject _ NEW[LIST OF CDRoutingObjects.PlacedObject _ NIL]; []_SymTab.Store[nodes, "Vdd", pos]; pos^ _ CONS[po, pos^] } } }; IF layoutStyle = hybrid AND maxWidth > 0 THEN [] _ IPCTG.Components[channel.ch, polarity, AddVdd]; construct the end object of a channel PROC [key: Key, val: Val] RETURNS [quit: BOOLEAN _ FALSE]; PROC [instance: CoreRouteFlat.Instance, netONode: CoreRouteFlat.NetONode] RETURNS [quit: BOOLEAN _ FALSE]; PROC [instance: CoreRouteFlat.Instance, netONode: CoreRouteFlat.NetONode] RETURNS [quit: BOOLEAN _ FALSE]; PROC [oNode: CoreRouteFlat.ONode, pin: CoreRouteFlat.Pin] RETURNS [quit: BOOLEAN _ FALSE]; include a pin in a shell; also extend a wire if necessary Routing Area Manipulation apply EachEdgeEntity to entities of ob pinIR is the rectangle expressing the InterestRect of the pin in the InterestRect coordinate system of the outer. IncludeRoutingOb: PUBLIC PROC [cell: CD.Object, ob: CD.Object, position: CD.Position_[0, 0], orientation: D2Orient.Orientation_original] RETURNS [application: CD.Instance] = { include an routing object in a cell; position refers to base of interest rect LabelProc: PROC [name: Rope.ROPE] RETURNS [label: Route.Label] ~ { call back for routing object conversion label _ name}; IF ~CDCells.IsEmpty[ob] THEN { routingOb: CD.Object _ CoreRoute.MakeRoutingCell[ob, LabelProc]; application _ GCPrivate.IncludeOb[cell: cell, ob: routingOb, position: position, orientation: orientation]}}; Detail Route Entry add a pin to the appropriate segment in net add a channel end connection find an existing segment by name; if none, make a NEW one Router Callbacks PROC [channelData: REF, eachNet: EachChannelNetProc]; PROC [channelData, netData: REF, eachPin: EachChannelPinProc]; ʾ– "cedar" style˜codešœ™KšœB™BKšœ*Ïkœ™.Kšœ)™)K™+—K˜š ˜ Kšœ„œ œœ.˜ÌK˜—šÏnœœœ˜!Kšœœjœ œ&˜®Kšœ ˜—headšÏl ™ Kšœ œœÏc-˜Qšœœœ˜Kšœœ ˜5Kšœ œœ œ (˜LK˜—Kšœ œœ ˜!šœ œœ˜Kšœœœ˜"Kšœ œ˜Kšœœœ $˜DKšœœœ $˜BKšœ œœœ $˜DK˜—Kšœœœ  1˜Kšœ œœ˜Kšœœ ˜Kšœœ ˜Kšœœ ™Kšœœ˜Kšœ˜——šœ ™ š ž œœœ œ'œ œ ˜mšœ™K™—šž œ!˜,š œ œœœœ™LKšœ™K˜—šžœ˜ Kšœœœ˜6—K˜šœ/œ˜PKšœ˜Kšœ˜—šœœ˜œœ™pKšœM™MK™šž œœ œœ™BKšœ'™'K™K™—šœœ™Kšœ œ3™@Kšœm™m———šŸ™š žœœDœ%œ)œ˜¬Kšœ+™+Kšœ œT˜bKšœ;˜;Kšœœ˜1Kšœ˜Kšœ˜K˜—šžœœDœ#œ˜Kšœ™Kšœ;˜;šœ˜Kšœ+œ˜0Kšœ'œ˜,Kšœ˜—Kšœ˜Kšœ˜K˜—š ž œœ,œœœ˜iKšœ2œ™9šœ œœ*œ œœ œ˜fKšœ2œ˜QKšœ˜—šœ œœ ˜4Kšœ œ4˜AKšœ.˜.Kšœœ˜5———šŸ™šžœ$˜8Kšœœ™5šž œ˜%Kšœœ˜%šœ œœ˜Kšœœ ˜$š œœœ'œœ˜KKšœ˜šœ˜Kšœ!˜!Kšœ'˜'Kšœ#˜#Kšœ˜Kšœ˜Kšœ˜—Kšœ˜ ———Kšœ%œœ˜OKšœ/˜/K˜—šžœ$˜5Kšœœ™>Kšœœ ˜š œœœ œœ˜DKšœ˜Kšœœœ˜>Kšœp˜pKšœ˜ ——K˜Kšœ˜—K˜J˜J˜J˜—…—KøwÔ