DIRECTORY Basics, Cabbage, CabbagePrivate, CD, CDBasics, CDCells, CDOps, CDProperties, CDRects, CDSimpleRules, CDSymbolicObjects, Connections, Core, CoreGeometry, CoreOps, Convert, HashTable, List, PW, PWRoute, Rope, Route, RouteUtil, RTBasic, Sinix, SinixOps; CabbageProcsImpl: CEDAR PROGRAM IMPORTS Basics, Cabbage, CD, CDBasics, CDCells, CDOps, CDProperties, CDRects, CDSimpleRules, CDSymbolicObjects, Connections, CoreGeometry, CoreOps, Convert, HashTable, List, PW, PWRoute, Rope, Route, RouteUtil, RTBasic, Sinix, SinixOps EXPORTS CabbagePrivate SHARES Route = { cabbageXPos: ATOM _ $CabbageXPos; cabbageYPos: ATOM _ $CabbageYPos; CreateHandle: PUBLIC PROC [inner, bottomLeft, bottom, bottomRight, right, topRight, top, topLeft, left: Cabbage.Object, connections: Connections.Table, parms: Cabbage.PadRingParams, name: Rope.ROPE, routeType: CabbagePrivate.RouteType] RETURNS [handle: CabbagePrivate.Handle]~ { handle _ NEW[CabbagePrivate.HandleRec _ [name: name, connections: connections, parms: parms]]; handle.routeType _ routeType; handle.rules _ CreateRouterParms[parms]; handle.powerDistribution _ NEW[CabbagePrivate.PowerDistributionRec]; handle.globalRouting _ NEW[CabbagePrivate.GlobalRoutingRec]; IF routeType = normal THEN handle.detailedRouting _ NEW[CabbagePrivate.DetailedRoutingRec] ELSE handle.detailedRoutingPL _ NEW[CabbagePrivate.DetailedRoutingPLRec]; GetSizes[handle, inner, bottomLeft, bottom, bottomRight, right, topRight, top, topLeft, left]; IF handle.connections # NIL THEN InitWires[handle]; AssignPositions[handle]}; CreateRouterParms: PROC [parms: Cabbage.PadRingParams] RETURNS [designRules: CabbagePrivate.DesignRules] = { hLayer: CD.Layer _ CDSimpleRules.GetLayer[parms.technologyKey, parms.horizLayer]; vLayer: CD.Layer _ CDSimpleRules.GetLayer[parms.technologyKey, parms.vertLayer]; viaTable: HashTable.Table _ IF parms.viaTable # NIL THEN parms.viaTable ELSE HashTable.Create[equal: EqualProc, hash: HashProc]; designRules _ NEW[CabbagePrivate.DesignRulesRec]; designRules.horizParms.parms _ NEW[PWRoute.RouterParamsRec _ [trunkLayer: parms.horizLayer, branchLayer: parms.vertLayer, technologyKey: parms.technologyKey, wireWidthProc: parms.wireWidthProc, signalIncomplete: parms.signalIncomplete, signalBreakAtExit: FALSE, signalSinglePinNets: parms.signalSinglePinNets, viaTable: viaTable]]; designRules.vertParms.parms _ NEW[PWRoute.RouterParamsRec _ [trunkLayer: parms.vertLayer, branchLayer: parms.horizLayer, technologyKey: parms.technologyKey, wireWidthProc: parms.wireWidthProc, signalIncomplete: parms.signalIncomplete, signalBreakAtExit: FALSE, signalSinglePinNets: parms.signalSinglePinNets, viaTable: viaTable]]; designRules.horizParms.rules _ Route.CreateDesignRules[parms.technologyKey, hLayer, vLayer, horizontal]; designRules.vertParms.rules _ Route.CreateDesignRules[parms.technologyKey, hLayer, vLayer, vertical]; designRules.horizParms.rules.trunkToEdge _ designRules.horizParms.rules.trunkToTrunk; designRules.vertParms.rules.trunkToEdge _ designRules.vertParms.rules.trunkToTrunk}; GetSizes: PROC [handle: CabbagePrivate.Handle, inner, bottomLeft, bottom, bottomRight, right, topRight, top, topLeft, left: Cabbage.Object] ~ { lambda: INT _ handle.rules.horizParms.rules.CDLambda; handle.inner _ GetObjectDescription[inner, lambda, lambda]; handle.bottom _ GetObjectDescription[bottom, lambda, lambda]; handle.right _ GetObjectDescription[right, lambda, lambda]; handle.top _ GetObjectDescription[top, lambda, lambda]; handle.left _ GetObjectDescription[left, lambda, lambda]; handle.bottomLeft _ GetObjectDescription[bottomLeft, handle.left.size.x, handle.bottom.size.y]; handle.bottomRight _ GetObjectDescription[bottomRight, handle.right.size.x, handle.bottom.size.y]; handle.topRight _ GetObjectDescription[topRight, handle.right.size.x, handle.top.size.y]; handle.topLeft _ GetObjectDescription[topLeft, handle.left.size.x, handle.top.size.y]}; GetObjectDescription: PROC [object: Cabbage.Object, minX, minY: INT] RETURNS [desc: CabbagePrivate.ObjectDescription] ~ { desc.object _ object; IF object = NIL THEN desc.size _ [minX, minY] ELSE { desc.size _ RTBasic.IRSize[object]; desc.size.x _ MAX[minX, desc.size.x]; desc.size.y _ MAX[minY, desc.size.y]}}; AssignPositions: PROC [handle: CabbagePrivate.Handle] ~ { hBottom, hTop, vLeft, vRight: INT; [hBottom, hTop, vLeft, vRight] _ GetSize[handle]; handle.bottom.origin _ [handle.bottomLeft.size.x + (handle.size.x - hBottom)/2, 0]; handle.right.origin _ [handle.size.x - handle.right.size.x, handle.bottomRight.size.y + (handle.size.y - vRight)/2]; handle.top.origin _ [handle.topLeft.size.x + (handle.size.x - hTop)/2, handle.size.y - handle.top.size.y]; handle.left.origin _ [0, handle.bottomLeft.size.y + (handle.size.y - vLeft)/2]; DoCorners[handle]; DoRoutingAreas[handle]}; InitWires: PROC [handle: CabbagePrivate.Handle] ~ { LookForGndAndVdd: Connections.EachNetAction ~ { IF Rope.Equal[net.name, "Vdd"] THEN handle.vddNet _ net ELSE IF Rope.Equal[net.name, "Gnd"] THEN handle.gndNet _ net}; EachNet: Connections.EachNetAction ~ { EachSegment: Connections.EachSegmentAction ~ { newNet.width _ MAX[newNet.width, segment.range.max - segment.range.min]}; newNet: Connections.Net _ NEW[Connections.NetRec _ [name: net.name, width: net.width]]; IF net.width <= 0 THEN [] _ Connections.EnumerateSegments[net, EachSegment]; [] _ Connections.Store[handle.widthTable, net.name, newNet]}; handle.widthTable _ Connections.CreateForRopes[]; [] _ Connections.EnumerateNets[handle.connections, LookForGndAndVdd]; [] _ Connections.EnumerateNets[handle.connections, EachNet]}; CheckInnerPos: PUBLIC PROC [handle: CabbagePrivate.Handle, innerPos: CD.Position] ~ { actualInnerPos: CD.Position _ innerPos; lowerY: INT _ handle.bottom.origin.y + handle.bottom.size.y; upperY: INT _ handle.top.origin.y - handle.inner.size.y; lowerX: INT _ handle.left.origin.x + handle.left.size.x; upperX: INT _ handle.right.origin.x - handle.inner.size.x; IF ~((lowerX <= innerPos.x AND innerPos.x <= upperX) AND (lowerY <= innerPos.y AND innerPos.y <= upperY)) THEN { Cabbage.Signal[callingError, "The position specified for the inner object (innerPos) is invalid."]; actualInnerPos _ [(lowerX + upperX)/2, (lowerY + lowerY)/2]}; handle.inner.origin _ actualInnerPos}; DistributePower: PUBLIC PROC [handle: CabbagePrivate.Handle] ~ { horizParms: CabbagePrivate.ParmSet _ handle.rules.horizParms; vertParms: CabbagePrivate.ParmSet _ handle.rules.vertParms; space: INT _ 2*horizParms.rules.trunkToTrunk + horizParms.rules.trunkSpacing + vertParms.rules.contactSize + vertParms.rules.trunkSpacing + 2*vertParms.rules.trunkToTrunk; trunkWidth: INT _ (handle.parms.powerCellWidth - space)/2; RouteOutsideChannels[handle, trunkWidth]; AssignPositions[handle]; ConstructPowerChannels[handle, trunkWidth]; AssignPositions[handle]; RouteOutsideSwitchBoxes[handle]}; RouteOutsideChannels: PROC [handle: CabbagePrivate.Handle, viaSize: INT] ~ { outerChanWidth: INT _ handle.parms.outerChanWidth; powerWidth: INT _ outerChanWidth + handle.parms.powerCellWidth; horizParms: CabbagePrivate.ParmSet _ handle.rules.horizParms; vertParms: CabbagePrivate.ParmSet _ handle.rules.vertParms; horizInnerRange: Connections.Range _ [handle.inner.origin.x, handle.inner.origin.x + handle.inner.size.x]; horizOuterRange: Connections.Range _ [handle.left.origin.x + handle.left.size.x + powerWidth, handle.right.origin.x - powerWidth]; vertInnerRange: Connections.Range _ [handle.inner.origin.y, handle.inner.origin.y + handle.inner.size.y]; vertOuterRange: Connections.Range _ [handle.bottom.origin.y + handle.bottom.size.y + powerWidth, handle.top.origin.y - powerWidth]; handle.powerDistribution.channels[bottom] _ RouteOutsideChannel[handle, handle.bottom, bottom, horizOuterRange, horizOuterRange, outerChanWidth, viaSize, vertParms]; handle.powerDistribution.channels[right] _ RouteOutsideChannel[handle, handle.right, right, vertInnerRange, vertOuterRange, outerChanWidth, viaSize, horizParms]; handle.powerDistribution.channels[top] _ RouteOutsideChannel[handle, handle.top, top, horizOuterRange, horizOuterRange, outerChanWidth, viaSize, vertParms]; handle.powerDistribution.channels[left] _ RouteOutsideChannel[handle, handle.left, left, vertInnerRange, vertOuterRange, outerChanWidth, viaSize, horizParms]}; ConstructPowerChannels: PROC [handle: CabbagePrivate.Handle, trunkWidth: INT] ~ { powerCellWidth: INT _ handle.parms.powerCellWidth; powerWidth: INT _ handle.parms.outerChanWidth + powerCellWidth; horizParms: CabbagePrivate.ParmSet _ handle.rules.horizParms; vertParms: CabbagePrivate.ParmSet _ handle.rules.vertParms; horizInnerRange: Connections.Range _ [handle.inner.origin.x, handle.inner.origin.x + handle.inner.size.x]; horizOuterRange: Connections.Range _ [handle.left.origin.x + handle.left.size.x + powerWidth, handle.right.origin.x - powerWidth]; vertInnerRange: Connections.Range _ [handle.inner.origin.y, handle.inner.origin.y + handle.inner.size.y]; vertOuterRange: Connections.Range _ [handle.bottom.origin.y + handle.bottom.size.y + powerWidth, handle.top.origin.y - powerWidth]; handle.powerDistribution.power[bottom] _ RoutePower[handle, handle.powerDistribution.channels[bottom], bottom, horizOuterRange, powerCellWidth, trunkWidth, horizParms, vertParms]; handle.powerDistribution.power[right] _ RoutePower[handle, handle.powerDistribution.channels[right], right, vertOuterRange, powerCellWidth, trunkWidth, vertParms, horizParms]; handle.powerDistribution.power[top] _ RoutePower[handle, handle.powerDistribution.channels[top], top, horizOuterRange, powerCellWidth, trunkWidth, horizParms, vertParms]; handle.powerDistribution.power[left] _ RoutePower[handle, handle.powerDistribution.channels[left], left, vertOuterRange, powerCellWidth, trunkWidth, vertParms, horizParms]}; RouteOutsideChannel: PROC [handle: CabbagePrivate.Handle, outerObject: CabbagePrivate.ObjectDescription, -- outer Cabbage object side: Route.Side, -- the side of chip for which this channel is being constructed innerRange, outerRange: Connections.Range, -- innerRange is the span of the inner cell, outerRange the span of the appropriate power routing cell; innerRange may equal outerRange chWidth: INT, -- the only permitted width for channel viaSize: INT, -- the length of the via at the end of the channel parms: CabbagePrivate.ParmSet] RETURNS [channel: CabbagePrivate.Channel] ~ { result: Route.RoutingResult; retrieveRect: Route.RefRect; rect: CD.Rect; otherSide: Route.Side _ RTBasic.OtherSide[side]; blSide: Route.Side _ IF side=bottom OR side=top THEN left ELSE bottom; topOrRight: BOOLEAN _ side= right OR side=top; direction: RTBasic.Direction _ IF side= right OR side=left THEN vertical ELSE horizontal; obj1: Cabbage.Object _ IF topOrRight THEN MappedShellFromObject[handle, outerObject, otherSide, innerRange, outerRange, viaSize, parms.rules] ELSE ShellFromObject[handle, outerObject, otherSide, outerRange, parms.rules, TRUE]; obj2: Cabbage.Object _ IF topOrRight THEN ShellFromObject[handle, outerObject, otherSide, outerRange, parms.rules, TRUE] ELSE MappedShellFromObject[handle, outerObject, otherSide, innerRange, outerRange, viaSize, parms.rules]; bottomOrLeftObj: Cabbage.Object _ ShellFromOutsideEnd[handle, outerObject, otherSide, blSide, innerRange, outerRange, parms.rules]; topOrRightObj: Cabbage.Object _ ShellFromOutsideEnd[handle, outerObject, otherSide, RTBasic.OtherSide[blSide], innerRange, outerRange, parms.rules]; parms.parms.wireWidthProc _ GetWireWidth; parms.parms.makeTabKeyProc _ PinName; parms.parms.context _ NEW[PWRouteContext _ [direction: direction, table: handle.widthTable]]; result _ PWRoute.DoRoute[obj1, obj2, bottomOrLeftObj, topOrRightObj, parms.parms, side= right OR side=left, channel]; rect _ result.routingRect; SELECT side FROM bottom => { dist: INT _ MIN[rect.y1, rect.y2 - chWidth]; retrieveRect _ NEW[CD.Rect _ [rect.x1, dist, rect.x2, rect.y2]]}; right => { dist: INT _ MAX[rect.x2, rect.x1 + chWidth]; retrieveRect _ NEW[CD.Rect _ [rect.x1, rect.y1, dist, rect.y2]]}; top => { dist: INT _ MAX[rect.y2, rect.y1 + chWidth]; retrieveRect _ NEW[CD.Rect _ [rect.x1, rect.y1, rect.x2, dist]]}; left => { dist: INT _ MIN[rect.x1, rect.x2 - chWidth]; retrieveRect _ NEW[CD.Rect _ [dist, rect.y1, rect.x2, rect.y2]]}; ENDCASE; channel.object _ PWRoute.GetRouting[result, retrieveRect, parms.parms]; channel.size _ RTBasic.IRSize[channel.object]; channel.cellType _ ExtractChannel[channel, parms]}; RoutePower: PROC [handle: CabbagePrivate.Handle, channel: CabbagePrivate.Channel, -- inner or outer channel as determined by side chipSide: Route.Side, -- the side of the chip for which this channel is being constructed range: Connections.Range, -- the span along the appropriate power routing cell powerWidth: INT, -- the only permitted width for the power cell trunkWidth: INT, -- the width of the power trunk insideParms, outsideParms: CabbagePrivate.ParmSet] RETURNS [power: CabbagePrivate.Channel] ~ { ChanPublics: CoreGeometry.EachWirePinProc ~ { OuterPowerBranch: PROC [branchLength: INT, branchLayer, trunkLayer: CD.Layer] ~ { pos: CD.Position _ SELECT chipSide FROM bottom => [adjustedRange.min, 0], top => [adjustedRange.min, powerWidth - branchLength], left => [0, adjustedRange.min], right => [powerWidth - branchLength, adjustedRange.min], ENDCASE => Cabbage.Error[programmingError, "Not suppose to happen"]; SELECT chipSide FROM bottom, top => CDProperties.PutProp[RouteUtil.Include[object, CDRects.CreateRect[[max-min, branchLength], branchLayer], pos], $SignalName, name]; left, right => CDProperties.PutProp[RouteUtil.Include[object, CDRects.CreateRect[[branchLength, max-min], branchLayer], pos], $SignalName, name]; ENDCASE => Cabbage.Error[programmingError, "Not suppose to happen"]; IF branchLayer # trunkLayer THEN { via: CD.Object _ SELECT chipSide FROM bottom, top => RouteUtil.StitchVias[[max-min, trunkWidth], trunkLayer, branchLayer, insideParms.rules.CDLambda, NIL], left, right => RouteUtil.StitchVias[[trunkWidth, max-min], trunkLayer, branchLayer, insideParms.rules.CDLambda, NIL], ENDCASE => Cabbage.Error[programmingError, "Not suppose to happen"]; irSize: CD.Position _ RTBasic.IRSize[via]; xOffset: INT _ SELECT chipSide FROM bottom, top => (max-min - irSize.x)/2, left, right => (trunkWidth - irSize.x)/2, ENDCASE => Cabbage.Error[programmingError, "Not suppose to happen"]; yOffset: INT _ SELECT chipSide FROM bottom, top => (trunkWidth - irSize.y)/2, left, right => (max-min - irSize.y)/2, ENDCASE => Cabbage.Error[programmingError, "Not suppose to happen"]; viaPos: CD.Position _ SELECT chipSide FROM bottom => [adjustedRange.min + xOffset, branchLength - trunkWidth + yOffset], top => [adjustedRange.min + xOffset, powerWidth - branchLength + yOffset], left => [branchLength - trunkWidth + xOffset, adjustedRange.min + yOffset], right => [powerWidth - branchLength + xOffset, adjustedRange.min + yOffset], ENDCASE => Cabbage.Error[programmingError, "Not suppose to happen"]; CDProperties.PutProp[RouteUtil.Include[object, via, viaPos], $SignalName, name]}}; SignalBranch: PROC [] ~ { outsideLength: INT _ outsideParms.rules.trunkSpacing + distToOuter; insideLength: INT _ insideParms.rules.trunkSpacing + distToInner; SELECT chipSide FROM bottom => { CDProperties.PutProp[RouteUtil.Include[object, CDRects.CreateRect[[max-min, outsideLength], outsideLayer], [adjustedRange.min, 0]], $SignalName, name]; CDProperties.PutProp[RouteUtil.Include[object, CDRects.CreateRect[[max-min, insideLength], insideLayer], [adjustedRange.min, powerWidth - insideLength]], $SignalName, name]; [] _ RouteUtil.Include[object, RouteUtil.StitchVias[[max-min, insideParms.rules.contactSize], insideLayer, outsideLayer, insideParms.rules.CDLambda, NIL], [adjustedRange.min, outsideLength]]}; top => { CDProperties.PutProp[RouteUtil.Include[object, CDRects.CreateRect[[max-min, outsideLength], outsideLayer], [adjustedRange.min, powerWidth - outsideLength]], $SignalName, name]; CDProperties.PutProp[RouteUtil.Include[object, CDRects.CreateRect[[max-min, insideLength], insideLayer], [adjustedRange.min, 0]], $SignalName, name]; [] _ RouteUtil.Include[object, RouteUtil.StitchVias[[max-min, insideParms.rules.contactSize], insideLayer, outsideLayer, insideParms.rules.CDLambda, NIL], [adjustedRange.min, insideLength]]}; left => { CDProperties.PutProp[RouteUtil.Include[object, CDRects.CreateRect[[outsideLength, max-min], outsideLayer], [0, adjustedRange.min]], $SignalName, name]; CDProperties.PutProp[RouteUtil.Include[object, CDRects.CreateRect[[insideLength, max-min], insideLayer], [powerWidth - insideLength, adjustedRange.min]], $SignalName, name]; [] _ RouteUtil.Include[object, RouteUtil.StitchVias[[insideParms.rules.contactSize, max-min], insideLayer, outsideLayer, insideParms.rules.CDLambda, NIL], [outsideLength, adjustedRange.min]]}; right => { CDProperties.PutProp[RouteUtil.Include[object, CDRects.CreateRect[[outsideLength, max-min], outsideLayer], [powerWidth - outsideLength, adjustedRange.min]], $SignalName, name]; CDProperties.PutProp[RouteUtil.Include[object, CDRects.CreateRect[[insideLength, max-min], insideLayer], [0, adjustedRange.min]], $SignalName, name]; [] _ RouteUtil.Include[object, RouteUtil.StitchVias[[insideParms.rules.contactSize, max-min], insideLayer, outsideLayer, insideParms.rules.CDLambda, NIL], [insideLength, adjustedRange.min]]}; ENDCASE}; name: Rope.ROPE _ CoreOps.GetShortWireName[wire]; adjustedRange: Connections.Range _ [channelOrigin + min, channelOrigin + max]; IF side = otherSide THEN { SELECT TRUE FROM Rope.Equal[name, "Vdd"] => OuterPowerBranch[distToOuter, outsideLayer, insideLayer]; Rope.Equal[name, "Gnd"] => OuterPowerBranch[powerWidth - 2*insideParms.rules.trunkToTrunk, outsideLayer, outsideLayer]; ENDCASE => SignalBranch[]}}; EachNet: Connections.EachNetAction ~ { EachSegment: Connections.EachSegmentAction ~ { InnerPowerBranch: PROC [branchLength: INT, branchLayer, trunkLayer: CD.Layer] ~ { rectPos: CD.Position _ SELECT chipSide FROM bottom => [adjustedRange.min, powerWidth - branchLength], top => [adjustedRange.min, 0], left => [powerWidth - branchLength, adjustedRange.min], right => [0, adjustedRange.min], ENDCASE => Cabbage.Error[programmingError, "Not suppose to happen"]; SELECT chipSide FROM bottom, top => CDProperties.PutProp[RouteUtil.Include[object, CDRects.CreateRect[[segment.range.max-segment.range.min, branchLength], insideLayer], rectPos], $SignalName, net.name]; left, right => CDProperties.PutProp[RouteUtil.Include[object, CDRects.CreateRect[[branchLength, segment.range.max-segment.range.min], insideLayer], rectPos], $SignalName, net.name]; ENDCASE; IF branchLayer # trunkLayer THEN { via: CD.Object _ SELECT chipSide FROM bottom, top => RouteUtil.StitchVias[[segment.range.max-segment.range.min, trunkWidth], trunkLayer, branchLayer, insideParms.rules.CDLambda, NIL], left, right => RouteUtil.StitchVias[[trunkWidth, segment.range.max-segment.range.min], trunkLayer, branchLayer, insideParms.rules.CDLambda, NIL], ENDCASE => Cabbage.Error[programmingError, "Not suppose to happen"]; irSize: CD.Position _ RTBasic.IRSize[via]; xOffset: INT _ SELECT chipSide FROM bottom, top => (segment.range.max-segment.range.min - irSize.x)/2, left, right => (trunkWidth - irSize.x)/2, ENDCASE => Cabbage.Error[programmingError, "Not suppose to happen"]; yOffset: INT _ SELECT chipSide FROM bottom, top => (trunkWidth - irSize.y)/2, left, right => (segment.range.max-segment.range.min - irSize.y)/2, ENDCASE => Cabbage.Error[programmingError, "Not suppose to happen"]; viaPos: CD.Position _ SELECT chipSide FROM bottom => [adjustedRange.min + xOffset, powerWidth - branchLength + yOffset], top => [adjustedRange.min + xOffset, branchLength - trunkWidth + yOffset], left => [powerWidth - branchLength + xOffset, adjustedRange.min + yOffset], right => [branchLength - trunkWidth + xOffset, adjustedRange.min + yOffset], ENDCASE => Cabbage.Error[programmingError, "Not suppose to happen"]; CDProperties.PutProp[RouteUtil.Include[object, via, viaPos], $SignalName, net.name]}}; adjustedRange: Connections.Range _ [innerOrigin + segment.range.min, innerOrigin + segment.range.max]; IF segment.object = handle.inner.object AND segment.side = chipSide THEN { SELECT TRUE FROM Rope.Equal[net.name, "Vdd"] => InnerPowerBranch[powerWidth - distToOuter, insideLayer, insideLayer]; Rope.Equal[net.name, "Gnd"] => InnerPowerBranch[distToInner, insideLayer, outsideLayer]; ENDCASE}}; [] _ Connections.EnumerateSegments[net, EachSegment]}; PowerTrunk: PROC [position: CD.Position, layer, otherLayer: CD.Layer, name: Rope.ROPE, addVias: BOOLEAN] ~ { trunkSize: CD.Position _ SELECT chipSide FROM bottom, top => [range.max-range.min, trunkWidth], left, right => [trunkWidth, range.max-range.min], ENDCASE => Cabbage.Error[programmingError, "Not suppose to happen"]; trunk: CD.Object _ CDRects.CreateRect[trunkSize, layer]; CDProperties.PutProp[RouteUtil.Include[object, trunk, position], $SignalName, name]; IF addVias THEN { via: CD.Object _ RouteUtil.StitchVias[[trunkWidth, trunkWidth], layer, otherLayer, insideParms.rules.CDLambda, NIL]; irSize: CD.Position _ RTBasic.IRSize[via]; viaPosition: CD.Position _ SELECT chipSide FROM bottom, top => [range.max-range.min - irSize.x, (trunkWidth-irSize.y)/2], left, right => [(trunkWidth-irSize.x)/2, range.max-range.min - irSize.y], ENDCASE => Cabbage.Error[programmingError, "Not suppose to happen"]; branch: CD.Object _ CDRects.CreateRect[[trunkWidth, trunkWidth], otherLayer]; branchPosition: CD.Position _ SELECT chipSide FROM bottom, top => [range.max-range.min - trunkWidth, 0], left, right => [0, range.max-range.min - trunkWidth], ENDCASE => Cabbage.Error[programmingError, "Not suppose to happen"]; CDProperties.PutProp[RouteUtil.Include[object, branch, position], $SignalName, name]; CDProperties.PutProp[RouteUtil.Include[object, branch, CDBasics.AddPoints[position, branchPosition]], $SignalName, name]; CDProperties.PutProp[RouteUtil.Include[object, via, position], $SignalName, name]; CDProperties.PutProp[RouteUtil.Include[object, via, CDBasics.AddPoints[position, viaPosition]], $SignalName, name]}}; insideLayer: CD.Layer _ insideParms.rules.branchLayer; outsideLayer: CD.Layer _ outsideParms.rules.branchLayer; distToInner: INT _ trunkWidth + 2*insideParms.rules.trunkToTrunk; distToOuter: INT _ trunkWidth + 2*outsideParms.rules.trunkToTrunk; object: Cabbage.Object _ CDCells.CreateEmptyCell[]; mode: Sinix.Mode = SinixOps.GetExtractMode[insideParms.rules.technology]; otherSide: CoreGeometry.Side _ SELECT chipSide FROM bottom => top, right => left, top => bottom, left=> right, ENDCASE => Cabbage.Error[programmingError, "Not suppose to happen"]; innerOrigin: INT _ SELECT chipSide FROM bottom, top => handle.inner.origin.x, right, left => handle.inner.origin.y, ENDCASE => Cabbage.Error[programmingError, "Not suppose to happen."]; channelOrigin: INT _ SELECT chipSide FROM bottom, top => channel.origin.x, right, left => channel.origin.y, ENDCASE => Cabbage.Error[programmingError, "Not suppose to happen."]; interestRect: CD.Rect _ SELECT chipSide FROM bottom, top => [range.min, 0 , range.max, powerWidth], left, right => [0, range.min , powerWidth, range.max], ENDCASE => Cabbage.Error[programmingError, "Not suppose to happen"]; innerTrunkPos: CD.Position _ SELECT chipSide FROM bottom => [range.min, powerWidth - distToInner], top => [range.min, 2*insideParms.rules.trunkToTrunk], left => [powerWidth - distToInner, range.min], right => [2*insideParms.rules.trunkToTrunk, range.min], ENDCASE => Cabbage.Error[programmingError, "Not suppose to happen"]; outerTrunkPos: CD.Position _ SELECT chipSide FROM bottom => [range.min, 2*outsideParms.rules.trunkToTrunk], top => [range.min, powerWidth - distToOuter], left => [2*outsideParms.rules.trunkToTrunk, range.min], right => [powerWidth - distToOuter, range.min], ENDCASE => Cabbage.Error[programmingError, "Not suppose to happen"]; PowerTrunk[outerTrunkPos, insideLayer, outsideLayer, "Vdd", FALSE]; PowerTrunk[innerTrunkPos, outsideLayer, insideLayer, "Gnd", TRUE]; [] _ CoreGeometry.EnumerateNonOverlappingSides[mode.decoration, channel.cellType, ChanPublics]; [] _ Connections.EnumerateNets[handle.connections, EachNet]; power.object _ object; CDCells.SetInterestRect[design: NIL, cell: power.object, r: interestRect]; RTBasic.RepositionCell[power.object]; power.size _ RTBasic.IRSize[power.object]; power.cellType _ ExtractChannel[power, insideParms]}; RouteOutsideSwitchBoxes: PROC [handle: CabbagePrivate.Handle] ~ { vertParms: CabbagePrivate.ParmSet _ handle.rules.vertParms; powerWidth: INT _ handle.parms.outerChanWidth + handle.parms.powerCellWidth; leftHorizRange: Connections.Range _ [handle.left.origin.x + handle.left.size.x, handle.left.origin.x + handle.left.size.x + powerWidth]; rightHorizRange: Connections.Range _ [handle.right.origin.x - powerWidth, handle.right.origin.x]; bottomVertRange: Connections.Range _ [handle.bottom.origin.y + handle.bottom.size.y, handle.bottom.origin.y + handle.bottom.size.y + powerWidth]; topVertRange: Connections.Range _ [handle.top.origin.y- powerWidth, handle.top.origin.y]; vertParms.parms.okToDiddleLLPins _ TRUE; handle.powerDistribution.switchBoxes[bottomLeft] _ RouteOutsideSwitchBox[handle, bottomLeft, leftHorizRange, bottomVertRange, vertParms]; handle.powerDistribution.switchBoxes[topLeft] _ RouteOutsideSwitchBox[handle, topLeft, leftHorizRange, topVertRange, vertParms]; vertParms.parms.okToDiddleLLPins _ FALSE; vertParms.parms.okToDiddleURPins _ TRUE; handle.powerDistribution.switchBoxes[bottomRight] _ RouteOutsideSwitchBox[handle, bottomRight, rightHorizRange, bottomVertRange, vertParms]; handle.powerDistribution.switchBoxes[topRight] _ RouteOutsideSwitchBox[handle, topRight, rightHorizRange, topVertRange, vertParms]; vertParms.parms.okToDiddleLLPins _ FALSE; vertParms.parms.okToDiddleURPins _ FALSE}; RouteOutsideSwitchBox: PROC [handle: CabbagePrivate.Handle, corner: CabbagePrivate.Corners, horizRange, vertRange: Connections.Range, parms: CabbagePrivate.ParmSet] RETURNS [switchBox: CabbagePrivate.Channel] ~ { bottomObject, topObject, leftObject, rightObject: Cabbage.Object; SELECT corner FROM bottomLeft => { topObject _ PW.AbutListX[LIST[ShellFromFullChannel[handle.powerDistribution.channels[left], bottom, parms.rules.branchLayer, parms.rules], ShellFromFullChannel[handle.powerDistribution.power[left], bottom, parms.rules.branchLayer, parms.rules]]]; bottomObject _ ShellFromObject[handle, handle.bottom, top, horizRange, parms.rules, FALSE]; leftObject _ ShellFromObject[handle, handle.left, right, vertRange, parms.rules, FALSE]; rightObject _ PW.AbutListY[LIST[ShellFromFullChannel[handle.powerDistribution.channels[bottom], left, parms.rules.trunkLayer, parms.rules], ShellFromFullChannel[handle.powerDistribution.power[bottom], left, parms.rules.trunkLayer, parms.rules]]]}; bottomRight => { topObject _ PW.AbutListX[LIST[ShellFromFullChannel[handle.powerDistribution.power[right], bottom, parms.rules.branchLayer, parms.rules], ShellFromFullChannel[handle.powerDistribution.channels[right], bottom, parms.rules.branchLayer, parms.rules]]]; bottomObject _ ShellFromObject[handle, handle.bottom, top, horizRange, parms.rules, FALSE]; leftObject _ PW.AbutListY[LIST[ShellFromFullChannel[handle.powerDistribution.channels[bottom], right, parms.rules.trunkLayer, parms.rules], ShellFromFullChannel[handle.powerDistribution.power[bottom], right, parms.rules.trunkLayer, parms.rules]]]; rightObject _ ShellFromObject[handle, handle.right, left, vertRange, parms.rules, FALSE]}; topRight => { topObject _ ShellFromObject[handle, handle.top, bottom, horizRange, parms.rules, FALSE]; bottomObject _ PW.AbutListX[LIST[ShellFromFullChannel[handle.powerDistribution.power[right], top, parms.rules.branchLayer, parms.rules], ShellFromFullChannel[handle.powerDistribution.channels[right], top, parms.rules.branchLayer, parms.rules]]]; leftObject _ PW.AbutListY[LIST[ShellFromFullChannel[handle.powerDistribution.power[top], right, parms.rules.trunkLayer, parms.rules], ShellFromFullChannel[handle.powerDistribution.channels[top], right, parms.rules.trunkLayer, parms.rules]]]; rightObject _ ShellFromObject[handle, handle.right, left, vertRange, parms.rules, FALSE]}; topLeft => { topObject _ ShellFromObject[handle, handle.top, bottom, horizRange, parms.rules, FALSE]; bottomObject _ PW.AbutListX[LIST[ShellFromFullChannel[handle.powerDistribution.channels[left], top, parms.rules.branchLayer, parms.rules], ShellFromFullChannel[handle.powerDistribution.power[left], top, parms.rules.branchLayer, parms.rules]]]; leftObject _ ShellFromObject[handle, handle.left, right, vertRange, parms.rules, FALSE]; rightObject _ PW.AbutListY[LIST[ShellFromFullChannel[handle.powerDistribution.power[top], left, parms.rules.trunkLayer, parms.rules], ShellFromFullChannel[handle.powerDistribution.channels[top], left, parms.rules.trunkLayer, parms.rules]]]}; ENDCASE; parms.parms.wireWidthProc _ NIL; parms.parms.makeTabKeyProc _ NIL; parms.parms.context _ NEW[PWRouteContext _ [direction: parms.rules.trunkDirection, table: handle.widthTable]]; switchBox.object _ PWRoute.MakeChannel[bottomObject, topObject, leftObject, rightObject, NIL, parms.parms, FALSE, switchBox]; switchBox.size _ RTBasic.IRSize[switchBox.object]; switchBox.cellType _ ExtractChannel[switchBox, parms]}; GlobalRoute: PUBLIC PROC [handle: CabbagePrivate.Handle] ~ { EachNet: Connections.EachNetAction ~ { sortedSegments: CabbagePrivate.SegmentSeq _ SortSegments[handle, net]; IF sortedSegments # NIL THEN { segmentPair: CabbagePrivate.SegmentPair _ FindStartEndSegments[handle, net, sortedSegments]; AddNetToGlobalRoute[handle, net, segmentPair]}}; newConnections: Connections.Table _ MakeNewConnections[handle]; [] _ Connections.EnumerateNets[newConnections, EachNet]}; MakeNewConnections: PROC [handle: CabbagePrivate.Handle] RETURNS [newConnections: Connections.Table _ Connections.CreateForRopes[]] ~ { InsertPinsFromInner[handle, newConnections]; InsertPinsFromPower[handle, newConnections, bottom]; InsertPinsFromPower[handle, newConnections, right]; InsertPinsFromPower[handle, newConnections, top]; InsertPinsFromPower[handle, newConnections, left]}; InsertPinsFromInner: PROC [handle: CabbagePrivate.Handle, newConnections: Connections.Table] ~ { EachNet: Connections.EachNetAction ~ { EachSegment: Connections.EachSegmentAction ~ { IF segment.object = handle.inner.object THEN { newSegment: Connections.Segment _ NEW[Connections.SegmentRec _ [name: segment.name, object: segment.object, range: segment.range, side: segment.side, layer: segment.layer]]; newNet.segments _ CONS[newSegment, newNet.segments]; [] _ Connections.Store[newConnections, net.name, newNet]}}; newNet: Connections.Net _ NEW[Connections.NetRec _ [name: net.name, width: net.width]]; [] _ Connections.Store[newConnections, net.name, newNet]; [] _ Connections.EnumerateSegments[net, EachSegment]}; [] _ Connections.EnumerateNets[handle.connections, EachNet]}; InsertPinsFromPower: PROC [handle: CabbagePrivate.Handle, newConnections: Connections.Table, chipSide: RTBasic.Side] ~ { ChanPublics: CoreGeometry.EachWirePinProc ~ { name: Rope.ROPE _ CoreOps.GetShortWireName[wire]; segmentSide: Route.Side _ SELECT side FROM bottom => bottom, right => right, top => top, left=> left, ENDCASE => Cabbage.Error[programmingError, "Not suppose to happen"]; IF segmentSide = otherSide THEN { segment: Connections.Segment _ NEW[Connections.SegmentRec _ [name: name, object: handle.powerDistribution.power[chipSide].object, range: [min, max], side: segmentSide, layer: layer]]; net: Connections.Net _ Connections.Fetch[newConnections, name].net; net.segments _ CONS[segment, net.segments]; [] _ Connections.Store[newConnections, name, net]}; }; otherSide: Route.Side _ RTBasic.OtherSide[chipSide]; mode: Sinix.Mode = SinixOps.GetExtractMode[handle.rules.horizParms.rules.technology]; [] _ CoreGeometry.EnumerateNonOverlappingSides[mode.decoration, handle.powerDistribution.power[chipSide].cellType, ChanPublics]}; SortSegments: PROC [handle: CabbagePrivate.Handle, net: Connections.Net] RETURNS [sortedSegments: CabbagePrivate.SegmentSeq _ NIL] ~ { CountSegments: Connections.EachSegmentAction ~ {numSegments _ numSegments + 1}; PinCompare: List.CompareProc ~ { pos1, pos2: INT; TRUSTED{ pos1 _ PosOf[handle, LOOPHOLE[ref1]]; pos2 _ PosOf[handle, LOOPHOLE[ref2]]}; RETURN [Basics.CompareINT[pos1, pos2]]}; numSegments, index: INT _ 0; mungedSegmentList, sortedSegmentList: List.LORA; [] _ Connections.EnumerateSegments[net, CountSegments]; IF numSegments > 1 THEN { TRUSTED{mungedSegmentList _ List.Reverse[LOOPHOLE[net.segments]]}; sortedSegmentList _ List.Sort[mungedSegmentList, PinCompare]; sortedSegments _ NEW[CabbagePrivate.SegmentSeqRec[numSegments]]; FOR each: List.LORA _ sortedSegmentList, each.rest UNTIL each = NIL DO segment: Connections.Segment; TRUSTED{segment _ LOOPHOLE[each.first]}; sortedSegments[index] _ segment; index _ index + 1; ENDLOOP}}; FindStartEndSegments: PROC [handle: CabbagePrivate.Handle, net: Connections.Net, sortedSegments: CabbagePrivate.SegmentSeq] RETURNS [segmentPair: CabbagePrivate.SegmentPair _ [NIL, NIL]] ~ { minLength: INT _ LAST[INT]; perimeter: INT _ 2*(handle.size.x + handle.size.y); length: INT; startSeg, endSeg: Connections.Segment; FOR index: NAT IN [0 .. sortedSegments.numSegments) DO IF index < sortedSegments.numSegments - 1 THEN { startSeg _ sortedSegments[index+1]; endSeg _ sortedSegments[index]; length _ perimeter - PosOf[handle, startSeg] + PosOf[handle, endSeg]} ELSE { endSeg _ sortedSegments[index]; startSeg _ sortedSegments[0]; length _ PosOf[handle, endSeg] - PosOf[handle, startSeg]}; IF length < minLength THEN { minLength _ length; segmentPair.seg1 _ startSeg; segmentPair.seg2 _ endSeg} ENDLOOP; IF segmentPair.seg1 = NIL OR segmentPair.seg2 = NIL THEN Cabbage.Error[programmingError, "Not suppose to happen"]}; AddNetToGlobalRoute: PROC [handle: CabbagePrivate.Handle, net: Connections.Net, segmentPair: CabbagePrivate.SegmentPair] ~ { pos1: INT _ PosOf[handle, segmentPair.seg1]; pos2: INT _ PosOf[handle, segmentPair.seg2]; IF pos1 < pos2 THEN { FOR d: CabbagePrivate.Division IN CabbagePrivate.Division DO IF pos1 < PosOfDivision[handle, d] AND PosOfDivision[handle, d] < pos2 THEN handle.globalRouting.exitLists[d] _ CONS[net, handle.globalRouting.exitLists[d]] ENDLOOP} ELSE { FOR d: CabbagePrivate.Division IN CabbagePrivate.Division DO IF PosOfDivision[handle, d] > pos1 OR PosOfDivision[handle, d] < pos2 THEN handle.globalRouting.exitLists[d] _ CONS[net, handle.globalRouting.exitLists[d]] ENDLOOP}}; DetailedRoute: PUBLIC PROC [handle: CabbagePrivate.Handle] ~ { RouteChannels[handle]; AdjustPositions[handle]; IF handle.routeType = normal THEN RouteSwitchBoxes[handle] ELSE RouteSwitchBoxesPL[handle]; AdjustPositions[handle]}; RouteChannels: PROC [handle: CabbagePrivate.Handle] ~ { horizParms: CabbagePrivate.ParmSet _ handle.rules.horizParms; vertParms: CabbagePrivate.ParmSet _ handle.rules.vertParms; horizRange: Connections.Range _ [handle.inner.origin.x, handle.inner.origin.x + handle.inner.size.x]; vertRange: Connections.Range _ [handle.inner.origin.y, handle.inner.origin.y + handle.inner.size.y]; IF handle.routeType = normal THEN { handle.detailedRouting.channels[bottom] _ RouteChannel[handle, handle.powerDistribution.power[bottom], bottom, bottomLeft, bottomRight, horizRange, horizParms]; handle.detailedRouting.channels[right] _ RouteChannel[handle, handle.powerDistribution.power[right], right, rightBottom, rightTop, vertRange, vertParms]; handle.detailedRouting.channels[top] _ RouteChannel[handle, handle.powerDistribution.power[top], top, topLeft, topRight, horizRange, horizParms]; handle.detailedRouting.channels[left] _ RouteChannel[handle, handle.powerDistribution.power[left], left, leftBottom, leftTop, vertRange, vertParms]} ELSE { -- routeType = padLimited handle.detailedRoutingPL.channels[right] _ RouteChannel[handle, handle.powerDistribution.power[right], right, rightBottom, rightTop, vertRange, vertParms]; handle.detailedRoutingPL.channels[left] _ RouteChannel[handle, handle.powerDistribution.power[left], left, leftBottom, leftTop, vertRange, vertParms]}}; RouteChannel: PROC [handle: CabbagePrivate.Handle, boundingChannel: CabbagePrivate.Channel, -- the power channel to use chipSide: Route.Side, -- the side of chip for which this channel is being constructed llDiv, urDiv: CabbagePrivate.Division, -- the lower and upper boundries of the channel range: Connections.Range, -- the range of interest along the channel side parms: CabbagePrivate.ParmSet] RETURNS [channel: CabbagePrivate.Channel] ~ { result: Route.RoutingResult; retrieveRect: Route.RefRect; rect: CD.Rect; offset: INT _ parms.rules.trunkToTrunk; otherSide: Route.Side _ RTBasic.OtherSide[chipSide]; direction: RTBasic.Direction _ IF chipSide= right OR chipSide=left THEN vertical ELSE horizontal; blSide: Route.Side _ IF chipSide=bottom OR chipSide=top THEN left ELSE bottom; topOrRight: BOOLEAN _ chipSide= right OR chipSide=top; obj1: Cabbage.Object _ IF topOrRight THEN ShellFromObject[handle, handle.inner, chipSide, range, parms.rules, TRUE] ELSE ShellFromChannel[boundingChannel, otherSide, parms.rules.branchLayer, range, parms.rules]; obj2: Cabbage.Object _ IF topOrRight THEN ShellFromChannel[boundingChannel, otherSide, parms.rules.branchLayer, range, parms.rules] ELSE ShellFromObject[handle, handle.inner, chipSide, range, parms.rules, TRUE]; bottomOrLeftObj: Cabbage.Object _ ShellFromEnd[handle, llDiv, blSide, parms.rules]; topOrRightObj: Cabbage.Object _ ShellFromEnd[handle, urDiv, RTBasic.OtherSide[blSide], parms.rules]; parms.parms.wireWidthProc _ GetWireWidth; parms.parms.makeTabKeyProc _ PinName; parms.parms.context _ NEW[PWRouteContext _ [direction: direction, table: handle.widthTable]]; result _ PWRoute.DoRoute[obj1, obj2, bottomOrLeftObj, topOrRightObj, parms.parms, chipSide=right OR chipSide=left, channel]; rect _ result.routingRect; SELECT chipSide FROM bottom => { size: INT _ handle.inner.origin.y - (boundingChannel.origin.y + boundingChannel.size.y); retrieveRect _ NEW[CD.Rect _ [rect.x1, MIN[rect.y1, rect.y2 - size + offset], rect.x2, rect.y2 + offset]]}; right => { size: INT _ boundingChannel.origin.x - (handle.inner.origin.x + handle.inner.size.x); retrieveRect _ NEW[CD.Rect _ [rect.x1 - offset, rect.y1, MAX[rect.x2, rect.x1 + size - offset], rect.y2]]}; top => { size: INT _ boundingChannel.origin.y - (handle.inner.origin.y + handle.inner.size.y); retrieveRect _ NEW[CD.Rect _ [rect.x1, rect.y1 - offset, rect.x2, MAX[rect.y2, rect.x1 + size - offset]]]}; left => { size: INT _ handle.inner.origin.x - (boundingChannel.origin.x + boundingChannel.size.x); retrieveRect _ NEW[CD.Rect _ [MIN[rect.x1, rect.x2 - size + offset], rect.y1, rect.x2 + offset, rect.y2]]}; ENDCASE; channel.object _ PWRoute.GetRouting[result, retrieveRect, parms.parms]; channel.size _ RTBasic.IRSize[channel.object]; channel.cellType _ ExtractChannel[channel, parms]}; RouteSwitchBoxes: PROC [handle: CabbagePrivate.Handle] ~ { horizParms: CabbagePrivate.ParmSet _ handle.rules.horizParms; leftHorizRange: Connections.Range _ [handle.left.origin.x + handle.left.size.x, handle.inner.origin.x]; rightHorizRange: Connections.Range _ [handle.inner.origin.x + handle.inner.size.x, handle.right.origin.x]; bottomVertRange: Connections.Range _ [handle.bottom.origin.y + handle.bottom.size.y, handle.inner.origin.y]; topVertRange: Connections.Range _ [handle.inner.origin.y + handle.inner.size.y, handle.top.origin.y]; horizParms.parms.okToDiddleLLPins _ TRUE; horizParms.parms.okToDiddleURPins _ FALSE; handle.detailedRouting.switchBoxes[bottomLeft] _ RouteSwitchBox[handle, bottomLeft, leftHorizRange, bottomVertRange, horizParms]; horizParms.parms.okToDiddleLLPins _ FALSE; horizParms.parms.okToDiddleURPins _ TRUE; handle.detailedRouting.switchBoxes[bottomRight] _ RouteSwitchBox[handle, bottomRight, rightHorizRange, bottomVertRange, horizParms]; horizParms.parms.okToDiddleLLPins _ FALSE; horizParms.parms.okToDiddleURPins _ TRUE; handle.detailedRouting.switchBoxes[topRight] _ RouteSwitchBox[handle, topRight, rightHorizRange, topVertRange, horizParms]; horizParms.parms.okToDiddleLLPins _ TRUE; horizParms.parms.okToDiddleURPins _ FALSE; handle.detailedRouting.switchBoxes[topLeft] _ RouteSwitchBox[handle, topLeft, leftHorizRange, topVertRange, horizParms]; horizParms.parms.okToDiddleLLPins _ FALSE; horizParms.parms.okToDiddleURPins _ FALSE}; RouteSwitchBoxesPL: PROC [handle: CabbagePrivate.Handle] ~ { horizParms: CabbagePrivate.ParmSet _ handle.rules.horizParms; powerWidth: INT _ handle.parms.outerChanWidth + handle.parms.powerCellWidth; horizRange: Connections.Range _ [handle.left.origin.x + handle.left.size.x + powerWidth, handle.right.origin.x - powerWidth]; bottomVertRange: Connections.Range _ [handle.bottom.origin.y + handle.bottom.size.y + powerWidth, handle.inner.origin.y]; topVertRange: Connections.Range _ [handle.inner.origin.y + handle.inner.size.y, handle.top.origin.y - powerWidth]; horizParms.parms.okToDiddleLLPins _ TRUE; horizParms.parms.okToDiddleURPins _ TRUE; handle.detailedRoutingPL.switchBoxes[bottom] _ RouteSwitchBoxPL[handle, bottom, horizRange, bottomVertRange, horizParms]; handle.detailedRoutingPL.switchBoxes[top] _ RouteSwitchBoxPL[handle, top, horizRange, topVertRange, horizParms]; horizParms.parms.okToDiddleLLPins _ FALSE; horizParms.parms.okToDiddleURPins _ FALSE}; RouteSwitchBoxPL: PROC [handle: CabbagePrivate.Handle, side: RTBasic.TBSide, horizRange, vertRange: Connections.Range, parms: CabbagePrivate.ParmSet] RETURNS [switchBox: CabbagePrivate.Channel] ~ { bottomObject, topObject: Cabbage.Object; leftObject: Cabbage.Object _ ShellFromChannel[handle.powerDistribution.power[left], right, parms.rules.trunkLayer, vertRange, parms.rules]; rightObject: Cabbage.Object _ ShellFromChannel[handle.powerDistribution.power[right], left, parms.rules.trunkLayer, vertRange, parms.rules]; innerRange: Connections.Range _ [handle.inner.origin.x, handle.inner.origin.x + handle.inner.size.x]; direction: RTBasic.Direction _ IF side= right OR side=left THEN vertical ELSE horizontal; SELECT side FROM bottom => { innerObject: Cabbage.Object _ ShellFromObject[handle, handle.inner, bottom, innerRange, parms.rules, TRUE]; topObject _ PW.AbutListX[LIST[ShellFromFullChannel[handle.detailedRoutingPL.channels[left], bottom, parms.rules.branchLayer, parms.rules], innerObject, ShellFromFullChannel[handle.detailedRoutingPL.channels[right], bottom, parms.rules.branchLayer, parms.rules]]]; bottomObject _ ShellFromChannel[handle.powerDistribution.power[bottom], top, parms.rules.branchLayer, horizRange, parms.rules]}; top => { innerObject: Cabbage.Object _ ShellFromObject[handle, handle.inner, top, innerRange, parms.rules, TRUE]; bottomObject _ PW.AbutListX[LIST[ShellFromFullChannel[handle.detailedRoutingPL.channels[left], top, parms.rules.branchLayer, parms.rules], innerObject, ShellFromFullChannel[handle.detailedRoutingPL.channels[right], top, parms.rules.branchLayer, parms.rules]]]; topObject _ ShellFromChannel[handle.powerDistribution.power[top], bottom, parms.rules.branchLayer, horizRange, parms.rules]}; ENDCASE; parms.parms.wireWidthProc _ GetWireWidth; parms.parms.makeTabKeyProc _ PinName; parms.parms.context _ NEW[PWRouteContext _ [direction: direction, table: handle.widthTable]]; switchBox.object _ PWRoute.MakeChannel[bottomObject, topObject, leftObject, rightObject, NIL, parms.parms, FALSE, switchBox]; switchBox.size _ RTBasic.IRSize[switchBox.object]; switchBox.cellType _ ExtractChannel[switchBox, parms]}; RouteSwitchBox: PROC [handle: CabbagePrivate.Handle, corner: CabbagePrivate.Corners, horizRange, vertRange: Connections.Range, parms: CabbagePrivate.ParmSet] RETURNS [switchBox: CabbagePrivate.Channel] ~ { bottomObject, topObject, leftObject, rightObject: Cabbage.Object; SELECT corner FROM bottomLeft => { topObject _ ShellFromFullChannel[handle.detailedRouting.channels[left], bottom, parms.rules.branchLayer, parms.rules]; bottomObject _ ShellFromChannel[handle.powerDistribution.power[bottom], top, parms.rules.branchLayer, horizRange, parms.rules]; leftObject _ ShellFromChannel[handle.powerDistribution.power[left], right, parms.rules.trunkLayer, vertRange, parms.rules]; rightObject _ ShellFromFullChannel[handle.detailedRouting.channels[bottom], left, parms.rules.trunkLayer, parms.rules]}; bottomRight => { topObject _ ShellFromFullChannel[handle.detailedRouting.channels[right], bottom, parms.rules.branchLayer, parms.rules]; bottomObject _ ShellFromChannel[handle.powerDistribution.power[bottom], top, parms.rules.branchLayer, horizRange, parms.rules]; rightObject _ ShellFromChannel[handle.powerDistribution.power[right], left, parms.rules.trunkLayer, vertRange, parms.rules]; leftObject _ ShellFromFullChannel[handle.detailedRouting.channels[bottom], right, parms.rules.trunkLayer, parms.rules]}; topRight => { bottomObject _ ShellFromFullChannel[handle.detailedRouting.channels[right], top, parms.rules.branchLayer, parms.rules]; topObject _ ShellFromChannel[handle.powerDistribution.power[top], bottom, parms.rules.branchLayer, horizRange, parms.rules]; rightObject _ ShellFromChannel[handle.powerDistribution.power[right], left, parms.rules.trunkLayer, vertRange, parms.rules]; leftObject _ ShellFromFullChannel[handle.detailedRouting.channels[top], right, parms.rules.trunkLayer, parms.rules]}; topLeft => { bottomObject _ ShellFromFullChannel[handle.detailedRouting.channels[left], top, parms.rules.branchLayer, parms.rules]; topObject _ ShellFromChannel[handle.powerDistribution.power[top], bottom, parms.rules.branchLayer, horizRange, parms.rules]; leftObject _ ShellFromChannel[handle.powerDistribution.power[left], right, parms.rules.trunkLayer, vertRange, parms.rules]; rightObject _ ShellFromFullChannel[handle.detailedRouting.channels[top], left, parms.rules.trunkLayer, parms.rules]}; ENDCASE; parms.parms.wireWidthProc _ GetWireWidth; parms.parms.context _ handle.widthTable; switchBox.object _ PWRoute.MakeChannel[bottomObject, topObject, leftObject, rightObject, NIL, parms.parms, FALSE, switchBox]; switchBox.size _ RTBasic.IRSize[switchBox.object]; switchBox.cellType _ ExtractChannel[switchBox, parms]}; MakeChip: PUBLIC PROC [handle: CabbagePrivate.Handle] RETURNS [chip: Cabbage.Object _ CDCells.CreateEmptyCell[]] ~ { IncludeObject[handle.inner.object, handle.inner.origin, chip]; IncludeObject[handle.bottomLeft.object, handle.bottomLeft.origin, chip]; IncludeObject[handle.bottom.object, handle.bottom.origin, chip]; IncludeObject[handle.bottomRight.object, handle.bottomRight.origin, chip]; IncludeObject[handle.right.object, handle.right.origin, chip]; IncludeObject[handle.topRight.object, handle.topRight.origin, chip]; IncludeObject[handle.top.object, handle.top.origin, chip]; IncludeObject[handle.topLeft.object, handle.topLeft.origin, chip]; IncludeObject[handle.left.object, handle.left.origin, chip]; IF handle.routeType = normal THEN { FOR side: Cabbage.Side IN Cabbage.Side DO IncludeObject[handle.detailedRouting.channels[side].object, handle.detailedRouting.channels[side].origin, chip]; ENDLOOP; FOR corner: CabbagePrivate.Corners IN CabbagePrivate.Corners DO IncludeObject[handle.detailedRouting.switchBoxes[corner].object, handle.detailedRouting.switchBoxes[corner].origin, chip]; ENDLOOP} ELSE { FOR side: Cabbage.Side IN RTBasic.LRSide DO IncludeObject[handle.detailedRoutingPL.channels[side].object, handle.detailedRoutingPL.channels[side].origin, chip]; ENDLOOP; FOR side: Cabbage.Side IN RTBasic.TBSide DO IncludeObject[handle.detailedRoutingPL.switchBoxes[side].object, handle.detailedRoutingPL.switchBoxes[side].origin, chip]; ENDLOOP}; FOR side: Cabbage.Side IN Cabbage.Side DO IncludeObject[handle.powerDistribution.channels[side].object, handle.powerDistribution.channels[side].origin, chip]; IncludeObject[handle.powerDistribution.power[side].object, handle.powerDistribution.power[side].origin, chip]; ENDLOOP; FOR corner: CabbagePrivate.Corners IN CabbagePrivate.Corners DO IncludeObject[handle.powerDistribution.switchBoxes[corner].object, handle.powerDistribution.switchBoxes[corner].origin, chip]; ENDLOOP; [] _ RTBasic.RepositionCell[chip]}; MappedShellFromObject: PROC [handle: CabbagePrivate.Handle, objectDes: CabbagePrivate.ObjectDescription, pinSide: Route.Side, -- the side of the object on which pins are to be considered innerRange, outerRange: Connections.Range, -- innerRange is the span of the inner cell, outerRangethe span of the appropriate power routing cell viaSize: INT, -- the size of the via alont the lenght of the cell rules: Route.DesignRules] RETURNS [shell: Cabbage.Object _ CDCells.CreateEmptyCell[]] ~ { EnterPowerOnInner: Connections.EachNetAction ~ { EachSegment: Connections.EachSegmentAction ~ { IF (segment.object = handle.inner.object AND segment.side = otherSide) AND (Rope.Equal[net.name, "Vdd"] OR Rope.Equal[net.name, "Gnd"]) THEN Insert[obstacles, [innerOrigin + segment.range.min, innerOrigin + segment.range.max], rules.branchToBranch]}; [] _ Connections.EnumerateSegments[net, EachSegment]}; EnterPowerOnOuter: Connections.EachNetAction ~ { EachSegment: Connections.EachSegmentAction ~ { IF (segment.object = objectDes.object AND segment.side = pinSide) AND (Rope.Equal[net.name, "Vdd"] OR Rope.Equal[net.name, "Gnd"]) THEN Insert[obstacles, [outerOrigin + segment.range.min, outerOrigin + segment.range.max], rules.branchToBranch]}; [] _ Connections.EnumerateSegments[net, EachSegment]}; EachOuterNet: Connections.EachNetAction ~ { EachSegment: Connections.EachSegmentAction ~ { IF (segment.object = objectDes.object AND segment.side = pinSide) THEN { useThisPin: BOOLEAN _ TRUE; newRange: Connections.Range; powerNet: BOOLEAN _ Rope.Equal[net.name, "Vdd"] OR Rope.Equal[net. name, "Gnd"]; adjustedRange: Connections.Range _ [outerOrigin + segment.range.min, outerOrigin + segment.range.max]; IF ProperSubset[adjustedRange, outerRange] THEN { IF powerNet THEN newRange _ adjustedRange ELSE IF HashTable.Insert[netTable, net.name, NIL] THEN newRange _ FindMiddleRange[adjustedRange, obstacles] ELSE useThisPin _ FALSE} ELSE IF ProperSubset[adjustedRange, [FIRST[INT], outerRange.min]] THEN { IF powerNet THEN { Cabbage.Signal[callingError, Rope.Cat[net.name, " pin on pad frame is in invalid position (within lower power bus corner)"]]; useThisPin _ FALSE} ELSE IF HashTable.Insert[netTable, net.name, NIL] THEN { lowerRange: Connections.Range _ [outerRange.min, outerRange.min + (adjustedRange.max-adjustedRange.min)]; newRange _ FindLowerRange[lowerRange, obstacles]} ELSE useThisPin _ FALSE} ELSE IF ProperSubset[adjustedRange, [outerRange.max, LAST[INT]]] THEN { IF powerNet THEN { Cabbage.Signal[callingError, Rope.Cat[net.name, " pin on pad frame is in invalid position (within upper power bus corner)"]]; useThisPin _ FALSE} ELSE IF HashTable.Insert[netTable, net.name, NIL] THEN { upperRange: Connections.Range _ [outerRange.max - (adjustedRange.max-adjustedRange.min), outerRange.max]; newRange _ FindUpperRange[upperRange, obstacles]} ELSE useThisPin _ FALSE} ELSE { Cabbage.Signal[callingError, Rope.Cat["Segment on net: ", net.name, " crosses boundary of power routing area"]]; useThisPin _ FALSE}; IF useThisPin THEN { denotes: CD.Rect _ SELECT pinSide FROM bottom => [newRange.min, oldIR.y2-rules.trunkWidth, newRange.max, oldIR.y2], right => [oldIR.x1, newRange.min, oldIR.x1+rules.trunkWidth, newRange.max], top => [newRange.min, oldIR.y1, newRange.max, oldIR.y1+rules.trunkWidth], left => [oldIR.x2-rules.trunkWidth, newRange.min, oldIR.x2, newRange.max], ENDCASE => Cabbage.Error[programmingError, "Not suppose to happen."]; IncludePin[object: shell, name: net.name, denotes: denotes, layer: rules.branchLayer]; IF ~powerNet THEN -- power nets were inserted first Insert[obstacles, newRange, rules.branchToBranch]; }}}; [] _ Connections.EnumerateSegments[net, EachSegment]}; netTable: HashTable.Table _ HashTable.Create[equal: HashTable.RopeEqual, hash: HashTable.HashRope]; oldIR: CD.Rect _ CD.InterestRect[objectDes.object]; interestRect: CD.Rect _ SELECT pinSide FROM bottom, top => interestRect _ [outerRange.min, oldIR.y1, outerRange.max, oldIR.y2], left, right => [oldIR.x1, outerRange.min, oldIR.x2, outerRange.max], ENDCASE => Cabbage.Error[programmingError, "Not suppose to happen."]; otherSide: Route.Side _ RTBasic.OtherSide[pinSide]; innerOrigin: INT _ SELECT pinSide FROM bottom, top => handle.inner.origin.x, right, left => handle.inner.origin.y, ENDCASE => Cabbage.Error[programmingError, "Not suppose to happen."]; outerOrigin: INT _ SELECT pinSide FROM bottom, top => objectDes.origin.x, right, left => objectDes.origin.y, ENDCASE => Cabbage.Error[programmingError, "Not suppose to happen."]; obstacles: BitTable _ CreateBitTable[outerRange.min, outerRange.max, rules.CDLambda]; Insert[obstacles, [outerRange.min, outerRange.min + viaSize], rules.branchToBranch]; Insert[obstacles, [outerRange.max - viaSize, outerRange.max], rules.branchToBranch]; Insert[obstacles, [innerRange.min - 3*rules.branchToBranch, innerRange.min + 3*rules.branchToBranch], rules.branchToBranch]; Insert[obstacles, [innerRange.max - 3*rules.branchToBranch, innerRange.max + 3*rules.branchToBranch], rules.branchToBranch]; [] _ Connections.EnumerateNets[handle.connections, EnterPowerOnInner]; [] _ Connections.EnumerateNets[handle.connections, EnterPowerOnOuter]; [] _ Connections.EnumerateNets[handle.connections, EachOuterNet]; CDCells.SetInterestRect[design: NIL, cell: shell, r: interestRect]; RTBasic.RepositionCell[shell]}; ShellFromOutsideEnd: PROC [handle: CabbagePrivate.Handle, objectDes: CabbagePrivate.ObjectDescription, pinsOnSide, endOfChannel: Route.Side, innerRange, outerRange: Connections.Range, -- the span along the appropriate padring cell rules: Route.DesignRules] RETURNS [shell: Cabbage.Object _ CDCells.CreateEmptyCell[]] ~ { EachNet: Connections.EachNetAction ~ { EachSegment: Connections.EachSegmentAction ~ { IF (segment.object = objectDes.object AND segment.side = pinsOnSide) THEN { adjustedRange: Connections.Range _ [origin + segment.range.min, origin + segment.range.max]; IF CrossesBoundry[adjustedRange, interestingRange] THEN Cabbage.Signal[callingError, Rope.Cat["Segment on net: ", net.name, " crosses boundary of power routing areas"]]; IF ProperSubset[adjustedRange, interestingRange] AND ~Member[net.name, netNameList] THEN { width: INT _ MAX[rules.trunkWidth, net.width]; dist _ dist + rules.trunkWidth; SELECT endOfChannel FROM bottom => IncludePin[object: shell, name: net.name, denotes: [dist, rules.trunkWidth, dist + width, 2*rules.trunkWidth], layer: rules.trunkLayer]; right => IncludePin[object: shell, name: net.name, denotes: [0, dist, rules.trunkWidth, dist + width], layer: rules.trunkLayer]; top => IncludePin[object: shell, name: net.name, denotes: [dist, 0, dist + width, rules.trunkWidth], layer: rules.trunkLayer]; left => IncludePin[object: shell, name: net.name, denotes: [rules.trunkWidth, dist, 2*rules.trunkWidth, dist + width], layer: rules.trunkLayer]; ENDCASE; netNameList _ CONS[net.name, netNameList]; dist _ dist + width}}}; [] _ Connections.EnumerateSegments[net, EachSegment]}; dist: INT _ rules.trunkWidth; netNameList: LIST OF Rope.ROPE _ LIST["Vdd", "Gnd"]; -- pre load with power names interestRect: CD.Rect; interestingRange: Connections.Range _ SELECT endOfChannel FROM left, bottom => [FIRST[INT], outerRange.min], right, top => [outerRange.max, LAST[INT]], ENDCASE => Cabbage.Error[programmingError, "Not suppose to happen."]; origin: INT _ SELECT pinsOnSide FROM bottom, top => objectDes.origin.x, right, left => objectDes.origin.y, ENDCASE => Cabbage.Error[programmingError, "Not suppose to happen."]; [] _ Connections.EnumerateNets[handle.connections, EachNet]; interestRect _ SELECT endOfChannel FROM bottom, top => [0, 0, dist + rules.trunkWidth, 2*rules.trunkWidth], left, right => [0, 0, 2*rules.trunkWidth, dist + 2*rules.trunkWidth], ENDCASE => Cabbage.Error[programmingError, "Not suppose to happen"]; CDCells.SetInterestRect[design: NIL, cell: shell, r: interestRect]; RTBasic.RepositionCell[shell]}; ShellFromObject: PROC [handle: CabbagePrivate.Handle, objectDes: CabbagePrivate.ObjectDescription, side: Route.Side, -- the side of the object on which pins are to be considered range: Connections.Range, -- the span along objectDes to consider rules: Route.DesignRules, includePowerNets: BOOLEAN] RETURNS [shell: Cabbage.Object _ CDCells.CreateEmptyCell[]] ~ { EachNet: Connections.EachNetAction ~ { EachSegment: Connections.EachSegmentAction ~ { IF (segment.object = objectDes.object AND segment.side = side) THEN { adjustedRange: Connections.Range _ [origin + segment.range.min, origin + segment.range.max]; powerNet: BOOLEAN _ Rope.Equal[net.name, "Vdd"] OR Rope.Equal[net. name, "Gnd"]; IF CrossesBoundry[adjustedRange, range] THEN Cabbage.Signal[callingError, Rope.Cat["Segment on net: ", net.name, " crosses a boundary of the power routing areas"]]; IF ProperSubset[adjustedRange, range] AND (includePowerNets OR ~powerNet) THEN { SELECT side FROM bottom => IncludePin[object: shell, name: net.name, denotes: [adjustedRange.min, oldIR.y1, adjustedRange.max, oldIR.y1+rules.trunkWidth], layer: segment.layer]; right => IncludePin[object: shell, name: net.name, denotes: [oldIR.x2-rules.trunkWidth, adjustedRange.min, oldIR.x2, adjustedRange.max], layer: segment.layer]; top => IncludePin[object: shell, name: net.name, denotes: [adjustedRange.min, oldIR.y2-rules.trunkWidth, adjustedRange.max, oldIR.y2], layer: segment.layer]; left => IncludePin[object: shell, name: net.name, denotes: [oldIR.x1, adjustedRange.min, oldIR.x1+rules.trunkWidth, adjustedRange.max], layer: segment.layer]; ENDCASE}}}; [] _ Connections.EnumerateSegments[net, EachSegment]}; oldIR: CD.Rect _ CD.InterestRect[objectDes.object]; interestRect: CD.Rect; origin: INT _ SELECT side FROM bottom, top => objectDes.origin.x, right, left => objectDes.origin.y, ENDCASE => Cabbage.Error[programmingError, "Not suppose to happen."]; [] _ Connections.EnumerateNets[handle.connections, EachNet]; interestRect _ SELECT side FROM bottom, top => interestRect _ [range.min, oldIR.y1, range.max, oldIR.y2], left, right => [oldIR.x1, range.min, oldIR.x2, range.max], ENDCASE => Cabbage.Error[programmingError, "Not suppose to happen."]; CDCells.SetInterestRect[design: NIL, cell: shell, r: interestRect]; RTBasic.RepositionCell[shell]}; ShellFromEnd: PROC [handle: CabbagePrivate.Handle, division: CabbagePrivate.Division, side: Route.Side, rules: Route.DesignRules] RETURNS [shell: Cabbage.Object _ CDCells.CreateEmptyCell[]] ~ { EachExit: EachExitAction ~ { IF ~(Rope.Equal[net.name, "Vdd"] OR Rope.Equal[net. name, "Gnd"]) THEN { width: INT _ MAX[rules.trunkWidth, net.width]; dist _ dist + rules.trunkWidth; SELECT side FROM bottom => IncludePin[object: shell, name: net.name, denotes: [dist, rules.trunkWidth, dist + width, 2*rules.trunkWidth], layer: rules.trunkLayer]; right => IncludePin[object: shell, name: net.name, denotes: [0, dist, rules.trunkWidth, dist + width], layer: rules.trunkLayer]; top => IncludePin[object: shell, name: net.name, denotes: [dist, 0, dist + width, rules.trunkWidth], layer: rules.trunkLayer]; left => IncludePin[object: shell, name: net.name, denotes: [rules.trunkWidth, dist, 2*rules.trunkWidth, dist + width], layer: rules.trunkLayer]; ENDCASE; dist _ dist + width}}; dist: INT _ 0; interestRect: CD.Rect; [] _ EnumerateExits[handle.globalRouting.exitLists[division], division, EachExit]; interestRect _ SELECT side FROM bottom, top => [0, 0, dist + rules.trunkWidth, 2*rules.trunkWidth], left, right => [0, 0, 2*rules.trunkWidth, dist + rules.trunkWidth], ENDCASE => Cabbage.Error[programmingError, "Not suppose to happen"]; CDCells.SetInterestRect[design: NIL, cell: shell, r: interestRect]; RTBasic.RepositionCell[shell]}; ShellFromFullChannel: PROC [channel: CabbagePrivate.Channel, side: Route.Side, pinLayer: CD.Layer, rules: Route.DesignRules] RETURNS [shell: Cabbage.Object] ~ { rect: CD.Rect _ CD.InterestRect[channel.object]; range: Connections.Range _ SELECT side FROM bottom, top => [rect.x1, rect.x2], left, right => [rect.y1, rect.y2], ENDCASE => Cabbage.Error[programmingError, "Not suppose to happen"]; RETURN [ShellFromChannel[channel, side, pinLayer, range, rules]]}; ShellFromChannel: PROC [channel: CabbagePrivate.Channel, pinSide: Route.Side, pinLayer: CD.Layer, range: Connections.Range, rules: Route.DesignRules] RETURNS [shell: Cabbage.Object _ CDCells.CreateEmptyCell[]] ~ { ChanPublics: CoreGeometry.EachWirePinProc ~ { name: Rope.ROPE _ CoreOps.GetShortWireName[wire]; IF layer = pinLayer THEN { SELECT side FROM bottom => IF range.min <= rect.x1+max AND rect.x1+max <= range.max AND pinSide = bottom THEN IncludePin[object: shell, name: name, denotes: [rect.x1+min, rect.y1, rect.x1+max, rect.y1+depth], layer: layer]; right => IF range.min <= rect.y1+max AND rect.y1+max <= range.max AND pinSide = right THEN IncludePin[object: shell, name: name, denotes: [rect.x2-depth, rect.y1+min, rect.x2, rect.y1+max], layer: layer]; top => IF range.min <= rect.x1+max AND rect.x1+max <= range.max AND pinSide = top THEN IncludePin[object: shell, name: name, denotes: [rect.x1+min, rect.y2-depth, rect.x1+max, rect.y2], layer: layer]; left => IF range.min <= rect.y1+max AND rect.y1+max <= range.max AND pinSide = left THEN IncludePin[object: shell, name: name, denotes: [rect.x1, rect.y1+min, rect.x1+depth, rect.y1+max], layer: layer]; ENDCASE}}; mode: Sinix.Mode = SinixOps.GetExtractMode[rules.technology]; depth: Route.Number _ rules.trunkWidth; rect: CD.Rect _ CD.InterestRect[channel.object]; newRect: CD.Rect _ SELECT pinSide FROM bottom, top => [range.min, rect.y1, range.max, rect.y2], left, right => [rect.x1, range.min, rect.x2, range.max], ENDCASE => Cabbage.Error[programmingError, "Not suppose to happen"]; [] _ CoreGeometry.EnumerateNonOverlappingSides[mode.decoration, channel.cellType, ChanPublics]; CDCells.SetInterestRect[design: NIL, cell: shell, r: newRect]; RTBasic.RepositionCell[shell]}; AdjustPositions: PROC [handle: CabbagePrivate.Handle] ~ { powerWidth: INT _ handle.parms.outerChanWidth + handle.parms.powerCellWidth; routeType: CabbagePrivate.RouteType _ handle.routeType; sizeBottomArea: INT _ handle.inner.origin.y - (handle.bottom.origin.y + handle.bottom.size.y); sizeBottomRouting: INT _ powerWidth + (IF routeType = normal THEN handle.detailedRouting.channels[bottom].size.y ELSE handle.detailedRoutingPL.switchBoxes[bottom].size.y); adjBottom: INT _ sizeBottomRouting - sizeBottomArea; sizeLeftArea: INT _ handle.inner.origin.x - (handle.left.origin.x + handle.left.size.x); sizeLeftRouting: INT _ powerWidth + (IF routeType = normal THEN handle.detailedRouting.channels[left].size.x ELSE handle.detailedRoutingPL.channels[left].size.x); adjLeft: INT _ sizeLeftRouting - sizeLeftArea; adjTop, adjRight, sizeTopArea, sizeTopRouting, sizeRightArea, sizeRightRouting: INT; handle.inner.origin _ CDBasics.AddPoints[handle.inner.origin, [MAX[0, adjLeft], MAX[0, adjBottom]]]; handle.bottom.origin _ CDBasics.AddPoints[handle.bottom.origin, [MAX[0, adjLeft], 0]]; handle.right.origin _ CDBasics.AddPoints[handle.right.origin, [MAX[0, adjLeft], MAX[0, adjBottom]]]; handle.top.origin _ CDBasics.AddPoints[handle.top.origin, [MAX[0, adjLeft], MAX[0, adjBottom]]]; handle.left.origin _ CDBasics.AddPoints[handle.left.origin, [0, MAX[0, adjBottom]]]; sizeTopArea _ handle.top.origin.y - (handle.inner.origin.y + handle.inner.size.y); sizeTopRouting _ powerWidth + (IF routeType = normal THEN handle.detailedRouting.channels[top].size.y ELSE handle.detailedRoutingPL.switchBoxes[top].size.y); adjTop _ sizeTopRouting - sizeTopArea; sizeRightArea _ handle.right.origin.x - (handle.inner.origin.x + handle.inner.size.x); sizeRightRouting _ powerWidth + (IF routeType = normal THEN handle.detailedRouting.channels[right].size.x ELSE handle.detailedRoutingPL.channels[right].size.x); adjRight _ sizeRightRouting - sizeRightArea; handle.top.origin _ CDBasics.AddPoints[handle.top.origin, [0, MAX[0, adjTop]]]; handle.right.origin _ CDBasics.AddPoints[handle.right.origin, [MAX[0, adjRight], 0]]; [] _ GetSize[handle]; DoCorners[handle]; DoRoutingAreas[handle]}; IncludeObject: PROC [object: Cabbage.Object, origin: CD.Position, chip: Cabbage.Object] ~ { IF object # NIL THEN [] _ RouteUtil.Include[cell: chip, ob: object, position: CDOps.FitObjectI[ob: object, location: origin, orientation: original].off, orientation: original]}; ExtractChannel: PROC [channel: CabbagePrivate.Channel, parms: CabbagePrivate.ParmSet] RETURNS [cellType: Core.CellType] ~ { mode: Sinix.Mode = SinixOps.GetExtractMode[parms.rules.technology]; cellType _ NARROW [Sinix.Extract[channel.object, mode].result]}; PosOf: PROC [handle: CabbagePrivate.Handle, segment: Connections.Segment] RETURNS [INT] ~ { range: Connections.Range _ RangeOf[handle, segment]; RETURN[(range.min+range.max)/2]}; RangeOf: PROC [handle: CabbagePrivate.Handle, segment: Connections.Segment] RETURNS [range: Connections.Range] ~ { range _ SELECT TRUE FROM segment.object = handle.inner.object => InnerRange[handle, segment], segment.object = handle.bottom.object => range _ OuterRange[handle, segment], segment.object = handle.right.object => OuterRange[handle, segment], segment.object = handle.top.object => OuterRange[handle, segment], segment.object = handle.left.object => OuterRange[handle, segment], segment.object = handle.powerDistribution.power[bottom].object => PowerRange[handle, segment], segment.object = handle.powerDistribution.power[right].object => PowerRange[handle, segment], segment.object = handle.powerDistribution.power[top].object => PowerRange[handle, segment], segment.object = handle.powerDistribution.power[left].object => PowerRange[handle, segment], ENDCASE => Cabbage.Error[callingError, Rope.Cat["Invalid object in segment: ", segment.name]]}; InnerRange: PROC [handle: CabbagePrivate.Handle, segment: Connections.Segment] RETURNS [range: Connections.Range] ~ { SELECT segment.side FROM bottom => {origin: INT _ handle.inner.origin.x; range _ [origin + segment.range.min, origin + segment.range.max]}; right => {origin: INT _ handle.size.x + handle.inner.origin.y; range _ [origin + segment.range.min, origin + segment.range.max]}; top => {origin: INT _ handle.size.x +handle.size.y + (handle.size.x - handle.inner.origin.x); range _ [origin - segment.range.max, origin - segment.range.min]}; left => {origin: INT _ 2*handle.size.x +handle.size.y + (handle.size.y - handle.inner.origin.y); range _ [origin - segment.range.max, origin - segment.range.min]}; ENDCASE}; OuterRange: PROC [handle: CabbagePrivate.Handle, segment: Connections.Segment] RETURNS [range: Connections.Range] ~ { SELECT RTBasic.OtherSide[segment.side] FROM bottom => {origin: INT _ handle.bottom.origin.x; range _ [origin + segment.range.min, origin + segment.range.max]}; right => {origin: INT _ handle.size.x + handle.right.origin.y; range _ [origin + segment.range.min, origin + segment.range.max]}; top => {origin: INT _ handle.size.x +handle.size.y + (handle.size.x - handle.top.origin.x); range _ [origin - segment.range.max, origin - segment.range.min]}; left => {origin: INT _ 2*handle.size.x +handle.size.y + (handle.size.y - handle.left.origin.y); range _ [origin - segment.range.max, origin - segment.range.min]}; ENDCASE}; PowerRange: PROC [handle: CabbagePrivate.Handle, segment: Connections.Segment] RETURNS [range: Connections.Range] ~ { SELECT RTBasic.OtherSide[segment.side] FROM bottom => {origin: INT _ handle.powerDistribution.power[bottom].origin.x; range _ [origin + segment.range.min, origin + segment.range.max]}; right => {origin: INT _ handle.size.x + handle.powerDistribution.power[right].origin.y; range _ [origin + segment.range.min, origin + segment.range.max]}; top => {origin: INT _ handle.size.x +handle.size.y + (handle.size.x - handle.powerDistribution.power[top].origin.x); range _ [origin - segment.range.max, origin - segment.range.min]}; left => {origin: INT _ 2*handle.size.x +handle.size.y + (handle.size.y - handle.powerDistribution.power[left].origin.y); range _ [origin - segment.range.max, origin - segment.range.min]}; ENDCASE}; PosOfDivision: PROC [handle: CabbagePrivate.Handle, division: CabbagePrivate.Division] RETURNS [pos: INT] ~ { SELECT division FROM bottomLeft => pos _ handle.inner.origin.x; bottomRight => pos _ handle.inner.origin.x + handle.inner.size.x; rightBottom => pos _ handle.size.x + handle.inner.origin.y; rightTop => pos _ handle.size.x + handle.inner.origin.y + handle.inner.size.y; topRight => pos _ handle.size.x +handle.size.y + (handle.size.x - handle.inner.origin.x - handle.inner.size.x); topLeft => pos _ handle.size.x +handle.size.y + (handle.size.x - handle.inner.origin.x); leftTop => pos _ 2*handle.size.x +handle.size.y + (handle.size.y - handle.inner.origin.y - handle.inner.size.y); leftBottom => pos _ 2*handle.size.x +handle.size.y + (handle.size.y - handle.inner.origin.y); ENDCASE}; EachExitAction: TYPE = PROC [division: CabbagePrivate.Division, net: Connections.Net] RETURNS [quit: BOOLEAN _ FALSE]; EnumerateExits: PROC [exitList: CabbagePrivate.ExitList, division: CabbagePrivate.Division, eachExitAction: EachExitAction] RETURNS [quit: BOOLEAN _ FALSE] ~ { FOR list: CabbagePrivate.ExitList _ exitList, list.rest WHILE ~quit AND list # NIL DO exit: Connections.Net _ list.first; quit _ eachExitAction[division, exit]; ENDLOOP}; CrossesBoundry: PROC [r1, r2: Connections.Range] RETURNS [crosses: BOOLEAN] ~ { crosses _(r1.min <= r2.min AND r2.min <= r1.max) OR (r1.min <= r2.max AND r2.max <= r1.max); }; ProperSubset: PROC [r1, r2: Connections.Range] RETURNS [subset: BOOLEAN] ~ { subset _((r2.min <= r1.min AND r1.min <= r2.max) AND (r2.min <= r1.max AND r1.max <= r2.max)); }; GetSize: PROC [handle: CabbagePrivate.Handle] RETURNS [hBottom, hTop, vLeft, vRight: INT] ~ { vMiddle, hMiddle: INT; powerWidth: INT _ handle.parms.outerChanWidth + handle.parms.powerCellWidth; IF handle.routeType = normal THEN { vMiddle _ handle.bottom.size.y + powerWidth + handle.detailedRouting.channels[bottom].size.y + handle.inner.size.y + handle.detailedRouting.channels[top].size.y + powerWidth + handle.top.size.y; hMiddle _ handle.left.size.x + powerWidth + handle.detailedRouting.channels[left].size.x + handle.inner.size.x + handle.detailedRouting.channels[right].size.x + powerWidth + handle.right.size.x} ELSE { hCenter: INT _ powerWidth + handle.detailedRoutingPL.channels[left].size.x + handle.inner.size.x + handle.detailedRoutingPL.channels[right].size.x + powerWidth; hInner: INT _ MAX[hCenter, handle.detailedRoutingPL.switchBoxes[top].size.x, handle.detailedRoutingPL.switchBoxes[bottom].size.x]; vInner: INT _ powerWidth + handle.detailedRoutingPL.switchBoxes[bottom].size.y + handle.inner.size.y + handle.detailedRoutingPL.switchBoxes[top].size.y + powerWidth; vMiddle _ handle.bottom.size.y + vInner + handle.top.size.y; hMiddle _ handle.left.size.x + hInner + handle.right.size.x}; vLeft _ handle.bottomLeft.size.y + handle.left.size.y + handle.topLeft.size.y; vRight _ handle.bottomRight.size.y + handle.right.size.y + handle.topRight.size.y; hBottom _ handle.bottomLeft.size.x + handle.bottom.size.x + handle.bottomRight.size.x; hTop _ handle.topLeft.size.x + handle.top.size.x + handle.topRight.size.x; handle.size.y _ MAX[vLeft, vMiddle, vRight]; handle.size.x _ MAX[hBottom, hMiddle, hTop]}; DoCorners: PROC [handle: CabbagePrivate.Handle] ~ { handle.bottomLeft.origin _ [0, 0]; handle.bottomRight.origin _ [handle.size.x - handle.bottomRight.size.x, 0]; handle.topRight.origin _ [handle.size.x - handle.topRight.size.x, handle.size.y - handle.topRight.size.y]; handle.topLeft.origin _ [0, handle.size.y - handle.topLeft.size.y]}; DoRoutingAreas: PROC [handle: CabbagePrivate.Handle] ~ { outerChanWidth: INT _ handle.parms.outerChanWidth; powerWidth: INT _ outerChanWidth + handle.parms.powerCellWidth; routeType: CabbagePrivate.RouteType _ handle.routeType; leftInterior: INT _ handle.left.origin.x + handle.left.size.x; -- right of left pads rightInterior: INT _ handle.right.origin.x; -- left of right pads bottomInterior: INT _ handle.bottom.origin.y + handle.bottom.size.y; -- top of bottom pads topInterior: INT _ handle.top.origin.y; -- bottom of top pads leftOfInner: INT _ handle.inner.origin.x; -- left of inner object rightOfInner: INT _ handle.inner.origin.x + handle.inner.size.x; -- right of inner object bottomOfInner: INT _ handle.inner.origin.y; -- bottom of inner object topOfInner: INT _ handle.inner.origin.y + handle.inner.size.y; -- top of inner object IF routeType = normal THEN { handle.detailedRouting.channels[bottom].origin _ [leftOfInner, bottomOfInner - handle.detailedRouting.channels[bottom].size.y]; handle.detailedRouting.channels[right].origin _ [rightOfInner, bottomOfInner]; handle.detailedRouting.channels[top].origin _ [leftOfInner, topOfInner]; handle.detailedRouting.channels[left].origin _ [leftOfInner - handle.detailedRouting.channels[left].size.x, bottomOfInner]; handle.detailedRouting.switchBoxes[bottomLeft].origin _ [leftInterior + powerWidth, bottomInterior + powerWidth]; handle.detailedRouting.switchBoxes[bottomRight].origin _ [rightOfInner, bottomInterior + powerWidth]; handle.detailedRouting.switchBoxes[topRight].origin _ [rightOfInner, topOfInner]; handle.detailedRouting.switchBoxes[topLeft].origin _ [leftInterior + powerWidth, topOfInner]} ELSE { -- routeType = padLimited handle.detailedRoutingPL.channels[right].origin _ [rightOfInner, bottomOfInner]; handle.detailedRoutingPL.channels[left].origin _ [leftOfInner - handle.detailedRoutingPL.channels[left].size.x, bottomOfInner]; handle.detailedRoutingPL.switchBoxes[bottom].origin _ [leftInterior + powerWidth, bottomInterior + powerWidth]; handle.detailedRoutingPL.switchBoxes[top].origin _ [leftInterior + powerWidth, topOfInner]}; handle.powerDistribution.channels[bottom].origin _ [leftInterior + powerWidth, bottomInterior]; handle.powerDistribution.channels[right].origin _ [rightInterior - outerChanWidth, bottomInterior + powerWidth]; handle.powerDistribution.channels[top].origin _ [leftInterior + powerWidth, topInterior - outerChanWidth]; handle.powerDistribution.channels[left].origin _ [leftInterior, bottomInterior + powerWidth]; handle.powerDistribution.power[bottom].origin _ [leftInterior + powerWidth, bottomInterior + outerChanWidth]; handle.powerDistribution.power[right].origin _ [rightInterior - powerWidth, bottomInterior + powerWidth]; handle.powerDistribution.power[top].origin _ [leftInterior + powerWidth, topInterior - powerWidth]; handle.powerDistribution.power[left] .origin_ [leftInterior + outerChanWidth, bottomInterior + powerWidth]; handle.powerDistribution.switchBoxes[bottomLeft].origin _ [leftInterior, bottomInterior]; handle.powerDistribution.switchBoxes[bottomRight].origin _ [rightInterior - powerWidth, bottomInterior]; handle.powerDistribution.switchBoxes[topRight].origin _ [rightInterior - powerWidth, topInterior - powerWidth]; handle.powerDistribution.switchBoxes[topLeft].origin _ [leftInterior, topInterior - powerWidth]}; IncludePin: PROC [object: CD.Object, name: Rope.ROPE, denotes: CD.Rect, layer: CD.Layer] ~ { pin: CD.Object _ CDSymbolicObjects.CreatePin[CDBasics.SizeOfRect[denotes]]; pinInstance: CD.Instance _ RouteUtil.Include[cell: object, ob: pin, position: CDBasics.BaseOfRect[denotes], orientation: original]; CDProperties.PutInstanceProp[pinInstance, cabbageXPos, NEW[INT _ denotes.x1]]; CDProperties.PutInstanceProp[pinInstance, cabbageYPos, NEW[INT _ denotes.y1]]; CDSymbolicObjects.SetName[pinInstance, name]; CDSymbolicObjects.SetLayer[pinInstance, layer]}; Member: PROC [item: Rope.ROPE, list: LIST OF Rope.ROPE] RETURNS [BOOLEAN] ~ { UNTIL list = NIL DO IF Rope.Equal[list.first, item] THEN RETURN [TRUE]; list _ list.rest; ENDLOOP; RETURN [FALSE]}; EqualProc: PROC [k1, k2: HashTable.Key] RETURNS [eq: BOOL] = { p1: Route.Position _ NARROW[k1, REF Route.Position]^; p2: Route.Position _ NARROW[k2, REF Route.Position]^; eq _ p1.x = p2.x AND p1.y = p2.y}; HashProc: PROC [k: HashTable.Key] RETURNS [hash: CARDINAL] = { size: Route.Position _ NARROW[k, REF Route.Position]^; hash _ size.x + size.y}; BitTable: TYPE = REF BitTableRec; BitTableRec: TYPE = RECORD[ bitSize: NAT _ 8, -- CD.Number per lambdas min, max: INT _ 0, -- outerRange bits: PACKED SEQUENCE size: NAT OF BOOL]; -- TRUE=busy Translate: PROC [obstacles: BitTable, pos: INT] RETURNS [bitIndex: NAT] ~ INLINE { bitIndex _ (pos-obstacles.min)/obstacles.bitSize; IF bitIndex NOT IN [0..obstacles.size) THEN ERROR}; CreateBitTable: PROC [min, max: INT, bitSize: NAT] RETURNS [bitTable: BitTable] ~ { size: NAT _ (max/bitSize)-(min/bitSize)+1; bitTable _ NEW[BitTableRec[size]]; bitTable.bitSize _ bitSize; bitTable.min _ min; bitTable.max _ max; FOR i: NAT IN [0..size) DO bitTable[i] _ FALSE; ENDLOOP}; PositionOccupied: PROC [obstacles: BitTable, pos: INT] RETURNS [BOOL] ~ INLINE { RETURN[obstacles[Translate[obstacles, pos]]]}; NextPos: PROC [obstacles: BitTable, from: INT, goingUp: BOOL] RETURNS [next: INT] ~ INLINE { next _ IF goingUp THEN from+1 ELSE from-1}; Edge: PROC [obstacles: BitTable, goingUp: BOOL] RETURNS [pos: INT] ~ INLINE { pos _ IF goingUp THEN obstacles.max ELSE obstacles.min}; SetOccupied: PROC [obstacles: BitTable, pos: INT] ~ INLINE { IF pos NOT IN [obstacles.min..obstacles.max] THEN RETURN; obstacles[Translate[obstacles, pos]] _ TRUE}; Insert: PROC [obstacles: BitTable, range: Connections.Range, spacing: INT] ~ { FOR pos: INT IN [range.min-spacing..range.max+spacing] DO SetOccupied[obstacles, pos]; ENDLOOP}; IsFree: PROC [range: Connections.Range, obstacles: BitTable, goingUp: BOOL] RETURNS [isFree: BOOL, nextTry: INT] ~ { FOR pos: INT IN [range.min..range.max] DO IF PositionOccupied[obstacles, pos] THEN RETURN[FALSE, FindNextFree[obstacles, pos, goingUp]]; ENDLOOP; RETURN[TRUE, range.min]}; FindNextFree: PROC [obstacles: BitTable, from: INT, goingUp: BOOL] RETURNS [free: INT] ~ { free _ from; WHILE PositionOccupied[obstacles, free] AND free#Edge[obstacles, goingUp] DO free _ NextPos[obstacles, free, goingUp]; ENDLOOP}; FindLowerRange: PROC [adjustedRange: Connections.Range, obstacles: BitTable] RETURNS [newRange: Connections.Range] ~ { isFree: BOOL _ FALSE; nextTry: INT; newRange _ adjustedRange; WHILE ~isFree DO [isFree, nextTry] _ IsFree[newRange, obstacles, TRUE]; IF nextTry>=obstacles.max THEN Cabbage.Signal[noResource, "No space for pin on power bus side."]; newRange _ [nextTry + obstacles.bitSize, nextTry + obstacles.bitSize + (adjustedRange.max-adjustedRange.min)]; -- noop if isFree ENDLOOP}; FindUpperRange: PROC [adjustedRange: Connections.Range, obstacles: BitTable] RETURNS [newRange: Connections.Range] ~ { isFree: BOOL _ FALSE; nextTry: INT; newRange _ adjustedRange; WHILE ~isFree DO [isFree, nextTry] _ IsFree[newRange, obstacles, FALSE]; IF nextTry<=obstacles.min THEN Cabbage.Signal[noResource, "No space for pin on power bus side."]; newRange _ [nextTry - obstacles.bitSize - (adjustedRange.max-adjustedRange.min), nextTry - obstacles.bitSize]; -- noop if isFree ENDLOOP}; FindMiddleRange: PROC [adjustedRange: Connections.Range, obstacles: BitTable] RETURNS [newRange: Connections.Range] ~ { IF IsFree[adjustedRange, obstacles, FALSE].isFree THEN RETURN[adjustedRange] ELSE { fellOffLower, fellOffUpper: BOOL _ FALSE; lower, upper: Connections.Range; -- CEDAR Bug! Signals in initialization upper _ FindLowerRange[adjustedRange, obstacles ! Cabbage.Signal => IF errorType=noResource THEN {fellOffUpper _ TRUE; CONTINUE}]; lower _ FindUpperRange[adjustedRange, obstacles ! Cabbage.Signal => IF errorType=noResource THEN {fellOffLower _ TRUE; CONTINUE}]; IF fellOffUpper AND fellOffLower THEN Cabbage.Signal[noResource, "No space for pin on power bus side."]; IF fellOffUpper THEN RETURN[lower]; IF fellOffLower THEN RETURN[upper]; IF adjustedRange.min-lower.min