<> <> <> <> <> <> <> <> <> <<>> 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] ~ { handle.inner _ GetObjectDescription[inner, handle.bottom _ GetObjectDescription[bottom, handle.right _ GetObjectDescription[right, handle.top _ GetObjectDescription[top, handle.left _ GetObjectDescription[left, 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] ~ { <> 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 * trunkBTWidth: INT _ (handle.parms.powerBTCellWidth * RouteOutsideChannels[handle]; AssignPositions[handle]; RouteOutsideSwitchBoxes[handle]; ConstructPowerChannels[handle, trunkLRWidth, trunkBTWidth]; ConstructPowerCorners[handle, trunkLRWidth, trunkBTWidth]; AssignPositions[handle];}; RouteOutsideChannels: PROC [handle: CabbagePrivate.Handle] ~ { <> <> outerBTChanWidth: INT _ handle.parms.outerBTChanWidth * outerLRChanWidth: INT _ handle.parms.outerLRChanWidth * powerLRCellWidth: INT _ handle.parms.powerLRCellWidth * powerBTCellWidth: INT _ handle.parms.powerBTCellWidth * 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] ~ { <> <> powerLRCellWidth: INT _ handle.parms.powerLRCellWidth * powerBTCellWidth: INT _ handle.parms.powerBTCellWidth * powerLRWidth: INT _ handle.parms.outerLRChanWidth * powerBTWidth: INT _ handle.parms.outerBTChanWidth * 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 { <> <<-- irSize stuff should be remove in Cabbage25>> via: CD.Object _ SELECT chipSide FROM bottom, top => RouteUtil.StitchVias[[max-min, trunkWidth], trunkLayer, branchLayer, left, right => RouteUtil.StitchVias[[trunkWidth, max-min], trunkLayer, branchLayer, 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, [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, [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, [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, [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, left, right => RouteUtil.StitchVias[[trunkWidth, segment.range.max-segment.range.min], trunkLayer, branchLayer, 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[]; 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; outerLRChanWidth: INT _ handle.parms.outerLRChanWidth * outerBTChanWidth: INT _ handle.parms.outerBTChanWidth * 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] ~ { <> <> 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] ~ { horLayer: CD.Layer _ horizInsideParms.rules.branchLayer; verLayer: CD.Layer _ horizOutsideParms.rules.branchLayer; trunkSz: CD.Position _ [trunkLRWidth, trunkBTWidth]; cellSz: CD.Position _ [handle.parms.powerLRCellWidth * 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, 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] ~ { horizInsideParms: CabbagePrivate.ParmSet _ handle.rules.horizInsideParms; powerLRWidth: INT _ handle.parms.outerLRChanWidth * powerBTWidth: INT _ handle.parms.outerBTChanWidth * 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 { < we may use tight spacing>> <> 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 { <> <> <<(net = Vdd OR net = Gnd) gets a special name>> name _ IF powerNet THEN Rope.Cat[net.name, lowerSuffix] ELSE net.name; IF RefTab.Insert[netTable, name, NIL] THEN { pinWidth: 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 { <> <> <<(net = Vdd OR net = Gnd) gets a special name>> name _ IF powerNet THEN Rope.Cat[net.name, upperSuffix] ELSE net.name; IF RefTab.Insert[netTable, name, NIL] THEN { pinWidth: 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[ 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."]; 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, 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[ 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]}; 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[ 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]}; 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] ~ { <> powerLRWidth: INT _ handle.parms.outerLRChanWidth * powerBTWidth: INT _ handle.parms.outerBTChanWidth * 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 [ <> RETURN[Rope.Cat["[", Convert.RopeFromInt[range.min/ 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; powerLRWidth: INT _ handle.parms.outerLRChanWidth * powerBTWidth: INT _ handle.parms.outerBTChanWidth * 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] ~ { outerLRChanWidth: INT _ handle.parms.outerLRChanWidth * outerBTChanWidth: INT _ handle.parms.outerBTChanWidth * powerLRWidth: INT _ outerLRChanWidth + handle.parms.powerLRCellWidth * powerBTWidth: INT _ outerBTChanWidth + handle.parms.powerBTCellWidth * 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}; }.