DIRECTORY Basics, Cabbage, CabbagePrivate, CD, CDBasics, CDCells, CDOps, CDProperties, CDRects, CDSimpleRules, CDSymbolicObjects, Connections, Core, CoreGeometry, CoreOps, Convert, HashTable, List, PW, PWRoute, Rope, Route, RouteUtil, RTBasic, Sinix, SinixOps;

CabbageProcsImpl: CEDAR PROGRAM
IMPORTS Basics, Cabbage, CD, CDBasics, CDCells, CDOps, CDProperties, CDRects, CDSimpleRules, CDSymbolicObjects, Connections, CoreGeometry, CoreOps, Convert, HashTable, List, PW, PWRoute, Rope, Route, RouteUtil, RTBasic, Sinix, SinixOps
EXPORTS CabbagePrivate
SHARES Route = {
cabbageXPos: ATOM _ $CabbageXPos;
cabbageYPos: ATOM _ $CabbageYPos;

CreateHandle: PUBLIC PROC [inner, bottomLeft, bottom, bottomRight, right, topRight, top, topLeft, left: Cabbage.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];
viaTable: HashTable.Table _ IF parms.viaTable # NIL THEN parms.viaTable ELSE HashTable.Create[equal: EqualProc, hash: HashProc];
designRules _ NEW[CabbagePrivate.DesignRulesRec];

designRules.horizParms.parms _ NEW[PWRoute.RouterParamsRec _ [trunkLayer: parms.horizLayer, branchLayer: parms.vertLayer, technologyKey: parms.technologyKey, wireWidthProc: parms.wireWidthProc, signalIncomplete: parms.signalIncomplete, signalBreakAtExit: FALSE, signalSinglePinNets: parms.signalSinglePinNets, viaTable: viaTable]];
designRules.vertParms.parms _ NEW[PWRoute.RouterParamsRec _ [trunkLayer: parms.vertLayer, branchLayer: parms.horizLayer, technologyKey: parms.technologyKey, wireWidthProc: parms.wireWidthProc, signalIncomplete: parms.signalIncomplete, signalBreakAtExit: FALSE, signalSinglePinNets: parms.signalSinglePinNets, viaTable: viaTable]];

designRules.horizParms.rules _ Route.CreateDesignRules[parms.technologyKey, hLayer, vLayer, horizontal];
designRules.vertParms.rules _ Route.CreateDesignRules[parms.technologyKey, hLayer, vLayer, vertical];
designRules.horizParms.rules.trunkToEdge _ designRules.horizParms.rules.trunkToTrunk;
designRules.vertParms.rules.trunkToEdge _ designRules.vertParms.rules.trunkToTrunk};

GetSizes: PROC [handle: CabbagePrivate.Handle, inner, bottomLeft, bottom, bottomRight, right, topRight, top, topLeft, left: Cabbage.Object] ~ {

lambda: INT _ handle.rules.horizParms.rules.CDLambda;
handle.inner _ GetObjectDescription[inner, lambda, lambda];

handle.bottom _ GetObjectDescription[bottom, lambda, lambda];
handle.right _ GetObjectDescription[right, lambda, lambda];
handle.top _ GetObjectDescription[top, lambda, lambda];
handle.left _ GetObjectDescription[left, lambda, lambda];

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: Cabbage.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] ~ {
horizParms: CabbagePrivate.ParmSet _ handle.rules.horizParms;
vertParms: CabbagePrivate.ParmSet _ handle.rules.vertParms;
space: INT _ 2*horizParms.rules.trunkToTrunk + horizParms.rules.trunkSpacing + vertParms.rules.contactSize + vertParms.rules.trunkSpacing + 2*vertParms.rules.trunkToTrunk;
trunkWidth: INT _ (handle.parms.powerCellWidth - space)/2;
RouteOutsideChannels[handle, trunkWidth];
AssignPositions[handle];
ConstructPowerChannels[handle, trunkWidth];
AssignPositions[handle];
RouteOutsideSwitchBoxes[handle]};

RouteOutsideChannels: PROC [handle: CabbagePrivate.Handle, viaSize: INT] ~ {
outerChanWidth: INT _ handle.parms.outerChanWidth;
powerWidth: INT _ outerChanWidth + handle.parms.powerCellWidth;
horizParms: CabbagePrivate.ParmSet _ handle.rules.horizParms;
vertParms: CabbagePrivate.ParmSet _ handle.rules.vertParms;
horizInnerRange: Connections.Range _ [handle.inner.origin.x, handle.inner.origin.x + handle.inner.size.x];
horizOuterRange: Connections.Range _ [handle.left.origin.x + handle.left.size.x + powerWidth, handle.right.origin.x - powerWidth];
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 + powerWidth, handle.top.origin.y - powerWidth];
handle.powerDistribution.channels[bottom] _ RouteOutsideChannel[handle, handle.bottom, bottom, horizOuterRange, horizOuterRange, outerChanWidth, viaSize, vertParms];
handle.powerDistribution.channels[right] _ RouteOutsideChannel[handle, handle.right, right, vertInnerRange, vertOuterRange, outerChanWidth, viaSize, horizParms];
handle.powerDistribution.channels[top] _ RouteOutsideChannel[handle, handle.top, top, horizOuterRange, horizOuterRange, outerChanWidth, viaSize, vertParms];
handle.powerDistribution.channels[left] _ RouteOutsideChannel[handle, handle.left, left, vertInnerRange, vertOuterRange, outerChanWidth, viaSize, horizParms]};

ConstructPowerChannels: PROC [handle: CabbagePrivate.Handle, trunkWidth: INT] ~ {

powerCellWidth: INT _ handle.parms.powerCellWidth;
powerWidth: INT _ handle.parms.outerChanWidth + powerCellWidth;
horizParms: CabbagePrivate.ParmSet _ handle.rules.horizParms;
vertParms: CabbagePrivate.ParmSet _ handle.rules.vertParms;
horizInnerRange: Connections.Range _ [handle.inner.origin.x, handle.inner.origin.x + handle.inner.size.x];
horizOuterRange: Connections.Range _ [handle.left.origin.x + handle.left.size.x + powerWidth, handle.right.origin.x - powerWidth];
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 + powerWidth, handle.top.origin.y - powerWidth];

handle.powerDistribution.power[bottom] _ RoutePower[handle, handle.powerDistribution.channels[bottom], bottom, horizOuterRange, powerCellWidth, trunkWidth, horizParms, vertParms];
handle.powerDistribution.power[right] _ RoutePower[handle, handle.powerDistribution.channels[right], right, vertOuterRange, powerCellWidth, trunkWidth, vertParms, horizParms];
handle.powerDistribution.power[top] _ RoutePower[handle, handle.powerDistribution.channels[top], top, horizOuterRange, powerCellWidth, trunkWidth, horizParms, vertParms];
handle.powerDistribution.power[left] _ RoutePower[handle, handle.powerDistribution.channels[left], left, vertOuterRange, powerCellWidth, trunkWidth, vertParms, horizParms]};

RouteOutsideChannel: PROC [handle: CabbagePrivate.Handle,
outerObject: CabbagePrivate.ObjectDescription, -- outer Cabbage object
side: Route.Side,	-- the side of chip for which this channel is being constructed
innerRange, outerRange: Connections.Range,  -- innerRange is the span of the inner cell, outerRange the span of the appropriate power routing cell; innerRange may equal outerRange
chWidth: INT,	-- the only permitted width for channel
viaSize: INT,	-- the length of the via at the end of the channel
parms: CabbagePrivate.ParmSet]
RETURNS [channel: CabbagePrivate.Channel] ~ {

result: Route.RoutingResult;
retrieveRect: Route.RefRect;
rect: CD.Rect;
otherSide: Route.Side _ RTBasic.OtherSide[side];
blSide: Route.Side _ IF side=bottom OR side=top THEN left ELSE bottom;
topOrRight: BOOLEAN _ side= right OR side=top;
direction: RTBasic.Direction _ IF side= right OR side=left THEN vertical ELSE horizontal;

obj1: Cabbage.Object _ IF topOrRight THEN MappedShellFromObject[handle, outerObject, otherSide, innerRange, outerRange, viaSize, parms.rules]
ELSE ShellFromObject[handle, outerObject, otherSide, outerRange, parms.rules, TRUE];
obj2: Cabbage.Object _ IF topOrRight THEN ShellFromObject[handle, outerObject, otherSide, outerRange, parms.rules, TRUE]
ELSE MappedShellFromObject[handle, outerObject, otherSide, innerRange, outerRange, viaSize, parms.rules];
bottomOrLeftObj: Cabbage.Object _ ShellFromOutsideEnd[handle, outerObject, otherSide, blSide, innerRange, outerRange, parms.rules];
topOrRightObj: Cabbage.Object _ ShellFromOutsideEnd[handle, outerObject, otherSide, RTBasic.OtherSide[blSide], innerRange, outerRange, parms.rules];

parms.parms.wireWidthProc _ GetWireWidth;
parms.parms.makeTabKeyProc _ PinName;
parms.parms.context _ NEW[PWRouteContext _ [direction: direction, table: handle.widthTable]];
result _ PWRoute.DoRoute[obj1, obj2, bottomOrLeftObj, topOrRightObj, parms.parms, side= right OR side=left, channel];

rect _ result.routingRect;
SELECT side FROM
bottom => {
dist: INT _ MIN[rect.y1, rect.y2 - chWidth];
retrieveRect _ NEW[CD.Rect _ [rect.x1, dist, rect.x2, rect.y2]]};
right => {
dist: INT _ MAX[rect.x2, rect.x1 + chWidth];
retrieveRect _ NEW[CD.Rect _ [rect.x1, rect.y1, dist, rect.y2]]};
top => {
dist: INT _ MAX[rect.y2, rect.y1 + chWidth];
retrieveRect _ NEW[CD.Rect _ [rect.x1, rect.y1, rect.x2, dist]]};
left => {
dist: INT _ MIN[rect.x1, rect.x2 - chWidth];
retrieveRect _ NEW[CD.Rect _ [dist, rect.y1, rect.x2, rect.y2]]};
ENDCASE;

channel.object _ PWRoute.GetRouting[result, retrieveRect, parms.parms];
channel.size _ RTBasic.IRSize[channel.object];
channel.cellType _ ExtractChannel[channel, parms]};

RoutePower: PROC [handle: CabbagePrivate.Handle,
channel: CabbagePrivate.Channel, -- inner or outer channel as determined by side
chipSide: Route.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 => CDProperties.PutProp[RouteUtil.Include[object, CDRects.CreateRect[[max-min, branchLength], branchLayer], pos], $SignalName, name];
left, right => CDProperties.PutProp[RouteUtil.Include[object, CDRects.CreateRect[[branchLength, max-min], branchLayer], pos], $SignalName, 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, insideParms.rules.CDLambda, NIL],
left, right => RouteUtil.StitchVias[[trunkWidth, max-min], trunkLayer, branchLayer, insideParms.rules.CDLambda, 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"];
CDProperties.PutProp[RouteUtil.Include[object, via, viaPos], $SignalName, name]}};

SignalBranch: PROC [] ~ {

outsideLength: INT _ outsideParms.rules.trunkSpacing + distToOuter;
insideLength: INT _ insideParms.rules.trunkSpacing + distToInner;
SELECT chipSide FROM
bottom => {
CDProperties.PutProp[RouteUtil.Include[object, CDRects.CreateRect[[max-min, outsideLength], outsideLayer], [adjustedRange.min, 0]], $SignalName, name];
CDProperties.PutProp[RouteUtil.Include[object, CDRects.CreateRect[[max-min, insideLength], insideLayer], [adjustedRange.min, powerWidth - insideLength]], $SignalName, name];
[] _ RouteUtil.Include[object, RouteUtil.StitchVias[[max-min, insideParms.rules.contactSize], insideLayer, outsideLayer, insideParms.rules.CDLambda, NIL], [adjustedRange.min, outsideLength]]};
top => {
CDProperties.PutProp[RouteUtil.Include[object, CDRects.CreateRect[[max-min, outsideLength], outsideLayer], [adjustedRange.min, powerWidth - outsideLength]], $SignalName, name];
CDProperties.PutProp[RouteUtil.Include[object, CDRects.CreateRect[[max-min, insideLength], insideLayer], [adjustedRange.min, 0]], $SignalName, name];
[] _ RouteUtil.Include[object, RouteUtil.StitchVias[[max-min, insideParms.rules.contactSize], insideLayer, outsideLayer, insideParms.rules.CDLambda, NIL], [adjustedRange.min, insideLength]]};
left => {
CDProperties.PutProp[RouteUtil.Include[object, CDRects.CreateRect[[outsideLength, max-min], outsideLayer], [0, adjustedRange.min]], $SignalName, name];
CDProperties.PutProp[RouteUtil.Include[object, CDRects.CreateRect[[insideLength, max-min], insideLayer], [powerWidth - insideLength, adjustedRange.min]], $SignalName, name];
[] _ RouteUtil.Include[object, RouteUtil.StitchVias[[insideParms.rules.contactSize, max-min], insideLayer, outsideLayer, insideParms.rules.CDLambda, NIL], [outsideLength, adjustedRange.min]]};
right => {
CDProperties.PutProp[RouteUtil.Include[object, CDRects.CreateRect[[outsideLength, max-min], outsideLayer], [powerWidth - outsideLength, adjustedRange.min]], $SignalName, name];
CDProperties.PutProp[RouteUtil.Include[object, CDRects.CreateRect[[insideLength, max-min], insideLayer], [0, adjustedRange.min]], $SignalName, name];
[] _ RouteUtil.Include[object, RouteUtil.StitchVias[[insideParms.rules.contactSize, max-min], insideLayer, outsideLayer, insideParms.rules.CDLambda, NIL], [insideLength, adjustedRange.min]]};
ENDCASE};

name: Rope.ROPE _ CoreOps.GetShortWireName[wire];
adjustedRange: Connections.Range _ [channelOrigin + min, channelOrigin + max];
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 => CDProperties.PutProp[RouteUtil.Include[object, CDRects.CreateRect[[segment.range.max-segment.range.min, branchLength], insideLayer], rectPos], $SignalName, net.name];
left, right => CDProperties.PutProp[RouteUtil.Include[object, CDRects.CreateRect[[branchLength, segment.range.max-segment.range.min], insideLayer], rectPos], $SignalName, 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, insideParms.rules.CDLambda, NIL],
left, right => RouteUtil.StitchVias[[trunkWidth, segment.range.max-segment.range.min], trunkLayer, branchLayer, insideParms.rules.CDLambda, 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"];
CDProperties.PutProp[RouteUtil.Include[object, via, viaPos], $SignalName, 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, otherLayer: CD.Layer, name: Rope.ROPE, addVias: BOOLEAN] ~ {
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];
CDProperties.PutProp[RouteUtil.Include[object, trunk, position], $SignalName, name];
IF addVias THEN {
via: CD.Object _ RouteUtil.StitchVias[[trunkWidth, trunkWidth], layer, otherLayer, insideParms.rules.CDLambda, NIL];
irSize: CD.Position _ RTBasic.IRSize[via];
viaPosition: CD.Position _ SELECT chipSide FROM
bottom, top => [range.max-range.min - irSize.x, (trunkWidth-irSize.y)/2],
left, right => [(trunkWidth-irSize.x)/2, range.max-range.min - irSize.y],
ENDCASE => Cabbage.Error[programmingError, "Not suppose to happen"];


branch: CD.Object _ CDRects.CreateRect[[trunkWidth, trunkWidth], otherLayer];
branchPosition: CD.Position _ SELECT chipSide FROM
bottom, top => [range.max-range.min - trunkWidth, 0],
left, right => [0, range.max-range.min - trunkWidth],
ENDCASE => Cabbage.Error[programmingError, "Not suppose to happen"];
CDProperties.PutProp[RouteUtil.Include[object, branch, position], $SignalName, name];
CDProperties.PutProp[RouteUtil.Include[object, branch, CDBasics.AddPoints[position, branchPosition]], $SignalName, name];
CDProperties.PutProp[RouteUtil.Include[object, via, position], $SignalName, name];
CDProperties.PutProp[RouteUtil.Include[object, via, CDBasics.AddPoints[position, viaPosition]], $SignalName, name]}};

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;
object: Cabbage.Object _ CDCells.CreateEmptyCell[];
mode: Sinix.Mode = SinixOps.GetExtractMode[insideParms.rules.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, outsideLayer, "Vdd", FALSE];
PowerTrunk[innerTrunkPos, outsideLayer, insideLayer, "Gnd", TRUE];

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

power.object _ object;
CDCells.SetInterestRect[design: NIL, cell: power.object, r: interestRect];
RTBasic.RepositionCell[power.object];
power.size _ RTBasic.IRSize[power.object];
power.cellType _ ExtractChannel[power, insideParms]};

RouteOutsideSwitchBoxes: PROC [handle: CabbagePrivate.Handle] ~ {
vertParms: CabbagePrivate.ParmSet _ handle.rules.vertParms;

powerWidth: INT _ handle.parms.outerChanWidth + handle.parms.powerCellWidth;
leftHorizRange: Connections.Range _ [handle.left.origin.x + handle.left.size.x, handle.left.origin.x + handle.left.size.x + powerWidth];
rightHorizRange: Connections.Range _ [handle.right.origin.x - powerWidth, handle.right.origin.x];
bottomVertRange: Connections.Range _ [handle.bottom.origin.y + handle.bottom.size.y, handle.bottom.origin.y + handle.bottom.size.y + powerWidth];
topVertRange: Connections.Range _ [handle.top.origin.y- powerWidth, handle.top.origin.y];

vertParms.parms.okToDiddleLLPins _ TRUE;
handle.powerDistribution.switchBoxes[bottomLeft] _ RouteOutsideSwitchBox[handle, bottomLeft, leftHorizRange, bottomVertRange, vertParms];
handle.powerDistribution.switchBoxes[topLeft] _ RouteOutsideSwitchBox[handle, topLeft, leftHorizRange, topVertRange, vertParms];
vertParms.parms.okToDiddleLLPins _ FALSE; vertParms.parms.okToDiddleURPins _ TRUE;
handle.powerDistribution.switchBoxes[bottomRight] _ RouteOutsideSwitchBox[handle, bottomRight, rightHorizRange, bottomVertRange, vertParms];
handle.powerDistribution.switchBoxes[topRight] _ RouteOutsideSwitchBox[handle, topRight, rightHorizRange, topVertRange, vertParms];
vertParms.parms.okToDiddleLLPins _ FALSE; vertParms.parms.okToDiddleURPins _ FALSE};

RouteOutsideSwitchBox: PROC [handle: CabbagePrivate.Handle,  corner: CabbagePrivate.Corners, horizRange, vertRange: Connections.Range, parms: CabbagePrivate.ParmSet] RETURNS [switchBox: CabbagePrivate.Channel] ~ {

bottomObject, topObject, leftObject, rightObject: Cabbage.Object;

SELECT corner FROM
bottomLeft => {
topObject _ PW.AbutListX[LIST[ShellFromFullChannel[handle.powerDistribution.channels[left], bottom, parms.rules.branchLayer, parms.rules], ShellFromFullChannel[handle.powerDistribution.power[left], bottom, parms.rules.branchLayer, parms.rules]]];
bottomObject _ ShellFromObject[handle, handle.bottom, top, horizRange, parms.rules, FALSE];
leftObject _ ShellFromObject[handle, handle.left, right, vertRange, parms.rules, FALSE];
rightObject _ PW.AbutListY[LIST[ShellFromFullChannel[handle.powerDistribution.channels[bottom], left, parms.rules.trunkLayer, parms.rules], ShellFromFullChannel[handle.powerDistribution.power[bottom], left, parms.rules.trunkLayer, parms.rules]]]};

bottomRight => {
topObject _ PW.AbutListX[LIST[ShellFromFullChannel[handle.powerDistribution.power[right], bottom, parms.rules.branchLayer, parms.rules],  ShellFromFullChannel[handle.powerDistribution.channels[right], bottom, parms.rules.branchLayer, parms.rules]]];
bottomObject _ ShellFromObject[handle, handle.bottom, top, horizRange, parms.rules, FALSE];
leftObject _ PW.AbutListY[LIST[ShellFromFullChannel[handle.powerDistribution.channels[bottom], right, parms.rules.trunkLayer, parms.rules], ShellFromFullChannel[handle.powerDistribution.power[bottom], right, parms.rules.trunkLayer, parms.rules]]];
rightObject _ ShellFromObject[handle, handle.right, left, vertRange, parms.rules, FALSE]};

topRight => {
topObject _ ShellFromObject[handle, handle.top, bottom, horizRange, parms.rules, FALSE];
bottomObject _ PW.AbutListX[LIST[ShellFromFullChannel[handle.powerDistribution.power[right], top, parms.rules.branchLayer, parms.rules], ShellFromFullChannel[handle.powerDistribution.channels[right], top, parms.rules.branchLayer, parms.rules]]];
leftObject _ PW.AbutListY[LIST[ShellFromFullChannel[handle.powerDistribution.power[top], right, parms.rules.trunkLayer, parms.rules], ShellFromFullChannel[handle.powerDistribution.channels[top], right, parms.rules.trunkLayer, parms.rules]]];
rightObject _ ShellFromObject[handle, handle.right, left, vertRange, parms.rules, FALSE]};

topLeft => {
topObject _ ShellFromObject[handle, handle.top, bottom, horizRange, parms.rules, FALSE];
bottomObject _ PW.AbutListX[LIST[ShellFromFullChannel[handle.powerDistribution.channels[left], top, parms.rules.branchLayer, parms.rules], ShellFromFullChannel[handle.powerDistribution.power[left], top, parms.rules.branchLayer, parms.rules]]];
leftObject _ ShellFromObject[handle, handle.left, right, vertRange, parms.rules, FALSE];
rightObject _ PW.AbutListY[LIST[ShellFromFullChannel[handle.powerDistribution.power[top], left, parms.rules.trunkLayer, parms.rules], ShellFromFullChannel[handle.powerDistribution.channels[top], left, parms.rules.trunkLayer, parms.rules]]]};

ENDCASE;

parms.parms.wireWidthProc _ NIL;
parms.parms.makeTabKeyProc _ NIL;
parms.parms.context _ NEW[PWRouteContext _ [direction: parms.rules.trunkDirection, table: handle.widthTable]];
switchBox.object _ PWRoute.MakeChannel[bottomObject, topObject, leftObject, rightObject, NIL, parms.parms, FALSE, switchBox];
switchBox.size _ RTBasic.IRSize[switchBox.object];
switchBox.cellType _ ExtractChannel[switchBox, parms]};
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 _ CoreOps.GetShortWireName[wire];
segmentSide: Route.Side _ SELECT side FROM
bottom => bottom, right => right, top => top, left=> left,
ENDCASE => Cabbage.Error[programmingError, "Not suppose to happen"];
IF segmentSide = otherSide THEN {
segment: Connections.Segment _ NEW[Connections.SegmentRec _ [name: name, object: handle.powerDistribution.power[chipSide].object, range: [min, max], side: segmentSide, layer: layer]];
net: Connections.Net _ Connections.Fetch[newConnections, name].net;
net.segments _ CONS[segment, net.segments];
[] _ Connections.Store[newConnections, name, net]};
};

otherSide: Route.Side _ RTBasic.OtherSide[chipSide];
mode: Sinix.Mode = SinixOps.GetExtractMode[handle.rules.horizParms.rules.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] ~ {

horizParms: CabbagePrivate.ParmSet _ handle.rules.horizParms;
vertParms: CabbagePrivate.ParmSet _ handle.rules.vertParms;
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, horizParms];
handle.detailedRouting.channels[right] _ RouteChannel[handle, handle.powerDistribution.power[right], right, rightBottom, rightTop, vertRange, vertParms];
handle.detailedRouting.channels[top] _ RouteChannel[handle, handle.powerDistribution.power[top], top, topLeft, topRight, horizRange, horizParms];
handle.detailedRouting.channels[left] _ RouteChannel[handle, handle.powerDistribution.power[left], left, leftBottom, leftTop, vertRange, vertParms]}
ELSE { -- routeType = padLimited
handle.detailedRoutingPL.channels[right] _ RouteChannel[handle, handle.powerDistribution.power[right], right, rightBottom, rightTop, vertRange, vertParms];
handle.detailedRoutingPL.channels[left] _ RouteChannel[handle, handle.powerDistribution.power[left], left, leftBottom, leftTop, vertRange, vertParms]}};

RouteChannel: PROC [handle: CabbagePrivate.Handle,
boundingChannel: CabbagePrivate.Channel,	-- the power channel to use
chipSide: Route.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] ~ {

result: Route.RoutingResult;
retrieveRect: Route.RefRect;
rect: CD.Rect;
offset: INT _ parms.rules.trunkToTrunk;
otherSide: Route.Side _ RTBasic.OtherSide[chipSide];
direction: RTBasic.Direction _ IF chipSide= right OR chipSide=left THEN vertical ELSE horizontal;
blSide: Route.Side _ IF chipSide=bottom OR chipSide=top THEN left ELSE bottom;
topOrRight: BOOLEAN _ chipSide= right OR chipSide=top;
obj1: Cabbage.Object _ IF topOrRight THEN ShellFromObject[handle, handle.inner, chipSide, range, parms.rules, TRUE]
ELSE ShellFromChannel[boundingChannel, otherSide, parms.rules.branchLayer, range, parms.rules];
obj2: Cabbage.Object _ IF topOrRight THEN ShellFromChannel[boundingChannel, otherSide, parms.rules.branchLayer, range, parms.rules]
ELSE ShellFromObject[handle, handle.inner, chipSide, range, parms.rules, TRUE];
bottomOrLeftObj: Cabbage.Object _ ShellFromEnd[handle, llDiv, blSide, parms.rules];
topOrRightObj: Cabbage.Object _ ShellFromEnd[handle, urDiv, RTBasic.OtherSide[blSide], parms.rules];

parms.parms.wireWidthProc _ GetWireWidth;
parms.parms.makeTabKeyProc _ PinName;
parms.parms.context _ NEW[PWRouteContext _ [direction: direction, table: handle.widthTable]];
result _ PWRoute.DoRoute[obj1, obj2, bottomOrLeftObj, topOrRightObj, parms.parms, chipSide=right OR chipSide=left, channel];

rect _ result.routingRect;
SELECT chipSide FROM
bottom => {
size: INT _ 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: INT _ 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: INT _ 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: INT _ 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 _ PWRoute.GetRouting[result, retrieveRect, parms.parms];
channel.size _ RTBasic.IRSize[channel.object];
channel.cellType _ ExtractChannel[channel, parms]};

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

horizParms: CabbagePrivate.ParmSet _ handle.rules.horizParms;

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

horizParms.parms.okToDiddleLLPins _ TRUE; horizParms.parms.okToDiddleURPins _ FALSE;
handle.detailedRouting.switchBoxes[bottomLeft] _ RouteSwitchBox[handle, bottomLeft, leftHorizRange, bottomVertRange, horizParms];

horizParms.parms.okToDiddleLLPins _ FALSE; horizParms.parms.okToDiddleURPins _ TRUE;
handle.detailedRouting.switchBoxes[bottomRight] _ RouteSwitchBox[handle, bottomRight, rightHorizRange, bottomVertRange, horizParms];

horizParms.parms.okToDiddleLLPins _ FALSE; horizParms.parms.okToDiddleURPins _ TRUE;
handle.detailedRouting.switchBoxes[topRight] _ RouteSwitchBox[handle, topRight, rightHorizRange, topVertRange, horizParms];

horizParms.parms.okToDiddleLLPins _ TRUE; horizParms.parms.okToDiddleURPins _ FALSE;
handle.detailedRouting.switchBoxes[topLeft] _ RouteSwitchBox[handle, topLeft, leftHorizRange, topVertRange, horizParms];
horizParms.parms.okToDiddleLLPins _ FALSE; horizParms.parms.okToDiddleURPins _ FALSE};

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

horizParms: CabbagePrivate.ParmSet _ handle.rules.horizParms;
powerWidth: INT _ handle.parms.outerChanWidth + handle.parms.powerCellWidth;

horizRange: Connections.Range _ [handle.left.origin.x + handle.left.size.x + powerWidth, handle.right.origin.x - powerWidth];
bottomVertRange: Connections.Range _ [handle.bottom.origin.y + handle.bottom.size.y + powerWidth, handle.inner.origin.y];
topVertRange: Connections.Range _ [handle.inner.origin.y + handle.inner.size.y, handle.top.origin.y - powerWidth];

horizParms.parms.okToDiddleLLPins _ TRUE; horizParms.parms.okToDiddleURPins _ TRUE;
handle.detailedRoutingPL.switchBoxes[bottom] _ RouteSwitchBoxPL[handle, bottom, horizRange, bottomVertRange, horizParms];
handle.detailedRoutingPL.switchBoxes[top] _ RouteSwitchBoxPL[handle, top, horizRange, topVertRange, horizParms];
horizParms.parms.okToDiddleLLPins _ FALSE; horizParms.parms.okToDiddleURPins _ FALSE};

RouteSwitchBoxPL: PROC [handle: CabbagePrivate.Handle, side: RTBasic.TBSide, horizRange, vertRange: Connections.Range, parms: CabbagePrivate.ParmSet] RETURNS [switchBox: CabbagePrivate.Channel] ~ {

bottomObject, topObject: Cabbage.Object;
leftObject: Cabbage.Object _ ShellFromChannel[handle.powerDistribution.power[left], right, parms.rules.trunkLayer, vertRange, parms.rules];
rightObject: Cabbage.Object _ ShellFromChannel[handle.powerDistribution.power[right], left, parms.rules.trunkLayer, vertRange, parms.rules];
innerRange: Connections.Range _ [handle.inner.origin.x, handle.inner.origin.x + handle.inner.size.x];
direction: RTBasic.Direction _ IF side= right OR side=left THEN vertical ELSE horizontal;

SELECT side FROM
bottom => {
innerObject: Cabbage.Object _ ShellFromObject[handle, handle.inner, bottom, innerRange, parms.rules, TRUE];
topObject _ PW.AbutListX[LIST[ShellFromFullChannel[handle.detailedRoutingPL.channels[left], bottom, parms.rules.branchLayer, parms.rules], innerObject, ShellFromFullChannel[handle.detailedRoutingPL.channels[right], bottom, parms.rules.branchLayer, parms.rules]]];
bottomObject _ ShellFromChannel[handle.powerDistribution.power[bottom], top, parms.rules.branchLayer, horizRange, parms.rules]};

top => {
innerObject: Cabbage.Object _ ShellFromObject[handle, handle.inner, top, innerRange, parms.rules, TRUE];
bottomObject _ PW.AbutListX[LIST[ShellFromFullChannel[handle.detailedRoutingPL.channels[left], top, parms.rules.branchLayer, parms.rules], innerObject, ShellFromFullChannel[handle.detailedRoutingPL.channels[right], top, parms.rules.branchLayer, parms.rules]]];
topObject _ ShellFromChannel[handle.powerDistribution.power[top], bottom, parms.rules.branchLayer, horizRange, parms.rules]};

ENDCASE;

parms.parms.wireWidthProc _ GetWireWidth;
parms.parms.makeTabKeyProc _ PinName;
parms.parms.context _ NEW[PWRouteContext _ [direction: direction, table: handle.widthTable]];
switchBox.object _ PWRoute.MakeChannel[bottomObject, topObject, leftObject, rightObject, NIL, parms.parms, FALSE, switchBox];
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] RETURNS [switchBox: CabbagePrivate.Channel] ~ {

bottomObject, topObject, leftObject, rightObject: Cabbage.Object;
SELECT corner FROM
bottomLeft => {
topObject _ ShellFromFullChannel[handle.detailedRouting.channels[left], bottom, parms.rules.branchLayer, parms.rules];
bottomObject _ ShellFromChannel[handle.powerDistribution.power[bottom], top, parms.rules.branchLayer, horizRange, parms.rules];
leftObject _ ShellFromChannel[handle.powerDistribution.power[left], right, parms.rules.trunkLayer, vertRange, parms.rules];
rightObject _ ShellFromFullChannel[handle.detailedRouting.channels[bottom], left, parms.rules.trunkLayer, parms.rules]};

bottomRight => {
topObject _ ShellFromFullChannel[handle.detailedRouting.channels[right], bottom, parms.rules.branchLayer, parms.rules];
bottomObject _ ShellFromChannel[handle.powerDistribution.power[bottom], top, parms.rules.branchLayer, horizRange, parms.rules];
rightObject _ ShellFromChannel[handle.powerDistribution.power[right], left, parms.rules.trunkLayer, vertRange, parms.rules];
leftObject _ ShellFromFullChannel[handle.detailedRouting.channels[bottom], right, parms.rules.trunkLayer, parms.rules]};

topRight => {
bottomObject _ ShellFromFullChannel[handle.detailedRouting.channels[right], top, parms.rules.branchLayer, parms.rules];
topObject _ ShellFromChannel[handle.powerDistribution.power[top], bottom, parms.rules.branchLayer, horizRange, parms.rules];
rightObject _ ShellFromChannel[handle.powerDistribution.power[right], left, parms.rules.trunkLayer, vertRange, parms.rules];
leftObject _ ShellFromFullChannel[handle.detailedRouting.channels[top], right, parms.rules.trunkLayer, parms.rules]};

topLeft => {
bottomObject _ ShellFromFullChannel[handle.detailedRouting.channels[left], top, parms.rules.branchLayer, parms.rules];
topObject _ ShellFromChannel[handle.powerDistribution.power[top], bottom, parms.rules.branchLayer, horizRange, parms.rules];
leftObject _ ShellFromChannel[handle.powerDistribution.power[left], right, parms.rules.trunkLayer, vertRange, parms.rules];
rightObject _ ShellFromFullChannel[handle.detailedRouting.channels[top], left, parms.rules.trunkLayer, parms.rules]};

ENDCASE;

parms.parms.wireWidthProc _ GetWireWidth;
parms.parms.context _ handle.widthTable;
switchBox.object _ PWRoute.MakeChannel[bottomObject, topObject, leftObject, rightObject, NIL, parms.parms, FALSE, switchBox];
switchBox.size _ RTBasic.IRSize[switchBox.object];
switchBox.cellType _ ExtractChannel[switchBox, parms]};
MakeChip: PUBLIC PROC [handle: CabbagePrivate.Handle] RETURNS [chip: Cabbage.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: Cabbage.Side IN Cabbage.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: Cabbage.Side IN RTBasic.LRSide DO
IncludeObject[handle.detailedRoutingPL.channels[side].object, handle.detailedRoutingPL.channels[side].origin, chip];
ENDLOOP;
FOR side: Cabbage.Side IN RTBasic.TBSide DO
IncludeObject[handle.detailedRoutingPL.switchBoxes[side].object, handle.detailedRoutingPL.switchBoxes[side].origin, chip];
ENDLOOP};

FOR side: Cabbage.Side IN Cabbage.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];
ENDLOOP;

[] _ RTBasic.RepositionCell[chip]};
MappedShellFromObject: PROC [handle: CabbagePrivate.Handle,
objectDes: CabbagePrivate.ObjectDescription,
pinSide: Route.Side,	-- the side of the object on which pins are to be considered
innerRange, outerRange: Connections.Range,  -- innerRange is the span of the inner cell, outerRangethe span of the appropriate power routing cell
viaSize: INT,	-- the size of the via alont the lenght of the cell
rules: Route.DesignRules]
RETURNS [shell: Cabbage.Object _ CDCells.CreateEmptyCell[]] ~ {

EnterPowerOnInner: Connections.EachNetAction ~ {
EachSegment: Connections.EachSegmentAction ~ {
IF (segment.object = handle.inner.object AND segment.side = otherSide) AND (Rope.Equal[net.name, "Vdd"] OR Rope.Equal[net.name, "Gnd"]) THEN
Insert[obstacles, [innerOrigin + segment.range.min, innerOrigin + segment.range.max], rules.branchToBranch]};

[] _ Connections.EnumerateSegments[net, EachSegment]};

EnterPowerOnOuter: Connections.EachNetAction ~ {
EachSegment: Connections.EachSegmentAction ~ {
IF (segment.object = objectDes.object AND segment.side = pinSide) AND (Rope.Equal[net.name, "Vdd"] OR Rope.Equal[net.name, "Gnd"]) THEN
Insert[obstacles, [outerOrigin + segment.range.min, outerOrigin + segment.range.max], rules.branchToBranch]};

[] _ Connections.EnumerateSegments[net, EachSegment]};

EachOuterNet: Connections.EachNetAction ~ {
EachSegment: Connections.EachSegmentAction ~ {
IF (segment.object = objectDes.object AND segment.side = pinSide) THEN {
useThisPin: BOOLEAN _ TRUE;
newRange: Connections.Range;
powerNet: BOOLEAN _ Rope.Equal[net.name, "Vdd"] OR Rope.Equal[net. name, "Gnd"];
adjustedRange: Connections.Range _ [outerOrigin + segment.range.min, outerOrigin + segment.range.max];
IF ProperSubset[adjustedRange, outerRange] THEN { 
IF powerNet THEN newRange _ adjustedRange
ELSE IF HashTable.Insert[netTable, net.name, NIL] THEN 
newRange _ FindMiddleRange[adjustedRange, obstacles]
ELSE useThisPin _ FALSE}

ELSE IF ProperSubset[adjustedRange, [FIRST[INT], outerRange.min]] THEN {
IF powerNet THEN {
Cabbage.Signal[callingError, Rope.Cat[net.name, " pin on pad frame is in invalid position (within lower power bus corner)"]];
useThisPin _ FALSE}
ELSE IF HashTable.Insert[netTable, net.name, NIL] THEN { 
lowerRange: Connections.Range _ [outerRange.min, outerRange.min + (adjustedRange.max-adjustedRange.min)];
newRange _ FindLowerRange[lowerRange, obstacles]}
ELSE useThisPin _ FALSE}

ELSE IF ProperSubset[adjustedRange, [outerRange.max, LAST[INT]]] THEN {
IF powerNet THEN {
Cabbage.Signal[callingError, Rope.Cat[net.name, " pin on pad frame is in invalid position (within upper power bus corner)"]];
useThisPin _ FALSE}
ELSE IF HashTable.Insert[netTable, net.name, NIL] THEN {
upperRange: Connections.Range _ [outerRange.max - (adjustedRange.max-adjustedRange.min), outerRange.max];
newRange _ FindUpperRange[upperRange, obstacles]}
ELSE useThisPin _ FALSE}

ELSE {
Cabbage.Signal[callingError, Rope.Cat["Segment on net: ", net.name, " crosses boundary of power routing area"]];
useThisPin _ FALSE};

IF useThisPin THEN {
denotes: CD.Rect _ SELECT pinSide FROM
bottom => [newRange.min, oldIR.y2-rules.trunkWidth, newRange.max, oldIR.y2],
right => [oldIR.x1, newRange.min, oldIR.x1+rules.trunkWidth, newRange.max],
top => [newRange.min, oldIR.y1, newRange.max, oldIR.y1+rules.trunkWidth],
left => [oldIR.x2-rules.trunkWidth, newRange.min, oldIR.x2, newRange.max],
ENDCASE => Cabbage.Error[programmingError, "Not suppose to happen."];
IncludePin[object: shell, name: net.name, denotes: denotes, layer: rules.branchLayer];
IF ~powerNet THEN  -- power nets were inserted first
Insert[obstacles, newRange, rules.branchToBranch];
}}};

[] _ Connections.EnumerateSegments[net, EachSegment]};

netTable: HashTable.Table _ HashTable.Create[equal: HashTable.RopeEqual, hash: HashTable.HashRope];
oldIR: CD.Rect _ CD.InterestRect[objectDes.object];
interestRect: CD.Rect _ SELECT pinSide FROM
bottom, top => interestRect _ [outerRange.min, oldIR.y1, outerRange.max, oldIR.y2],
left, right => [oldIR.x1, outerRange.min, oldIR.x2, outerRange.max],
ENDCASE => Cabbage.Error[programmingError, "Not suppose to happen."];
otherSide: Route.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."];

obstacles: BitTable _ CreateBitTable[outerRange.min, outerRange.max, rules.CDLambda];
Insert[obstacles, [outerRange.min, outerRange.min + viaSize], rules.branchToBranch];
Insert[obstacles, [outerRange.max - viaSize, outerRange.max], rules.branchToBranch];
Insert[obstacles, [innerRange.min - 3*rules.branchToBranch, innerRange.min + 3*rules.branchToBranch], rules.branchToBranch];
Insert[obstacles, [innerRange.max - 3*rules.branchToBranch, innerRange.max + 3*rules.branchToBranch], rules.branchToBranch];

[] _ Connections.EnumerateNets[handle.connections, EnterPowerOnInner];
[] _ Connections.EnumerateNets[handle.connections, EnterPowerOnOuter];
[] _ Connections.EnumerateNets[handle.connections, EachOuterNet];
CDCells.SetInterestRect[design: NIL, cell: shell, r: interestRect];
RTBasic.RepositionCell[shell]};

ShellFromOutsideEnd: PROC [handle: CabbagePrivate.Handle,
objectDes: CabbagePrivate.ObjectDescription,
pinsOnSide, endOfChannel: Route.Side,
innerRange, outerRange: Connections.Range,  -- the span along the appropriate padring cell
rules: Route.DesignRules]
RETURNS [shell: Cabbage.Object _ CDCells.CreateEmptyCell[]] ~ {
EachNet: Connections.EachNetAction ~ {
EachSegment: Connections.EachSegmentAction ~ {
IF (segment.object = objectDes.object AND segment.side = pinsOnSide) THEN {
adjustedRange: Connections.Range _ [origin + segment.range.min, origin + segment.range.max];
IF CrossesBoundry[adjustedRange, interestingRange] THEN 
Cabbage.Signal[callingError, Rope.Cat["Segment on net: ", net.name, " crosses boundary of power routing areas"]];
IF ProperSubset[adjustedRange, interestingRange] AND ~Member[net.name, netNameList] THEN { 
width: INT _ MAX[rules.trunkWidth, net.width];
dist _ dist + rules.trunkWidth;
SELECT endOfChannel FROM
bottom => IncludePin[object: shell, name: net.name, denotes: [dist, rules.trunkWidth, dist + width, 2*rules.trunkWidth], layer: rules.trunkLayer];
right => IncludePin[object: shell, name: net.name, denotes: [0, dist, rules.trunkWidth, dist + width], layer: rules.trunkLayer];
top => IncludePin[object: shell, name: net.name, denotes: [dist, 0, dist + width, rules.trunkWidth], layer: rules.trunkLayer];
left => IncludePin[object: shell, name: net.name, denotes: [rules.trunkWidth, dist, 2*rules.trunkWidth, dist + width], layer: rules.trunkLayer];
ENDCASE;
netNameList _ CONS[net.name, netNameList];
dist _ dist + width}}};

[] _ Connections.EnumerateSegments[net, EachSegment]};

dist: INT _ rules.trunkWidth;
netNameList: LIST OF Rope.ROPE _ LIST["Vdd", "Gnd"];  -- pre load with power names
interestRect: CD.Rect;
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."];
[] _ Connections.EnumerateNets[handle.connections, EachNet];
interestRect _ SELECT endOfChannel FROM
bottom, top => [0, 0, dist + rules.trunkWidth, 2*rules.trunkWidth],
left, right => [0, 0, 2*rules.trunkWidth, dist + 2*rules.trunkWidth],
ENDCASE => Cabbage.Error[programmingError, "Not suppose to happen"];
CDCells.SetInterestRect[design: NIL, cell: shell, r: interestRect];
RTBasic.RepositionCell[shell]};

ShellFromObject: PROC [handle: CabbagePrivate.Handle,
objectDes: CabbagePrivate.ObjectDescription,
side: Route.Side,  -- the side of the object on which pins are to be considered
range: Connections.Range, -- the span along objectDes to consider
rules: Route.DesignRules,
includePowerNets: BOOLEAN]
RETURNS [shell: Cabbage.Object _ CDCells.CreateEmptyCell[]] ~ {

EachNet: Connections.EachNetAction ~ {
EachSegment: Connections.EachSegmentAction ~ {
IF (segment.object = objectDes.object AND segment.side = side) THEN {
adjustedRange: Connections.Range _ [origin + segment.range.min, origin + segment.range.max];
powerNet: BOOLEAN _ Rope.Equal[net.name, "Vdd"] OR Rope.Equal[net. name, "Gnd"];
IF CrossesBoundry[adjustedRange, range] THEN 
Cabbage.Signal[callingError, Rope.Cat["Segment on net: ", net.name, " crosses a boundary of the power routing areas"]];
IF ProperSubset[adjustedRange, range] AND (includePowerNets OR ~powerNet) THEN { 
SELECT side FROM
bottom => IncludePin[object: shell, name: net.name, denotes: [adjustedRange.min, oldIR.y1, adjustedRange.max, oldIR.y1+rules.trunkWidth], layer: segment.layer];
right => IncludePin[object: shell, name: net.name, denotes: [oldIR.x2-rules.trunkWidth, adjustedRange.min, oldIR.x2, adjustedRange.max], layer: segment.layer];
top => IncludePin[object: shell, name: net.name, denotes: [adjustedRange.min, oldIR.y2-rules.trunkWidth, adjustedRange.max, oldIR.y2], layer: segment.layer];
left => IncludePin[object: shell, name: net.name, denotes: [oldIR.x1, adjustedRange.min, oldIR.x1+rules.trunkWidth, adjustedRange.max], layer: segment.layer];
ENDCASE}}};

[] _ Connections.EnumerateSegments[net, EachSegment]};

oldIR: CD.Rect _ CD.InterestRect[objectDes.object];
interestRect: CD.Rect;
origin: INT _ SELECT side FROM
bottom, top => objectDes.origin.x,
right, left => objectDes.origin.y,
ENDCASE => Cabbage.Error[programmingError, "Not suppose to happen."];
[] _ Connections.EnumerateNets[handle.connections, EachNet];
interestRect _ SELECT side FROM
bottom, top => interestRect _ [range.min, oldIR.y1, range.max, oldIR.y2],
left, right => [oldIR.x1, range.min, oldIR.x2, range.max],
ENDCASE => Cabbage.Error[programmingError, "Not suppose to happen."];
CDCells.SetInterestRect[design: NIL, cell: shell, r: interestRect];
RTBasic.RepositionCell[shell]};

ShellFromEnd: PROC [handle: CabbagePrivate.Handle, division: CabbagePrivate.Division, side: Route.Side, rules: Route.DesignRules] RETURNS [shell: Cabbage.Object _ CDCells.CreateEmptyCell[]] ~ {

EachExit: EachExitAction ~ {
IF ~(Rope.Equal[net.name, "Vdd"] OR Rope.Equal[net. name, "Gnd"]) THEN {
width: INT _ MAX[rules.trunkWidth, net.width];
dist _ dist + rules.trunkWidth;
SELECT side FROM
bottom => IncludePin[object: shell, name: net.name, denotes: [dist, rules.trunkWidth, dist + width, 2*rules.trunkWidth], layer: rules.trunkLayer];
right => IncludePin[object: shell, name: net.name, denotes: [0, dist, rules.trunkWidth, dist + width], layer: rules.trunkLayer];
top => IncludePin[object: shell, name: net.name, denotes: [dist, 0, dist + width, rules.trunkWidth], layer: rules.trunkLayer];
left => IncludePin[object: shell, name: net.name, denotes: [rules.trunkWidth, dist, 2*rules.trunkWidth, dist + width], layer: rules.trunkLayer];
ENDCASE;
dist _ dist + width}};

dist: INT _ 0;
interestRect: CD.Rect;
[] _ EnumerateExits[handle.globalRouting.exitLists[division], division, EachExit];
interestRect _ SELECT side FROM
bottom, top => [0, 0, dist + rules.trunkWidth, 2*rules.trunkWidth],
left, right => [0, 0, 2*rules.trunkWidth, dist + rules.trunkWidth],
ENDCASE => Cabbage.Error[programmingError, "Not suppose to happen"];
CDCells.SetInterestRect[design: NIL, cell: shell, r: interestRect];
RTBasic.RepositionCell[shell]};

ShellFromFullChannel: PROC [channel: CabbagePrivate.Channel, side: Route.Side, pinLayer: CD.Layer, rules: Route.DesignRules] RETURNS [shell: Cabbage.Object] ~ {

rect: CD.Rect _ CD.InterestRect[channel.object];
range: Connections.Range _ SELECT side FROM
bottom, top => [rect.x1, rect.x2],
left, right => [rect.y1, rect.y2],
ENDCASE => Cabbage.Error[programmingError, "Not suppose to happen"];
RETURN [ShellFromChannel[channel, side, pinLayer, range, rules]]};

ShellFromChannel: PROC [channel: CabbagePrivate.Channel, pinSide: Route.Side, pinLayer: CD.Layer, range: Connections.Range, rules: Route.DesignRules] RETURNS [shell: Cabbage.Object _ CDCells.CreateEmptyCell[]] ~ {

ChanPublics: CoreGeometry.EachWirePinProc ~ {
name: Rope.ROPE _ CoreOps.GetShortWireName[wire];
IF layer = pinLayer THEN {
SELECT side FROM
bottom => IF range.min <= rect.x1+max AND rect.x1+max <= range.max AND pinSide = bottom THEN IncludePin[object: shell, name: name, denotes: [rect.x1+min, rect.y1, rect.x1+max, rect.y1+depth], layer: layer];
right => IF range.min <= rect.y1+max AND rect.y1+max <= range.max AND pinSide = right THEN IncludePin[object: shell, name: name, denotes: [rect.x2-depth, rect.y1+min, rect.x2, rect.y1+max], layer: layer];
top => IF range.min <= rect.x1+max AND rect.x1+max <= range.max AND pinSide = top THEN IncludePin[object: shell, name: name, denotes: [rect.x1+min, rect.y2-depth, rect.x1+max, rect.y2], layer: layer];
left => IF range.min <= rect.y1+max AND rect.y1+max <= range.max AND pinSide = left THEN IncludePin[object: shell, name: name, denotes: [rect.x1, rect.y1+min, rect.x1+depth, rect.y1+max], layer: layer];
ENDCASE}};

mode: Sinix.Mode = SinixOps.GetExtractMode[rules.technology];
depth: Route.Number _ rules.trunkWidth;
rect: CD.Rect _ CD.InterestRect[channel.object];
newRect: CD.Rect _ SELECT pinSide FROM
bottom, top => [range.min, rect.y1, range.max, rect.y2],
left, right => [rect.x1, range.min, rect.x2, range.max],
ENDCASE => Cabbage.Error[programmingError, "Not suppose to happen"];
[] _ CoreGeometry.EnumerateNonOverlappingSides[mode.decoration, channel.cellType, ChanPublics];
CDCells.SetInterestRect[design: NIL, cell: shell, r: newRect];
RTBasic.RepositionCell[shell]};
AdjustPositions: PROC [handle: CabbagePrivate.Handle] ~ {

powerWidth: INT _ handle.parms.outerChanWidth + handle.parms.powerCellWidth;
routeType: CabbagePrivate.RouteType _ handle.routeType;
sizeBottomArea: INT _ handle.inner.origin.y - (handle.bottom.origin.y + handle.bottom.size.y);
sizeBottomRouting: INT _ powerWidth + (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 _ powerWidth + (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 _ powerWidth + (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 _ powerWidth + (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: Cabbage.Object, origin: CD.Position, chip: Cabbage.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.rules.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);
};

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

GetSize: PROC [handle: CabbagePrivate.Handle] RETURNS [hBottom, hTop, vLeft, vRight: INT] ~ {

vMiddle, hMiddle: INT;
powerWidth: INT _ handle.parms.outerChanWidth + handle.parms.powerCellWidth;
IF handle.routeType = normal THEN {
vMiddle _ handle.bottom.size.y + powerWidth + handle.detailedRouting.channels[bottom].size.y + handle.inner.size.y + handle.detailedRouting.channels[top].size.y + powerWidth + handle.top.size.y;
hMiddle _ handle.left.size.x + powerWidth + handle.detailedRouting.channels[left].size.x + handle.inner.size.x + handle.detailedRouting.channels[right].size.x + powerWidth + handle.right.size.x}
ELSE {
hCenter: INT _ powerWidth + handle.detailedRoutingPL.channels[left].size.x + handle.inner.size.x + handle.detailedRoutingPL.channels[right].size.x + powerWidth;
hInner: INT _ MAX[hCenter, handle.detailedRoutingPL.switchBoxes[top].size.x, handle.detailedRoutingPL.switchBoxes[bottom].size.x];
vInner: INT _ powerWidth + handle.detailedRoutingPL.switchBoxes[bottom].size.y + handle.inner.size.y + handle.detailedRoutingPL.switchBoxes[top].size.y + powerWidth;
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] ~ {

outerChanWidth: INT _ handle.parms.outerChanWidth;
powerWidth: INT _ outerChanWidth + handle.parms.powerCellWidth;
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 + powerWidth, bottomInterior + powerWidth];
handle.detailedRouting.switchBoxes[bottomRight].origin _ [rightOfInner, bottomInterior + powerWidth];
handle.detailedRouting.switchBoxes[topRight].origin _ [rightOfInner, topOfInner];
handle.detailedRouting.switchBoxes[topLeft].origin _ [leftInterior + powerWidth, 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 + powerWidth, bottomInterior + powerWidth];
handle.detailedRoutingPL.switchBoxes[top].origin _ [leftInterior + powerWidth, topOfInner]};

handle.powerDistribution.channels[bottom].origin _ [leftInterior + powerWidth, bottomInterior];
handle.powerDistribution.channels[right].origin _ [rightInterior - outerChanWidth, bottomInterior + powerWidth];
handle.powerDistribution.channels[top].origin _ [leftInterior + powerWidth, topInterior - outerChanWidth];
handle.powerDistribution.channels[left].origin _ [leftInterior, bottomInterior + powerWidth];

handle.powerDistribution.power[bottom].origin _ [leftInterior + powerWidth, bottomInterior + outerChanWidth];
handle.powerDistribution.power[right].origin _ [rightInterior - powerWidth, bottomInterior + powerWidth];
handle.powerDistribution.power[top].origin _ [leftInterior + powerWidth, topInterior - powerWidth];
handle.powerDistribution.power[left] .origin_ [leftInterior + outerChanWidth, bottomInterior + powerWidth];

handle.powerDistribution.switchBoxes[bottomLeft].origin _ [leftInterior, bottomInterior];
handle.powerDistribution.switchBoxes[bottomRight].origin _ [rightInterior - powerWidth, bottomInterior];
handle.powerDistribution.switchBoxes[topRight].origin _ [rightInterior - powerWidth, topInterior - powerWidth];
handle.powerDistribution.switchBoxes[topLeft].origin _ [leftInterior, topInterior - powerWidth]};

IncludePin: PROC [object: CD.Object, name: Rope.ROPE, denotes: CD.Rect, layer: CD.Layer] ~ {

pin: CD.Object _ CDSymbolicObjects.CreatePin[CDBasics.SizeOfRect[denotes]];
pinInstance: CD.Instance _ RouteUtil.Include[cell: object, ob: pin, position: CDBasics.BaseOfRect[denotes], orientation: original];
CDProperties.PutInstanceProp[pinInstance, cabbageXPos, NEW[INT _ denotes.x1]];
CDProperties.PutInstanceProp[pinInstance, cabbageYPos, NEW[INT _ denotes.y1]];
CDSymbolicObjects.SetName[pinInstance, name];
CDSymbolicObjects.SetLayer[pinInstance, layer]};

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]};
EqualProc: PROC [k1, k2: HashTable.Key] RETURNS [eq: BOOL] = {
p1: Route.Position _ NARROW[k1, REF Route.Position]^;
p2: Route.Position _ NARROW[k2, REF Route.Position]^;
eq _ p1.x = p2.x AND p1.y = p2.y};

HashProc: PROC [k: HashTable.Key] RETURNS [hash: CARDINAL] = {
size: Route.Position _ NARROW[k, REF Route.Position]^;
hash _ size.x + size.y};
BitTable: TYPE = REF BitTableRec;
BitTableRec: TYPE = RECORD[
bitSize: NAT _ 8,				-- CD.Number per lambdas
min, max: INT _ 0,				-- outerRange
bits: PACKED SEQUENCE size: NAT OF BOOL];	-- TRUE=busy
Translate: PROC [obstacles: BitTable, pos: INT] RETURNS [bitIndex: NAT] ~ INLINE {
bitIndex _ (pos-obstacles.min)/obstacles.bitSize;
IF bitIndex NOT IN [0..obstacles.size) THEN ERROR};

CreateBitTable: PROC [min, max: INT, bitSize: NAT] RETURNS [bitTable: BitTable] ~ {
size: NAT _ (max/bitSize)-(min/bitSize)+1;
bitTable _ NEW[BitTableRec[size]];
bitTable.bitSize _ bitSize;
bitTable.min _ min;
bitTable.max _ max;
FOR i: NAT IN [0..size) DO
bitTable[i] _ FALSE;
ENDLOOP};

PositionOccupied: PROC [obstacles: BitTable, pos: INT] RETURNS [BOOL] ~ INLINE {
RETURN[obstacles[Translate[obstacles, pos]]]};

NextPos: PROC [obstacles: BitTable, from: INT, goingUp: BOOL] RETURNS [next: INT] ~ INLINE {
next _ IF goingUp THEN from+1 ELSE from-1};

Edge: PROC [obstacles: BitTable, goingUp: BOOL] RETURNS [pos: INT] ~ INLINE {
pos _ IF goingUp THEN obstacles.max ELSE obstacles.min};

SetOccupied: PROC [obstacles: BitTable, pos: INT] ~ INLINE {
IF pos NOT IN [obstacles.min..obstacles.max] THEN RETURN;
obstacles[Translate[obstacles, pos]] _ TRUE};

Insert: PROC [obstacles: BitTable, range: Connections.Range, spacing: INT] ~ {
FOR pos: INT IN [range.min-spacing..range.max+spacing] DO
SetOccupied[obstacles, pos];
ENDLOOP};

IsFree: PROC [range: Connections.Range, obstacles: BitTable, goingUp: BOOL] RETURNS [isFree: BOOL, nextTry: INT] ~ {
FOR pos: INT IN [range.min..range.max] DO
IF PositionOccupied[obstacles, pos] THEN RETURN[FALSE, FindNextFree[obstacles, pos, goingUp]];
ENDLOOP;
RETURN[TRUE, range.min]};

FindNextFree: PROC [obstacles: BitTable, from: INT, goingUp: BOOL] RETURNS [free: INT] ~ {
free _ from;
WHILE PositionOccupied[obstacles, free] AND free#Edge[obstacles, goingUp] DO
free _ NextPos[obstacles, free, goingUp];
ENDLOOP};

FindLowerRange: PROC [adjustedRange: Connections.Range, obstacles: BitTable] RETURNS [newRange: Connections.Range] ~ {
isFree: BOOL _ FALSE;
nextTry: INT;
newRange _ adjustedRange;
WHILE ~isFree DO
[isFree, nextTry] _ IsFree[newRange, obstacles, TRUE];
IF nextTry>=obstacles.max THEN Cabbage.Signal[noResource, "No space for pin on power bus side."];
newRange _ [nextTry + obstacles.bitSize, nextTry + obstacles.bitSize + (adjustedRange.max-adjustedRange.min)];	-- noop if isFree
ENDLOOP};

FindUpperRange: PROC [adjustedRange: Connections.Range, obstacles: BitTable] RETURNS [newRange: Connections.Range] ~ {
isFree: BOOL _ FALSE;
nextTry: INT;
newRange _ adjustedRange;
WHILE ~isFree DO
[isFree, nextTry] _ IsFree[newRange, obstacles, FALSE];
IF nextTry<=obstacles.min THEN Cabbage.Signal[noResource, "No space for pin on power bus side."];
newRange _ [nextTry - obstacles.bitSize - (adjustedRange.max-adjustedRange.min), nextTry - obstacles.bitSize];	-- noop if isFree
ENDLOOP};

FindMiddleRange: PROC [adjustedRange: Connections.Range, obstacles: BitTable] RETURNS [newRange: Connections.Range] ~ {
IF IsFree[adjustedRange, obstacles, FALSE].isFree THEN RETURN[adjustedRange]
ELSE {
fellOffLower, fellOffUpper: BOOL _ FALSE;
lower, upper: Connections.Range;	-- CEDAR Bug! Signals in initialization
upper _ FindLowerRange[adjustedRange, obstacles ! Cabbage.Signal => IF errorType=noResource THEN {fellOffUpper _ TRUE; CONTINUE}];
lower _ FindUpperRange[adjustedRange, obstacles ! Cabbage.Signal => IF errorType=noResource THEN {fellOffLower _ TRUE; CONTINUE}];
IF fellOffUpper AND fellOffLower THEN Cabbage.Signal[noResource, "No space for pin on power bus side."];
IF fellOffUpper THEN RETURN[lower];
IF fellOffLower THEN RETURN[upper];
IF adjustedRange.min-lower.min<upper.min-adjustedRange.min THEN RETURN[lower];
RETURN[upper]}};
PWRouteContext: TYPE = RECORD [
direction: RTBasic.Direction,
table: Connections.Table];

GetWireWidth: PWRoute.WireWidthProc ~ {
table: Connections.Table _ NARROW[context, REF PWRouteContext].table;
net: Connections.Net _ Connections.Fetch[table, netName].net;
wireWidth _ net.width};

PinName: PWRoute.MakeTabKeyProc ~ {
name: Rope.ROPE _ CDSymbolicObjects.GetName[pinInst];
IF Rope.Equal[name, "Vdd"] OR Rope.Equal[name, "Gnd"] THEN {
direction: RTBasic.Direction _ NARROW[context, REF PWRouteContext].direction;
refPosition: REF ANY _ IF direction = horizontal THEN CDProperties.GetInstanceProp[pinInst, cabbageXPos]
ELSE CDProperties.GetInstanceProp[pinInst, cabbageYPos];
position: INT _ NARROW[refPosition, REF INT]^;
tabIndex _ Rope.Cat[name, Convert.RopeFromInt[position]]}
ELSE
tabIndex _ name};

}.

��!��CabbageProcsImpl.mesa	
Copyright Ó 1986, 1987 by Xerox Corporation.  All rights reversed.
Created by Bryan Preas, June 4, 1986 4:02:08 pm PDT
Bryan Preas April 2, 1987 6:03:17 pm PST
Last Edited by: Louis Monier April 23, 1987 4:18:11 pm PDT

Cabbage needs to be fixed when PWRoute removes PWPins.
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.
horizParms and vertParms specify the routing for the specified direction; horizRange and vertRange describe the projection of the inner onto the pad ring

route the outside channels
construct the power routing channels; route signal pins on the outer straight accross with vias as necessary.
horizParms and vertParms 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
route one of the outside channels
construct the bonding objects to pass to the channel router
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
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
REMOVE branch stuff in Cabbage25

construct power trunks
build the branches
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
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
construct the bonding objects to pass to the channel router
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
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
Shell Construction
build a shell for inner edge of the outside channel and the outer edge of the power cell; input to PWRoute;  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 middle range
IF net = Vdd OR net = Gnd OR net has not been processed for this side THEN useThisPin
pin is within lower range
IF ~(net = Vdd OR net = Gnd) AND net has not been processed for this side THEN useThisPin
pin is within upper range
IF ~(net = Vdd OR net = Gnd) AND net has not been processed for this side THEN useThisPin
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
build a shell for end of the channel on the periprery; input to PWRoute
transfer pins on objectDes outside the range (on side endOfChannel) to shell.
pins go on rules.trunkLayer
 
PROC [key: Key, net: Net] RETURNS [quit: BOOLEAN _ FALSE]
PROC [net: Net, segment: Segment] RETURNS [quit: BOOLEAN _ FALSE]
build a shell 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]
build a shell for end of channel; input to router
PROC [division: CabbagePrivate.Division, net: Connections.Net] RETURNS [quit: BOOLEAN _ FALSE];
build a PWPins shell for the channel; use the full side of channel with pins on side
build a PWPins shell 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
Utility Procedures
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 r1 is within r2

short hand to make the following easier to understand
the outside routing channels
the power channels
the outside corners
include a pin(name, denotes, layer) in an object
properties are use to pass position info because of restrictions in PWPins
Return TRUE if item is on list
HashTable Procedures
call back procs for HashTable
Obstacle manipulation Procedures...
-- Assertion: obstacles do not overlap: if you insert a new obstacle and it overlaps an existing one in the table, the two are fused and the resulting union is put in the table; this should be maintained at all time
-- The table contains the projection of the pins with the design rule space on each side
-- [outerRange.min..outerRange.max] must map into [0..obstacles.size-1]
-- Assertion: pos must be in (obstacles.min..obstacles.max)!!!
-- Bloat range by a spacing on each side on insertion; there is space here, you know it!
-- when isFree, then nextTry=range.min
-- range must be valid (within outerRange)
find a neRange were pin is not hidden by a pin in obstacles and does not interfere with existing pin
pin should be close to outerRange.min
find a newRange were pin is not hidden by a pin in obstacles and does not interfere with existing pin
pin should be close to outerRange.max
find a neRange were pin is not hidden by a pin in obstacles and does not interfere with existing pin
PWRoute CallBacks
context to pass to PWRoute for wire widths (GetWireWidth) and pin names (PinName)
call back procs for PWRoute
PROC [netName: ROPE, context: REF ANY] RETURNS [wireWidth: INT]
PROC [pinInst: CD.Instance, context: REF ANY] RETURNS [tabIndex: Rope.ROPE]
call back Proc for PWRoute;  this separates Vdd and Gnd into two pin nets
Ê8Î��˜�code–
"Cedar" stylešœ™KšœB™BKšœ0Ïk™3Kšœ%™(Kšœ7™:K™�K™6—K˜�Kš	œ"œ™œ<˜„K˜�šÏnœœ˜Kšœœ“œ;˜ëKšœ˜Kšœ
˜—headšÏl™Kšœ
œ˜!Kšœ
œ˜!K˜�š
žœœœ¨œ'œ#˜–Kšœ	œR˜^Kšœ˜Kšœ(˜(Kšœœ&˜DKšœœ"˜<šœœ˜Kšœœ#˜?—šœ˜Kšœœ&˜D—Kšœ^˜^Kšœœœ˜3Kšœ˜K˜�—KšœŒ™Œšžœœ œ.˜lK˜�KšœœG˜QKšœœF˜PKš	œœœœœ4˜€Kšœœ ˜1K˜�KšœœÝœG˜ËKšœœÝœG˜ÊK˜�Kšœh˜hKšœe˜eKšœ*™*KšœU˜UKšœT˜TK˜�—šžœœ˜K˜�Kšœœ*˜5Kšœ;˜;K˜�Kšœ=˜=Kšœ;˜;Kšœ7˜7Kšœ9˜9K˜�Kšœ_˜_Kšœb˜bKšœY˜YKšœW˜WK˜�—šžœœ&œœ-˜yK˜�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šœ=˜=Kšœ;˜;Kšœœ¡˜«Kšœœ+˜:Kšœ)˜)Kšœ˜Kšœ+˜+Kšœ˜Kšœ!˜!K˜�—šžœœ*œ˜LKšœi™iKšœ™™™Kšœœ˜2Kšœœ0˜?Kšœ=˜=Kšœ;˜;Kšœj˜jKšœ‚˜‚Kšœi˜išœƒ˜ƒK™�—Kšœ™Kšœ¥˜¥Kšœ¡˜¡Kšœœ˜œKšœŸ˜ŸK˜�—šžœœ-œ˜QKšœm™mšœ™™™K˜�—Kšœœ˜2Kšœœ0˜?Kšœ=˜=Kšœ;˜;Kšœj˜jKšœ‚˜‚Kšœi˜iKšœƒ˜ƒK˜�Kšœ&™&Kšœ³˜³Kšœ¯˜¯Kšœª˜ªKšœ­˜­K˜�—Kšœ!™!šžœœ ˜9Kšœ/Ïc˜FKšœ ?˜QKšœ, ‡˜³Kšœ	œ '˜5Kšœ	œ 2˜@Kšœ˜Kšœ&˜-K˜�Kšœ˜Kšœ˜Kšœœ˜Kšœ0˜0Kš	œœ
œ
œœ˜FKšœœœ
˜.Kš	œœ
œœ
œ˜YK˜�Kšœ;™;šœœœd˜KšœJœ˜T—šœœœJœ˜xKšœe˜i—Kšœƒ˜ƒKšœ”˜”K˜�K˜)Kšœ%˜%KšœœD˜]Kšœ^œ˜uK˜�K˜šœ˜šœ˜Kšœœœ˜,Kšœœœ,˜A—šœ
˜
Kšœœœ˜,Kšœœœ,˜A—šœ˜Kšœœœ˜,Kšœœœ,˜A—šœ	˜	Kšœœœ˜,Kšœœœ,˜A—Kšœ˜K˜�—KšœG˜GKšœ.˜.Kšœ3˜3K˜�—šž
œœ ˜0Kšœ! /˜PKšœ C˜YKšœ 4˜OKšœœ .˜?Kšœœ ˜0Kšœ2˜2Kšœ$˜+K™3Kšœj™jKšœO™OK˜�šžœ"˜-Kšœœœœœœ™[K™>K˜�šžœœœœ˜Qšœœœ
˜'Kšœ!˜!Kšœ6˜6Kšœ˜Kšœ8˜8Kšœ=˜D—šœ
˜Kšœ‘˜‘Kšœ‘˜‘Kšœ=˜D—šœœ˜"Kšœ™Kš -™-šœœ
œ
˜%Kšœpœ˜uKšœpœ˜vKšœ=˜D—Kšœœ ˜*šœ	œœ
˜#Kšœ&˜&Kšœ)˜)Kšœ=˜D—šœ	œœ
˜#Kšœ)˜)Kšœ&˜&Kšœ=˜D—šœœœ
˜*KšœM˜MKšœJ˜JKšœK˜KKšœL˜LKšœ=˜D—KšœR˜R—K˜�—šžœœ˜K˜�Kšœœ1˜CKšœœ0˜Ašœ
˜šœ˜Kšœ—˜—Kšœ­˜­Kšœ•œ(˜À—šœ˜Kšœ°˜°Kšœ•˜•Kšœ•œ'˜¿—šœ	˜	Kšœ—˜—Kšœ­˜­Kšœ•œ(˜À—šœ
˜
Kšœ°˜°Kšœ•˜•Kšœ•œ'˜¿—Kšœ˜	—K˜�—Kšœœ"˜1KšœN˜Nšœœ˜šœœ˜KšœT˜TKšœw˜wKšœ˜——K˜�—šžœ˜&Kšœœœœ™9K™@šžœ#˜.Kšœœœœ™AK˜�šžœœœœ˜Qšœ	œœ
˜+Kšœ9˜9Kšœ˜Kšœ7˜7Kšœ ˜ Kšœ=˜D—šœ
˜Kšœµ˜µKšœµ˜µKšœ˜—šœœ˜"Kšœ™šœœ
œ
˜%KšœŒœ˜‘KšœŒœ˜’Kšœ=˜D—K˜�Kšœ™K˜�Kšœœ ˜*šœ	œœ
˜#KšœB˜BKšœ)˜)Kšœ=˜D—šœ	œœ
˜#Kšœ)˜)KšœC˜CKšœ=˜D—šœœœ
˜*KšœM˜MKšœJ˜JKšœK˜KKšœL˜LKšœ=˜D—KšœV˜V—K˜�—Kšœf˜fšœ&œœ˜Jšœœ˜Kšœd˜dKšœX˜XKšœ˜
———K˜�Kšœ6˜6K˜�—šž
œœœœœœ˜lšœœœ
˜-Kšœ1˜1Kšœ1˜1Kšœ=˜D—Kšœœ/˜8KšœT˜Tšœ	œ˜Kšœœhœ˜tKšœœ ˜*šœ
œœ
˜/KšœI˜IKšœI˜IKšœ=˜D—K˜�Kšœ ™ K˜�KšœœC˜Mšœœœ
˜2Kšœ5˜5Kšœ5˜5Kšœ=˜D—KšœU˜UKšœy˜yKšœR˜RKšœu˜u—K˜�—Kšœ
œ'˜6Kšœœ(˜8Kšœ
œ1˜AKšœ
œ2˜BKšœ3˜3Jšœ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šœ<œ˜CKšœ<œ˜BK˜�Kšœ™Kšœ_˜_Kšœ<˜<K˜�Kšœ˜Kšœ œ'˜JKšœ%˜%Kšœ*˜*Kšœ5˜5K˜�—šžœœ$˜AKšœ ™ Kšœ;˜;K˜�Kšœœ=˜LKšœˆ˜ˆKšœa˜aKšœ‘˜‘KšœY˜YK˜�Kšœ#œ˜(Kšœ‰˜‰Kšœ€˜€Kšœ#œ%œ˜RKšœŒ˜ŒKšœƒ˜ƒKšœ#œ%œ˜TK˜�—šžœœ‹œ(˜ÕKšœ?™?K˜�KšœA˜AK˜�šœ˜šœ˜KšœœœÙ˜öKšœTœ˜[KšœQœ˜XKšœœœØ˜÷K˜�—šœ˜KšœœœÜ˜ùKšœTœ˜[Kšœ
œœÙ˜÷KšœRœ˜ZK˜�—šœ
˜
KšœQœ˜XKšœœœÕ˜õKšœ
œœÓ˜ñKšœRœ˜ZK˜�—šœ˜KšœQœ˜XKšœœœÓ˜óKšœQœ˜XKšœœœÒ˜ñK˜�—Kšœ˜K˜�—Kšœœ˜ Kšœœ˜!KšœœU˜nKšœYœœ
˜}Kšœ2˜2Kšœ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šœ"œˆ˜­Jšœœ˜4Jšœ;˜;K˜�——Kšœœ:˜WKšœ9˜9Kšœ6˜6K˜�—Kšœ)™)Kšœ=˜=K˜�—šžœœ_˜xKšœ:™:šžœ"˜-Kšœœœœœœ™[K™>Kšœœ"˜1šœœ˜*Kšœ:˜:Kšœ=˜D—šœœ˜!Kšœœ•˜·KšœC˜CJšœœ˜+Jšœ3˜3—K˜—J˜�Kšœ4˜4JšœU˜UKšœ˜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šœœ#˜,šœ
œ˜šœœ˜<šœ"œ!˜LKšœ$œ(˜P—Kšœ˜——šœ˜šœœ˜<šœ!œ!˜JKšœ$œ(˜P—Kšœ˜
————šŸ™šž
œœœ$˜>K˜�Kšœ˜K˜Kšœœ˜:Kšœ˜ K˜K˜�—KšœT™Tšž
œœ$˜7K˜�Kšœ=˜=Kšœ;˜;Kšœe˜eKšœd˜dK˜�šœœ˜#Kšœ ˜ Kšœ™˜™Kšœ‘˜‘Kšœ”˜”—šœ ˜ Kšœ›˜›Kšœ˜˜˜—K˜�—Kšœ™šžœœ ˜2Kšœ) ˜DKšœ ?˜WKšœ' /˜VKšœ /˜JKšœ˜Kšœ&˜-K˜�Kšœ˜Kšœ˜Kšœœ˜Kšœœ˜'Kšœ4˜4Kš	œœœœ
œ˜aKš	œœœœœ˜NKšœœœ˜6Kšœ;™;šœœœEœ˜sKšœ[˜_—šœœœZ˜ƒKšœEœ˜O—KšœS˜SKšœd˜dK˜�K˜)Kšœ%˜%KšœœD˜]Kšœaœ˜|K˜�K˜šœ
˜šœ˜KšœœO˜XKšœœœœA˜k—šœ
˜
KšœœL˜UKšœœœ$œ/˜k—šœ˜KšœœL˜UKšœœœ-œ&˜k—šœ	˜	KšœœO˜XKšœœœ	œJ˜k—Kšœ˜K˜�—KšœG˜GKšœ.˜.Kšœ3˜3K˜�—KšœK™KKšœ*™*šžœœ$˜:K˜�Kšœ=˜=K˜�Kšœg˜gKšœj˜jKšœl˜lKšœe˜eK˜�Kšœ$œ&œ˜TKšœ˜K˜�Kšœ$œ&œ˜TKšœ„˜„K˜�Kšœ$œ&œ˜TKšœ{˜{K˜�Kšœ$œ&œ˜TKšœx˜xKšœ$œ&œ˜VK˜�—Kšœ$™$šžœœ$˜<K˜�Kšœ=˜=Kšœœ=˜LK˜�Kšœ}˜}Kšœy˜yKšœr˜rK˜�Kšœ$œ&œ˜SKšœy˜yKšœp˜pKšœ$œ&œ˜VK˜�—šžœœ€œ(˜ÅK˜�Kšœ(˜(Kšœ‹˜‹KšœŒ˜ŒKšœe˜eKš	œœ
œœ
œ˜YK˜�šœ˜šœ˜Kšœeœ˜kKšœœœê˜‡Kšœ€˜€K˜�—šœ˜Kšœbœ˜hKšœœœä˜„Kšœ}˜}K˜�—Kšœ˜K˜�—Kšœ)˜)Kšœ%˜%KšœœD˜]KšœYœœ
˜}Kšœ2˜2Kšœ7˜7K˜�—šžœœŠœ(˜ÍK˜�KšœA˜Ašœ˜šœ˜Kšœv˜vKšœ˜Kšœ{˜{Kšœx˜xK˜�—šœ˜Kšœw˜wKšœ˜Kšœ|˜|Kšœx˜xK˜�—šœ
˜
Kšœw˜wKšœ|˜|Kšœ|˜|Kšœu˜uK˜�—šœ˜Kšœv˜vKšœ|˜|Kšœ{˜{Kšœu˜uK˜�—Kšœ˜K˜�—Kšœ)˜)Kšœ(˜(KšœYœœ
˜}Kšœ2˜2Kšœ7˜7——šŸ™šžœœœ!œ7˜tKšœ<™<Kšœ™Kšœ>˜>KšœH˜HKšœ@˜@KšœJ˜JKšœ>˜>KšœD˜DKšœ:˜:KšœB˜BKšœ<˜<K˜�Kšœ™šœœ˜#šœœ˜)Kšœp˜pJšœ˜—šœ œ˜?Kšœz˜zJšœ˜——K˜�šœ˜šœœ˜+Kšœt˜tJšœ˜—šœœ˜+Kšœz˜zJšœ˜	—K˜�—KšœA™Ašœœ˜)Kšœt˜tKšœn˜nJšœ˜—šœ œ˜?Kšœ~˜~Jšœ˜J˜�—Kšœ#˜#——šŸ™šžœœ ˜;Kšœ,˜,Kšœ <˜QKšœ, e˜‘Kšœ	œ 3˜AKšœ˜Kšœ8˜?Kšœ§™§K™<K™;™GK˜�—šžœ˜0Kšœœœœ™9K™@šžœ#˜.Kšœœœœ™Aš	œ'œœœ˜ŒKšœm˜m——K˜�Kšœ6˜6K˜�—šžœ˜0Kšœœœœ™9K™@šžœ#˜.Kšœœœœ™Aš	œ$œœœ˜‡Kšœm˜m——K˜�Kšœ6˜6K˜�—šžœ˜+Kšœ0™0Kšœœœœ™9šžœ#˜.Kšœ+™+Kšœœœœ™Ašœ$œœ˜HKšœœœ˜Kšœ˜Kšœ
œœ˜PKšœf˜fšœ)œ˜2Kšœ™Kšœœœ*œ™UKšœ
œ˜)šœœ&œœ˜7Kšœ4˜4—šœœ˜K˜�——š
œœœœœ˜HKšœ™Kšœ
œœ*œ™Yšœ
œ˜Kšœ}˜}Kšœ
œ˜—šœœ&œœ˜9Kšœi˜iKšœ1˜1—Kšœœ˜K˜�—š
œœ.œœœ˜GKšœ™Kšœ
œœ*œ™Yšœ
œ˜Kšœ}˜}Kšœ
œ˜—šœœ&œœ˜8Kšœi˜iKšœ1˜1—Kšœœ˜K˜�—šœ˜Kšœp˜pKšœ
œ˜K˜�—šœœ˜šœ	œœ	˜&KšœL˜LKšœK˜KKšœI˜IKšœJ˜JKšœ>˜E—KšœV˜Všœœ !˜4Kšœ2˜2—Kšœ˜———K˜�Kšœ6˜6K˜�—Kšœc˜cKšœœœ ˜3šœœœ	˜+KšœS˜SKšœD˜DKšœ>˜E—Kšœ3˜3šœ
œœ	˜&Kšœ%˜%Kšœ%˜%Kšœ>˜E—šœ
œœ	˜&Kšœ"˜"Kšœ"˜"Kšœ>˜E—K˜�KšœO™OKšœ™KšœU˜UKšœT˜TKšœT˜TKšœ|˜|Kšœ|˜|K˜�KšœJ™JKšœF˜FKšœF˜FKšœA˜AKšœ œ ˜CKšœ˜K˜�—šžœœ ˜9Kšœ,˜,Kšœ%˜%Kšœ, .˜ZKšœ˜Kšœ8˜?KšœG™GKšœM™MKšœ™Kšœ™šžœ˜&Kšœœœœ™9šžœ#˜.Kšœœœœ™Ašœ$œœ˜KKšœ\˜\šœ1œ˜8Kšœq˜q—šœ/œ œ˜[Kšœœœ˜.Kšœ˜šœ˜Kšœ’˜’Kšœ€˜€Kšœ~˜~Kšœ˜Kšœ˜—Kšœœ˜*Kšœ˜———K˜�Kšœ6˜6K˜�—Kšœœ˜Kš
œ
œœœœ ˜RKšœœ˜šœ&œ˜>Kšœœœ˜-Kšœœœ˜*Kšœ>˜E—šœœœ˜$Kšœ"˜"Kšœ"˜"Kšœ>˜E—Kšœ<˜<šœœ˜'KšœC˜CKšœE˜EKšœ=˜D—Kšœ œ ˜CKšœ˜K˜�—šžœœ ˜5Kšœ,˜,Kšœ <˜OKšœ '˜AKšœ˜Kšœœ˜Kšœ8˜?šœ?™?K˜�—šžœ˜&Kšœœœœ™9šžœ#˜.Kšœœœœ™Ašœ$œœ˜EKšœ\˜\Kšœ
œœ˜Pšœ&œ˜-K˜w—šœ$œœœ˜Qšœ˜Kšœ ˜ KšœŸ˜ŸKšœ˜Kšœž˜žKšœ˜————K˜�Kšœ6˜6K˜�—Kšœœœ ˜3Kšœœ˜šœœœ˜Kšœ"˜"Kšœ"˜"Kšœ>˜E—Kšœ<˜<šœœ˜KšœI˜IKšœ:˜:Kšœ>˜E—Kšœ œ ˜CKšœ˜K˜�—šžœœpœ8˜Ášœ1™1K˜�—šžœ˜Kšœ;œœœ™_šœœœ˜HKšœœœ˜.Kšœ˜šœ˜Kšœ’˜’Kšœ€˜€Kšœ~˜~Kšœ˜Kšœ˜—šœ˜K˜�———Kšœœ˜Kšœœ˜KšœR˜Ršœœ˜KšœC˜CKšœC˜CKšœ=˜D—Kšœ œ ˜CKšœ˜K˜�—šžœœ?œ"œ˜ KšœT™TJ˜�Jšœœœ˜0šœœ˜+Kšœ"˜"Kšœ"˜"Kšœ=˜D—Kšœ<˜BK˜�—šžœœBœ<œ8˜ÕKšœ]™]K˜�šžœ"˜-Kšœœœœœœ™[Kšœ2™2Kšœœ"˜1šœœ˜šœ˜Kš	œ
œœœœr˜ÎKš	œ	œœœœr˜ÌKš	œœœœœr˜ÈKš	œœœœœr˜ÊKšœ˜
——K˜�—Jšœ=˜=Kšœ'˜'Kšœœœ˜0šœ	œœ	˜&Kšœ8˜8Kšœ8˜8Kšœ=˜D—Kšœ_˜_Kšœ œ˜>Kšœ˜——šŸ™šžœœ$˜9Kšœ,™,K˜�Kšœœ=˜LKšœ7˜7KšœœK˜^šœœœœ/˜pKšœ6˜:—Kšœœ&˜4KšœœG˜Xšœœœœ-˜lKšœ1˜5—Kšœ	œ"˜.KšœPœ˜TK˜�Kšœ?œœ˜dKšœAœ˜VKšœ?œœ˜dKšœ;œœ˜`Kšœ@œ˜TK˜�KšœR˜Ršœœœ,˜eKšœ3˜7—Kšœ&˜&KšœV˜Všœ!œœ.˜iKšœ2˜6—Kšœ,˜,Kšœ>œ˜OKšœ?œ˜UK˜�K˜K˜Kšœ˜K˜�—šž
œœ"œ$˜[šœ
œ˜Kšœœ˜œK˜�——šžœœBœ˜{Kšœ$™$K˜�JšœC˜CJšœœ/˜@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˜�—Kšœœ3™?šžœœœœ˜Ošœœ˜4Kšœœ˜)—K˜K˜�—Kšœœ™šžœœœ
œ˜Lšœœ˜5Kšœœ˜*—K˜K˜�—šžœœ!œ œ˜]K˜�Kšœœ˜Kšœœ=˜Lšœœ˜#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šœœ˜2Kšœœ0˜?Kšœ7˜7K™�Kšœ5™5Kšœœ. ˜TKšœœ ˜BKšœœ2 ˜ZKšœ
œ ˜?Kšœ
œ ˜BKšœœ0 ˜YKšœœ ˜FKšœœ0 ˜UK˜�šœœ˜Kšœ˜KšœN˜NKšœH˜HKšœ{˜{K˜�Kšœq˜qKšœe˜eKšœQ˜QKšœ]˜]—šœ ˜ KšœP˜PKšœ˜Kšœo˜oKšœ\˜\—K˜�Kšœ™Kšœ_˜_Kšœp˜pKšœj˜jKšœ]˜]K˜�Kšœ™Kšœm˜mKšœi˜iKšœc˜cKšœk˜kK˜�Kšœ™KšœY˜YKšœh˜hKšœo˜oKšœa˜aK˜�—šž
œœ
œœœœ˜\K˜�Kšœ0™0KšœJ™JKšœœD˜KKšœ
œt˜ƒKšœ7œœ˜NKšœ7œœ˜NKšœ-˜-Kšœ0˜0K˜�—šžœœ
œœœœœœ˜MKšœœ™šœœ˜Kšœœœœ˜3Kšœ˜Kšœ˜—Kšœœ˜——šŸ™Kšœ™šž	œœœœ˜>Kšœœœ˜5Kšœœœ˜5Kšœœ˜"K˜�—šžœœœœ˜>Kšœœœ˜6Kšœ˜——šŸ#™#Kš ×™×Kš X™XKšœ
œœ
˜!šœ
œœ˜Kšœ	œ	 ˜-Kšœ
œ	 
˜#Kšœœœœœœ ˜6—Kš G™Gšž	œœœœœœ˜RKšœ1˜1Kš
œ
œœœœ˜3K˜�—šžœœœœ˜SKšœœ!˜*Kšœœ˜"Kšœ˜Kšœ˜Kšœ˜šœœœ˜Kšœœ˜Kšœ˜	K˜�——šžœœœœœœ˜PKšœ(˜.K˜�—Kš >™>šžœœœœœœœ˜\Kšœœ	œœ	˜+K˜�—šžœœ œœœœ˜MKšœœ	œœ˜8K˜�—šžœœœœ˜<Kš
œœœ œœ˜9Kšœ'œ˜-K˜�—Kš X™Xšžœœ:œ˜Nšœœœ(˜9Kšœ˜Kšœ˜	—K˜�—Kš &™&Kš *™*šžœœ:œœ
œœ˜tšœœœ˜)Kšœ"œœœ)˜^Kšœ˜—Kšœœ˜K˜�—šžœœœœœœ˜ZKšœ˜šœ#œ˜LKšœ)˜)Kšœ˜	—K˜�—šžœœ9œ"˜vKšœd™dKšœ%™%Kšœœœ˜Kšœ	œ˜
Kšœ˜šœ	˜Kšœ0œ˜6KšœœC˜aKšœo ˜€Kšœ˜	—K˜�—šžœœ9œ"˜vKšœe™eKšœ%™%Kšœœœ˜Kšœ	œ˜
Kšœ˜šœ	˜Kšœ0œ˜7KšœœC˜aKšœo ˜€Kšœ˜	—K˜�—šžœœ9œ"˜wKšœd™dKšœ"œ	œœ˜Lšœ˜Kšœœœ˜)Kšœ! '˜HKš	œDœœœœ˜‚Kš	œDœœœœ˜‚KšœœœC˜hKšœœœ˜#Kšœœœ˜#Kšœ9œœ˜NKšœ
˜———šœŸ
™KšœQ™Qšœœœ˜Kšœ˜Kšœ˜K˜�—Kšœ™šžœ˜'Kšœœœœœ
œ™?Kšœœ
œ˜EK˜=Kšœ˜K˜�—šžœ˜#Kšœœœœœœ™KKšœI™IKšœœ&˜5šœœœ˜<Kšœœ
œ˜Mš	œ
œœœœ3˜hKšœ4˜8—Kš	œ
œœœœ˜.Kšœ9˜9—š˜Kšœ˜—K˜�—Kšœ˜—K˜�—�…—����<@�–Ò�