GCDetailRouteImpl.mesa
Copyright © 1986 by Xerox Corporation. All rights reserved.
Bryan Preas, February 19, 1987 9:06:53 pm PST
DIRECTORY
CD, CDBasics, CDCells, CDProperties, CDRects, CDSymbolicObjects, Convert, Core, CoreGeometry, CoreOps, GC, GCPrivate, HashTable, IP, IPCTG, IPTop, PWPins, PWRoute, Rope, Route, RTBasic, RTStructure, Sinix, SinixOps;
GCDetailRouteImpl: CEDAR PROGRAM
IMPORTS CD, CDBasics, CDCells, CDProperties, CDRects, CDSymbolicObjects, Convert, CoreGeometry, CoreOps, GC, GCPrivate, HashTable, IPCTG, RTBasic, PWPins, PWRoute, Rope, RTStructure, Sinix, SinixOps
EXPORTS GCPrivate = {
KeyFromProperty: PWRoute.MakeTabKeyProc ~ {
PROC[pinInst: CD.Instance, context: REF ANYNIL] 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: BOOLEANFALSE];
construct a channel
technologyKey: ATOMNARROW[context.rules.technology, CD.Technology].key;
trunkLayer: Rope.ROPEIF channel.direction = horizontal THEN context.rules.horizLayer ELSE context.rules.vertLayer;
branchLayer: Rope.ROPEIF 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: BOOLEANFALSE];
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: BOOLEANFALSE];
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: BOOLEANFALSE];
EachPhysicalPin: RTStructure.EachPhysicalPinAction ~ {
PROC [oPin: ObjectPin, pPin: PhysicalPin] RETURNS [quit: BOOLEANFALSE];
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.ROPEIF 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: BOOLEANIPCTG.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: BOOLFALSE];
EachExit: PWPins.InstanceEnumerator ~ {
[inst: CD.Instance] RETURNS [quit: BOOLFALSE]
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: INTIF 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: BOOLEANFALSE];
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: INTIF 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: BOOLEANFALSE] ~ {
determine if the net corresponds to a public wire
EachInstancePin: RTStructure.EachInstancePinAction ~ {
PROC [key: Key, instance: Instance, iPin: InstancePin] RETURNS [quit: BOOLEANFALSE];
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: BOOLFALSE];
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};
}.