CabbageProcsImpl.mesa
Copyright Ó 1986, 1987 by Xerox Corporation. All rights reversed.
Created by Bryan Preas, June 4, 1986 4:02:08 pm PDT
Last Edited by: Louis Monier April 23, 1987 4:18:11 pm PDT
Christian Le Cocq February 15, 1988 11:13:06 am PST
Jean-Marc Frailong November 17, 1987 5:54:52 pm PST
Don Curry November 8, 1987 7:46:13 pm PST
Bertrand Serlet April 29, 1987 5:36:05 pm PDT
Bryan Preas September 10, 1987 5:13:21 pm PDT
DIRECTORY Basics, Cabbage, CabbageObstacles, CabbagePrivate, CD, CDBasics, CDCells, CDOps, CDRects, CDRoutingObjects, CDSimpleRules, Connections, Core, CoreGeometry, CoreOps, Convert, DABasics, List, RefTab, RefTabExtras, Rope, Route, RouteUtil, RTBasic, Sinix, SinixOps, SymTab;
CabbageProcsImpl: CEDAR PROGRAM
IMPORTS Basics, Cabbage, CabbageObstacles, CD, CDBasics, CDCells, CDOps, CDRects, CDRoutingObjects, CDSimpleRules, Connections, CoreGeometry, CoreOps, Convert, List, RefTab, RefTabExtras, Rope, Route, RouteUtil, RTBasic, Sinix, SinixOps, SymTab
EXPORTS CabbagePrivate = {
Local Types
routing description for a net on a channel
NetInChan: TYPE = REF NetInChanRec;
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: Rope.ROPENIL,
trunkSize: INT ← 0,
leftOrBottomExit, rightOrTopExit: BOOLFALSE, -- used for channels only (not SB's)
pinsInSeg: LIST OF Pin ← NIL  -- pins for this net on this channel
];
pin description for pins in a net on a channel
Pin: TYPE = REF PinRec;
PinRec: TYPE = RECORD[
min, max, depth: CD.Number ← 0,
layer: CD.Layer,
side: DABasics.Side
];
how to handle power
PowerMode: TYPE = {makeTwoPinPowerNets, busPower, matchPin, likeOtherNets, none};
Initialization
CreateHandle: PUBLIC PROC [inner, bottomLeft, bottom, bottomRight, right, topRight, top, topLeft, left: CD.Object, connections: Connections.Table, parms: Cabbage.PadRingParams, name: Rope.ROPE, routeType: CabbagePrivate.RouteType] RETURNS [handle: CabbagePrivate.Handle]~ {
handle ← NEW[CabbagePrivate.HandleRec ← [name: name, connections: connections, parms: parms]];
handle.routeType ← routeType;
handle.rules ← CreateRouterParms[parms];
handle.powerDistribution ← NEW[CabbagePrivate.PowerDistributionRec];
handle.globalRouting ← NEW[CabbagePrivate.GlobalRoutingRec];
IF routeType = normal THEN
handle.detailedRouting ← NEW[CabbagePrivate.DetailedRoutingRec]
ELSE
handle.detailedRoutingPL ← NEW[CabbagePrivate.DetailedRoutingPLRec];
GetSizes[handle, inner, bottomLeft, bottom, bottomRight, right, topRight, top, topLeft, left];
IF handle.connections # NIL THEN InitWires[handle];
AssignPositions[handle]};
Define the routing design rules. technologyKey values are predefinded for now. horizLayer, vertLayer should be "poly", "metal" or "metal2".
CreateRouterParms: PROC [parms: Cabbage.PadRingParams] RETURNS [designRules: CabbagePrivate.DesignRules] = {
hLayer: CD.Layer ← CDSimpleRules.GetLayer[parms.technologyKey, parms.horizLayer];
vLayer: CD.Layer ← CDSimpleRules.GetLayer[parms.technologyKey, parms.vertLayer];
designRules ← NEW[CabbagePrivate.DesignRulesRec];
designRules.horizInsideParms.parms ← Route.DefaultDesignRulesParameters[technologyHint: parms.technologyKey, horizLayer: hLayer, vertLayer: vLayer, trunkDirection: horizontal];
designRules.vertInsideParms.parms ← Route.DefaultDesignRulesParameters[technologyHint: parms.technologyKey, horizLayer: hLayer, vertLayer: vLayer, trunkDirection: vertical];
designRules.horizOutsideParms.parms ← Route.DefaultDesignRulesParameters[technologyHint: parms.technologyKey, horizLayer: vLayer, vertLayer: hLayer, trunkDirection: horizontal];
designRules.vertOutsideParms.parms ← Route.DefaultDesignRulesParameters[technologyHint: parms.technologyKey, horizLayer: vLayer, vertLayer: hLayer, trunkDirection: vertical];
designRules.horizInsideParms.rules ← Route.DefaultDesignRules[designRules.horizInsideParms.parms];
designRules.vertInsideParms.rules ← Route.DefaultDesignRules[designRules.vertInsideParms.parms];
designRules.horizOutsideParms.rules ← Route.DefaultDesignRules[designRules.horizOutsideParms.parms];
designRules.vertOutsideParms.rules ← Route.DefaultDesignRules[designRules.vertOutsideParms.parms];
put in wider spacings at sides of channels
designRules.horizOutsideParms.rules.trunkToEdge ← designRules.horizOutsideParms.rules.trunkToTrunk;
designRules.vertOutsideParms.rules.trunkToEdge ← designRules.vertOutsideParms.rules.trunkToTrunk};
GetSizes: PROC [handle: CabbagePrivate.Handle, inner, bottomLeft, bottom, bottomRight, right, topRight, top, topLeft, left: CD.Object] ~ {
l: INT = CDSimpleRules.GetTechnology[handle.parms.technologyKey].lambda;
handle.inner ← GetObjectDescription[inner, l, l];
handle.bottom ← GetObjectDescription[bottom, l, l];
handle.right ← GetObjectDescription[right, l, l];
handle.top ← GetObjectDescription[top, l, l];
handle.left ← GetObjectDescription[left, l, l];
handle.bottomLeft ← GetObjectDescription[bottomLeft, handle.left.size.x, handle.bottom.size.y];
handle.bottomRight ← GetObjectDescription[bottomRight, handle.right.size.x, handle.bottom.size.y];
handle.topRight ← GetObjectDescription[topRight, handle.right.size.x, handle.top.size.y];
handle.topLeft ← GetObjectDescription[topLeft, handle.left.size.x, handle.top.size.y]};
GetObjectDescription: PROC [object: CD.Object, minX, minY: INT] RETURNS [desc: CabbagePrivate.ObjectDescription] ~ {
desc.object ← object;
IF object = NIL
THEN desc.size ← [minX, minY]
ELSE {
desc.size ← RTBasic.IRSize[object];
desc.size.x ← MAX[minX, desc.size.x];
desc.size.y ← MAX[minY, desc.size.y]}};
AssignPositions: PROC [handle: CabbagePrivate.Handle] ~ {
hBottom, hTop, vLeft, vRight: INT;
[hBottom, hTop, vLeft, vRight] ← GetSize[handle];
handle.bottom.origin ← [handle.bottomLeft.size.x + (handle.size.x - hBottom)/2, 0];
handle.right.origin ← [handle.size.x - handle.right.size.x, handle.bottomRight.size.y + (handle.size.y - vRight)/2];
handle.top.origin ← [handle.topLeft.size.x + (handle.size.x - hTop)/2, handle.size.y - handle.top.size.y];
handle.left.origin ← [0, handle.bottomLeft.size.y + (handle.size.y - vLeft)/2];
DoCorners[handle];
DoRoutingAreas[handle]};
InitWires: PROC [handle: CabbagePrivate.Handle] ~ {
LookForGndAndVdd: Connections.EachNetAction ~ {
PROC [key: Key, net: Net] RETURNS [quit: BOOLEANFALSE]
IF Rope.Equal[net.name, "Vdd"] THEN handle.vddNet ← net
ELSE IF Rope.Equal[net.name, "Gnd"] THEN handle.gndNet ← net};
EachNet: Connections.EachNetAction ~ {
PROC [key: Key, net: Net] RETURNS [quit: BOOLEANFALSE]
EachSegment: Connections.EachSegmentAction ~ {
PROC [net: Net, segment: Segment] RETURNS [quit: BOOLEANFALSE]
newNet.width ← MAX[newNet.width, segment.range.max - segment.range.min]};
newNet: Connections.Net ← NEW[Connections.NetRec ← [name: net.name, width: net.width]];
IF net.width <= 0 THEN
[] ← Connections.EnumerateSegments[net, EachSegment];
[] ← Connections.Store[handle.widthTable, net.name, newNet]};
handle.widthTable ← Connections.CreateForRopes[];
[] ← Connections.EnumerateNets[handle.connections, LookForGndAndVdd];
[] ← Connections.EnumerateNets[handle.connections, EachNet]};
CheckInnerPos: PUBLIC PROC [handle: CabbagePrivate.Handle, innerPos: CD.Position] ~ {
actualInnerPos: CD.Position ← innerPos;
lowerY: INT ← handle.bottom.origin.y + handle.bottom.size.y;
upperY: INT ← handle.top.origin.y - handle.inner.size.y;
lowerX: INT ← handle.left.origin.x + handle.left.size.x;
upperX: INT ← handle.right.origin.x - handle.inner.size.x;
IF ~((lowerX <= innerPos.x AND innerPos.x <= upperX) AND (lowerY <= innerPos.y AND innerPos.y <= upperY)) THEN {
Cabbage.Signal[callingError, "The position specified for the inner object (innerPos) is invalid."];
actualInnerPos ← [(lowerX + upperX)/2, (lowerY + lowerY)/2]};
handle.inner.origin ← actualInnerPos};
Power Distribution
DistributePower: PUBLIC PROC [handle: CabbagePrivate.Handle] ~ {
make the power distribution channels
l: INT = CDSimpleRules.GetTechnology[handle.parms.technologyKey].lambda;
horizInsideRules: Route.DesignRules ← handle.rules.horizInsideParms.rules;
vertInsideRules: Route.DesignRules ← handle.rules.vertInsideParms.rules;
horizOutsideRules: Route.DesignRules ← handle.rules.horizOutsideParms.rules;
vertOutsideRules: Route.DesignRules ← handle.rules.vertOutsideParms.rules;
horizSpace: INT ← 2*horizOutsideRules.trunkToTrunk + horizOutsideRules.trunkSpacing + horizInsideRules.contactSize + horizInsideRules.trunkSpacing + 2*horizInsideRules.trunkToTrunk;
vertSpace: INT ← 2*vertOutsideRules.trunkToTrunk + vertOutsideRules.trunkSpacing + vertInsideRules.contactSize + vertInsideRules.trunkSpacing + 2*vertInsideRules.trunkToTrunk;
trunkLRWidth: INT ← (handle.parms.powerLRCellWidth * l - vertSpace)/2;
trunkBTWidth: INT ← (handle.parms.powerBTCellWidth * l - horizSpace)/2;
RouteOutsideChannels[handle];
AssignPositions[handle];
RouteOutsideSwitchBoxes[handle];
ConstructPowerChannels[handle, trunkLRWidth, trunkBTWidth];
ConstructPowerCorners[handle, trunkLRWidth, trunkBTWidth];
AssignPositions[handle];};
RouteOutsideChannels: PROC [handle: CabbagePrivate.Handle] ~ {
route the outside channels; move signal pins on the outer from the shadow of the power pins on the inner.
horizOutsideParms and vertOutsideParms specify the routing for the specified direction; horizRange and vertRange describe the projection of the inner onto the pad ring
l: INT = CDSimpleRules.GetTechnology[handle.parms.technologyKey].lambda;
outerBTChanWidth: INT ← handle.parms.outerBTChanWidth * l;
outerLRChanWidth: INT ← handle.parms.outerLRChanWidth * l;
powerLRCellWidth: INT ← handle.parms.powerLRCellWidth * l;
powerBTCellWidth: INT ← handle.parms.powerBTCellWidth * l;
horizOutsideParms: CabbagePrivate.ParmSet ← handle.rules.horizOutsideParms;
vertOutsideParms: CabbagePrivate.ParmSet ← handle.rules.vertOutsideParms;
horizOuterRange: Connections.Range ← [handle.left.origin.x + handle.left.size.x + outerLRChanWidth, handle.right.origin.x - outerLRChanWidth];
horizMidRange: Connections.Range ← [horizOuterRange.min + powerLRCellWidth, horizOuterRange.max - powerLRCellWidth];
vertInnerRange: Connections.Range ← [handle.inner.origin.y, handle.inner.origin.y + handle.inner.size.y];
vertOuterRange: Connections.Range ← [handle.bottom.origin.y + handle.bottom.size.y + outerBTChanWidth, handle.top.origin.y - outerBTChanWidth];
vertMidRange: Connections.Range ← [vertOuterRange.min + powerBTCellWidth, vertOuterRange.max - powerBTCellWidth];
route the outside channels
handle.powerDistribution.channels[bottom] ← RouteOutsideChannel[handle, handle.bottom, bottom, horizMidRange, horizMidRange, horizOuterRange, outerBTChanWidth, horizOutsideParms];
handle.powerDistribution.channels[right] ← RouteOutsideChannel[handle, handle.right, right, vertInnerRange, vertMidRange, vertOuterRange, outerLRChanWidth, vertOutsideParms];
handle.powerDistribution.channels[top] ← RouteOutsideChannel[handle, handle.top, top, horizMidRange, horizMidRange, horizOuterRange, outerBTChanWidth, horizOutsideParms];
handle.powerDistribution.channels[left] ← RouteOutsideChannel[handle, handle.left, left, vertInnerRange, vertMidRange, vertOuterRange, outerLRChanWidth, vertOutsideParms]};
RouteOutsideChannel: PROC [handle: CabbagePrivate.Handle,
outerObject: CabbagePrivate.ObjectDescription,  -- outer Cabbage object
side: DABasics.Side, -- the side of chip for which this channel is being constructed
innerRange, midRange, outerRange: Connections.Range, -- innerRange is the span of the inner cell; midRange is range of power cell, outerRange the span of the appropriate power routing cell; innerRange may equal outerRange
chWidth: INT,    -- the only permitted width for channel
parms: CabbagePrivate.ParmSet]
RETURNS [channel: CabbagePrivate.Channel] ~ {
route one of the outside channels
InitNet: Connections.EachNetAction = {net.netDat ← NIL};
intermediateResult: Route.IntermediateResult;
retrieveRect: REF DABasics.Rect;
rect: DABasics.Rect;
otherSide: DABasics.Side ← RTBasic.OtherSide[side];
blSide: DABasics.Side ← IF side=bottom OR side=top THEN left ELSE bottom;
actualSize: INT;  -- the resulting channel width
clear the routing specification for this channel
[] ← Connections.EnumerateNets[handle.connections, InitNet];
construct the bonding objects to pass to the channel router
AddMappedPinsFromObject[handle, outerObject, otherSide, innerRange, midRange, outerRange, parms, "--L", "--U"];
AddPinsFromObject3Part[handle, outerObject, otherSide, midRange, outerRange, parms, TRUE, makeTwoPinPowerNets, busPower, "--L", "--", "--U"];
AddPinsFromOutsideEnd[handle, outerObject, otherSide, blSide, outerRange, parms, "--L"];
AddPinsFromOutsideEnd[handle, outerObject, otherSide, RTBasic.OtherSide[blSide], outerRange, parms, "--U"];
intermediateResult ← Route.ChannelRoute[enumerateNets: EnumerateChannelNets, min: outerRange.min, max: outerRange.max, rulesParameters: parms.parms, rules: parms.rules, name: NIL, enumerateObstructions: NIL, channelData: handle, optimization: handle.parms.opt, signalSinglePinNets: handle.parms.signalSinglePinNets];
rect ← intermediateResult.resultData.routingRect;
SELECT side FROM
bottom => {
dist: INTMIN[rect.y1, rect.y2 - chWidth];
retrieveRect ← NEW[DABasics.Rect ← [rect.x1, dist, rect.x2, rect.y2]]};
right => {
dist: INTMAX[rect.x2, rect.x1 + chWidth];
retrieveRect ← NEW[DABasics.Rect ← [rect.x1, rect.y1, dist, rect.y2]]};
top => {
dist: INTMAX[rect.y2, rect.y1 + chWidth];
retrieveRect ← NEW[DABasics.Rect ← [rect.x1, rect.y1, rect.x2, dist]]};
left => {
dist: INTMIN[rect.x1, rect.x2 - chWidth];
retrieveRect ← NEW[DABasics.Rect ← [dist, rect.y1, rect.x2, rect.y2]]};
ENDCASE;
channel.object ← Route.ChannelRetrieve[intermediateResult: intermediateResult, enumerateNets: EnumerateChannelNets, brokenNets: NIL, channelData: handle, retrieveRect: retrieveRect].object;
compare channel.size to required channel width
channel.size ← RTBasic.IRSize[channel.object];
actualSize ← SELECT side FROM
bottom, top => channel.size.y,
left, right => channel.size.x,
ENDCASE => 0;
IF actualSize > chWidth THEN Cabbage.Signal[noResource, "Outer routing channel is to small. Increase outerWidth (may need to decrease powerWidth)."];
channel.cellType ← ExtractChannel[channel, parms]};
ConstructPowerChannels: PROC [handle: CabbagePrivate.Handle, trunkLRWidth, trunkBTWidth: INT] ~ {
construct the power routing channels; route signal pins on the outer straight accross with vias as necessary.
horizInsideParms and vertInsideParms specify the routing for the specified direction; horizRange and vertRange describe the projection of the inner onto the pad ring
l: INT = CDSimpleRules.GetTechnology[handle.parms.technologyKey].lambda;
powerLRCellWidth: INT ← handle.parms.powerLRCellWidth * l;
powerBTCellWidth: INT ← handle.parms.powerBTCellWidth * l;
powerLRWidth: INT ← handle.parms.outerLRChanWidth * l + powerLRCellWidth;
powerBTWidth: INT ← handle.parms.outerBTChanWidth * l + powerBTCellWidth;
horizInsideParms: CabbagePrivate.ParmSet ← handle.rules.horizInsideParms;
horizOutsideParms: CabbagePrivate.ParmSet ← handle.rules.horizOutsideParms;
vertInsideParms: CabbagePrivate.ParmSet ← handle.rules.vertInsideParms;
vertOutsideParms: CabbagePrivate.ParmSet ← handle.rules.vertOutsideParms;
horizOuterRange: Connections.Range ← [handle.left.origin.x + handle.left.size.x + powerLRWidth, handle.right.origin.x - powerLRWidth];
vertOuterRange: Connections.Range ← [handle.bottom.origin.y + handle.bottom.size.y + powerBTWidth, handle.top.origin.y - powerBTWidth];
construct the power distribution cells
handle.powerDistribution.power[bottom] ← RoutePower[handle, handle.powerDistribution.channels[bottom], bottom, horizOuterRange, powerBTCellWidth, trunkBTWidth, horizInsideParms, horizOutsideParms];
handle.powerDistribution.power[right] ← RoutePower[handle, handle.powerDistribution.channels[right], right, vertOuterRange, powerLRCellWidth, trunkLRWidth, vertInsideParms, vertOutsideParms];
handle.powerDistribution.power[top] ← RoutePower[handle, handle.powerDistribution.channels[top], top, horizOuterRange, powerBTCellWidth, trunkBTWidth, horizInsideParms, horizOutsideParms];
handle.powerDistribution.power[left] ← RoutePower[handle, handle.powerDistribution.channels[left], left, vertOuterRange, powerLRCellWidth, trunkLRWidth, vertInsideParms, vertOutsideParms]};
RoutePower: PROC [handle: CabbagePrivate.Handle,
channel: CabbagePrivate.Channel, -- inner or outer channel as determined by side
chipSide: DABasics.Side,  -- the side of the chip for which this channel is being constructed
range: Connections.Range, -- the span along the appropriate power routing cell
powerWidth: INT,  -- the only permitted width for the power cell
trunkWidth: INT,  -- the width of the power trunk
insideParms, outsideParms: CabbagePrivate.ParmSet]
RETURNS [power: CabbagePrivate.Channel] ~ {
build the power routing cell for the indicated side
connect the Vdd and Gnd pin via a bus connection and transfer the signal pins across with appropriate vias
inside and outside pins are put on the [inside|outside]Parms.rules.branchLayer
ChanPublics: CoreGeometry.EachWirePinProc ~ {
PROC [wire: Wire, min, max: INT, side: Side, layer: CD.Layer] RETURNS [quit: BOOLFALSE];
store the pins on the appropriate side of the adjacent channel
OuterPowerBranch: PROC [branchLength: INT, branchLayer, trunkLayer: CD.Layer] ~ {
pos: CD.Position ← SELECT chipSide FROM
bottom => [adjustedRange.min, 0],
top => [adjustedRange.min, powerWidth - branchLength],
left => [0, adjustedRange.min],
right => [powerWidth - branchLength, adjustedRange.min],
ENDCASE => Cabbage.Error[programmingError, "Not suppose to happen"];
SELECT chipSide FROM
bottom, top => AddPO[objectNets, [CDRects.CreateRect[[max-min, branchLength], branchLayer], pos], name];
left, right => AddPO[objectNets, [CDRects.CreateRect[[branchLength, max-min], branchLayer], pos], name];
ENDCASE => Cabbage.Error[programmingError, "Not suppose to happen"];
IF branchLayer # trunkLayer THEN {
add the via at the right place
-- irSize stuff should be remove in Cabbage25
via: CD.Object ← SELECT chipSide FROM
bottom, top => RouteUtil.StitchVias[[max-min, trunkWidth], trunkLayer, branchLayer, l, NIL],
left, right => RouteUtil.StitchVias[[trunkWidth, max-min], trunkLayer, branchLayer, l, NIL],
ENDCASE => Cabbage.Error[programmingError, "Not suppose to happen"];
irSize: CD.Position ← RTBasic.IRSize[via];
xOffset: INTSELECT chipSide FROM
bottom, top => (max-min - irSize.x)/2,
left, right => (trunkWidth - irSize.x)/2,
ENDCASE => Cabbage.Error[programmingError, "Not suppose to happen"];
yOffset: INTSELECT chipSide FROM
bottom, top => (trunkWidth - irSize.y)/2,
left, right => (max-min - irSize.y)/2,
ENDCASE => Cabbage.Error[programmingError, "Not suppose to happen"];
viaPos: CD.Position ← SELECT chipSide FROM
bottom => [adjustedRange.min + xOffset, branchLength - trunkWidth + yOffset],
top => [adjustedRange.min + xOffset, powerWidth - branchLength + yOffset],
left => [branchLength - trunkWidth + xOffset, adjustedRange.min + yOffset],
right => [powerWidth - branchLength + xOffset, adjustedRange.min + yOffset],
ENDCASE => Cabbage.Error[programmingError, "Not suppose to happen"];
AddPO[objectNets, [via, viaPos], name]}};
SignalBranch: PROC [] ~ {
outsideLength: INT ← outsideParms.rules.trunkSpacing + distToOuter;
insideLength: INT ← insideParms.rules.trunkSpacing + distToInner;
SELECT chipSide FROM
bottom => {
AddPO[objectNets, [CDRects.CreateRect[[max-min, outsideLength], outsideLayer], [adjustedRange.min, 0]], name];
AddPO[objectNets, [CDRects.CreateRect[[max-min, insideLength], insideLayer], [adjustedRange.min, powerWidth - insideLength]], name];
AddPO[objectNets, [RouteUtil.StitchVias[[max-min, insideParms.rules.contactSize], insideLayer, outsideLayer, l, NIL], [adjustedRange.min, outsideLength]], name]};
top => {
AddPO[objectNets, [CDRects.CreateRect[[max-min, outsideLength], outsideLayer], [adjustedRange.min, powerWidth - outsideLength]], name];
AddPO[objectNets, [CDRects.CreateRect[[max-min, insideLength], insideLayer], [adjustedRange.min, 0]], name];
AddPO[objectNets, [RouteUtil.StitchVias[[max-min, insideParms.rules.contactSize], insideLayer, outsideLayer, l, NIL], [adjustedRange.min, insideLength]], name]};
left => {
AddPO[objectNets, [CDRects.CreateRect[[outsideLength, max-min], outsideLayer], [0, adjustedRange.min]], name];
AddPO[objectNets, [CDRects.CreateRect[[insideLength, max-min], insideLayer], [powerWidth - insideLength, adjustedRange.min]], name];
AddPO[objectNets, [RouteUtil.StitchVias[[insideParms.rules.contactSize, max-min], insideLayer, outsideLayer, l, NIL], [outsideLength, adjustedRange.min]], name]};
right => {
AddPO[objectNets, [CDRects.CreateRect[[outsideLength, max-min], outsideLayer], [powerWidth - outsideLength, adjustedRange.min]], name];
AddPO[objectNets, [CDRects.CreateRect[[insideLength, max-min], insideLayer], [0, adjustedRange.min]], name];
AddPO[objectNets, [RouteUtil.StitchVias[[insideParms.rules.contactSize, max-min], insideLayer, outsideLayer, l, NIL], [insideLength, adjustedRange.min]], name]};
ENDCASE};
adjustedRange: Connections.Range ← [channelOrigin + min, channelOrigin + max];
name: Rope.ROPE ← NameFromWire[wire];
distinguish constructed Vdd and Gnd by (Vdd | Gnd)--
other nets may start with Vdd and Gnd
IF side = otherSide THEN {
SELECT TRUE FROM
Rope.Equal[name, "Vdd"] => OuterPowerBranch[distToOuter, outsideLayer, insideLayer];
Rope.Equal[name, "Gnd"] => OuterPowerBranch[powerWidth - 2*insideParms.rules.trunkToTrunk, outsideLayer, outsideLayer];
ENDCASE => SignalBranch[]}};
EachNet: Connections.EachNetAction ~ {
PROC [key: Key, net: Net] RETURNS [quit: BOOLEANFALSE]
store the power pins on the appropriate side of the inner object
EachSegment: Connections.EachSegmentAction ~ {
PROC [net: Net, segment: Segment] RETURNS [quit: BOOLEANFALSE]
InnerPowerBranch: PROC [branchLength: INT, branchLayer, trunkLayer: CD.Layer] ~ {
rectPos: CD.Position ← SELECT chipSide FROM
bottom => [adjustedRange.min, powerWidth - branchLength],
top => [adjustedRange.min, 0],
left => [powerWidth - branchLength, adjustedRange.min],
right => [0, adjustedRange.min],
ENDCASE => Cabbage.Error[programmingError, "Not suppose to happen"];
SELECT chipSide FROM
bottom, top => AddPO[objectNets, [CDRects.CreateRect[[segment.range.max-segment.range.min, branchLength], insideLayer], rectPos], net.name];
left, right => AddPO[objectNets, [CDRects.CreateRect[[branchLength, segment.range.max-segment.range.min], insideLayer], rectPos], net.name];
ENDCASE;
IF branchLayer # trunkLayer THEN {
add the via at the right place
via: CD.Object ← SELECT chipSide FROM
bottom, top => RouteUtil.StitchVias[[segment.range.max-segment.range.min, trunkWidth], trunkLayer, branchLayer, l, NIL],
left, right => RouteUtil.StitchVias[[trunkWidth, segment.range.max-segment.range.min], trunkLayer, branchLayer, l, NIL],
ENDCASE => Cabbage.Error[programmingError, "Not suppose to happen"];
irSize to go away in Cabbage25
irSize: CD.Position ← RTBasic.IRSize[via];
xOffset: INTSELECT chipSide FROM
bottom, top => (segment.range.max-segment.range.min - irSize.x)/2,
left, right => (trunkWidth - irSize.x)/2,
ENDCASE => Cabbage.Error[programmingError, "Not suppose to happen"];
yOffset: INTSELECT chipSide FROM
bottom, top => (trunkWidth - irSize.y)/2,
left, right => (segment.range.max-segment.range.min - irSize.y)/2,
ENDCASE => Cabbage.Error[programmingError, "Not suppose to happen"];
viaPos: CD.Position ← SELECT chipSide FROM
bottom => [adjustedRange.min + xOffset, powerWidth - branchLength + yOffset],
top => [adjustedRange.min + xOffset, branchLength - trunkWidth + yOffset],
left => [powerWidth - branchLength + xOffset, adjustedRange.min + yOffset],
right => [branchLength - trunkWidth + xOffset, adjustedRange.min + yOffset],
ENDCASE => Cabbage.Error[programmingError, "Not suppose to happen"];
AddPO[objectNets, [via, viaPos], net.name]}};
adjustedRange: Connections.Range ← [innerOrigin + segment.range.min, innerOrigin + segment.range.max];
IF segment.object = handle.inner.object AND segment.side = chipSide THEN {
SELECT TRUE FROM
Rope.Equal[net.name, "Vdd"] => InnerPowerBranch[powerWidth - distToOuter, insideLayer, insideLayer];
Rope.Equal[net.name, "Gnd"] => InnerPowerBranch[distToInner, insideLayer, outsideLayer];
ENDCASE}};
[] ← Connections.EnumerateSegments[net, EachSegment]};
PowerTrunk: PROC [position: CD.Position, layer: CD.Layer, name: Rope.ROPE] ~ {
trunkSize: CD.Position ← SELECT chipSide FROM
bottom, top => [range.max-range.min, trunkWidth],
left, right => [trunkWidth, range.max-range.min],
ENDCASE => Cabbage.Error[programmingError, "Not suppose to happen"];
trunk: CD.Object ← CDRects.CreateRect[trunkSize, layer];
AddPO[objectNets, [trunk, position], name]};
objectNets: SymTab.Ref ← SymTab.Create[];
l: INT = CDSimpleRules.GetTechnology[handle.parms.technologyKey].lambda;
insideLayer: CD.Layer ← insideParms.rules.branchLayer;
outsideLayer: CD.Layer ← outsideParms.rules.branchLayer;
distToInner: INT ← trunkWidth + 2*insideParms.rules.trunkToTrunk;
distToOuter: INT ← trunkWidth + 2*outsideParms.rules.trunkToTrunk;
mode: Sinix.Mode = SinixOps.GetExtractMode[insideParms.parms.technology];
otherSide: CoreGeometry.Side ← SELECT chipSide FROM
bottom => top, right => left, top => bottom, left=> right,
ENDCASE => Cabbage.Error[programmingError, "Not suppose to happen"];
innerOrigin: INTSELECT chipSide FROM
bottom, top => handle.inner.origin.x,
right, left => handle.inner.origin.y,
ENDCASE => Cabbage.Error[programmingError, "Not suppose to happen."];
channelOrigin: INTSELECT chipSide FROM
bottom, top => channel.origin.x,
right, left => channel.origin.y,
ENDCASE => Cabbage.Error[programmingError, "Not suppose to happen."];
interestRect: CD.Rect ← SELECT chipSide FROM
bottom, top => [range.min, 0 , range.max, powerWidth],
left, right => [0, range.min , powerWidth, range.max],
ENDCASE => Cabbage.Error[programmingError, "Not suppose to happen"];
construct power trunks
innerTrunkPos: CD.Position ← SELECT chipSide FROM
bottom => [range.min, powerWidth - distToInner],
top => [range.min, 2*insideParms.rules.trunkToTrunk],
left => [powerWidth - distToInner, range.min],
right => [2*insideParms.rules.trunkToTrunk, range.min],
ENDCASE => Cabbage.Error[programmingError, "Not suppose to happen"];
outerTrunkPos: CD.Position ← SELECT chipSide FROM
bottom => [range.min, 2*outsideParms.rules.trunkToTrunk],
top => [range.min, powerWidth - distToOuter],
left => [2*outsideParms.rules.trunkToTrunk, range.min],
right => [powerWidth - distToOuter, range.min],
ENDCASE => Cabbage.Error[programmingError, "Not suppose to happen"];
PowerTrunk[outerTrunkPos, insideLayer, "Vdd"];
PowerTrunk[innerTrunkPos, outsideLayer, "Gnd"];
build the branches
[] ← CoreGeometry.EnumerateNonOverlappingSides[mode.decoration, channel.cellType, ChanPublics];
[] ← Connections.EnumerateNets[handle.connections, EachNet];
power.object ← CDRoutingObjects.CreateRoutingObject
[CDRoutingObjects.CreateNodes[objectNets], interestRect];
RTBasic.RepositionCell[power.object];
power.size ← RTBasic.IRSize[power.object];
power.cellType ← ExtractChannel[power, insideParms]};
RouteOutsideSwitchBoxes: PROC [handle: CabbagePrivate.Handle] ~ {
route the switchboxes in the outside corners. these switchboxes connect the power busses; any signal pins on the padring get transfered to the adjacent channel
vertOutsideParms: CabbagePrivate.ParmSet ← handle.rules.vertOutsideParms;
l: INT = CDSimpleRules.GetTechnology[handle.parms.technologyKey].lambda;
outerLRChanWidth: INT ← handle.parms.outerLRChanWidth * l;
outerBTChanWidth: INT ← handle.parms.outerBTChanWidth * l;
leftHorizRange: Connections.Range ← [handle.left.origin.x + handle.left.size.x, handle.left.origin.x + handle.left.size.x + outerLRChanWidth];
rightHorizRange: Connections.Range ← [handle.right.origin.x - outerLRChanWidth, handle.right.origin.x];
bottomVertRange: Connections.Range ← [handle.bottom.origin.y + handle.bottom.size.y, handle.bottom.origin.y + handle.bottom.size.y + outerBTChanWidth];
topVertRange: Connections.Range ← [handle.top.origin.y- outerBTChanWidth, handle.top.origin.y];
handle.powerDistribution.switchBoxes[bottomLeft] ← RouteOutsideSwitchBox[handle, bottomLeft, leftHorizRange, bottomVertRange, vertOutsideParms, TRUE, FALSE];
handle.powerDistribution.switchBoxes[topLeft] ← RouteOutsideSwitchBox[handle, topLeft, leftHorizRange, topVertRange, vertOutsideParms, FALSE, TRUE];
handle.powerDistribution.switchBoxes[bottomRight] ← RouteOutsideSwitchBox[handle, bottomRight, rightHorizRange, bottomVertRange, vertOutsideParms, TRUE, FALSE];
handle.powerDistribution.switchBoxes[topRight] ← RouteOutsideSwitchBox[handle, topRight, rightHorizRange, topVertRange, vertOutsideParms, FALSE, TRUE]};
RouteOutsideSwitchBox: PROC [handle: CabbagePrivate.Handle, corner: CabbagePrivate.Corners, horizRange, vertRange: Connections.Range, parms: CabbagePrivate.ParmSet, okToDiddleLLPins, okToDiddleURPins: BOOL] RETURNS [switchBox: CabbagePrivate.Channel] ~ {
construct a switchbox for one of the power distribution corners
InitNet: Connections.EachNetAction = {net.netDat ← NIL};
routingRect: DABasics.Rect ← [horizRange.min, vertRange.min, horizRange.max, vertRange.max];
outerTB: RTBasic.TBSide ←
SELECT corner FROM
bottomLeft, bottomRight => bottom,
topLeft, topRight => top,
ENDCASE => Cabbage.Error[programmingError, "Not suppose to happen."];
outerLR: RTBasic.LRSide ←
SELECT corner FROM
bottomLeft, topLeft => left,
bottomRight, topRight => right,
ENDCASE => Cabbage.Error[programmingError, "Not suppose to happen."];
objectTB: CabbagePrivate.ObjectDescription ←
SELECT corner FROM
bottomLeft, bottomRight => handle.bottom,
topLeft, topRight => handle.top,
ENDCASE => Cabbage.Error[programmingError, "Not suppose to happen."];
objectLR: CabbagePrivate.ObjectDescription ←
SELECT corner FROM
bottomLeft, topLeft => handle.left,
bottomRight, topRight => handle.right,
ENDCASE => Cabbage.Error[programmingError, "Not suppose to happen."];
clear the routing specification for this channel
[] ← Connections.EnumerateNets[handle.connections, InitNet];
add pins around the switch box
AddPinsFromFullChannel[handle, handle.powerDistribution.channels[outerTB], outerLR, parms.rules.branchLayer, parms, busPower, "--TB"]; -- end of routing channel on top or bottom
AddPinsFromObject[handle, objectTB, RTBasic.OtherSide[outerTB], horizRange, parms, TRUE, busPower, "--TB"]; -- outer top or bottom object
AddPinsFromObject[handle, objectLR, RTBasic.OtherSide[outerLR], vertRange, parms, TRUE, busPower, "--LR"]; -- outer left or right object
AddPinsFromFullChannel[handle, handle.powerDistribution.channels[outerLR], outerTB, parms.rules.trunkLayer, parms, busPower, "--LR"]; -- end of outer routing channel on left or right
switchBox.object ← Route.SwitchBox[enumerateNets: EnumerateSwitchBoxNets, routingRect: routingRect, rulesParameters: parms.parms, name: handle.name, enumerateObstructions: NIL, switchBoxData: handle, optimization: handle.parms.opt, signalSinglePinNets: handle.parms.signalSinglePinNets, okToDiddleLLPins: okToDiddleLLPins, okToDiddleURPins: okToDiddleURPins].object;
switchBox.size ← RTBasic.IRSize[switchBox.object];
switchBox.cellType ← ExtractChannel[switchBox, parms]};
ConstructPowerCorners: PROC [handle: CabbagePrivate.Handle, trunkLRWidth, trunkBTWidth: INT] ~ {
construct the power routing for the corners;
horizInsideParms and vertInsideParms specify the routing for the specified direction; horizRange and vertRange describe the projection of the inner onto the pad ring
l: INT = CDSimpleRules.GetTechnology[handle.parms.technologyKey].lambda;
horizInsideParms: CabbagePrivate.ParmSet ← handle.rules.horizInsideParms;
horizOutsideParms: CabbagePrivate.ParmSet ← handle.rules.horizOutsideParms;
vertInsideParms: CabbagePrivate.ParmSet ← handle.rules.vertInsideParms;
vertOutsideParms: CabbagePrivate.ParmSet ← handle.rules.vertOutsideParms;
construct the corner power distribution cells
handle.powerDistribution.powerCorners[bottomLeft] ← ConstructPowerCorner[handle, bottomLeft, trunkLRWidth, trunkBTWidth, horizInsideParms, horizOutsideParms, vertInsideParms, vertOutsideParms];
handle.powerDistribution.powerCorners[topLeft] ← ConstructPowerCorner[handle, topLeft, trunkLRWidth, trunkBTWidth, horizInsideParms, horizOutsideParms, vertInsideParms, vertOutsideParms];
handle.powerDistribution.powerCorners[bottomRight] ← ConstructPowerCorner[handle, bottomRight, trunkLRWidth, trunkBTWidth, horizInsideParms, horizOutsideParms, vertInsideParms, vertOutsideParms];
handle.powerDistribution.powerCorners[topRight] ← ConstructPowerCorner[handle, topRight, trunkLRWidth, trunkBTWidth, horizInsideParms, horizOutsideParms, vertInsideParms, vertOutsideParms]};
ConstructPowerCorner: PROC [
handle:    CabbagePrivate.Handle,
corner:    CabbagePrivate.Corners,
trunkLRWidth:  INT,
trunkBTWidth:  INT,
horizInsideParms: CabbagePrivate.ParmSet,
horizOutsideParms: CabbagePrivate.ParmSet,
vertInsideParms:  CabbagePrivate.ParmSet,
vertOutsideParm: CabbagePrivate.ParmSet]
RETURNS [powerCorner: CabbagePrivate.Channel] ~ {
l: INT = CDSimpleRules.GetTechnology[handle.parms.technologyKey].lambda;
horLayer: CD.Layer ← horizInsideParms.rules.branchLayer;
verLayer: CD.Layer ← horizOutsideParms.rules.branchLayer;
trunkSz:   CD.Position ← [trunkLRWidth, trunkBTWidth];
cellSz:   CD.Position ←
[handle.parms.powerLRCellWidth * l,  handle.parms.powerBTCellWidth * l];
outSideDist:  CD.Position ←
[2*horizOutsideParms.rules.trunkToTrunk, 2*vertOutsideParm.rules.trunkToTrunk];
inSideDist:  CD.Position ←
[2*horizInsideParms.rules.trunkToTrunk,  2*vertInsideParms.rules.trunkToTrunk];
vddHor: CD.Object ← CDRects.CreateRect[[cellSz.x - outSideDist.x, trunkSz.y], horLayer];
gndHor: CD.Object ← CDRects.CreateRect[[trunkSz.x + inSideDist.x, trunkSz.y], verLayer];
vddVer: CD.Object ← CDRects.CreateRect[[trunkSz.x, cellSz.y - outSideDist.y], verLayer];
gndVer: CD.Object ← CDRects.CreateRect[[trunkSz.x, trunkSz.y + inSideDist.y], horLayer];
via: CD.Object ← RouteUtil.StitchVias[[trunkSz.x, trunkSz.y], horLayer, verLayer, l, NIL];
outerTrunkPos: CD.Position ← SELECT corner FROM
bottomLeft => [   outSideDist.x,    outSideDist.y],
topLeft  => [   outSideDist.x, cellSz.y - outSideDist.y],
bottomRight => [cellSz.x - outSideDist.x,    outSideDist.y],
topRight  => [cellSz.x - outSideDist.x, cellSz.y- outSideDist.y],
ENDCASE  => ERROR;
innerTrunkPos: CD.Position ← SELECT corner FROM
bottomLeft => [cellSz.x - trunkSz.x - inSideDist.x, cellSz.y - trunkSz.y - inSideDist.y],
topLeft  => [cellSz.x - trunkSz.x - inSideDist.x,    trunkSz.y + inSideDist.y],
bottomRight => [   trunkSz.x + inSideDist.x, cellSz.y - trunkSz.y - inSideDist.y],
topRight  => [   trunkSz.x + inSideDist.x,    trunkSz.y + inSideDist.y],
ENDCASE  => ERROR;
Include: PROC[obj: CD.Object, pos: CD.Position, name: Rope.ROPE] = {
transPos: CD.Position ← CDBasics.BaseOfRect[CDBasics.MapRect[
CD.InterestRect[obj],
(SELECT corner FROM
bottomLeft => [pos, original],
topLeft  => [pos, CD.mirrorY],
bottomRight => [pos, mirrorX],
topRight  => [pos, rotate180],
ENDCASE  => ERROR)]];
AddPO[objectNets, [obj, transPos], name]};
objectNets: SymTab.Ref ← SymTab.Create[];
Include[via,   outerTrunkPos, "Vdd"];
Include[vddHor,  outerTrunkPos, "Vdd"];
Include[vddVer,  outerTrunkPos, "Vdd"];
Include[via,   innerTrunkPos, "Gnd"];
Include[gndHor,  innerTrunkPos, "Gnd"];
Include[gndVer,  innerTrunkPos, "Gnd"];
powerCorner.object ← CDRoutingObjects.CreateRoutingObject
[CDRoutingObjects.CreateNodes[objectNets], [0, 0, cellSz.x, cellSz.y]];
RTBasic.RepositionCell[powerCorner.object];
powerCorner.size ← RTBasic.IRSize[powerCorner.object]};
Global Routing
GlobalRoute: PUBLIC PROC [handle: CabbagePrivate.Handle] ~ {
find the strategic paths for all nets
EachNet: Connections.EachNetAction ~ {
PROC [key: Key, net: Net] RETURNS [quit: BOOLEANFALSE]
sortedSegments: CabbagePrivate.SegmentSeq ← SortSegments[handle, net];
IF sortedSegments # NIL THEN {
segmentPair: CabbagePrivate.SegmentPair ← FindStartEndSegments[handle, net, sortedSegments];
AddNetToGlobalRoute[handle, net, segmentPair]}};
newConnections: Connections.Table ← MakeNewConnections[handle];
[] ← Connections.EnumerateNets[newConnections, EachNet]};
MakeNewConnections: PROC [handle: CabbagePrivate.Handle] RETURNS [newConnections: Connections.Table ← Connections.CreateForRopes[]] ~ {
Make a new set of connections to account for new power ring
store the net and the segments on the net
InsertPinsFromInner[handle, newConnections];
now do the power objects
InsertPinsFromPower[handle, newConnections, bottom];
InsertPinsFromPower[handle, newConnections, right];
InsertPinsFromPower[handle, newConnections, top];
InsertPinsFromPower[handle, newConnections, left]};
InsertPinsFromInner: PROC [handle: CabbagePrivate.Handle, newConnections: Connections.Table] ~ {
insert all of the pins from the inner object into the new table
EachNet: Connections.EachNetAction ~ {
PROC [key: Key, net: Net] RETURNS [quit: BOOLEANFALSE]
EachSegment: Connections.EachSegmentAction ~ {
PROC [net: Net, segment: Segment] RETURNS [quit: BOOLEANFALSE]
IF segment.object = handle.inner.object THEN {
make a new copy of the segment and put it in the table
newSegment: Connections.Segment ← NEW[Connections.SegmentRec ← [name: segment.name, object: segment.object, range: segment.range, side: segment.side, layer: segment.layer]];
newNet.segments ← CONS[newSegment, newNet.segments];
[] ← Connections.Store[newConnections, net.name, newNet]}};
newNet: Connections.Net ← NEW[Connections.NetRec ← [name: net.name, width: net.width]];
[] ← Connections.Store[newConnections, net.name, newNet];
[] ← Connections.EnumerateSegments[net, EachSegment]};
store the net and the segments on the net
[] ← Connections.EnumerateNets[handle.connections, EachNet]};
InsertPinsFromPower: PROC [handle: CabbagePrivate.Handle, newConnections: Connections.Table, chipSide: RTBasic.Side] ~ {
insert the pins on the appropriate side into the new table
ChanPublics: CoreGeometry.EachWirePinProc ~ {
PROC [wire: Wire, min, max: INT, side: Side, layer: CD.Layer] RETURNS [quit: BOOLFALSE];
store the pins on the appropriate side of the adjacent channel
name: Rope.ROPE ← NameFromWire[wire];
IF side = otherSide THEN {
segment: Connections.Segment ← NEW[Connections.SegmentRec ← [name: name, object: handle.powerDistribution.power[chipSide].object, range: [min, max], side: side, layer: layer]];
net: Connections.Net ← Connections.Fetch[newConnections, name].net;
net.segments ← CONS[segment, net.segments];
[] ← Connections.Store[newConnections, name, net]}};
otherSide: DABasics.Side ← RTBasic.OtherSide[chipSide];
mode: Sinix.Mode = SinixOps.GetExtractMode[handle.rules.horizInsideParms.parms.technology];
[] ← CoreGeometry.EnumerateNonOverlappingSides[mode.decoration, handle.powerDistribution.power[chipSide].cellType, ChanPublics]};
SortSegments: PROC [handle: CabbagePrivate.Handle, net: Connections.Net] RETURNS [sortedSegments: CabbagePrivate.SegmentSeq ← NIL] ~ {
Sort the segments on this net in order arround the periphery
CountSegments: Connections.EachSegmentAction ~ {numSegments ← numSegments + 1};
PinCompare: List.CompareProc ~ {
pos1, pos2: INT;
TRUSTED{
pos1 ← PosOf[handle, LOOPHOLE[ref1]];
pos2 ← PosOf[handle, LOOPHOLE[ref2]]};
RETURN [Basics.CompareInt[pos1, pos2]]};
numSegments, index: INT ← 0;
mungedSegmentList, sortedSegmentList: List.LORA;
[] ← Connections.EnumerateSegments[net, CountSegments];
IF numSegments > 1 THEN {
Use Reverse to get a new copy of the list because Sort is destructive
TRUSTED{mungedSegmentList ← List.Reverse[LOOPHOLE[net.segments]]};
sortedSegmentList ← List.Sort[mungedSegmentList, PinCompare];
sortedSegments ← NEW[CabbagePrivate.SegmentSeqRec[numSegments]];
FOR each: List.LORA ← sortedSegmentList, each.rest UNTIL each = NIL DO
segment: Connections.Segment;
TRUSTED{segment ← LOOPHOLE[each.first]};
sortedSegments[index] ← segment;
index ← index + 1;
ENDLOOP}};
Find the start and end segments of a net arround the periphery
FindStartEndSegments: PROC [handle: CabbagePrivate.Handle, net: Connections.Net, sortedSegments: CabbagePrivate.SegmentSeq] RETURNS [segmentPair: CabbagePrivate.SegmentPair ← [NIL, NIL]] ~ {
minLength: INTLAST[INT];
perimeter: INT ← 2*(handle.size.x + handle.size.y);
length: INT;
startSeg, endSeg: Connections.Segment;
FOR index: NAT IN [0 .. sortedSegments.numSegments) DO
IF index < sortedSegments.numSegments - 1 THEN {
startSeg ← sortedSegments[index+1];
endSeg ← sortedSegments[index];
length ← perimeter - PosOf[handle, startSeg] + PosOf[handle, endSeg]}
ELSE {
endSeg ← sortedSegments[index];
startSeg ← sortedSegments[0];
length ← PosOf[handle, endSeg] - PosOf[handle, startSeg]};
IF length < minLength THEN {
minLength ← length;
segmentPair.seg1 ← startSeg;
segmentPair.seg2 ← endSeg}
ENDLOOP;
IF segmentPair.seg1 = NIL OR segmentPair.seg2 = NIL THEN
Cabbage.Error[programmingError, "Not suppose to happen"]};
Add this net to the global route
AddNetToGlobalRoute: PROC [handle: CabbagePrivate.Handle, net: Connections.Net, segmentPair: CabbagePrivate.SegmentPair] ~ {
pos1: INT ← PosOf[handle, segmentPair.seg1];
pos2: INT ← PosOf[handle, segmentPair.seg2];
IF pos1 < pos2 THEN {
FOR d: CabbagePrivate.Division IN CabbagePrivate.Division DO
IF pos1 < PosOfDivision[handle, d] AND PosOfDivision[handle, d] < pos2 THEN
handle.globalRouting.exitLists[d] ← CONS[net, handle.globalRouting.exitLists[d]]
ENDLOOP}
ELSE {
FOR d: CabbagePrivate.Division IN CabbagePrivate.Division DO
IF PosOfDivision[handle, d] > pos1 OR PosOfDivision[handle, d] < pos2 THEN
handle.globalRouting.exitLists[d] ← CONS[net, handle.globalRouting.exitLists[d]]
ENDLOOP}};
Detailed Routing
DetailedRoute: PUBLIC PROC [handle: CabbagePrivate.Handle] ~ {
RouteChannels[handle];
AdjustPositions[handle];
IF handle.routeType = normal THEN RouteSwitchBoxes[handle]
ELSE RouteSwitchBoxesPL[handle];
AdjustPositions[handle]};
route all of the channels or just the left and right channels depending on routeType
RouteChannels: PROC [handle: CabbagePrivate.Handle] ~ {
horizInsideParms: CabbagePrivate.ParmSet ← handle.rules.horizInsideParms;
vertInsideParms: CabbagePrivate.ParmSet ← handle.rules.vertInsideParms;
horizRange: Connections.Range ← [handle.inner.origin.x, handle.inner.origin.x + handle.inner.size.x];
vertRange: Connections.Range ← [handle.inner.origin.y, handle.inner.origin.y + handle.inner.size.y];
IF handle.routeType = normal THEN {
handle.detailedRouting.channels[bottom] ← RouteChannel[handle, handle.powerDistribution.power[bottom], bottom, bottomLeft, bottomRight, horizRange, horizInsideParms];
handle.detailedRouting.channels[right] ← RouteChannel[handle, handle.powerDistribution.power[right], right, rightBottom, rightTop, vertRange, vertInsideParms];
handle.detailedRouting.channels[top] ← RouteChannel[handle, handle.powerDistribution.power[top], top, topLeft, topRight, horizRange, horizInsideParms];
handle.detailedRouting.channels[left] ← RouteChannel[handle, handle.powerDistribution.power[left], left, leftBottom, leftTop, vertRange, vertInsideParms]}
ELSE { -- routeType = padLimited
handle.detailedRoutingPL.channels[right] ← RouteChannel[handle, handle.powerDistribution.power[right], right, rightBottom, rightTop, vertRange, vertInsideParms];
handle.detailedRoutingPL.channels[left] ← RouteChannel[handle, handle.powerDistribution.power[left], left, leftBottom, leftTop, vertRange, vertInsideParms]}};
route one of the channels
RouteChannel: PROC [handle: CabbagePrivate.Handle,
boundingChannel: CabbagePrivate.Channel, -- the power channel to use
chipSide: DABasics.Side,   -- the side of chip for which this channel is being constructed
llDiv, urDiv: CabbagePrivate.Division, -- the lower and upper boundries of the channel
range: Connections.Range,  -- the range of interest along the channel side
parms: CabbagePrivate.ParmSet]
RETURNS [channel: CabbagePrivate.Channel] ~ {
InitNet: Connections.EachNetAction = {net.netDat ← NIL};
intermediateResult: Route.IntermediateResult;
retrieveRect: REF DABasics.Rect;
rect: DABasics.Rect;
offset: INT ← parms.rules.trunkToTrunk;
size: INT;    -- required channel width
actualSize: INT;   -- the channel width that was produced
otherSide: DABasics.Side ← RTBasic.OtherSide[chipSide];
blSide: DABasics.Side ← IF chipSide=bottom OR chipSide=top THEN left ELSE bottom;
clear the routing specification for this channel
[] ← Connections.EnumerateNets[handle.connections, InitNet];
construct the bonding objects to pass to the channel router
AddPinsFromObject[handle, handle.inner, chipSide, range, parms, FALSE, makeTwoPinPowerNets, "--"];
AddPinsFromChannel[handle, boundingChannel, otherSide, parms.rules.branchLayer, range, parms, none, NIL];
AddPinsFromEnd[handle, llDiv, blSide, parms];
AddPinsFromEnd[handle, urDiv, RTBasic.OtherSide[blSide], parms];
intermediateResult ← Route.ChannelRoute[enumerateNets: EnumerateChannelNets, min: range.min, max: range.max, rulesParameters: parms.parms, rules: parms.rules, name: handle.name, enumerateObstructions: NIL, channelData: handle, optimization: handle.parms.opt, signalSinglePinNets: handle.parms.signalSinglePinNets];
rect ← intermediateResult.resultData.routingRect;
SELECT chipSide FROM
bottom => {
size ← handle.inner.origin.y - (boundingChannel.origin.y + boundingChannel.size.y);
retrieveRect ← NEW[CD.Rect ← [rect.x1, MIN[rect.y1, rect.y2 - size + offset], rect.x2, rect.y2 + offset]]};
right => {
size ← boundingChannel.origin.x - (handle.inner.origin.x + handle.inner.size.x);
retrieveRect ← NEW[CD.Rect ← [rect.x1 - offset, rect.y1, MAX[rect.x2, rect.x1 + size - offset], rect.y2]]};
top => {
size ← boundingChannel.origin.y - (handle.inner.origin.y + handle.inner.size.y);
retrieveRect ← NEW[CD.Rect ← [rect.x1, rect.y1 - offset, rect.x2, MAX[rect.y2, rect.x1 + size - offset]]]};
left => {
size ← handle.inner.origin.x - (boundingChannel.origin.x + boundingChannel.size.x);
retrieveRect ← NEW[CD.Rect ← [MIN[rect.x1, rect.x2 - size + offset], rect.y1, rect.x2 + offset, rect.y2]]};
ENDCASE;
channel.object ← Route.ChannelRetrieve[intermediateResult: intermediateResult, enumerateNets: EnumerateChannelNets, brokenNets: NIL, channelData: handle, retrieveRect: retrieveRect].object;
compare channel.size to required channel width
channel.size ← RTBasic.IRSize[channel.object];
actualSize ← SELECT chipSide FROM
bottom, top => channel.size.y,
left, right => channel.size.x,
ENDCASE => 0;
IF actualSize > size THEN Cabbage.Signal[noResource, "Inner routing channel is to small. Decrease powerWidth and/or outerWidth."];
channel.cellType ← ExtractChannel[channel, parms]};
adjust the positions of everything to account for the actual channel widths
route all of the switchBoxes (the corners)
RouteSwitchBoxes: PROC [handle: CabbagePrivate.Handle] ~ {
horizInsideParms: CabbagePrivate.ParmSet ← handle.rules.horizInsideParms;
leftHorizRange: Connections.Range ← [handle.left.origin.x + handle.left.size.x, handle.inner.origin.x];
rightHorizRange: Connections.Range ← [handle.inner.origin.x + handle.inner.size.x, handle.right.origin.x];
bottomVertRange: Connections.Range ← [handle.bottom.origin.y + handle.bottom.size.y, handle.inner.origin.y];
topVertRange: Connections.Range ← [handle.inner.origin.y + handle.inner.size.y, handle.top.origin.y];
handle.detailedRouting.switchBoxes[bottomLeft] ← RouteSwitchBox[handle, bottomLeft, leftHorizRange, bottomVertRange, horizInsideParms, TRUE, FALSE];
handle.detailedRouting.switchBoxes[bottomRight] ← RouteSwitchBox[handle, bottomRight, rightHorizRange, bottomVertRange, horizInsideParms, FALSE, TRUE];
handle.detailedRouting.switchBoxes[topRight] ← RouteSwitchBox[handle, topRight, rightHorizRange, topVertRange, horizInsideParms, FALSE, TRUE];
handle.detailedRouting.switchBoxes[topLeft] ← RouteSwitchBox[handle, topLeft, leftHorizRange, topVertRange, horizInsideParms, TRUE, FALSE]};
route the bottom and top switchBoxes
RouteSwitchBoxesPL: PROC [handle: CabbagePrivate.Handle] ~ {
l: INT = CDSimpleRules.GetTechnology[handle.parms.technologyKey].lambda;
horizInsideParms: CabbagePrivate.ParmSet ← handle.rules.horizInsideParms;
powerLRWidth: INT ← handle.parms.outerLRChanWidth * l + handle.parms.powerLRCellWidth * l;
powerBTWidth: INT ← handle.parms.outerBTChanWidth * l + handle.parms.powerBTCellWidth * l;
horizRange: Connections.Range ← [handle.left.origin.x + handle.left.size.x + powerLRWidth, handle.right.origin.x - powerLRWidth];
bottomVertRange: Connections.Range ← [handle.bottom.origin.y + handle.bottom.size.y + powerBTWidth, handle.inner.origin.y];
topVertRange: Connections.Range ← [handle.inner.origin.y + handle.inner.size.y, handle.top.origin.y - powerBTWidth];
handle.detailedRoutingPL.switchBoxes[bottom] ← RouteSwitchBoxPL[handle, bottom, horizRange, bottomVertRange, horizInsideParms, TRUE, TRUE];
handle.detailedRoutingPL.switchBoxes[top] ← RouteSwitchBoxPL[handle, top, horizRange, topVertRange, horizInsideParms, TRUE, TRUE]};
RouteSwitchBoxPL: PROC [handle: CabbagePrivate.Handle, side: RTBasic.TBSide, horizRange, vertRange: Connections.Range, parms: CabbagePrivate.ParmSet, okToDiddleLLPins, okToDiddleURPins: BOOLFALSE] RETURNS [switchBox: CabbagePrivate.Channel] ~ {
InitNet: Connections.EachNetAction = {net.netDat ← NIL};
innerRange: Connections.Range ← [handle.inner.origin.x, handle.inner.origin.x + handle.inner.size.x];
rect: DABasics.Rect ← [horizRange.min, vertRange.min, horizRange.max, vertRange.max];
clear the routing specification for this channel
[] ← Connections.EnumerateNets[handle.connections, InitNet];
AddPinsFromChannel[handle, handle.powerDistribution.power[left], right, parms.rules.trunkLayer, vertRange, parms, likeOtherNets, NIL]; -- left end of SB
AddPinsFromChannel[handle, handle.powerDistribution.power[right], left, parms.rules.trunkLayer, vertRange, parms, likeOtherNets, NIL]; -- right end of SB
AddPinsFromObject[handle, handle.inner, side, innerRange, parms, FALSE, makeTwoPinPowerNets, "--"]; -- inner side
AddPinsFromChannel[handle, handle.powerDistribution.power[side], RTBasic.OtherSide[side], parms.rules.branchLayer, horizRange, parms, none, NIL]; -- outer side
AddPinsFromFullChannel[handle, handle.detailedRoutingPL.channels[left], side, parms.rules.branchLayer, parms, likeOtherNets, NIL]; -- channel on inner side
AddPinsFromFullChannel[handle, handle.detailedRoutingPL.channels[right], side, parms.rules.branchLayer, parms, likeOtherNets, NIL]; -- channel on inner side
switchBox.object ← Route.SwitchBox[enumerateNets: EnumerateSwitchBoxNets, routingRect: rect, rulesParameters: parms.parms, name: NIL, enumerateObstructions: NIL, switchBoxData: handle, optimization: handle.parms.opt, signalSinglePinNets: handle.parms.signalSinglePinNets, okToDiddleLLPins: okToDiddleLLPins, okToDiddleURPins: okToDiddleURPins].object;
switchBox.size ← RTBasic.IRSize[switchBox.object];
switchBox.cellType ← ExtractChannel[switchBox, parms]};
RouteSwitchBox: PROC [handle: CabbagePrivate.Handle, corner: CabbagePrivate.Corners, horizRange, vertRange: Connections.Range, parms: CabbagePrivate.ParmSet, okToDiddleLLPins, okToDiddleURPins: BOOLFALSE] RETURNS [switchBox: CabbagePrivate.Channel] ~ {
InitNet: Connections.EachNetAction = {net.netDat ← NIL};
rect: DABasics.Rect ← [horizRange.min, vertRange.min, horizRange.max, vertRange.max];
outerTB: RTBasic.TBSide ←
SELECT corner FROM
bottomLeft, bottomRight => bottom,
topLeft, topRight => top,
ENDCASE => Cabbage.Error[programmingError, "Not suppose to happen."];
outerLR: RTBasic.LRSide ←
SELECT corner FROM
bottomLeft, topLeft => left,
bottomRight, topRight => right,
ENDCASE => Cabbage.Error[programmingError, "Not suppose to happen."];
clear the routing specification for this channel
[] ← Connections.EnumerateNets[handle.connections, InitNet];
AddPinsFromFullChannel[handle, handle.detailedRouting.channels[outerLR], outerTB, parms.rules.branchLayer, parms, likeOtherNets, NIL]; -- pins from side channel
AddPinsFromChannel[handle, handle.powerDistribution.power[outerTB], RTBasic.OtherSide[outerTB], parms.rules.branchLayer, horizRange, parms, likeOtherNets, NIL]; -- pins from top or bottom outer side
AddPinsFromChannel[handle, handle.powerDistribution.power[outerLR], RTBasic.OtherSide[outerLR], parms.rules.trunkLayer, vertRange, parms, likeOtherNets, NIL]; -- pins from left or right outer side
AddPinsFromFullChannel[handle, handle.detailedRouting.channels[outerTB], outerLR, parms.rules.trunkLayer, parms, likeOtherNets, NIL]; -- pins from top or bottom channel
switchBox.object ← Route.SwitchBox[enumerateNets: EnumerateSwitchBoxNets, routingRect: rect, rulesParameters: parms.parms, name: NIL, enumerateObstructions: NIL, switchBoxData: handle, optimization: handle.parms.opt, signalSinglePinNets: handle.parms.signalSinglePinNets, okToDiddleLLPins: okToDiddleLLPins, okToDiddleURPins: okToDiddleURPins].object;
switchBox.size ← RTBasic.IRSize[switchBox.object];
switchBox.cellType ← ExtractChannel[switchBox, parms]};
Object Generation
MakeChip: PUBLIC PROC [handle: CabbagePrivate.Handle] RETURNS [chip: CD.Object ← CDCells.CreateEmptyCell[]] ~ {
construct the chip; all of the peices have been constructed
first include the input cells
IncludeObject[handle.inner.object, handle.inner.origin, chip];
IncludeObject[handle.bottomLeft.object, handle.bottomLeft.origin, chip];
IncludeObject[handle.bottom.object, handle.bottom.origin, chip];
IncludeObject[handle.bottomRight.object, handle.bottomRight.origin, chip];
IncludeObject[handle.right.object, handle.right.origin, chip];
IncludeObject[handle.topRight.object, handle.topRight.origin, chip];
IncludeObject[handle.top.object, handle.top.origin, chip];
IncludeObject[handle.topLeft.object, handle.topLeft.origin, chip];
IncludeObject[handle.left.object, handle.left.origin, chip];
next include the signal routing
IF handle.routeType = normal THEN {
FOR side: DABasics.Side IN DABasics.Side DO
IncludeObject[handle.detailedRouting.channels[side].object, handle.detailedRouting.channels[side].origin, chip];
ENDLOOP;
FOR corner: CabbagePrivate.Corners IN CabbagePrivate.Corners DO
IncludeObject[handle.detailedRouting.switchBoxes[corner].object, handle.detailedRouting.switchBoxes[corner].origin, chip];
ENDLOOP}
ELSE {
FOR side: DABasics.Side IN RTBasic.LRSide DO
IncludeObject[handle.detailedRoutingPL.channels[side].object, handle.detailedRoutingPL.channels[side].origin, chip];
ENDLOOP;
FOR side: DABasics.Side IN RTBasic.TBSide DO
IncludeObject[handle.detailedRoutingPL.switchBoxes[side].object, handle.detailedRoutingPL.switchBoxes[side].origin, chip];
ENDLOOP};
finally the power cells, outside routing channels and switchboxes
FOR side: DABasics.Side IN DABasics.Side DO
IncludeObject[handle.powerDistribution.channels[side].object, handle.powerDistribution.channels[side].origin, chip];
IncludeObject[handle.powerDistribution.power[side].object, handle.powerDistribution.power[side].origin, chip];
ENDLOOP;
FOR corner: CabbagePrivate.Corners IN CabbagePrivate.Corners DO
IncludeObject[handle.powerDistribution.switchBoxes[corner].object, handle.powerDistribution.switchBoxes[corner].origin, chip];
IncludeObject[handle.powerDistribution.powerCorners[corner].object, handle.powerDistribution.powerCorners[corner].origin, chip];
ENDLOOP;
[] ← RTBasic.RepositionCell[chip]};
Add Pin Operations
AddMappedPinsFromObject: PROC [handle: CabbagePrivate.Handle,
objectDes: CabbagePrivate.ObjectDescription,
pinSide: DABasics.Side,  -- the side of the object on which pins are to be considered
innerRange, midRange, outerRange: Connections.Range, -- innerRange is the span of the inner cell, midRange is the free range, outerRange is the span of the appropriate power routing cell
parms: CabbagePrivate.ParmSet,
lowerSuffix, upperSuffix: Rope.ROPE] ~ {
add pins for inner edge of the outside channel and the outer edge of the power cell; pins are on the branch layer of rules (rules.branchLayer).
map signal pins outside outerRange to just inside outerRange
map Vdd and Gnd pins in outerRange to their same positions;
map only a single pin per wire outside innerRange but inside outerRange
EnterPowerOnInner: Connections.EachNetAction ~ {
PROC [key: Key, net: Net] RETURNS [quit: BOOLEANFALSE]
store the power pins on the appropriate side of the inner object
EachSegment: Connections.EachSegmentAction ~ {
PROC [net: Net, segment: Segment] RETURNS [quit: BOOLEANFALSE]
IF (segment.object = handle.inner.object AND segment.side = otherSide) AND powerNet THEN
CabbageObstacles.Insert[obstacles, [innerOrigin + segment.range.min, innerOrigin + segment.range.max], powerSpacing]};
powerNet: BOOLEAN ← Rope.Equal[net.name, "Vdd"] OR Rope.Equal[net.name, "Gnd"];
[] ← Connections.EnumerateSegments[net, EachSegment]};
EnterPowerOnOuter: Connections.EachNetAction ~ {
PROC [key: Key, net: Net] RETURNS [quit: BOOLEANFALSE]
store the power pins on the appropriate side of the inner object
EachSegment: Connections.EachSegmentAction ~ {
PROC [net: Net, segment: Segment] RETURNS [quit: BOOLEANFALSE]
IF (segment.object = objectDes.object AND segment.side = pinSide) AND powerNet THEN
CabbageObstacles.Insert[obstacles, [outerOrigin + segment.range.min, outerOrigin + segment.range.max], powerSpacing]};
powerNet: BOOLEAN ← Rope.Equal[net.name, "Vdd"] OR Rope.Equal[net.name, "Gnd"];
[] ← Connections.EnumerateSegments[net, EachSegment]};
EachOuterNet: Connections.EachNetAction ~ {
examine the nets on the outer object: objectDes
PROC [key: Key, net: Net] RETURNS [quit: BOOLEANFALSE]
EachSegment: Connections.EachSegmentAction ~ {
keep the segments of interest on objectDes
PROC [net: Net, segment: Segment] RETURNS [quit: BOOLEANFALSE]
IF (segment.object = objectDes.object AND segment.side = pinSide AND useNet) THEN {
useThisPin: BOOLEANTRUE;
newRange: Connections.Range;
name: Rope.ROPENIL;
adjustedRange: Connections.Range ← [outerOrigin + segment.range.min, outerOrigin + segment.range.max];
IF ProperSubset[adjustedRange, midRange ] THEN {
pin is within inner range ==> we may use tight spacing
IF net = Vdd OR net = Gnd OR net has not been processed for this side THEN useThisPin
IF powerNet THEN useThisPin ← FALSE -- power pins for middle range are put in from object
ELSE IF RefTab.Insert[netTable, net.name, NIL] THEN {
newRange ← CabbageObstacles.FindMiddleRange[adjustedRange, obstacles];
name ← net.name}
ELSE useThisPin ← FALSE}
ELSE IF ProperSubset[adjustedRange, lowerRange] OR CrossesBoundry[adjustedRange, lowerRange] THEN {
pin is within lower range, search upwards
IF net has not been processed for this side THEN useThisPin
(net = Vdd OR net = Gnd) gets a special name
name ← IF powerNet THEN Rope.Cat[net.name, lowerSuffix] ELSE net.name;
IF RefTab.Insert[netTable, name, NIL] THEN {
pinWidth: INTIF powerNet THEN parms.rules.branchWidth ELSE adjustedRange.max-adjustedRange.min;
lowerRange: Connections.Range ← [outerRange.min, outerRange.min + pinWidth];
newRange ← CabbageObstacles.FindLowerRange[lowerRange, obstacles]}
ELSE useThisPin ← FALSE}
ELSE IF ProperSubset[adjustedRange, upperRange] OR CrossesBoundry[adjustedRange, upperRange] THEN {
pin is within upper range, search downwards
IF net has not been processed for this side THEN useThisPin
(net = Vdd OR net = Gnd) gets a special name
name ← IF powerNet THEN Rope.Cat[net.name, upperSuffix] ELSE net.name;
IF RefTab.Insert[netTable, name, NIL] THEN {
pinWidth: INTIF powerNet THEN parms.rules.branchWidth ELSE adjustedRange.max-adjustedRange.min;
upperRange: Connections.Range ← [outerRange.max - pinWidth, outerRange.max];
newRange ← CabbageObstacles.FindUpperRange[upperRange, obstacles]}
ELSE useThisPin ← FALSE}
ELSE {
Cabbage.Signal[callingError, Rope.Cat["Segment on net: ", net.name, " crosses boundary of power routing area at ", RopeFromRange[l, adjustedRange]]];
useThisPin ← FALSE};
IF useThisPin THEN {
spacing: INTIF ProperSubset[newRange, innerRange] THEN innerSpacing ELSE outerSpacing;
trunkWidth: INTIF powerNet THEN MAX[parms.rules.trunkWidth, parms.rules.branchWidth] ELSE net.width;
netDat: NetInChan ← IF net.netDat = NIL THEN NEW[NetInChanRec] ELSE NARROW[net.netDat];
AddPin[net, netDat, name, newRange, rules.branchLayer, pinSide, trunkWidth];
[] ← Connections.Store[handle.connections, key, net];
CabbageObstacles.Insert[obstacles, newRange, spacing]}}};
powerNet: BOOLEAN ← Rope.Equal[net.name, "Vdd"] OR Rope.Equal[net. name, "Gnd"];
useNet: BOOL ← (~NetOnlyOnSide[handle, net, otherSide] AND NumberPinsOnSide[handle, net, otherSide] >= 1);
[] ← Connections.EnumerateSegments[net, EachSegment]};
rules: Route.DesignRules ← parms.rules;
netTable: RefTab.Ref ← RefTab.Create[equal: RefTabExtras.EqualRope, hash: RefTabExtras.HashRope];
otherSide: DABasics.Side ← RTBasic.OtherSide[pinSide];
innerOrigin: INTSELECT pinSide FROM
bottom, top => handle.inner.origin.x,
right, left => handle.inner.origin.y,
ENDCASE => Cabbage.Error[programmingError, "Not suppose to happen."];
outerOrigin: INTSELECT pinSide FROM
bottom, top => objectDes.origin.x,
right, left => objectDes.origin.y,
ENDCASE => Cabbage.Error[programmingError, "Not suppose to happen."];
l: INT = CDSimpleRules.GetTechnology[handle.parms.technologyKey].lambda;
boundryOffset: INT ← 3*rules.branchToBranch; -- the size of the stay out area at the boundry
powerSpacing: INT ← MAX[rules.branchSpacing, rules.trunkSpacing]; -- the size of the stay out area between power pins
innerSpacing: INT ← MAX[rules.branchSpacing, rules.trunkSpacing]; -- the size of the stay out area between pins on channel sides
outerSpacing: INT ← 2*rules.branchToBranch; -- the size of the stay out area between pins on switchbox ends
lowerRange: Connections.Range ← [FIRST[INT], midRange.min];
upperRange: Connections.Range ← [midRange.max, LAST[INT]];
insert obstacles for vias on end of power bus and at boundries of routing areas
all obstacles (pins, inner power publics, ...) are contained in a sorted table; the data is a Connections.Segment; the key is the origin, i.e. data.range.min
obstacles: CabbageObstacles.BitTable ← CabbageObstacles.CreateBitTable[outerRange.min, outerRange.max, l];
CabbageObstacles.Insert[obstacles, [outerRange.min, midRange.min + boundryOffset], innerSpacing];
CabbageObstacles.Insert[obstacles, [midRange.max - boundryOffset, outerRange.max], innerSpacing];
CabbageObstacles.Insert[obstacles, [innerRange.min - boundryOffset, innerRange.min + boundryOffset], innerSpacing];
CabbageObstacles.Insert[obstacles, [innerRange.max - boundryOffset, innerRange.max + boundryOffset], innerSpacing];
process the inner power obstacles an the find places for the outer signals
[] ← Connections.EnumerateNets[handle.connections, EnterPowerOnInner];
[] ← Connections.EnumerateNets[handle.connections, EnterPowerOnOuter];
[] ← Connections.EnumerateNets[handle.connections, EachOuterNet]};
AddPinsFromOutsideEnd: PROC [handle: CabbagePrivate.Handle,
objectDes: CabbagePrivate.ObjectDescription,
pinsOnSide, endOfChannel: DABasics.Side,
outerRange: Connections.Range, -- the span along the appropriate padring cell
parms: CabbagePrivate.ParmSet,
suffix: Rope.ROPE] ~ {  -- suffix for power nets
add pins on the end of the channel to the routing for the current channel
transfer pins on objectDes outside the range (on side endOfChannel) to routing.
pins go on rules.trunkLayer
EachNet: Connections.EachNetAction ~ {
PROC [key: Key, net: Net] RETURNS [quit: BOOLEANFALSE]
EachSegment: Connections.EachSegmentAction ~ {
PROC [net: Net, segment: Segment] RETURNS [quit: BOOLEANFALSE]
IF (segment.object = objectDes.object AND segment.side = pinsOnSide AND useNet) THEN {
adjustedRange: Connections.Range ← [origin + segment.range.min, origin + segment.range.max];
IF ReallyCrossesBoundry[adjustedRange, interestingRange] THEN
Cabbage.Signal[callingError, Rope.Cat["Segment on net: ", net.name, " crosses boundary of power routing area at ", RopeFromRange[l, adjustedRange]]];
IF ProperSubset[adjustedRange, interestingRange] AND ~Member[net.name, netNameList] THEN {
netDat: NetInChan ← IF net.netDat = NIL THEN NEW[NetInChanRec] ELSE NARROW[net.netDat];
name: Rope.ROPEIF powerNet THEN Rope.Cat[net.name, suffix] ELSE net.name;
AddEnd[net, netDat, name, endOfChannel, 0];
[] ← Connections.Store[handle.connections, key, net];
netNameList ← CONS[net.name, netNameList]}}};
powerNet: BOOLEAN ← Rope.Equal[net.name, "Vdd"] OR Rope.Equal[net. name, "Gnd"];
useNet: BOOL ← NumberPinsOnSide[handle, net, otherSide] >= 2 OR (~NetOnlyOnSide[handle, net, otherSide] AND NumberPinsOnSide[handle, net, otherSide] >= 1);
[] ← Connections.EnumerateSegments[net, EachSegment]};
l: INT = CDSimpleRules.GetTechnology[handle.parms.technologyKey].lambda;
netNameList: LIST OF Rope.ROPENIL;
interestingRange: Connections.Range ← SELECT endOfChannel FROM
left, bottom => [FIRST[INT], outerRange.min],
right, top => [outerRange.max, LAST[INT]],
ENDCASE => Cabbage.Error[programmingError, "Not suppose to happen."];
origin: INTSELECT pinsOnSide FROM
bottom, top => objectDes.origin.x,
right, left => objectDes.origin.y,
ENDCASE => Cabbage.Error[programmingError, "Not suppose to happen."];
otherSide: DABasics.Side ← RTBasic.OtherSide[pinsOnSide];
[] ← Connections.EnumerateNets[handle.connections, EachNet]};
AddPinsFromObject: PROC [handle: CabbagePrivate.Handle,
objectDes: CabbagePrivate.ObjectDescription,
side: DABasics.Side,  -- the side of the object on which pins are to be considered
range: Connections.Range, -- the span along objectDes to consider
parms: CabbagePrivate.ParmSet,
filterSinglePins: BOOL,   -- TRUE => disregard single pin nets
powerMode: PowerMode,  -- tells what to do with power
suffix: Rope.ROPE] ~ {  -- suffix for power nets
add pins to routing for side of channel or switchbox; input to router
AddPinsFromObject3Part[handle, objectDes, side, range, range, parms, filterSinglePins, powerMode, powerMode, suffix, suffix, suffix]};
AddPinsFromObject3Part: PROC [handle: CabbagePrivate.Handle,
objectDes: CabbagePrivate.ObjectDescription,
side: DABasics.Side,   -- the side of the object on which pins are to be considered
innerRange, outerRange: Connections.Range, -- the span along objectDes to consider
parms: CabbagePrivate.ParmSet,
filterSinglePins: BOOL,   -- TRUE => disregard single pin nets
innerPowerMode, outerPowerMode: PowerMode, -- tells what to do with power
lowerSuffix, innerSuffix, upperSuffix: Rope.ROPE] ~ { -- suffix for power nets
add pins to routing for side of channel or switchbox; input to router
EnterPin: PROC [net: Connections.Net, powerMode: PowerMode, key: Connections.Key, adjustedRange: Connections.Range, layer: CD.Layer, suffix: Rope.ROPE] ~ {
powerNet: BOOLEAN ← Rope.Equal[net.name, "Vdd"] OR Rope.Equal[net.name, "Gnd"];
netDat: NetInChan ← IF net.netDat = NIL THEN NEW[NetInChanRec] ELSE NARROW[net.netDat];
IF powerMode = makeTwoPinPowerNets AND powerNet THEN {
name: Rope.ROPE ← Rope.Cat[net.name, suffix, Convert.RopeFromInt[netDat.segmentCount]];
AddPin[net, netDat, name, adjustedRange, layer, RTBasic.OtherSide[side], 0];
AddPin[net, netDat, name, adjustedRange, layer, side, 0]}
ELSE IF powerMode = busPower AND powerNet THEN {
trunkWidth: INTMAX[parms.rules.trunkWidth, parms.rules.branchWidth];
name: Rope.ROPE ← Rope.Cat[net.name, suffix];
AddPin[net, netDat, name, adjustedRange, layer, RTBasic.OtherSide[side], trunkWidth]}
ELSE IF powerMode = matchPin AND powerNet THEN {
trunkWidth: INTMAX[parms.rules.trunkWidth, adjustedRange.max - adjustedRange.min];
name: Rope.ROPE ← Rope.Cat[net.name, suffix];
AddPin[net, netDat, name, adjustedRange, layer, RTBasic.OtherSide[side], trunkWidth]}
ELSE IF powerMode = none AND powerNet THEN NULL
ELSE AddPin[net, netDat, net.name, adjustedRange, layer, RTBasic.OtherSide[side], 0];
[] ← Connections.Store[handle.connections, key, net]};
EachNet: Connections.EachNetAction ~ {
PROC [key: Key, net: Net] RETURNS [quit: BOOLEANFALSE]
EachSegment: Connections.EachSegmentAction ~ {
PROC [net: Net, segment: Segment] RETURNS [quit: BOOLEANFALSE]
IF (segment.object = objectDes.object AND segment.side = side AND useNet) THEN {
adjustedRange: Connections.Range ← [origin + segment.range.min, origin + segment.range.max];
IF ReallyCrossesBoundry[adjustedRange, outerRange] THEN
Cabbage.Signal[callingError, Rope.Cat["Segment on net: ", net.name, " crosses a boundary of power routing area at ", RopeFromRange[l, adjustedRange]]]
ELSE IF ProperSubset[adjustedRange, innerRange] THEN
EnterPin[net, innerPowerMode, key, adjustedRange, segment.layer, innerSuffix]
ELSE IF ProperSubset[adjustedRange, lowerRange] OR CrossesBoundry[adjustedRange, lowerRange] THEN
EnterPin[net, outerPowerMode, key, adjustedRange, segment.layer, lowerSuffix]
ELSE IF ProperSubset[adjustedRange, upperRange] OR CrossesBoundry[adjustedRange, upperRange] THEN
EnterPin[net, outerPowerMode, key, adjustedRange, segment.layer, upperSuffix]}};
useNet: BOOL ← ~filterSinglePins OR NumberPinsOnSide[handle, net, otherSide] >= 2 OR (~NetOnlyOnSide[handle, net, otherSide] AND NumberPinsOnSide[handle, net, otherSide] >= 1);
[] ← Connections.EnumerateSegments[net, EachSegment]};
l: INT = CDSimpleRules.GetTechnology[handle.parms.technologyKey].lambda;
lowerRange: Connections.Range ← [outerRange.min, innerRange.min];
upperRange: Connections.Range ← [innerRange.max, outerRange.max];
rules: Route.DesignRules ← parms.rules;
origin: INTSELECT side FROM
bottom, top => objectDes.origin.x,
right, left => objectDes.origin.y,
ENDCASE => Cabbage.Error[programmingError, "Not suppose to happen."];
otherSide: DABasics.Side ← RTBasic.OtherSide[side];
[] ← Connections.EnumerateNets[handle.connections, EachNet]};
AddPinsFromEnd: PROC [handle: CabbagePrivate.Handle, division: CabbagePrivate.Division, side: DABasics.Side, parms: CabbagePrivate.ParmSet] ~ {
add pins from global routing for end of channel; input to router
EachExit: EachExitAction ~ {
PROC [division: CabbagePrivate.Division, net: Connections.Net] RETURNS [quit: BOOLEANFALSE];
powerNet: BOOLEAN ← Rope.Equal[net.name, "Vdd"] OR Rope.Equal[net. name, "Gnd"];
IF ~powerNet THEN {
have to get the net from valid data structure;
trunkWidth: INTIF powerNet THEN MAX[parms.rules.trunkWidth, parms.rules.branchWidth] ELSE net.width;
realNet: Connections.Net ← Connections.Fetch[handle.connections, net.name].net;
netDat: NetInChan ← IF realNet.netDat = NIL THEN NEW[NetInChanRec] ELSE NARROW[realNet.netDat];
AddEnd[realNet, netDat, realNet.name, side, trunkWidth];
[] ← Connections.Store[handle.connections, realNet.name, realNet]}};
[] ← EnumerateExits[handle.globalRouting.exitLists[division], division, EachExit]};
AddPinsFromFullChannel: PROC [handle: CabbagePrivate.Handle,
channel: CabbagePrivate.Channel,
side: DABasics.Side,
pinLayer: CD.Layer,
parms: CabbagePrivate.ParmSet,
powerMode: PowerMode,  -- tells what to do with power
suffix: Rope.ROPE] ~ {  -- suffix for power nets
includePowerNets, makeTwoPinPowerNets: BOOL] ~ {
add pins for the channel; use the full side of channel with pins on side
range: Connections.Range ← SELECT side FROM
bottom, top => [channel.origin.x, channel.origin.x + channel.size.x],
left, right => [channel.origin.y, channel.origin.y + channel.size.y],
ENDCASE => Cabbage.Error[programmingError, "Not suppose to happen"];
AddPinsFromChannel[handle, channel, side, pinLayer, range, parms, powerMode, suffix]};
AddPinsFromChannel: PROC [handle: CabbagePrivate.Handle,
channel: CabbagePrivate.Channel,
pinSide: DABasics.Side,
pinLayer: CD.Layer,
range: Connections.Range,
parms: CabbagePrivate.ParmSet,
powerMode: PowerMode,  -- tells what to do with power
suffix: Rope.ROPE] ~ {  -- suffix for power nets
add pins for for the channel; use the pins on side; range is the span along that side
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
net: Connections.Net ← Connections.Fetch[handle.connections, NameFromWire[wire]].net;
powerNet: BOOLEAN ← Rope.Equal[net.name, "Vdd"] OR Rope.Equal[net. name, "Gnd"];
pin: Pin ← NIL;
wireLimits: Connections.Range ← SELECT side FROM
bottom, top => [channel.origin.x+min, channel.origin.x+max],
left, right => [channel.origin.y+min, channel.origin.y+max],
ENDCASE => Cabbage.Error[programmingError, "Not suppose to happen."];
IF range.min <= wireLimits.min AND wireLimits.max <= range.max AND pinSide = side AND layer = pinLayer THEN {
netDat: NetInChan ← IF net.netDat = NIL THEN NEW[NetInChanRec] ELSE NARROW[net.netDat];
IF powerMode = makeTwoPinPowerNets AND powerNet THEN {
name: Rope.ROPE ← Rope.Cat[net.name, suffix, Convert.RopeFromInt[netDat.segmentCount]];
AddPin[net, netDat, name, wireLimits, layer, RTBasic.OtherSide[pinSide], 0];
AddPin[net, netDat, name, wireLimits, layer, pinSide, 0]}
ELSE IF powerMode = busPower AND powerNet THEN {
name: Rope.ROPE ← Rope.Cat[net.name, suffix];
trunkWidth: INTIF powerNet THEN MAX[parms.rules.trunkWidth, parms.rules.branchWidth] ELSE net.width;
AddPin[net, netDat, name, wireLimits, layer, RTBasic.OtherSide[pinSide], trunkWidth]}
ELSE IF powerMode = matchPin AND powerNet THEN {
trunkWidth: INT ← MAX[parms.rules.trunkWidth, max - min];
name: Rope.ROPE ← Rope.Cat[net.name, suffix];
AddPin[net, netDat, name, wireLimits, layer, RTBasic.OtherSide[pinSide], trunkWidth]}
ELSE IF powerMode = none AND powerNet THEN NULL
ELSE AddPin[net, netDat, net.name, wireLimits, layer, RTBasic.OtherSide[pinSide], 0];
[] ← Connections.Store[handle.connections, net.name, net]}};
mode: Sinix.Mode = SinixOps.GetExtractMode[parms.parms.technology];
[] ← CoreGeometry.EnumerateNonOverlappingSides[mode.decoration, channel.cellType, ChanPublics]};
AddPin: PROC [net: Connections.Net, netDat: NetInChan, name: Rope.ROPE, range: Connections.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];
segment.pinsInSeg ← CONS[pin, segment.pinsInSeg];
first size definition wins; 0 is default
IF segment.trunkSize = 0 AND trunkWidth # 0 THEN segment.trunkSize ← trunkWidth;
net.netDat ← netDat};
AddEnd: PROC [net: Connections.Net, netDat: NetInChan, name: Rope.ROPE, side: DABasics.Side, trunkWidth: INT] ~ {
add a channel end connection
segment: Segment ← LookUpSegment[netDat, name];
SELECT side FROM
bottom, left => segment.leftOrBottomExit ← TRUE;
right, top => segment.rightOrTopExit ← TRUE;
ENDCASE;
first size definition wins; 0 is default
IF segment.trunkSize = 0 AND trunkWidth # 0 THEN segment.trunkSize ← trunkWidth;
net.netDat ← netDat};
LookUpSegment: PROC [netDat: NetInChan, name: 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.name, name] THEN segment ← segList.first;
ENDLOOP;
IF segment = NIL THEN { -- not found, make a NEW one
segment ← NEW[SegmentRec ← [name: name]];
netDat.segmentCount ← netDat.segmentCount + 1;
netDat.segsInNet ← CONS[segment, netDat.segsInNet]}};
Utility Procedures
AddPO: PROC[nets: SymTab.Ref, po: CDRoutingObjects.PlacedObject, nm: Rope.ROPE] = {
refList: REF LIST OF CDRoutingObjects.PlacedObject ← NARROW[SymTab.Fetch[nets, nm].val];
IF refList=NIL THEN {
refList ← NEW[LIST OF CDRoutingObjects.PlacedObject];
[]←SymTab.Store[nets, nm, refList]};
refList^ ← CONS[po, refList^]};
NameFromWire: PROC [wire: Core.Wire] RETURNS [name: Rope.ROPE] ~ {
get name from a wire. This is needed because the wire name has been diddled
a suffix has been added because of the extractor
distinguish constructed Vdd and Gnd by (Vdd | Gnd)--; other nets may start with Vdd and Gnd
wireName: Rope.ROPE ← CoreOps.GetShortWireName[wire];
prefix: Rope.ROPE ← Rope.Substr[wireName, 0, 5];
name ← IF Rope.Equal[prefix, "Vdd--"] THEN "Vdd"
ELSE IF Rope.Equal[prefix, "Gnd--"] THEN "Gnd"
ELSE wireName};
AdjustPositions: PROC [handle: CabbagePrivate.Handle] ~ {
adjust the vertical and horizontal dimension
l: INT = CDSimpleRules.GetTechnology[handle.parms.technologyKey].lambda;
powerLRWidth: INT ← handle.parms.outerLRChanWidth * l + handle.parms.powerLRCellWidth * l;
powerBTWidth: INT ← handle.parms.outerBTChanWidth * l + handle.parms.powerBTCellWidth * l;
routeType: CabbagePrivate.RouteType ← handle.routeType;
sizeBottomArea: INT ← handle.inner.origin.y - (handle.bottom.origin.y + handle.bottom.size.y);
sizeBottomRouting: INT ← powerBTWidth + (IF routeType = normal THEN handle.detailedRouting.channels[bottom].size.y
ELSE handle.detailedRoutingPL.switchBoxes[bottom].size.y);
adjBottom: INT ← sizeBottomRouting - sizeBottomArea;
sizeLeftArea: INT ← handle.inner.origin.x - (handle.left.origin.x + handle.left.size.x);
sizeLeftRouting: INT ← powerLRWidth + (IF routeType = normal THEN handle.detailedRouting.channels[left].size.x
ELSE handle.detailedRoutingPL.channels[left].size.x);
adjLeft: INT ← sizeLeftRouting - sizeLeftArea;
adjTop, adjRight, sizeTopArea, sizeTopRouting, sizeRightArea, sizeRightRouting: INT;
handle.inner.origin ← CDBasics.AddPoints[handle.inner.origin, [MAX[0, adjLeft], MAX[0, adjBottom]]];
handle.bottom.origin ← CDBasics.AddPoints[handle.bottom.origin, [MAX[0, adjLeft], 0]];
handle.right.origin ← CDBasics.AddPoints[handle.right.origin, [MAX[0, adjLeft], MAX[0, adjBottom]]];
handle.top.origin ← CDBasics.AddPoints[handle.top.origin, [MAX[0, adjLeft], MAX[0, adjBottom]]];
handle.left.origin ← CDBasics.AddPoints[handle.left.origin, [0, MAX[0, adjBottom]]];
sizeTopArea ← handle.top.origin.y - (handle.inner.origin.y + handle.inner.size.y);
sizeTopRouting ← powerBTWidth + (IF routeType = normal THEN handle.detailedRouting.channels[top].size.y
ELSE handle.detailedRoutingPL.switchBoxes[top].size.y);
adjTop ← sizeTopRouting - sizeTopArea;
sizeRightArea ← handle.right.origin.x - (handle.inner.origin.x + handle.inner.size.x);
sizeRightRouting ← powerLRWidth + (IF routeType = normal THEN handle.detailedRouting.channels[right].size.x
ELSE handle.detailedRoutingPL.channels[right].size.x);
adjRight ← sizeRightRouting - sizeRightArea;
handle.top.origin ← CDBasics.AddPoints[handle.top.origin, [0, MAX[0, adjTop]]];
handle.right.origin ← CDBasics.AddPoints[handle.right.origin, [MAX[0, adjRight], 0]];
[] ← GetSize[handle];
DoCorners[handle];
DoRoutingAreas[handle]};
IncludeObject: PROC [object: CD.Object, origin: CD.Position, chip: CD.Object] ~ {
IF object # NIL THEN
[] ← RouteUtil.Include[cell: chip, ob: object, position: CDOps.FitObjectI[ob: object, location: origin, orientation: original].off, orientation: original]};
ExtractChannel: PROC [channel: CabbagePrivate.Channel, parms: CabbagePrivate.ParmSet] RETURNS [cellType: Core.CellType] ~ {
extract connectivity for the channel
mode: Sinix.Mode = SinixOps.GetExtractMode[parms.parms.technology];
cellType ← NARROW [Sinix.Extract[channel.object, mode].result]};
PosOf: PROC [handle: CabbagePrivate.Handle, segment: Connections.Segment] RETURNS [INT] ~ {
Find the position of a segment projected to the periphery. The lower left corner is the origin.
range: Connections.Range ← RangeOf[handle, segment];
RETURN[(range.min+range.max)/2]};
Find the range of a segment projected to the periphery. The lower left corner is the origin.
RangeOf: PROC [handle: CabbagePrivate.Handle, segment: Connections.Segment] RETURNS [range: Connections.Range] ~ {
range ← SELECT TRUE FROM
segment.object = handle.inner.object => InnerRange[handle, segment],
segment.object = handle.bottom.object => range ← OuterRange[handle, segment],
segment.object = handle.right.object => OuterRange[handle, segment],
segment.object = handle.top.object => OuterRange[handle, segment],
segment.object = handle.left.object => OuterRange[handle, segment],
segment.object = handle.powerDistribution.power[bottom].object => PowerRange[handle, segment],
segment.object = handle.powerDistribution.power[right].object => PowerRange[handle, segment],
segment.object = handle.powerDistribution.power[top].object => PowerRange[handle, segment],
segment.object = handle.powerDistribution.power[left].object => PowerRange[handle, segment],
ENDCASE => Cabbage.Error[callingError, Rope.Cat["Invalid object in segment: ", segment.name]]};
InnerRange: PROC [handle: CabbagePrivate.Handle, segment: Connections.Segment] RETURNS [range: Connections.Range] ~ {
SELECT segment.side FROM
bottom =>
{origin: INT ← handle.inner.origin.x;
range ← [origin + segment.range.min, origin + segment.range.max]};
right =>
{origin: INT ← handle.size.x + handle.inner.origin.y;
range ← [origin + segment.range.min, origin + segment.range.max]};
top =>
{origin: INT ← handle.size.x +handle.size.y + (handle.size.x - handle.inner.origin.x);
range ← [origin - segment.range.max, origin - segment.range.min]};
left =>
{origin: INT ← 2*handle.size.x +handle.size.y + (handle.size.y - handle.inner.origin.y);
range ← [origin - segment.range.max, origin - segment.range.min]};
ENDCASE};
OuterRange: PROC [handle: CabbagePrivate.Handle, segment: Connections.Segment] RETURNS [range: Connections.Range] ~ {
SELECT RTBasic.OtherSide[segment.side] FROM
bottom =>
{origin: INT ← handle.bottom.origin.x;
range ← [origin + segment.range.min, origin + segment.range.max]};
right =>
{origin: INT ← handle.size.x + handle.right.origin.y;
range ← [origin + segment.range.min, origin + segment.range.max]};
top =>
{origin: INT ← handle.size.x +handle.size.y + (handle.size.x - handle.top.origin.x);
range ← [origin - segment.range.max, origin - segment.range.min]};
left =>
{origin: INT ← 2*handle.size.x +handle.size.y + (handle.size.y - handle.left.origin.y);
range ← [origin - segment.range.max, origin - segment.range.min]};
ENDCASE};
PowerRange: PROC [handle: CabbagePrivate.Handle, segment: Connections.Segment] RETURNS [range: Connections.Range] ~ {
SELECT RTBasic.OtherSide[segment.side] FROM
bottom =>
{origin: INT ← handle.powerDistribution.power[bottom].origin.x;
range ← [origin + segment.range.min, origin + segment.range.max]};
right =>
{origin: INT ← handle.size.x + handle.powerDistribution.power[right].origin.y;
range ← [origin + segment.range.min, origin + segment.range.max]};
top =>
{origin: INT ← handle.size.x +handle.size.y + (handle.size.x - handle.powerDistribution.power[top].origin.x);
range ← [origin - segment.range.max, origin - segment.range.min]};
left =>
{origin: INT ← 2*handle.size.x +handle.size.y + (handle.size.y - handle.powerDistribution.power[left].origin.y);
range ← [origin - segment.range.max, origin - segment.range.min]};
ENDCASE};
PosOfDivision: PROC [handle: CabbagePrivate.Handle, division: CabbagePrivate.Division] RETURNS [pos: INT] ~ {
SELECT division FROM
bottomLeft => pos ← handle.inner.origin.x;
bottomRight => pos ← handle.inner.origin.x + handle.inner.size.x;
rightBottom => pos ← handle.size.x + handle.inner.origin.y;
rightTop => pos ← handle.size.x + handle.inner.origin.y + handle.inner.size.y;
topRight => pos ← handle.size.x +handle.size.y + (handle.size.x - handle.inner.origin.x - handle.inner.size.x);
topLeft => pos ← handle.size.x +handle.size.y + (handle.size.x - handle.inner.origin.x);
leftTop => pos ← 2*handle.size.x +handle.size.y + (handle.size.y - handle.inner.origin.y - handle.inner.size.y);
leftBottom => pos ← 2*handle.size.x +handle.size.y + (handle.size.y - handle.inner.origin.y);
ENDCASE};
EachExitAction: TYPE = PROC [division: CabbagePrivate.Division, net: Connections.Net] RETURNS [quit: BOOLEANFALSE];
EnumerateExits: PROC [exitList: CabbagePrivate.ExitList, division: CabbagePrivate.Division, eachExitAction: EachExitAction] RETURNS [quit: BOOLEANFALSE] ~ {
FOR list: CabbagePrivate.ExitList ← exitList, list.rest WHILE ~quit AND list # NIL DO
exit: Connections.Net ← list.first;
quit ← eachExitAction[division, exit];
ENDLOOP};
CrossesBoundry: PROC [r1, r2: Connections.Range] RETURNS [crosses: BOOLEAN] ~ {
returns TRUE if either end but not both ends of r1 is within r2
crosses ←(r1.min <= r2.min AND r2.min <= r1.max) OR
(r1.min <= r2.max AND r2.max <= r1.max)};
ReallyCrossesBoundry: PROC [r1, r2: Connections.Range] RETURNS [reallyCrosses: BOOLEAN] ~ {
returns TRUE if either end but not both ends of r1 is within r2; r1 on boundry doesn't count
reallyCrosses ←(r1.min < r2.min AND r2.min < r1.max) OR
(r1.min < r2.max AND r2.max < r1.max)};
ProperSubset: PROC [r1, r2: Connections.Range] RETURNS [subset: BOOLEAN] ~ {
returns TRUE if r1 is within r2
subset ←((r2.min <= r1.min AND r1.min <= r2.max) AND
(r2.min <= r1.max AND r1.max <= r2.max))};
RopeFromRange: PROC [l: INT, range: Connections.Range] RETURNS [Rope.ROPE] ~ {
convert a range to rope scalled by lambda
RETURN[Rope.Cat["[", Convert.RopeFromInt[range.min/l], ", ", Convert.RopeFromInt[range.max/l], "["]]};
NetOnlyOnSide: PROC [handle: CabbagePrivate.Handle, net: Connections.Net, side: DABasics.Side] RETURNS [onlyOnSide: BOOLTRUE] ~ {
TRUE if net is only on specified side
EachSegment: Connections.EachSegmentAction ~ {
keep the segments of interest on objectDes
PROC [net: Net, segment: Segment] RETURNS [quit: BOOLEANFALSE]
IF segment.object # object.object OR segment.side # otherSide THEN {onlyOnSide ← FALSE; quit ← TRUE}};
object: CabbagePrivate.ObjectDescription ← SELECT side FROM
bottom => handle.bottom, right => handle.right, top => handle.top, left => handle.left,
ENDCASE => Cabbage.Error[programmingError, "Not suppose to happen."];
otherSide: DABasics.Side ← RTBasic.OtherSide[side];
[] ← Connections.EnumerateSegments[net, EachSegment]};
NumberPinsOnSide: PROC [handle: CabbagePrivate.Handle, net: Connections.Net, side: DABasics.Side] RETURNS [count: INT0] ~ {
counts pins in net on specified side
EachSegment: Connections.EachSegmentAction ~ {
keep the segments of interest on objectDes
PROC [net: Net, segment: Segment] RETURNS [quit: BOOLEANFALSE]
IF segment.object = object.object AND segment.side = otherSide THEN count ← count + 1};
object: CabbagePrivate.ObjectDescription ← SELECT side FROM
bottom => handle.bottom, right => handle.right, top => handle.top, left => handle.left,
ENDCASE => Cabbage.Error[programmingError, "Not suppose to happen."];
otherSide: DABasics.Side ← RTBasic.OtherSide[side];
[] ← Connections.EnumerateSegments[net, EachSegment]};
GetSize: PROC [handle: CabbagePrivate.Handle] RETURNS [hBottom, hTop, vLeft, vRight: INT] ~ {
vMiddle, hMiddle: INT;
l: INT = CDSimpleRules.GetTechnology[handle.parms.technologyKey].lambda;
powerLRWidth: INT ← handle.parms.outerLRChanWidth * l + handle.parms.powerLRCellWidth * l;
powerBTWidth: INT ← handle.parms.outerBTChanWidth * l + handle.parms.powerBTCellWidth * l;
IF handle.routeType = normal THEN {
vMiddle ← handle.bottom.size.y + powerBTWidth + handle.detailedRouting.channels[bottom].size.y + handle.inner.size.y + handle.detailedRouting.channels[top].size.y + powerBTWidth + handle.top.size.y;
hMiddle ← handle.left.size.x + powerLRWidth + handle.detailedRouting.channels[left].size.x + handle.inner.size.x + handle.detailedRouting.channels[right].size.x + powerLRWidth + handle.right.size.x}
ELSE {
hCenter: INT ← powerLRWidth + handle.detailedRoutingPL.channels[left].size.x + handle.inner.size.x + handle.detailedRoutingPL.channels[right].size.x + powerLRWidth;
hInner: INTMAX[hCenter, handle.detailedRoutingPL.switchBoxes[top].size.x, handle.detailedRoutingPL.switchBoxes[bottom].size.x];
vInner: INT ← powerBTWidth + handle.detailedRoutingPL.switchBoxes[bottom].size.y + handle.inner.size.y + handle.detailedRoutingPL.switchBoxes[top].size.y + powerBTWidth;
vMiddle ← handle.bottom.size.y + vInner + handle.top.size.y;
hMiddle ← handle.left.size.x + hInner + handle.right.size.x};
vLeft ← handle.bottomLeft.size.y + handle.left.size.y + handle.topLeft.size.y;
vRight ← handle.bottomRight.size.y + handle.right.size.y + handle.topRight.size.y;
hBottom ← handle.bottomLeft.size.x + handle.bottom.size.x + handle.bottomRight.size.x;
hTop ← handle.topLeft.size.x + handle.top.size.x + handle.topRight.size.x;
handle.size.y ← MAX[vLeft, vMiddle, vRight];
handle.size.x ← MAX[hBottom, hMiddle, hTop]};
DoCorners: PROC [handle: CabbagePrivate.Handle] ~ {
handle.bottomLeft.origin ← [0, 0];
handle.bottomRight.origin ← [handle.size.x - handle.bottomRight.size.x, 0];
handle.topRight.origin ← [handle.size.x - handle.topRight.size.x, handle.size.y - handle.topRight.size.y];
handle.topLeft.origin ← [0, handle.size.y - handle.topLeft.size.y]};
DoRoutingAreas: PROC [handle: CabbagePrivate.Handle] ~ {
l: INT = CDSimpleRules.GetTechnology[handle.parms.technologyKey].lambda;
outerLRChanWidth: INT ← handle.parms.outerLRChanWidth * l;
outerBTChanWidth: INT ← handle.parms.outerBTChanWidth * l;
powerLRWidth: INT ← outerLRChanWidth + handle.parms.powerLRCellWidth * l;
powerBTWidth: INT ← outerBTChanWidth + handle.parms.powerBTCellWidth * l;
routeType: CabbagePrivate.RouteType ← handle.routeType;
short hand to make the following easier to understand
leftInterior: INT ← handle.left.origin.x + handle.left.size.x; -- right of left pads
rightInterior: INT ← handle.right.origin.x;  -- left of right pads
bottomInterior: INT ← handle.bottom.origin.y + handle.bottom.size.y; -- top of bottom pads
topInterior: INT ← handle.top.origin.y;   -- bottom of top pads
leftOfInner: INT ← handle.inner.origin.x;  -- left of inner object
rightOfInner: INT ← handle.inner.origin.x + handle.inner.size.x; -- right of inner object
bottomOfInner: INT ← handle.inner.origin.y;  -- bottom of inner object
topOfInner: INT ← handle.inner.origin.y + handle.inner.size.y; -- top of inner object
IF routeType = normal THEN {
handle.detailedRouting.channels[bottom].origin ← [leftOfInner, bottomOfInner - handle.detailedRouting.channels[bottom].size.y];
handle.detailedRouting.channels[right].origin ← [rightOfInner, bottomOfInner];
handle.detailedRouting.channels[top].origin ← [leftOfInner, topOfInner];
handle.detailedRouting.channels[left].origin ← [leftOfInner - handle.detailedRouting.channels[left].size.x, bottomOfInner];
handle.detailedRouting.switchBoxes[bottomLeft].origin ← [leftInterior + powerLRWidth, bottomInterior + powerBTWidth];
handle.detailedRouting.switchBoxes[bottomRight].origin ← [rightOfInner, bottomInterior + powerBTWidth];
handle.detailedRouting.switchBoxes[topRight].origin ← [rightOfInner, topOfInner];
handle.detailedRouting.switchBoxes[topLeft].origin ← [leftInterior + powerLRWidth, topOfInner]}
ELSE { -- routeType = padLimited
handle.detailedRoutingPL.channels[right].origin ← [rightOfInner, bottomOfInner];
handle.detailedRoutingPL.channels[left].origin ← [leftOfInner - handle.detailedRoutingPL.channels[left].size.x, bottomOfInner];
handle.detailedRoutingPL.switchBoxes[bottom].origin ← [leftInterior + powerLRWidth, bottomInterior + powerBTWidth];
handle.detailedRoutingPL.switchBoxes[top].origin ← [leftInterior + powerLRWidth, topOfInner]};
the outside routing channels
handle.powerDistribution.channels[bottom].origin ← [leftInterior + outerLRChanWidth, bottomInterior];
handle.powerDistribution.channels[right].origin ← [rightInterior - outerLRChanWidth, bottomInterior + outerBTChanWidth];
handle.powerDistribution.channels[top].origin ← [leftInterior + outerLRChanWidth, topInterior - outerBTChanWidth];
handle.powerDistribution.channels[left].origin ← [leftInterior, bottomInterior + outerBTChanWidth];
the power channels
handle.powerDistribution.power[bottom].origin ← [leftInterior + powerLRWidth, bottomInterior + outerBTChanWidth];
handle.powerDistribution.power[right].origin ← [rightInterior - powerLRWidth, bottomInterior + powerBTWidth];
handle.powerDistribution.power[top].origin ← [leftInterior + powerLRWidth, topInterior - powerBTWidth];
handle.powerDistribution.power[left] .origin← [leftInterior + outerLRChanWidth, bottomInterior + powerBTWidth];
the outside switchbox corners
handle.powerDistribution.switchBoxes[bottomLeft].origin ← [leftInterior, bottomInterior];
handle.powerDistribution.switchBoxes[bottomRight].origin ← [rightInterior - outerLRChanWidth, bottomInterior];
handle.powerDistribution.switchBoxes[topRight].origin ← [rightInterior - outerLRChanWidth, topInterior - outerBTChanWidth];
handle.powerDistribution.switchBoxes[topLeft].origin ← [leftInterior, topInterior - outerBTChanWidth];
the outside power rail corners
handle.powerDistribution.powerCorners[bottomLeft].origin ← [leftInterior + outerLRChanWidth, bottomInterior + outerBTChanWidth];
handle.powerDistribution.powerCorners[bottomRight].origin ← [rightInterior - powerLRWidth, bottomInterior + outerBTChanWidth];
handle.powerDistribution.powerCorners[topRight].origin ← [rightInterior - powerLRWidth, topInterior - powerBTWidth];
handle.powerDistribution.powerCorners[topLeft].origin ← [leftInterior + outerLRChanWidth, topInterior - powerBTWidth]};
Member: PROC [item: Rope.ROPE, list: LIST OF Rope.ROPE] RETURNS [BOOLEAN] ~ {
Return TRUE if item is on list
UNTIL list = NIL DO
IF Rope.Equal[list.first, item] THEN RETURN [TRUE];
list ← list.rest;
ENDLOOP;
RETURN [FALSE]};
Router Callbacks
EnumerateChannelNets: Route.EnumerateChannelNetsProc ~ {
PROC [channelData: REF, eachNet: EachChannelNetProc];
ChannelNet: Connections.EachNetAction ~ {
PROC [key: Key, net: Net] RETURNS [quit: BOOLFALSE];
IF net.netDat # NIL THEN {
netDat: NetInChan ← NARROW[net.netDat];
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}};
connections: Connections.Table ← NARROW[channelData, CabbagePrivate.Handle].connections;
[] ← Connections.EnumerateNets[connections, 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};
EnumerateSwitchBoxNets: Route.EnumerateSwitchBoxNetsProc ~ {
PROC [switchBoxData: REF, eachNet: EachSwitchBoxNetProc];;
SwitchBoxNet: Connections.EachNetAction ~ {
PROC [key: Key, net: Net] RETURNS [quit: BOOLFALSE];
IF net.netDat # NIL THEN {
netDat: NetInChan ← NARROW[net.netDat];
FOR segs: LIST OF Segment ← netDat.segsInNet, segs.rest UNTIL segs = NIL DO
seg: Segment ← segs.first;
eachNet[name: seg.name,
enumeratePins: SwitchBoxSignalPins,
trunkSize: seg.trunkSize,
switchBoxData: switchBoxData,
netData: seg];
ENDLOOP}};
connections: Connections.Table ← NARROW[switchBoxData, CabbagePrivate.Handle].connections;
[] ← Connections.EnumerateNets[connections, SwitchBoxNet]};
SwitchBoxSignalPins: Route.EnumerateSwitchBoxPinsProc ~ {
PROC [switchBoxData, netData: REF, eachPin: EachSwitchBoxNetProc];
seg: Segment ← NARROW[netData];
FOR pins: LIST OF Pin ← seg.pinsInSeg, pins.rest UNTIL pins = NIL DO
pin: Pin ← pins.first;
eachPin[side: pin.side, min: pin.min, max: pin.max, depth: pin.depth, layer: pin.layer];
ENDLOOP};
}.