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 = {
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.ROPE _ NIL,
trunkSize: INT _ 0,
leftOrBottomExit, rightOrTopExit: BOOL _ FALSE,	-- used for channels only (not SB's)
pinsInSeg: LIST OF Pin _ NIL		-- pins for this net on this channel
];

Pin: TYPE = REF PinRec;
PinRec: TYPE = RECORD[
min, max, depth: CD.Number _ 0,
layer: CD.Layer,
side: DABasics.Side
];

PowerMode: TYPE = {makeTwoPinPowerNets, busPower, matchPin, likeOtherNets, none};
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]};

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];
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 ~ {
IF Rope.Equal[net.name, "Vdd"] THEN handle.vddNet _ net
ELSE IF Rope.Equal[net.name, "Gnd"] THEN handle.gndNet _ net};

EachNet: Connections.EachNetAction ~ {
EachSegment: Connections.EachSegmentAction ~ {
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};
DistributePower: PUBLIC PROC [handle: CabbagePrivate.Handle] ~ {
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] ~ {
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];

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] ~ {

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

[] _ Connections.EnumerateNets[handle.connections, InitNet];

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: INT _ MIN[rect.y1, rect.y2 -  chWidth];
retrieveRect _ NEW[DABasics.Rect _ [rect.x1, dist, rect.x2, rect.y2]]};
right => {
dist: INT _ MAX[rect.x2, rect.x1 + chWidth];
retrieveRect _ NEW[DABasics.Rect _ [rect.x1, rect.y1, dist, rect.y2]]};
top => {
dist: INT _ MAX[rect.y2, rect.y1 + chWidth];
retrieveRect _ NEW[DABasics.Rect _ [rect.x1, rect.y1, rect.x2, dist]]};
left => {
dist: INT _ MIN[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;
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] ~ {

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];

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] ~ {

ChanPublics: CoreGeometry.EachWirePinProc ~ {

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 {
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: INT _ SELECT chipSide FROM
bottom, top => (max-min - irSize.x)/2,
left, right => (trunkWidth - irSize.x)/2,
ENDCASE => Cabbage.Error[programmingError, "Not suppose to happen"];
yOffset: INT _ SELECT 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];

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 ~ {
EachSegment: Connections.EachSegmentAction ~ {

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 {
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: CD.Position _ RTBasic.IRSize[via];
xOffset: INT _ SELECT 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: INT _ SELECT 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: INT _ SELECT chipSide FROM
bottom, top => handle.inner.origin.x,
right, left => handle.inner.origin.y,
ENDCASE => Cabbage.Error[programmingError, "Not suppose to happen."];
channelOrigin: INT _ SELECT 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"];
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"];

[] _ CoreGeometry.EnumerateNonOverlappingSides[mode.decoration, channel.cellType, ChanPublics];
[] _ Connections.EnumerateNets[handle.connections, EachNet];

power.object _ CDRoutingObjects.CreateRoutingObject
[CDRoutingObjects.CreateNodes[objectNets], interestRect];
power.size _ RTBasic.IRSize[power.object];
power.cellType _ ExtractChannel[power, insideParms]};

RouteOutsideSwitchBoxes: PROC [handle: CabbagePrivate.Handle] ~ {

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] ~ {

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."];

[] _ Connections.EnumerateNets[handle.connections, InitNet];

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] ~ {

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;

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]];
powerCorner.size _ RTBasic.IRSize[powerCorner.object]};
GlobalRoute: PUBLIC PROC [handle: CabbagePrivate.Handle] ~ {
EachNet: Connections.EachNetAction ~ {
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[]] ~ {

InsertPinsFromInner[handle, newConnections];

InsertPinsFromPower[handle, newConnections, bottom];
InsertPinsFromPower[handle, newConnections, right];
InsertPinsFromPower[handle, newConnections, top];
InsertPinsFromPower[handle, newConnections, left]};

InsertPinsFromInner: PROC [handle: CabbagePrivate.Handle, newConnections: Connections.Table] ~ {
EachNet: Connections.EachNetAction ~ {
EachSegment: Connections.EachSegmentAction ~ {
IF segment.object = handle.inner.object THEN {
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]};

[] _ Connections.EnumerateNets[handle.connections, EachNet]};

InsertPinsFromPower: PROC [handle: CabbagePrivate.Handle, newConnections: Connections.Table, chipSide: RTBasic.Side] ~ {
ChanPublics: CoreGeometry.EachWirePinProc ~ {
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] ~ {

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 {
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}};

FindStartEndSegments: PROC [handle: CabbagePrivate.Handle, net: Connections.Net, sortedSegments: CabbagePrivate.SegmentSeq] RETURNS [segmentPair: CabbagePrivate.SegmentPair _ [NIL, NIL]] ~ {

minLength: INT _ LAST[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"]};

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}};
DetailedRoute: PUBLIC PROC [handle: CabbagePrivate.Handle] ~ {

RouteChannels[handle];
AdjustPositions[handle];
IF handle.routeType = normal THEN RouteSwitchBoxes[handle]
ELSE RouteSwitchBoxesPL[handle];
AdjustPositions[handle]};

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]}};

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;

[] _ Connections.EnumerateNets[handle.connections, InitNet];

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;
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]};

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]};

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: BOOL _ FALSE] 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];

[] _ 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: BOOL _ FALSE] 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."];
[] _ 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]};
MakeChip: PUBLIC PROC [handle: CabbagePrivate.Handle] RETURNS [chip: CD.Object _ CDCells.CreateEmptyCell[]] ~ {
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];

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};

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]};
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] ~ {

EnterPowerOnInner: Connections.EachNetAction ~ {
EachSegment: Connections.EachSegmentAction ~ {
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 ~ {
EachSegment: Connections.EachSegmentAction ~ {
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 ~ {
EachSegment: Connections.EachSegmentAction ~ {
IF (segment.object = objectDes.object AND segment.side = pinSide AND useNet) THEN {
useThisPin: BOOLEAN _ TRUE;
newRange: Connections.Range;
name: Rope.ROPE _ NIL;
adjustedRange: Connections.Range _ [outerOrigin + segment.range.min, outerOrigin + segment.range.max];
IF ProperSubset[adjustedRange, midRange ] THEN { 
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 {
name _ IF powerNet THEN Rope.Cat[net.name, lowerSuffix] ELSE net.name;
IF RefTab.Insert[netTable, name, NIL] THEN { 
pinWidth: INT _ IF 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 {
name _ IF powerNet THEN Rope.Cat[net.name, upperSuffix] ELSE net.name;
IF RefTab.Insert[netTable, name, NIL] THEN {
pinWidth: INT _ IF 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: INT _ IF ProperSubset[newRange, innerRange] THEN innerSpacing ELSE outerSpacing;
trunkWidth: INT _ IF 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: INT _ SELECT pinSide FROM
bottom, top => handle.inner.origin.x,
right, left => handle.inner.origin.y,
ENDCASE => Cabbage.Error[programmingError, "Not suppose to happen."];
outerOrigin: INT _ SELECT 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]];

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];

[] _ 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
EachNet: Connections.EachNetAction ~ {
EachSegment: Connections.EachSegmentAction ~ {
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.ROPE _ IF 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.ROPE _ NIL;
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: INT _ SELECT 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

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

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: INT _ MAX[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: INT _ MAX[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 ~ {
EachSegment: Connections.EachSegmentAction ~ {
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: INT _ SELECT 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] ~ {

EachExit: EachExitAction ~ {
powerNet: BOOLEAN _ Rope.Equal[net.name, "Vdd"] OR Rope.Equal[net. name, "Gnd"];
IF ~powerNet THEN {
trunkWidth: INT _ IF 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

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

ChanPublics: CoreGeometry.EachWirePinProc ~ {
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: INT _ IF 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] ~ {
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];
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] ~ {
segment: Segment _ LookUpSegment[netDat, name];
SELECT side FROM
bottom, left => segment.leftOrBottomExit _ TRUE;
right, top => segment.rightOrTopExit _ TRUE;
ENDCASE;
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] ~ {
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]}};
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] ~ {
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] ~ {

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] ~ {

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] ~ {

range: Connections.Range _ RangeOf[handle, segment];
RETURN[(range.min+range.max)/2]};

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: BOOLEAN _ FALSE];

EnumerateExits: PROC [exitList: CabbagePrivate.ExitList, division: CabbagePrivate.Division, eachExitAction: EachExitAction] RETURNS [quit: BOOLEAN _ FALSE] ~ {

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] ~ {
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] ~ {
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] ~ {
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] ~ {
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: BOOL _ TRUE] ~ {
EachSegment: Connections.EachSegmentAction ~ {
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: INT _ 0] ~ {
EachSegment: Connections.EachSegmentAction ~ {
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: INT _ MAX[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;
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]};

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];

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];

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];
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] ~ {
UNTIL list = NIL DO
IF Rope.Equal[list.first, item] THEN RETURN [TRUE];
list _ list.rest;
ENDLOOP;
RETURN [FALSE]};
EnumerateChannelNets: Route.EnumerateChannelNetsProc ~ {
ChannelNet: Connections.EachNetAction ~ {
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 ~ {

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 ~ {
SwitchBoxNet: Connections.EachNetAction ~ {
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 ~ {

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};
}.

���%��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

Local Types
routing description for a net on a channel
pin description for pins in a net on a channel
how to handle power
Initialization
Define the routing design rules.  technologyKey values are predefinded for now. horizLayer, vertLayer should be "poly", "metal" or "metal2".

put in wider spacings at sides of channels
PROC [key: Key, net: Net] RETURNS [quit: BOOLEAN _ FALSE]
PROC [key: Key, net: Net] RETURNS [quit: BOOLEAN _ FALSE]
PROC [net: Net, segment: Segment] RETURNS [quit: BOOLEAN _ FALSE]
Power Distribution
make the power distribution channels
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
route the outside channels
route one of the outside channels
clear the routing specification for this channel
construct the bonding objects to pass to the channel router

compare channel.size to required channel width
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
construct the power distribution cells
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 
PROC [wire: Wire, min, max: INT, side: Side, layer: CD.Layer] RETURNS [quit: BOOL _ FALSE];
store the pins on the appropriate side of the adjacent channel
add the via at the right place
-- irSize stuff should be remove in Cabbage25
distinguish constructed Vdd and Gnd by (Vdd | Gnd)--
other nets may start with Vdd and Gnd
PROC [key: Key, net: Net] RETURNS [quit: BOOLEAN _ FALSE]
store the power pins on the appropriate side of the inner object
PROC [net: Net, segment: Segment] RETURNS [quit: BOOLEAN _ FALSE]
add the via at the right place
irSize to go away in Cabbage25

construct power trunks
build the branches
RTBasic.RepositionCell[power.object];
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
construct a switchbox for one of the power distribution corners
clear the routing specification for this channel
add pins around the switch box
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
construct the corner power distribution cells
RTBasic.RepositionCell[powerCorner.object];
Global Routing
find the strategic paths for all nets
PROC [key: Key, net: Net] RETURNS [quit: BOOLEAN _ FALSE]
Make a new set of connections to account for new power ring
store the net and the segments on the net
now do the power objects
insert all of the pins from the inner object into the new table
PROC [key: Key, net: Net] RETURNS [quit: BOOLEAN _ FALSE]
PROC [net: Net, segment: Segment] RETURNS [quit: BOOLEAN _ FALSE]
make a new copy of the segment and put it in the table
store the net and the segments on the net
insert the pins on the appropriate side into the new table
PROC [wire: Wire, min, max: INT, side: Side, layer: CD.Layer] RETURNS [quit: BOOL _ FALSE];
store the pins on the appropriate side of the adjacent channel
Sort the segments on this net in order arround the periphery 
Use Reverse to get a new copy of the list because Sort is destructive
Find the start and end segments of a net arround the periphery
Add this net to the global route
Detailed Routing
route all of the channels or just the left and right channels depending on routeType
route one of the channels
clear the routing specification for this channel
construct the bonding objects to pass to the channel router

compare channel.size to required channel width
adjust the positions of everything to account for the actual channel widths
route all of the switchBoxes (the corners)
route the bottom and top switchBoxes
clear the routing specification for this channel

clear the routing specification for this channel
Object Generation
construct the chip;  all of the peices have been constructed
first include the input cells
next include the signal routing
finally the power cells, outside routing channels and switchboxes
Add Pin Operations
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
PROC [key: Key, net: Net] RETURNS [quit: BOOLEAN _ FALSE]
store the power pins on the appropriate side of the inner object
PROC [net: Net, segment: Segment] RETURNS [quit: BOOLEAN _ FALSE]
PROC [key: Key, net: Net] RETURNS [quit: BOOLEAN _ FALSE]
store the power pins on the appropriate side of the inner object
PROC [net: Net, segment: Segment] RETURNS [quit: BOOLEAN _ FALSE]
examine the nets on the outer object: objectDes
PROC [key: Key, net: Net] RETURNS [quit: BOOLEAN _ FALSE]
keep the segments of interest on objectDes 
PROC [net: Net, segment: Segment] RETURNS [quit: BOOLEAN _ FALSE]
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
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
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
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
process the inner power obstacles an the find places for the outer signals
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
 
PROC [key: Key, net: Net] RETURNS [quit: BOOLEAN _ FALSE]
PROC [net: Net, segment: Segment] RETURNS [quit: BOOLEAN _ FALSE]
add pins to routing for side of channel or switchbox; input to router
add pins to routing for side of channel or switchbox; input to router
PROC [key: Key, net: Net] RETURNS [quit: BOOLEAN _ FALSE]
PROC [net: Net, segment: Segment] RETURNS [quit: BOOLEAN _ FALSE]
add pins from global routing for end of channel; input to router
PROC [division: CabbagePrivate.Division, net: Connections.Net] RETURNS [quit: BOOLEAN _ FALSE];
have to get the net from valid data structure;
includePowerNets, makeTwoPinPowerNets: BOOL] ~ {
add pins for the channel; use the full side of channel with pins on side
add pins for for the channel; use the pins on side; range is the span along that side
PROC [wire: Wire, min, max: INT, side: Side, layer: CD.Layer] RETURNS [quit: BOOL _ FALSE];
add decoration for public; wire is an unbound wire
add a pin to the appropriate segment in net
first size definition wins; 0 is default
add a channel end connection
first size definition wins; 0 is default
find an existing segment by name; if none, make a NEW one
Utility Procedures
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
adjust the vertical and horizontal dimension
extract connectivity for the channel
Find the position of a segment projected to the periphery.  The lower left corner is the origin.
Find the range of a segment projected to the periphery.  The lower left corner is the origin.
returns TRUE if either end but not both ends of r1 is within r2
returns TRUE if either end but not both ends of r1 is within r2; r1 on boundry doesn't count 
returns TRUE if r1 is within r2
convert a range to rope scalled by lambda
TRUE if net is only on specified side
keep the segments of interest on objectDes 
PROC [net: Net, segment: Segment] RETURNS [quit: BOOLEAN _ FALSE]

counts pins in net on specified side
keep the segments of interest on objectDes 
PROC [net: Net, segment: Segment] RETURNS [quit: BOOLEAN _ FALSE]


short hand to make the following easier to understand
the outside routing channels
the power channels
the outside switchbox corners

the outside power rail corners
Return TRUE if item is on list
Router Callbacks
PROC [channelData: REF, eachNet: EachChannelNetProc];
PROC [key: Key, net: Net] RETURNS [quit: BOOL _ FALSE];
PROC [channelData, netData: REF, eachPin: EachChannelPinProc];
PROC [switchBoxData: REF, eachNet: EachSwitchBoxNetProc];;
PROC [key: Key, net: Net] RETURNS [quit: BOOL _ FALSE];
PROC [switchBoxData, netData: REF, eachPin: EachSwitchBoxNetProc];
Ê>��˜�code–
"Cedar" stylešœ™KšœB™BKšœ0Ïk™3Kšœ7™:K™3K™3K™)Kšœ*™-Kšœ*™-K™�—Kš	œ4œØ˜—K˜�šÏnœœ˜Kšœ$œÇ˜ôKšœ˜—headšÏl™Kšœ*™*Kšœœœ˜#šœœœ˜KšœœÏc˜6Kšœœœœ (˜JKšœ˜K˜�—Kšœ	œœ˜šœœœ˜Kšœœœ˜Kšœœ˜Kšœ"œœ $˜TKšœœœœ $˜BK˜K˜�—Kšœ.™.Kšœœœ˜šœœœ˜Kšœœ˜Kšœœ˜Kšœ˜Kšœ˜K˜�—Kšœ™KšœœB˜Q—šŸ™šžœœœOœRœ'œ#˜‘Kšœ	œR˜^Kšœ˜Kšœ(˜(Kšœœ&˜DKšœœ"˜<šœœ˜Kšœœ#˜?—šœ˜Kšœœ&˜D—Kšœ^˜^Kšœœœ˜3Kšœ˜K˜�—KšœŒ™Œšžœœ œ.˜lK˜�KšœœG˜QKšœœF˜PKšœœ ˜1K˜�Kšœ°˜°Kšœ­˜­Kšœ±˜±Kšœ®˜®K˜�Kšœb˜bKšœ`˜`Kšœd˜dKšœb˜bK™�Kšœ*™*Kšœc˜cKšœb˜bK˜�—šžœœnœ˜ŠK˜�KšÏgœœB˜HKšœ+¡œ¡œ˜1K˜�Kšœ-¡œ¡œ˜3Kšœ+¡œ¡œ˜1Kšœ'¡œ¡œ˜-Kšœ)¡œ¡œ˜/K˜�Kšœ_˜_Kšœb˜bKšœY˜YKšœW˜WK˜�—š
žœœ
œœœ-˜tK˜�Kšœ˜šœ
œ˜Kšœ˜šœ˜Kšœ#˜#Kšœœ˜%Kšœœ˜'—K˜�——šžœœ$˜9K˜�Kšœœ˜"Kšœ1˜1K˜�KšœS˜SKšœt˜tKšœj˜jKšœO˜OK˜�Kšœ˜Kšœ˜K˜�—šž	œœ$˜3K˜�šžœ˜/Kšœœœœ™9Kšœœ˜7Kšœœœ˜>K˜�—šžœ˜&Kšœœœœ™9šžœ#˜.Kšœœœœ™AKšœœ7˜I—K˜�Kšœœ:˜Wšœœ˜Kšœ5˜5—Kšœ=˜=K˜�—K˜1KšœE˜EKšœ=˜=K˜�—šž
œœœ+œ˜UK˜�Kšœœ˜'Kšœœ1˜<Kšœœ-˜8Kšœœ-˜8Kšœœ/˜:š
œœœœœ˜pKšœc˜cKšœ=˜=—Kšœ&˜&——šŸ™šžœœœ$˜@Kšœ$™$Kš¡œœB˜HKšœJ˜JKšœH˜HKšœL˜LKšœJ˜JKšœœ¦˜µKšœœ¡˜¯Kšœœ$¡œ˜FKšœœ$¡œ˜GKšœ˜Kšœ˜Kšœ ˜ Kšœ;˜;Kšœ:˜:Kšœ˜K˜�—šžœœ$˜>Kšœi™iKšœ§™§Kš¡œœB˜HKšœœ#¡œ˜:Kšœœ#¡œ˜:Kšœœ#¡œ˜:Kšœœ#¡œ˜:KšœK˜KKšœI˜IKšœŽ˜ŽKšœt˜tKšœi˜iKšœ˜Kšœq˜qK˜�Kšœ™Kšœ³˜³Kšœ®˜®Kšœª˜ªKšœ¬˜¬K˜�—šžœœ ˜9Kšœ0 ˜GKšœ ?˜TKšœ5 ©˜ÞKšœ	œ '˜8Kšœ˜šœ&˜-Kšœ!™!—K˜�Kšžœ,œ˜8K˜�Kšœ-˜-Kšœœ˜ Kšœ˜Kšœ3˜3Kš	œœ
œ
œœ˜IKšœœ ˜0K˜�Kšœ0™0Kšœ<˜<K˜�Kšœ;™;Kšœo˜oKšœTœ5˜KšœX˜XKšœk˜kK˜�Kšœ¯œœn˜¼K˜�Kšœ1˜1šœ˜šœ˜Kšœœœ˜-Kšœœ5˜G—šœ
˜
Kšœœœ˜,Kšœœ5˜G—šœ˜Kšœœœ˜,Kšœœ5˜G—šœ	˜	Kšœœœ˜,Kšœœ5˜G—Kšœ˜K˜�—Kšœ€œ:˜½K™�Kšœ.™.Kšœ.˜.šœ
œ˜Kšœ˜Kšœ˜Kšœ˜
—Kšœœz˜–Kšœ3˜3K˜�—šžœœ=œ˜aKšœm™mšœ¥™¥K˜�—Kš¡œœB˜HKšœœ#¡œ˜:Kšœœ#¡œ˜:Kšœœ#¡œ˜IKšœœ#¡œ˜IKšœI˜IKšœK˜KKšœG˜GKšœI˜IKšœ†˜†Kšœ‡˜‡K˜�Kšœ&™&KšœÅ˜ÅKšœ¿˜¿Kšœ¼˜¼Kšœ½˜½K˜�—šž
œœ ˜0Kšœ! /˜PKšœ C˜]Kšœ 4˜NKšœœ .˜@Kšœœ ˜1Kšœ2˜2Kšœ$˜+K™3Kšœj™jKšœO™OK˜�šžœ"˜-Kšœœœœœœ™[K™>K˜�šžœœœœ˜Qšœœœ
˜'Kšœ!˜!Kšœ6˜6Kšœ˜Kšœ8˜8Kšœ=˜D—šœ
˜Kšœh˜hKšœh˜hKšœ=˜D—šœœ˜"Kšœ™Kš -™-šœœ
œ
˜%KšœT¡œœ˜\KšœT¡œœ˜]Kšœ=˜D—Kšœœ ˜*šœ	œœ
˜#Kšœ&˜&Kšœ)˜)Kšœ=˜D—šœ	œœ
˜#Kšœ)˜)Kšœ&˜&Kšœ=˜D—šœœœ
˜*KšœM˜MKšœJ˜JKšœK˜KKšœL˜LKšœ=˜D—Kšœ)˜)—K˜�—šžœœ˜K˜�Kšœœ1˜CKšœœ0˜Ašœ
˜šœ˜Kšœn˜nKšœ„˜„Kšœm¡œœ/˜¢—šœ˜Kšœ‡˜‡Kšœl˜lKšœm¡œœ.˜¡—šœ	˜	Kšœn˜nKšœ„˜„Kšœm¡œœ/˜¢—šœ
˜
Kšœ‡˜‡Kšœl˜lKšœm¡œœ.˜¡—Kšœ˜	—K˜�—KšœN˜NKšœœ˜%Kšœ2 ™4K™%K˜�šœœ˜šœœ˜KšœT˜TKšœw˜wKšœ˜——K˜�—šžœ˜&Kšœœœœ™9K™@šžœ#˜.Kšœœœœ™AK˜�šžœœœœ˜Qšœ	œœ
˜+Kšœ9˜9Kšœ˜Kšœ7˜7Kšœ ˜ Kšœ=˜D—šœ
˜KšœŒ˜ŒKšœŒ˜ŒKšœ˜—šœœ˜"Kšœ™šœœ
œ
˜%Kšœp¡œœ˜xKšœp¡œœ˜yKšœ=˜D—K˜�Kšœ™K˜�Kšœœ ˜*šœ	œœ
˜#KšœB˜BKšœ)˜)Kšœ=˜D—šœ	œœ
˜#Kšœ)˜)KšœB˜BKšœ=˜D—šœœœ
˜*KšœM˜MKšœJ˜JKšœK˜KKšœL˜LKšœ=˜D—Kšœ-˜-—K˜�—Kšœf˜fšœ&œœ˜Jšœœ˜Kšœd˜dKšœX˜XKšœ˜
———K˜�Kšœ6˜6K˜�—š
ž
œœœœœ˜Nšœœœ
˜-Kšœ1˜1Kšœ1˜1Kšœ=˜D—Kšœœ/˜8Kšœ,˜,K˜�—Kšœ)˜)Kš¡œœB˜HKšœ
œ'˜6Kšœœ(˜8Kšœ
œ1˜AKšœ
œ2˜BKšœI˜Išœœ
˜3Kšœ:˜:Kšœ=˜D—šœ
œœ
˜'Kšœ%˜%Kšœ%˜%Kšœ>˜E—šœœœ
˜)Kšœ ˜ Kšœ ˜ Kšœ>˜E—šœœœ
˜,Kšœ6˜6Kšœ6˜6Kšœ=˜D—K™�Kšœ™šœœœ
˜1Kšœ0˜0Kšœ5˜5Kšœ.˜.Kšœ7˜7Kšœ=˜D—šœœœ
˜1Kšœ9˜9Kšœ-˜-Kšœ7˜7Kšœ/˜/Kšœ=˜D—Kšœ.˜.Kšœ/˜/K˜�Kšœ™Kšœ_˜_Kšœ<˜<K˜�šœ3˜3Kšœ9˜9—Kšœ%™%Kšœ*˜*Kšœ5˜5K˜�—šžœœ$˜AKšœ ™ K˜�KšœI˜IKš¡œœB˜HKšœœ#¡œ˜:Kšœœ#¡œ˜:KšœŽ˜ŽKšœg˜gKšœ—˜—Kšœ_˜_K˜�Kšœœœ˜Kšœ‡œœ˜”Kšœ“œœ˜ KšœŠœœ˜˜K˜�—šžœœ®œœ(˜þKšœ?™?K˜�Kšžœ,œ˜8K˜�Kšœ\˜\K˜�šœ˜šœ˜Kšœ"˜"Kšœ˜Kšœ>˜E——šœ˜šœ˜Kšœ˜Kšœ˜Kšœ>˜E——šœ,˜,šœ˜Kšœ)˜)Kšœ ˜ Kšœ>˜E——šœ,˜,šœ˜Kšœ#˜#Kšœ&˜&Kšœ>˜E——K˜�Kšœ0™0Kšœ<˜<K˜�Kšœ™Kšœ‡ *˜±KšœSœ ˜‰KšœRœ ˜ˆKšœ† 0˜¶K˜�Kšœ¬œ¿˜îKšœ2˜2Kšœ7˜7K˜�—šžœœ=œ˜`Kšœ-™-šœ¥™¥K˜�—Kš¡œœB˜HKšœI˜IKšœK˜KKšœG˜GKšœI˜IK˜�Kšœ-™-KšœÁ˜ÁKšœ»˜»KšœÃ˜ÃKšœ¾˜¾K˜�—šžœœ˜Jšœ!˜!Jšœ"˜"Jšœœ˜Jšœœ˜Jšœ)˜)Jšœ*˜*Jšœ)˜)šœ(˜(Jšœ*˜1—Jš¡œœB˜HJšœ
œ,˜8Jšœ
œ-˜9Jšœœ)˜6šœ
œ˜Jšœ!¡œ#¡œ˜H—šœœ˜JšœM¡œ˜O—šœ
œ˜JšœM¡œ˜O—JšœœN˜XJšœœN˜XJšœœP˜ZJšœœN˜XJšœœK¡œœ˜Zšœœœ˜/Jšœ3˜3Jšœ9˜9Jšœ<˜<JšœA˜AJšœœ˜—šœœœ˜/JšœY˜YJšœO˜OJšœR˜RJšœH˜HJšœœ˜—šžœœœœœœ˜Dšœ
œ1˜=Jšœ˜šœœ˜Jšœ˜Jšœœ
˜Jšœ˜Jšœ˜Jšœœ˜——Jšœ*˜*—Kšœ)˜)Jšœ%˜%Jšœ'˜'Jšœ'˜'Jšœ%˜%Jšœ'˜'Jšœ'˜'šœ9˜9KšœG˜G—Jšœ+™+Jšœ7˜7——šŸ™šžœœœ$˜<Kšœ%™%šžœ˜&Kšœœœœ™9KšœF˜Fšœœœ˜Kšœ\˜\Kšœ0˜0—K˜�—K˜?Kšœ9˜9K˜�—šžœœ!œG˜‡Kšœ;™;K˜�Kšœ)™)Kšœ,˜,K˜�Kšœ™Kšœ4˜4Kšœ3˜3Kšœ1˜1Kšœ3˜3K˜�—šžœœG˜`Kšœ?™?šžœ˜&Kšœœœœ™9šžœ#˜.Kšœœœœ™Ašœ&œ˜.Kšœ6™6Kšœ"œˆ˜­Kšœœ˜4Kšœ;˜;K˜�——Kšœœ:˜WKšœ9˜9Kšœ6˜6K˜�—Kšœ)™)Kšœ=˜=K˜�—šžœœ_˜xKšœ:™:šžœ"˜-Kšœœœœœœ™[K™>Kšœœ˜%šœœ˜KšœœŽ˜°KšœC˜CKšœœ˜+Kšœ4˜4——K˜�Kšœ7˜7Kšœ[˜[Kšœ˜K˜�—šžœœ7œ.œ˜†Kšœ=™=K˜�šž
œB˜OK˜�—šž
œ˜ Kšœœ˜šœ˜Kšœœ˜%Kšœœ	˜&—Kšœ"˜(K˜�—Kšœœ˜Kšœ+œ˜0Kšœ7˜7šœœ˜KšœE™EKšœ"œ˜BKšœ=˜=Kšœœ,˜@š	œœ œœ˜FK˜Kšœœ˜(Kšœ ˜ Kšœ˜Kšœ˜
——K˜�—Kšœ>™>š
žœœbœ-œœ˜¾K˜�Kšœœœœ˜Kšœœ%˜3Kšœœ˜Kšœ&˜&šœœœ#˜6šœ(œ˜0Kšœ#˜#Kšœ˜KšœE˜E—šœ˜Kšœ˜Kšœ˜Kšœ:˜:—šœœ˜Kšœ˜Kšœ˜Kšœ˜—Kšœ˜—š
œœœœœ˜9K˜:—K˜�—Kšœ ™ šžœœc˜|K˜�Kšœœ#˜,Kšœœ#˜,šœ
œ˜šœœ˜<šœ!œ!˜KKšœ$œ(˜P—Kšœ˜——šœ˜šœœ˜<šœ!œ!˜JKšœ$œ(˜P—Kšœ˜
————šŸ™šž
œœœ$˜>K˜�Kšœ˜K˜Kšœœ˜:Kšœ˜ K˜K˜�—KšœT™Tšž
œœ$˜7K˜�KšœI˜IKšœG˜GKšœe˜eKšœd˜dK˜�šœœ˜#Kšœ¦˜¦KšœŸ˜ŸKšœ—˜—Kšœš˜š—šœ ˜ Kšœ¡˜¡Kšœž˜ž—K˜�—Kšœ™šžœœ ˜2Kšœ) ˜DKšœ ?˜ZKšœ' /˜VKšœ /˜JKšœ˜Kšœ&˜-K˜�Kšžœ,œ˜8K˜�Kšœ-˜-Kšœœ˜ Kšœ˜Kšœœ˜'Kšœœ ˜'Kšœœ &˜9Kšœ7˜7Kš	œœœœœ˜QK˜�Kšœ0™0Kšœ<˜<K˜�Kšœ;™;Kšœb˜bKšœdœ˜iKšœ-˜-Kšœ@˜@K˜�KšœÉœn˜ºK˜�Kšœ1˜1šœ
˜šœ˜KšœS˜SKšœœœœA˜k—šœ
˜
KšœP˜PKšœœœ$œ/˜k—šœ˜KšœP˜PKšœœœ-œ&˜k—šœ	˜	KšœS˜SKšœœœ	œJ˜k—Kšœ˜K˜�—Kšœ€œ:˜½K™�Kšœ.™.Kšœ.˜.šœ
œ
˜!Kšœ˜Kšœ˜Kšœ˜
—Kšœœj˜ƒKšœ3˜3K˜�—KšœK™KKšœ*™*šžœœ$˜:K˜�KšœI˜IK˜�Kšœg˜gKšœj˜jKšœl˜lKšœe˜eK˜�Kšœ‡œœ˜”K˜�KšœŠœœ˜—K˜�Kšœœœ˜ŽK˜�Kšœ~œœ˜ŒK˜�—Kšœ$™$šžœœ$˜<K˜�Kš¡œœB˜HKšœI˜IKšœœ#¡œ#¡œ˜ZKšœœ#¡œ#¡œ˜ZK˜�Kšœ˜Kšœ{˜{Kšœt˜tK˜�Kšœœœ˜‹Kšœvœœ˜ƒK˜�—š
žœœ¤œœœ(˜÷K˜�Kšžœ,œ˜8K˜�Kšœe˜eKšœU˜UK˜�Kšœ0™0Kšœ<˜<K˜�Kšœœ ˜˜Kšœœ ˜™Kšœd 
˜qKšœŒœ 
˜ŸKšœ}œ ˜›Kšœ~œ ˜œK˜�Kšœœœ¿˜ßKšœ2˜2Kšœ7˜7K˜�—š
žœœ®œœœ(˜ÿK˜�Kšžœ,œ˜8K˜�KšœU˜Ušœ˜šœ˜Kšœ"˜"Kšœ˜Kšœ>˜E——šœ˜šœ˜Kšœ˜Kšœ˜Kšœ>˜E——K™�Kšœ0™0Kšœ<˜<K˜�Kšœœ ˜ Kšœ›œ %˜ÆKšœ™œ %˜ÄKšœ€œ "˜¨K˜�Kšœœœ¿˜ßKšœ2˜2Kšœ7˜7——šŸ™š
žœœœ!œœ(˜oKšœ<™<Kšœ™Kšœ>˜>KšœH˜HKšœ@˜@KšœJ˜JKšœ>˜>KšœD˜DKšœ:˜:KšœB˜BKšœ<˜<K˜�Kšœ™šœœ˜#šœœ˜+Kšœp˜pKšœ˜—šœ œ˜?Kšœz˜zKšœ˜——K˜�šœ˜šœœ˜,Kšœt˜tKšœ˜—šœœ˜,Kšœz˜zKšœ˜	—K˜�—KšœA™Ašœœ˜+Kšœt˜tKšœn˜nKšœ˜—šœ œ˜?Kšœ~˜~Kšœ€˜€Kšœ˜K˜�—Kšœ#˜#——šŸ™šžœœ ˜=Kšœ,˜,Kšœ <˜UKšœ5 …˜ºKšœ˜Kšœœ˜(Kšœ™K™<K™;™GK˜�—šžœ˜0Kšœœœœ™9K™@šžœ#˜.Kšœœœœ™Ašœ'œœ
˜XKšœv˜v——K˜�Kšœ
œœ˜OKšœ6˜6K˜�—šžœ˜0Kšœœœœ™9K™@šžœ#˜.Kšœœœœ™Ašœ$œœ
˜SKšœv˜v——K˜�Kšœ
œœ˜OKšœ6˜6K˜�—šžœ˜+Kšœ/™/Kšœœœœ™9šžœ#˜.Kšœ+™+Kšœœœœ™Ašœ$œœ	œ˜SKšœœœ˜Kšœ˜Kšœœœ˜Kšœf˜fšœ(œ˜1Kšœ6™6Kšœœœ*œ™UKšœ
œœ 5˜Yšœœ#œœ˜6KšœF˜FKšœ˜—šœœ˜K˜�——šœœ)œ+œ˜cKšœ)™)Kšœ*œ™;Kšœœ™,Kšœœ
œ!œ
˜Fšœœœ˜-Kš	œ
œœ
œœ%˜bKšœL˜LKšœB˜B—Kšœœ˜K˜�—šœœ)œ+œ˜cKšœ+™+Kšœ*œ™;Kšœœ™,Kšœœ
œ!œ
˜Fšœœœ˜,Kš	œ
œœ
œœ%˜bKšœL˜LKšœB˜B—Kšœœ˜K˜�—šœ˜Kšœ¡œ˜•Kšœ
œ˜K˜�—šœœ˜Kš	œ	œœ$œœ˜YKšœœœ
œœ2œ˜gKš
œœœœœœœ
˜WKšœL˜LKšœ5˜5Kšœ9˜9———K˜�Kšœ
œœ˜PKšœœ^˜jKšœ6˜6K˜�—Kšœ'˜'Kšœa˜aKšœ6˜6šœ
œœ	˜&Kšœ%˜%Kšœ%˜%Kšœ>˜E—šœ
œœ	˜&Kšœ"˜"Kšœ"˜"Kšœ>˜E—Kš¡œœB˜HKšœœ /˜\Kšœœ1 3˜uKšœœ0 ?˜€Kšœœ ?˜kKšœ!œœ˜;Kšœ/œœ˜:K˜�KšœO™OKšœ™Kšœg¡œ˜jKšœa˜aKšœa˜aKšœs˜sKšœs˜sK˜�KšœJ™JKšœF˜FKšœF˜FKšœB˜BK˜�—šžœœ ˜;Kšœ,˜,Kšœ(˜(Kšœ .˜MKšœ˜Kšœ
œ ˜0K™IKšœO™OKšœ™Kšœ™šžœ˜&Kšœœœœ™9šžœ#˜.Kšœœœœ™Ašœ$œ'œ˜VKšœ\˜\šœ7œ˜>Kšœ¡œ˜•—šœ/œ œ˜[Kš
œœœœœœœ
˜WKš	œœœ
œœ
˜LKšœ+˜+Kšœ6˜6Kšœœ˜-———K˜�Kšœ
œœ˜PKšœœ˜›Kšœ6˜6K˜�—Kš¡œœB˜HKš	œ
œœœœ˜%šœ&œ˜>Kšœœœ˜-Kšœœœ˜*Kšœ>˜E—šœœœ˜$Kšœ"˜"Kšœ"˜"Kšœ>˜E—Kšœ9˜9Kšœ=˜=K˜�—šžœœ ˜7Kšœ,˜,Kšœ <˜RKšœ '˜AKšœ˜K˜>Kšœ ˜5Kšœ
œ ˜0KšœE™EK˜�Kšœ†˜†K˜�—šžœœ ˜<Kšœ,˜,Kšœ <˜SKšœ+ '˜RKšœ˜K˜>Kšœ+ ˜IKšœ,œ ˜NšœE™EK˜�—šžœœ˜›K˜�Kšœ
œœ˜OKš
œœœœœœœ
˜Wšœ!œ
œ˜6KšœœH˜WKšœL˜LKšœ9˜9—šœœœ
œ˜0Kšœœœ2˜GKšœœ˜-KšœU˜U—šœœœ
œ˜0Kšœœœ@˜UKšœœ˜-KšœU˜U—Kš	œœœ
œ˜/KšœQ˜UKšœ6˜6K˜�—šžœ˜&Kšœœœœ™9šžœ#˜.Kšœœœœ™Ašœ$œ!œ˜PKšœ\˜\šœ1œ˜8Kšœƒ¡œ˜–—šœœ)˜4KšœM˜M—šœœ)œ+˜aKšœM˜M—šœœ)œ+˜aKšœP˜P———K˜�Kšœœ¤˜°Kšœ6˜6K˜�—Kš¡œœB˜HKšœA˜AKšœA˜AKšœ'˜'šœœœ˜Kšœ"˜"Kšœ"˜"Kšœ>˜E—Kšœ3˜3Kšœ=˜=K˜�—šžœœ{˜šœ@™@K˜�—šžœ˜Kšœ;œœœ™_Kšœ
œœ˜Pšœœ˜Kšœ.™.Kš	œœœ
œ6œ˜gKšœO˜OKš
œœœœœœœ˜_Kšœ8˜8šœD˜DK˜�———KšœS˜SK˜�—šžœœ ˜<Kšœ ˜ Kšœ˜Kšœ
œ˜Kšœ˜Kšœ ˜5Kšœ
œ ˜0Kšœ'œ™0KšœH™HK˜�šœœ˜+KšœE˜EKšœE˜EKšœ=˜D—KšœV˜VK˜�—šžœœ ˜8Kšœ ˜ Kšœ˜Kšœ
œ˜Kšœ˜Kšœ˜Kšœ ˜5Kšœ
œ ˜0KšœU™UK˜�šžœ"˜-Kšœœœœœœ™[Kšœ2™2KšœU˜UKšœ
œœ˜PKšœœ˜šœ œ˜0Kšœ<˜<Kšœ<˜<Kšœ>˜E—š
œœœœœ˜mKš
œœœœœœœ
˜Wšœ!œ
œ˜6KšœœH˜WKšœL˜LKšœ9˜9—šœœœ
œ˜0Kšœœ˜-Kš	œœœ
œ6œ˜gKšœU˜U—šœœœ
œ˜0Kšœœ*˜9Kšœœ˜-KšœU˜U—Kš	œœœ
œ˜/KšœQ˜UKšœ<˜<—K˜�—KšœC˜CKšœ`˜`K˜�—š
žœœ6œ#œ)œ˜œKšœ+™+KšœœP˜^Kšœ/˜/Kšœœ˜1Kšœ(™(Kšœœœ ˜PKšœ˜K˜�—šžœœ6œ#œ˜qKšœ™Kšœ/˜/šœ˜Kšœ+œ˜0Kšœ'œ˜,Kšœ˜—Kšœ(™(Kšœœœ ˜PKšœ˜K˜�—š
ž
œœ œœœ˜]Kšœ2œ™9šœ
œœ*œœœœ˜fKšœ&œ˜EKšœ˜—K˜�šœœœ ˜4Kšœ
œ˜)Kšœ.˜.Kšœœ˜5———šŸ™šžœœ?œ˜SKš	œ	œœœ!œ˜Xšœ	œœ˜Kšœ
œœœ ˜5Kšœ$˜$—Kšœœ˜K˜�—šžœœœ
œ˜BKšœL™LKšœ0™0Kšœ2 )™[Kšœœ"˜5Kšœ
œ˜0šœœœ˜0Kšœœœ˜.Kšœ˜K˜�——šžœœ$˜9Kšœ,™,K˜�Kš¡œœB˜HKšœœ#¡œ#¡œ˜ZKšœœ#¡œ#¡œ˜ZKšœ7˜7KšœœK˜^šœœœœ/˜rKšœ6˜:—Kšœœ&˜4KšœœG˜Xšœœœœ-˜nKšœ1˜5—Kšœ	œ"˜.KšœPœ˜TK˜�Kšœ?œœ˜dKšœAœ˜VKšœ?œœ˜dKšœ;œœ˜`Kšœ@œ˜TK˜�KšœR˜Ršœ!œœ,˜gKšœ3˜7—Kšœ&˜&KšœV˜Všœ#œœ.˜kKšœ2˜6—Kšœ,˜,Kšœ>œ˜OKšœ?œ˜UK˜�K˜K˜Kšœ˜K˜�—š
ž
œœ
œœœ˜Qšœ
œ˜Kšœœ˜œK˜�——šžœœBœ˜{Kšœ$™$K˜�KšœC˜CKšœœ/˜@K˜�—šžœœ?œœ˜[Kšœ`™`K˜�Kšœ4˜4Kšœ˜!K˜�—Kšœ]™]šžœœ?œ˜rK˜�šœœœ˜KšœD˜DKšœM˜MKšœD˜DKšœB˜BKšœC˜CKšœ^˜^Kšœ]˜]Kšœ[˜[Kšœ\˜\KšœX˜_—K˜�—šž
œœ?œ˜uK˜�šœ˜šœ	˜	Kšœ	œ˜%KšœB˜B—šœ˜Kšœ	œ)˜5KšœB˜B—šœ˜Kšœ	œJ˜VKšœB˜B—šœ˜Kšœ	œL˜XKšœB˜B—Kšœ˜	—K˜�—šž
œœ?œ˜uK˜�šœ!˜+šœ	˜	Kšœ	œ˜&KšœB˜B—šœ˜Kšœ	œ)˜5KšœB˜B—šœ˜Kšœ	œH˜TKšœB˜B—šœ˜Kšœ	œK˜WKšœB˜B—Kšœ˜	K˜�——šž
œœ?œ˜uK˜�šœ!˜+šœ	˜	Kšœ	œ3˜?KšœB˜B—šœ˜Kšœ	œB˜NKšœB˜B—šœ˜Kšœ	œa˜mKšœB˜B—šœ˜Kšœ	œd˜pKšœB˜B—Kšœ˜	K˜�——šž
œœDœœ˜mK˜�šœ
˜Kšœ*˜*KšœA˜AKšœ;˜;KšœN˜NKšœo˜oKšœX˜XKšœp˜pKšœ]˜]Kšœ˜	—K˜�—šœœœ;œœœ˜vK˜�—š
žœœhœœœ˜ŸK˜�š	œ5œœœ˜UKšœ#˜#Kšœ&˜&Kšœ˜	—K˜�—šžœœœœ˜OKšœœ3™?šœœ˜3Kšœœ˜)—K˜�—šžœœœœ˜[KšœœQ™]šœ œ˜7Kšœœ˜'—K˜�—šžœœœ
œ˜LKšœœ™šœœ˜4Kšœœ˜*—K˜�—šž
œœ¡œœœœ˜NKšœ)™)Kšœ-¡œ%¡œ	˜fK˜�—š
ž
œœLœœœ˜„Kšœ!™%šžœ#˜.Kšœ+™+Kšœœœœ™AK™�Kš
œ œœœ	œ˜fK˜�—šœ+œ˜;K˜XKšœ>˜E—Kšœ3˜3Kšœ6˜6K˜�—š
žœœLœ	œœ˜~Kšœ$™$šžœ#˜.Kšœ+™+Kšœœœœ™AK™�Kšœ œœ˜WK˜�—šœ+œ˜;K˜XKšœ>˜E—Kšœ3˜3Kšœ6˜6K˜�—šžœœ!œ œ˜]K˜�Kšœœ˜Kš¡œœB˜HKšœœ#¡œ#¡œ˜ZKšœœ#¡œ#¡œ˜Zšœœ˜#KšœÆ˜ÆKšœÆ˜Æ—šœ˜Kšœ	œ˜˜¤Kšœœœq˜‚Kšœœž˜©Kšœ<˜<Kšœ=˜=K˜�—KšœN˜NKšœR˜RKšœV˜VKšœJ˜JK˜�Kšœœ˜,Kšœœ˜-K˜�—šž	œœ$˜3K˜�K˜"KšœK˜KKšœj˜jKšœD˜DK˜�—šžœœ$˜8K˜�Kš¡œœB˜HKšœœ#¡œ˜:Kšœœ#¡œ˜:Kšœœ6¡œ˜IKšœœ6¡œ˜IKšœ7˜7K™�Kšœ5™5Kšœœ. ˜TKšœœ ˜BKšœœ2 ˜ZKšœ
œ ˜?Kšœ
œ ˜BKšœœ0 ˜YKšœœ ˜FKšœœ0 ˜UK˜�šœœ˜Kšœ˜KšœN˜NKšœH˜HKšœ{˜{K˜�Kšœu˜uKšœg˜gKšœQ˜QKšœ_˜_—šœ ˜ KšœP˜PKšœ˜Kšœs˜sKšœ^˜^—K˜�Kšœ™Kšœe˜eKšœx˜xKšœr˜rKšœc˜cK˜�Kšœ™Kšœq˜qKšœm˜mKšœg˜gKšœo˜oK˜�Kšœ™KšœY˜YKšœn˜nKšœ{˜{Kšœf˜fK™�Kšœ™Kšœ€˜€Kšœ~˜~Kšœt˜tKšœw˜wK˜�—šžœœ
œœœœœœ˜MKšœœ™šœœ˜Kšœœœœ˜3Kšœ˜Kšœ˜—Kšœœ˜——šŸ™šžœ$˜8Kšœœ™5šž
œ˜)Kšœœœœ™7šœœœ˜Kšœœ
˜'K˜�šœœœ'œœ˜KKšœ˜šœ˜Kšœ!˜!Kšœ'˜'Kšœ#˜#Kšœ˜Kšœ˜Kšœ˜—Kšœ˜
———K˜�Kšœ!œ1˜XKšœ9˜9K˜�—šžœ$˜5Kšœœ™>K˜�Kšœœ
˜šœœœ œœ˜DKšœ˜Kšœœœ˜>Kšœl˜lKšœ˜	—K˜�—šžœ&˜<Kšœœ"™:šžœ˜+Kšœœœœ™7šœœœ˜Kšœœ
˜'K˜�šœœœ'œœ˜KKšœ˜šœ˜Kšœ#˜#Kšœ˜Kšœ˜Kšœ˜Kšœ˜
—K˜�———Kšœ!œ3˜ZKšœ;˜;K˜�—šžœ&˜9Kšœœ!™BK˜�Kšœœ
˜šœœœ œœ˜DKšœ˜KšœX˜XKšœ˜	——Kšœ˜—K˜�—�…—����OZ�³¥�