GCDetailRouteImpl:
CEDAR
PROGRAM
IMPORTS CD, CDBasics, CDCells, CDProperties, CDRects, CDSymbolicObjects, Convert, CoreGeometry, CoreOps, GC, GCPrivate, HashTable, IPCTG, RTBasic, PWPins, PWRoute, Rope, RTStructure, Sinix, SinixOps
KeyFromProperty: PWRoute.MakeTabKeyProc ~ {
PROC[pinInst: CD.Instance, context: REF ANY ← NIL] RETURNS [tabIndex: ROPE];
ref: REF ← CDProperties.GetInstanceProp[pinInst, GCPrivate.nameProp];
tabIndex ← IF ref = NIL THEN CDSymbolicObjects.GetName[pinInst]
ELSE NARROW[ref];
};
DoDetailRoute:
PUBLIC
PROC [context:
GC.Context]
RETURNS [result:
GC.Result] = {
Determine actual wiring paths.
MakeChannel: GCPrivate.EachChannelAction ~ {
PROC[context: GC.Context, channel: Channel] RETURNS [quit: BOOLEAN ← FALSE];
construct a channel
technologyKey: ATOM ← NARROW[context.rules.technology, CD.Technology].key;
trunkLayer: Rope.ROPE ← IF channel.direction = horizontal THEN context.rules.horizLayer ELSE context.rules.vertLayer;
branchLayer: Rope.ROPE ← IF channel.direction = horizontal THEN context.rules.vertLayer ELSE context.rules.horizLayer;
routerParams: PWRoute.RouterParams ← NEW[PWRoute.RouterParamsRec ← [trunkLayer: trunkLayer, branchLayer: branchLayer, technologyKey: technologyKey, makeTabKeyProc: KeyFromProperty, signalBreakAtExit: FALSE, signalSinglePinNets: FALSE, viaTable: table]];
GCPrivate.AssignCoordinates[context];
SELECT
TRUE
FROM
channel.ch = bottomChannel => {
channel.topOrRightShell ← MakeSide[context, channel, top, TRUE];
channel.bottomOrLeftShell ← MakeSide[context, channel, bottom, FALSE]};
channel.ch = rightChannel => {
channel.bottomOrLeftShell ← MakeSide[context, channel, left, TRUE];
channel.topOrRightShell ← MakeSide[context, channel, right, FALSE]};
channel.ch = topChannel => {
channel.bottomOrLeftShell ← MakeSide[context, channel, bottom, TRUE];
channel.topOrRightShell ← MakeSide[context, channel, top, FALSE]};
channel.ch = leftChannel => {
channel.topOrRightShell ← MakeSide[context, channel, right, TRUE];
channel.bottomOrLeftShell ← MakeSide[context, channel, left, FALSE]};
ENDCASE => {
channel.bottomOrLeftShell ← MakeSide[context, channel, ChanSide[channel, bottom], TRUE];
channel.topOrRightShell ← MakeSide[context, channel, ChanSide[channel, top], TRUE]};
channel.bottomOrLeftExitShell ← MakeEnd[context, channel, ChanSide[channel, left]];
channel.topOrRightExitShell ← MakeEnd[context, channel, ChanSide[channel, right]];
channel.result ← PWRoute.DoRoute[channel.bottomOrLeftShell, channel.topOrRightShell, channel.bottomOrLeftExitShell, channel.topOrRightExitShell, routerParams, channel.direction # horizontal, channel];
channel.cdObject ← PWRoute.GetRouting[channel.result, NIL];
channel.width ←
IF channel.direction = horizontal
THEN CDBasics.SizeOfRect[channel.result.routingRect].y
ELSE CDBasics.SizeOfRect[channel.result.routingRect].x;
channel.chanShell ← BuildChannelShell[context, channel];
IPCTG.SetWidth[channel.ch, channel.width]};
IncludeChannel: GCPrivate.EachChannelAction ~ {
PROC[context: GC.Context, channel: Channel] RETURNS [quit: BOOLEAN ← FALSE];
Include a previously routed channel into the object being constructed
first the channel
IF channel.cdObject #
NIL
THEN {
chanInst: CD.Instance;
chanInst ← GCPrivate.IncludeOb[cell: object, ob: channel.cdObject, position: channel.position];
RTBasic.SetCDCellName[channel.cdObject, Rope.Cat[context.name, "Channel", channel.name]];
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 => {
topPos: CD.Position ← [channel.position.x, channel.position.y + channel.width];
[] ← GCPrivate.IncludeOb[cell: object, ob: channel.topOrRightShell, position: topPos]};
channel.ch = rightChannel => {
bottomPos: CD.Position ← [channel.position.x - CD.InterestSize[channel.bottomOrLeftShell].x, channel.position.y];
[] ← GCPrivate.IncludeOb[cell: object, ob: channel.bottomOrLeftShell, position: bottomPos]};
channel.ch = topChannel => {
bottomPos: CD.Position ← [channel.position.x, channel.position.y - CD.InterestSize[channel.bottomOrLeftShell].y];
[] ← GCPrivate.IncludeOb[cell: object, ob: channel.bottomOrLeftShell, position: bottomPos]};
channel.ch = leftChannel => {
topPos: CD.Position ← [channel.position.x + channel.width, channel.position.y];
[] ← GCPrivate.IncludeOb[cell: object, ob: channel.topOrRightShell, position: topPos]};
ENDCASE => {
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];
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.topOrRightShell, position: topPos];
[] ← GCPrivate.IncludeOb[cell: object, ob: channel.bottomOrLeftShell, position: bottomPos]}};
IncludeInstance: RTStructure.EachInstanceAction ~ {
PROC [key: Key, instance: Instance] RETURNS [quit: BOOLEAN ← FALSE];
include an instance in the object being constructed
IF instance.object.cdObject #
NIL
THEN {
cdInst: CD.Instance ← GCPrivate.IncludeOb[cell: object, ob: instance.object.cdObject, position: instance.position, orientation: instance.orientation];
CDProperties.PutInstanceProp[cdInst, $InstanceName, instance.name]}};
topology: IPTop.Ref ← NARROW[context.topology];
bottomChannel, rightChannel, topChannel, leftChannel: IPCTG.Channel;
object: CD.Object ← CDCells.CreateEmptyCell[];
table: HashTable.Table ← IF context.parms.viaTable # NIL THEN context.parms.viaTable ELSE HashTable.Create[equal: EqualProc, hash: HashProc];
[bottomChannel, rightChannel, topChannel, leftChannel] ← IPCTG.GetBoundingChannels[topology.ctg];
[] ← GCPrivate.EnumerateChannelsInTopologicalOrder[context, MakeChannel];
GCPrivate.AssignCoordinates[context];
[] ← GCPrivate.EnumerateChannelsInTopologicalOrder[context, IncludeChannel];
[] ← RTStructure.EnumerateInstances[context.structure, IncludeInstance];
RTBasic.RepositionCell[object];
RTBasic.SetCDCellName[object, context.name];
result ← NEW[GC.ResultRec ← [context: context, object: object]]};
MakeSide:
PROC [context:
GC.Context, channel: GCPrivate.Channel, side: RTBasic.Side, internal:
BOOLEAN]
RETURNS [shell:
CD.Object ← CDCells.CreateEmptyCell[]] ~ {
construct a shell for the side of a channel
DoExternalPins:
IPCTG.EachComponentAction ~ {
IF co #
NIL
THEN {
EachInstancePin: RTStructure.EachInstancePinAction ~ {
PROC [key: Key, instance: Instance, iPin: InstancePin] RETURNS [quit: BOOLEAN ← FALSE];
EachPhysicalPin: RTStructure.EachPhysicalPinAction ~ {
PROC [oPin: ObjectPin, pPin: PhysicalPin] RETURNS [quit: BOOLEAN ← FALSE];
IF pPin.side = otherSide
AND internal
OR pPin.side = side
AND ~internal
THEN {
netDesc: GCPrivate.NetDesc ← NARROW[HashTable.Fetch[channel.connections, iPin.net].value];
phyPin: GCPrivate.PhyPinDesc ← NEW[GCPrivate.PhyPinDescRec ← [instance, iPin.oPin, pPin]];
tabIndex: Rope.
ROPE ←
IF GCPrivate.PinOnList[netDesc, phyPin]
THEN
iPin.net.name
ELSE Rope.Cat[iPin.net.name, "@", instance.name, "@", Convert.RopeFromInt[pPin.range.min]];
maxWidth ← MAX[maxWidth, IncludePin[NEW[GCPrivate.PhyPinDescRec ← [instance, iPin.oPin, pPin]], iPin.net.name, tabIndex, side, pinWidth, lower, upper, shell]]}};
IF ExternalNet[context, iPin.net.name]
THEN
[] ← RTStructure.EnumeratePhysicalPins[iPin.oPin, EachPhysicalPin]};
instance: RTStructure.Instance ← NARROW[co.any];
[] ← RTStructure.EnumerateInstancePins[instance, EachInstancePin]}};
EachNet: HashTable.EachPairAction ~ {
netDesc: GCPrivate.NetDesc ← NARROW[value];
FOR list:
LIST
OF GCPrivate.PhyPinDesc ← netDesc.pinList, list.rest
WHILE list #
NIL
DO
net: RTStructure.Net ← NARROW[key];
exteriorPublic: BOOLEAN ← IPCTG.IsBoundingChannel[topology.ctg, channel.ch] AND ExternalNet[context, net.name]; -- public pins (on next higher cell) are already included
IF list.first.pPin.side = otherSide
AND ~exteriorPublic
THEN
maxWidth ← MAX[maxWidth, IncludePin[list.first, net.name, net.name, side, pinWidth, lower, upper, shell]];
ENDLOOP;
};
DoChannelIntersection:
IPCTG.EachIntersectionAction ~ {
PROC[i: Intersection] RETURNS[quit: BOOL ← FALSE];
EachExit: PWPins.InstanceEnumerator ~ {
[inst: CD.Instance] RETURNS [quit: BOOL ← FALSE]
netName: Rope.ROPE ← CDSymbolicObjects.GetName[inst];
pinSide: RTBasic.Side ← RTStructure.FromSideToSide[PWPins.GetSide[otherChannel.chanShell, inst].side];
IF (internal
AND pinSide = otherSide)
OR (~internal
AND ExternalNet[context, netName]
AND pinSide = side)
THEN {
range: RTStructure.Range ← RTStructure.CoordsAlongSide[inst, otherChannel.chanShell, otherSide];
layer: CD.Layer ← CDSymbolicObjects.GetLayer[inst];
pinOb: CD.Object ← CDSymbolicObjects.CreateSegment[range.max - range.min, pinWidth];
pinLoc:
CD.Position ←
SELECT side
FROM
top => [otherChannel.position.x + range.min, upper.q],
left => [lower.q - pinWidth, otherChannel.position.y + range.min],
bottom => [otherChannel.position.x + range.min, lower.q - pinWidth],
right => [upper.q, otherChannel.position.y + range.min],
ENDCASE => GC.Error[programmingError, "Call maintainer"];
pinInst: CD.Instance ← GCPrivate.IncludeOb[shell, pinOb, pinLoc, SideToOrientation[side]];
CDSymbolicObjects.SetName[pinInst, netName];
CDSymbolicObjects.SetLayer[pinInst, layer];
}};
otherChannel: GCPrivate.Channel ← NARROW[i.ch.any];
IF otherChannel.chanShell #
NIL
THEN
[] ← PWPins.EnumerateEdgePins[otherChannel.chanShell, EachExit]};
rect: CD.Rect;
pinWidth: INT ← IF channel.direction = horizontal THEN context.rules.horizRules.branchWidth ELSE context.rules.vertRules.branchWidth;
maxWidth: INT ← pinWidth;
otherSide: RTBasic.Side ← RTBasic.OtherSide[side];
name: Rope.ROPE ← Rope.Cat[context.name, "Channel", channel.name, RTBasic.sideName[side]];
bottomOrLeft: BOOLEAN ← side = bottom OR side = left;
topOrRight: BOOLEAN ← ~bottomOrLeft;
polarity: IP.PolarityTypes ← IF (internal AND bottomOrLeft) OR (~internal AND topOrRight) THEN neg ELSE pos;
lower: RTBasic.PQPos ← GCPrivate.LowerChannelPQ[channel];
upper: RTBasic.PQPos ← GCPrivate.UpperChannelPQ[channel];
topology: IPTop.Ref ← NARROW[context.topology];
IF
IPCTG.IsBoundingChannel[topology.ctg, channel.ch]
THEN
[] ← IPCTG.Components[channel.ch, polarity, DoExternalPins];
[] ← HashTable.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 side
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"];
CDCells.SetInterestRect[design: NIL, cell: shell, r: rect]; -- set interestRect of shell
RTBasic.SetCDCellName[shell, name];
RTBasic.RepositionCell[shell];
};
MakeEnd:
PROC [context:
GC.Context, channel: GCPrivate.Channel, side: RTBasic.Side]
RETURNS [shell:
CD.Object ←
NIL] ~ {
construct the end object of a channel
EachNet: HashTable.EachPairAction ~ {
PROC [key: Key, value: Value] RETURNS [quit: BOOLEAN ← FALSE];
netDesc: GCPrivate.NetDesc ← NARROW[value];
net: RTStructure.Net ← NARROW[key];
publicNet: BOOLEAN ← RTStructure.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 {
width:
INT ←
IF context.structure.netWidth =
NIL
THEN pinWidth
ELSE MAX[pinWidth, context.structure.netWidth[net, context.structure, channel.direction, NIL]];
pinOb: CD.Object ← CDSymbolicObjects.CreateSegment[width, pinWidth];
pinLoc:
CD.Position ←
SELECT side
FROM
top => [last, 0],
left => [pinWidth, last],
bottom => [last, pinWidth],
right => [0, last],
ENDCASE => GC.Error[programmingError, "Call maintainer"];
pinInst: CD.Instance ← GCPrivate.IncludeOb[shell, pinOb, pinLoc, SideToOrientation[side]];
CDSymbolicObjects.SetLayer[pinInst, layer];
CDSymbolicObjects.SetName[pinInst, net.name];
last ← last + width + pinWidth};
};
ordinaryIntersection: BOOLEAN ← (channel.lowerIntType = normal AND (side = left OR side = bottom)) OR (channel.upperIntType = normal AND (side = right OR side = top));
otherSide: RTBasic.Side ← RTBasic.OtherSide[side];
name: Rope.ROPE ← Rope.Cat[context.name, "/Channel:", channel.name, RTBasic.sideName[side]];
layer: CD.Layer;
pinWidth, last: INT;
rect: CD.Rect;
shell ← CDCells.CreateEmptyCell[];
IF channel.direction = horizontal
THEN {
layer ← context.rules.horizRules.trunkLayer;
last ← pinWidth ← context.rules.horizRules.trunkWidth}
ELSE {
layer ← context.rules.vertRules.trunkLayer;
last ← pinWidth ← context.rules.vertRules.trunkWidth};
[] ← HashTable.Pairs[channel.connections, EachNet];
rect ←
SELECT side
FROM
bottom, top => [0, 0, last, 2*pinWidth],
left, right => [0, 0, 2*pinWidth, last],
ENDCASE => GC.Error[programmingError, "Call maintainer"];
CDCells.SetInterestRect[design: NIL, cell: shell, r: rect]; -- set interestRect of cell
RTBasic.SetCDCellName[shell, name];
RTBasic.RepositionCell[shell]};
SideToOrientation:
PROC [side: RTBasic.Side]
RETURNS [orientation:
CD.Orientation] ~ {
translate a side to an orientation
orientation ←
SELECT side
FROM
top => CDSymbolicObjects.OrientFromDirection[south],
left => CDSymbolicObjects.OrientFromDirection[east],
bottom => CDSymbolicObjects.OrientFromDirection[north],
right => CDSymbolicObjects.OrientFromDirection[west],
ENDCASE => GC.Error[programmingError, "Call maintainer"]};
ChanSide:
PROC [channel: GCPrivate.Channel, side: RTBasic.Side]
RETURNS [sideToUse: RTBasic.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 [context:
GC.Context, netName: Rope.
ROPE]
RETURNS [isExternal:
BOOLEAN ←
FALSE] ~ {
determine if the net corresponds to a public wire
EachInstancePin: RTStructure.EachInstancePinAction ~ {
PROC [key: Key, instance: Instance, iPin: InstancePin] RETURNS [quit: BOOLEAN ← FALSE];
quit ← Rope.Equal[netName, iPin.net.name]};
IF context.structure.outerInstance #
NIL
THEN
isExternal ← RTStructure.EnumerateInstancePins[context.structure.outerInstance, EachInstancePin]};
IncludePin:
PROC [phyPin: GCPrivate.PhyPinDesc, name, tabIndex: Rope.
ROPE, side: RTBasic.Side, pinWidth:
INT, lower, upper: RTBasic.PQPos, shell:
CD.Object]
RETURNS[width:
INT]~ {
include a pin in a shell; also extend a wire if necessary
instance: RTStructure.Instance ← phyPin.instance;
pPin: RTStructure.PhysicalPin ← phyPin.pPin;
range: RTStructure.Range ← RTStructure.TranslateRange[instance, pPin];
rangeSize: INT ← range.max - range.min;
pinOb: CD.Object ← CDSymbolicObjects.CreateSegment[rangeSize, pinWidth];
wireLoc, wireSize, pinLoc: CD.Position;
pinInst: CD.Instance;
SELECT side
FROM
top => {
width ← instance.position.y - upper.q + pPin.depth;
wireSize ← [rangeSize, width];
wireLoc ← [range.min, upper.q];
pinLoc ← [range.min, upper.q];
};
left => {
sidePos: INT ← instance.position.x + CD.InterestSize[instance.object.cdObject].x;
width ← lower.q - sidePos + pPin.depth;
wireSize ← [width, rangeSize];
wireLoc ← [sidePos - pPin.depth, range.min];
pinLoc ← [lower.q - pinWidth, range.min];
};
bottom => {
sidePos: INT ← instance.position.y + CD.InterestSize[instance.object.cdObject].y;
width ← lower.q - sidePos + pPin.depth;
wireSize ← [rangeSize, width];
wireLoc ← [range.min, sidePos - pPin.depth];
pinLoc ← [range.min, lower.q - pinWidth];
};
right => {
width ← instance.position.x - upper.q + pPin.depth;
wireSize ← [width, rangeSize];
wireLoc ← [upper.q, range.min];
pinLoc ← [upper.q, range.min];
};
ENDCASE;
IF width # 0
THEN {
wire: CD.Object ← CDRects.CreateRect[wireSize, pPin.layer];
[] ← GCPrivate.IncludeOb[cell: shell, ob: wire, position: wireLoc]};
pinInst ← GCPrivate.IncludeOb[shell, pinOb, pinLoc, SideToOrientation[side]];
CDSymbolicObjects.SetName[pinInst, name];
CDSymbolicObjects.SetLayer[pinInst, pPin.layer];
CDProperties.PutInstanceProp[pinInst, GCPrivate.nameProp, tabIndex]};
BuildChannelShell:
PROC [context:
GC.Context, channel: GCPrivate.Channel]
RETURNS [shell:
CD.Object ← CDCells.CreateEmptyCell[]] ~ {
build a PWPins shell for the channel
ChanPublics: CoreGeometry.EachWirePinProc ~ {
PROC [wire: Wire, min, max: INT, side: Side, layer: CD.Layer] RETURNS [quit: BOOL ← FALSE];
add decoration for public; wire is an unbound wire
name: Rope.ROPE ← CoreOps.GetShortWireName[wire];
SELECT side
FROM
bottom => AddPinToShell[object: shell, name: name, denotes: [rect.x1+min, rect.y1, rect.x1+max, rect.y1+depth], layer: layer];
right => AddPinToShell[object: shell, name: name, denotes: [rect.x2-depth, rect.y1+min, rect.x2, rect.y1+max], layer: layer];
top => AddPinToShell[object: shell, name: name, denotes: [rect.x1+min, rect.y2-depth, rect.x1+max, rect.y2], layer: layer];
left => AddPinToShell[object: shell, name: name, denotes: [rect.x1, rect.y1+min, rect.x1+depth, rect.y1+max], layer: layer];
ENDCASE};
mode: Sinix.Mode = SinixOps.GetExtractMode[context.rules.technology];
cellType: Core.CellType ← NARROW [Sinix.Extract[channel.cdObject, mode].result];
depth: Route.Number ← context.rules.horizRules.trunkWidth;
rect: CD.Rect ← CD.InterestRect[channel.cdObject];
[] ← CoreGeometry.EnumerateNonOverlappingSides[mode.decoration, cellType, ChanPublics];
CDCells.SetInterestRect[design: NIL, cell: shell, r: rect];
RTBasic.RepositionCell[shell]};
AddPinToShell:
PROC [object:
CD.Object, name: Rope.
ROPE, denotes:
CD.Rect, layer:
CD.Layer] ~ {
pin: CD.Object ← CDSymbolicObjects.CreatePin[CDBasics.SizeOfRect[denotes]];
pinInstance: CD.Instance ← GCPrivate.IncludeOb[cell: object, ob: pin, position: CDBasics.BaseOfRect[denotes], orientation: original];
CDSymbolicObjects.SetName[pinInstance, name];
CDSymbolicObjects.SetLayer[pinInstance, layer]};
EqualProc:
PROC [k1, k2: HashTable.Key]
RETURNS [eq:
BOOL] = {
p1: Route.Position ← NARROW[k1, REF Route.Position]^;
p2: Route.Position ← NARROW[k2, REF Route.Position]^;
eq ← p1.x = p2.x AND p1.y = p2.y};
HashProc:
PROC [k: HashTable.Key]
RETURNS [hash:
CARDINAL] = {
size: Route.Position ← NARROW[k, REF Route.Position]^;
hash ← size.x + size.y};
}.