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
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
Local Types
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.ROPENIL,
trunkSize:  INT ← 0,
leftOrBottomExit: BOOLFALSE, -- used for channels only (not SB's)
rightOrTopExit: BOOLFALSE, -- 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,
depth:  CD.Number ← 0,
layer:  CD.Layer,
side:  DABasics.Side];
DetailRoute
DoDetailRoute: PUBLIC PROC [context: GC.Context, layoutStyle: GC.LayoutStyle] RETURNS [result: GC.Result] = {
Determine actual wiring paths.
MakeChannel: GCPrivate.EachChannelAction ~ {
PROC[context: GC.Context, channel: Channel] RETURNS [quit: BOOLEANFALSE];
construct a channel
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;
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]};
IPCTG.SetWidth[channel.ch, channel.width]};
IncludeChannel: GCPrivate.EachChannelAction ~ {
PROC[context: GC.Context, channel: Channel] RETURNS [quit: BOOLEANFALSE];
Include a previously routed channel into the object being constructed
first the channel
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]]};
next include the cells containing the wires to get from the channel edges to cells
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 ~ {
PROC [instance: CoreRouteFlat.Instance] RETURNS [quit: BOOLEAN ← FALSE];
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 {
cdshell: CD.Instance ← IncludeRoutingOb
[object, instance.layShell, instance.position, instance.orientation];
CDProperties.PutInstanceProp[cdshell, $InstanceName, Rope.Cat[instance.name, "Tap.mask"] ]
}
};
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];
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]};
result ← NEW[GC.ResultRec ← [context: context, object: object]]};
Construction Utilities
MakeSide: PROC [context: GC.Context, rules: Route.DesignRules, channel: GCPrivate.Channel, chanSide: DABasics.Side, internal: BOOLEAN, layoutStyle: GC.LayoutStyle] RETURNS [shell: CD.Object ← NIL] ~ {
construct a shell for the chanSide of a channel and insert global routing info for this channel
DoExternalPins: IPCTG.EachComponentAction ~ {
PROC[co: Component] RETURNS[quit: BOOLFALSE];
add the external pins accross the channel for boundry channels
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 {
Gnd and Vdd are on separate planes for hybrids
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 {
include pin if it is a public pin, on the right layer, not on a global route and on a public side
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 ~ {
PROC [key: Key, val: Val] RETURNS [quit: BOOLFALSE];
add the pins from the nets
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: BOOLEANIPCTG.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 ~ {
PROC[i: Intersection] RETURNS[quit: BOOLFALSE];
add the pins from the channel intersections
EachExit: PublicEnumerator ~ {
[name: Rope.ROPE, min, max: INT, side: DABasics.Side, layer: CD.Layer] RETURNS [quit: BOOLFALSE]
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]};
AddVdd: IPCTG.EachComponentAction ~ {
PROC[co: Component] RETURNS[quit: BOOLFALSE];
add the vdd connections for hybrids
IF co # NIL THEN {
instance: CoreRouteFlat.Instance ← NARROW[co.any];
instSize: CD.Position ← CD.InterestSize[instance.layObject];
width: INTSELECT 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^] } } };
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 layoutStyle = hybrid AND maxWidth > 0 THEN
[] ← IPCTG.Components[channel.ch, polarity, AddVdd];
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] ~ {
construct the end object of a channel
EachNet: RefTab.EachPairAction ~ {
PROC [key: Key, val: Val] RETURNS [quit: BOOLEANFALSE];
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: BOOLEANFALSE] ~ {
TestONode: CoreRouteFlatProcs.EachNetONodeAction ~ {
PROC [instance: CoreRouteFlat.Instance, netONode: CoreRouteFlat.NetONode] RETURNS [quit: BOOLEANFALSE];
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 ~ {
PROC [instance: CoreRouteFlat.Instance, netONode: CoreRouteFlat.NetONode] RETURNS [quit: BOOLEANFALSE];
IF net = netONode.net THEN {
TestPin: CoreRouteFlatProcs.EachPinAction ~ {
PROC [oNode: CoreRouteFlat.ONode, pin: CoreRouteFlat.Pin] RETURNS [quit: BOOLEANFALSE];
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]~ {
include a pin in a shell; also extend a wire if necessary
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^]}};
Routing Area Manipulation
EnumerateEdgePins: PROC [context: GC.Context, channel: GCPrivate.Channel, eachEdgeEntity: PublicEnumerator] RETURNS [quit: BOOLFALSE] ~ {
apply EachEdgeEntity to entities of ob
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.ROPENARROW[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};
pinIR is the rectangle expressing the InterestRect of the pin in the InterestRect coordinate system of the outer.
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: BOOLFALSE];
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
AddPin: PROC [net: CoreRouteFlat.Net, netDat: NetInChan, name, lookUpName: Rope.ROPE, range: CoreRouteFlat.Range, layer: CD.Layer, side: DABasics.Side, trunkWidth: INT] ~ {
add a pin to the appropriate segment in net
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] ~ {
add a channel end connection
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] ~ {
find an existing segment by name; if none, make a NEW one
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]}};
Router Callbacks
EnumerateChannelNets: Route.EnumerateChannelNetsProc ~ {
PROC [channelData: REF, eachNet: EachChannelNetProc];
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 ~ {
PROC [channelData, netData: REF, eachPin: EachChannelPinProc];
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.