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