<<>> <> <> <> <> <<>> <> <> DIRECTORY Basics, Cabbage, CabbagePrivate, CD, CDBasics, CDCells, CDOps, CDSimpleRules, CDSymbolicObjects, Connections, Convert, Core, CoreGeometry, CoreOps, HashTable, List, PW, PWPins, PWRoute, Rope, Route, RouteUtil, RTBasic, Sinix, SinixOps, TerminalIO; CabbageProcsImpl: CEDAR PROGRAM IMPORTS Basics, Cabbage, CD, CDBasics, CDCells, CDOps, CDSimpleRules, CDSymbolicObjects, Connections, Convert, CoreGeometry, CoreOps, HashTable, List, PW, PWPins, PWRoute, Rope, Route, RouteUtil, RTBasic, Sinix, SinixOps, TerminalIO EXPORTS CabbagePrivate SHARES Route = BEGIN <> 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.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]; 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: NIL, 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: NIL, 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]}; 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.orgin _ [handle.bottomLeft.size.x + (handle.size.x - hBottom)/2, 0]; handle.right.orgin _ [handle.size.x - handle.right.size.x, handle.bottomRight.size.y + (handle.size.y - vRight)/2]; handle.top.orgin _ [handle.topLeft.size.x + (handle.size.x - hTop)/2, handle.size.y - handle.top.size.y]; handle.left.orgin _ [0, handle.bottomLeft.size.y + (handle.size.y - vLeft)/2]; DoCorners[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 ~ { IF segment.object # handle.inner.object OR UseSegment[handle, segment, net] THEN newNet.width _ MAX[newNet.width, segment.range.max - segment.range.min] ELSE TerminalIO.PutRope[Rope.Cat[Rope.Cat["Segment ignored on net: ", net.name, ", side: ", RTBasic.sideName[RTBasic.OtherSide[segment.side]], ", range: ["], Rope.Cat[Convert.RopeFromInt[segment.range.min], ", ", Convert.RopeFromInt[segment.range.max], "]\n"]]]}; 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.orgin.y + handle.bottom.size.y; upperY: INT _ handle.top.orgin.y - handle.inner.size.y; lowerX: INT _ handle.left.orgin.x + handle.left.size.x; upperX: INT _ handle.right.orgin.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.orgin _ actualInnerPos}; <> 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]}}; IF handle.connections # NIL THEN InitWires[handle]; AdjustPositions[handle]; [] _ Connections.EnumerateNets[handle.connections, EachNet]}; <> SortSegments: PROC [handle: CabbagePrivate.Handle, net: Connections.Net] RETURNS [sortedSegments: CabbagePrivate.SegmentSeq _ NIL] ~ { CountSegments: Connections.EachSegmentAction ~ { IF UseSegment[handle, segment, net] THEN numSegments _ numSegments + 1}; PinCompare: List.CompareProc ~ { pos1, pos2: INT; TRUSTED{ pos1 _ PosOf[handle, net, LOOPHOLE[ref1]]; pos2 _ PosOf[handle, net, 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]}; IF UseSegment[handle, segment, net] THEN { 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, net, startSeg] + PosOf[handle, net, endSeg]} ELSE { endSeg _ sortedSegments[index]; startSeg _ sortedSegments[0]; length _ PosOf[handle, net, endSeg] - PosOf[handle, net, 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, net, segmentPair.seg1]; pos2: INT _ PosOf[handle, net, 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.orgin.x, handle.inner.orgin.x + handle.inner.size.x]; vertRange: Connections.Range _ [handle.inner.orgin.y, handle.inner.orgin.y + handle.inner.size.y]; IF handle.routeType = normal THEN { handle.detailedRouting.channels[bottom] _ RouteChannel[handle, handle.bottom, handle.inner, bottom, bottomLeft, bottomRight, horizRange, horizParms]; handle.detailedRouting.channels[right] _ RouteChannel[handle, handle.inner, handle.right, right, rightBottom, rightTop, vertRange, vertParms]; handle.detailedRouting.channels[top] _ RouteChannel[handle, handle.inner, handle.top, top, topLeft, topRight, horizRange, horizParms]; handle.detailedRouting.channels[left] _ RouteChannel[handle, handle.left, handle.inner, left, leftBottom, leftTop, vertRange, vertParms]} ELSE { -- routeType = padLimited handle.detailedRoutingPL.channels[right] _ RouteChannel[handle, handle.inner, handle.right, right, rightBottom, rightTop, vertRange, vertParms]; handle.detailedRoutingPL.channels[left] _ RouteChannel[handle, handle.left, handle.inner, left, leftBottom, leftTop, vertRange, vertParms]}}; <> RouteChannel: PROC [handle: CabbagePrivate.Handle, llObject, urObject: CabbagePrivate.ObjectDescription, side: Route.Side, llDiv, urDiv: CabbagePrivate.Division, range: Connections.Range, parms: CabbagePrivate.ParmSet] RETURNS [channel: CabbagePrivate.Channel] ~ { result: Route.RoutingResult; retrieveRect: Route.RefRect; rect: CD.Rect; llSide, blSide: Route.Side; isX: BOOLEAN; dist, size, offset: INT; obj1, obj2, bottomOrLeftObj, topOrRightObj: Cabbage.Object; SELECT side FROM bottom => {isX _ FALSE; llSide _ top; blSide _ left}; right => {isX _ TRUE; llSide _ right; blSide _ bottom}; top => {isX _ FALSE; llSide _ top; blSide _ left}; left => {isX _ TRUE; llSide _ right; blSide _ bottom}; ENDCASE; obj1 _ BuildObject[handle, llObject, llSide, range, parms.rules, NIL]; obj2 _ BuildObject[handle, urObject, RTBasic.OtherSide[llSide], range, parms.rules, NIL]; bottomOrLeftObj _ BuildEnd[handle, llDiv, blSide, parms.rules]; topOrRightObj _ BuildEnd[handle, urDiv, RTBasic.OtherSide[blSide], parms.rules]; parms.parms.wireWidthProc _ GetWireWidth; parms.parms.context _ handle.widthTable; result _ PWRoute.DoRoute[obj1, obj2, bottomOrLeftObj, topOrRightObj, parms.parms, isX, channel]; rect _ result.routingRect; offset _ result.routingArea.rules.trunkToTrunk; SELECT side FROM bottom => { size _ urObject.orgin.y - (llObject.orgin.y + llObject.size.y); dist _ MIN[rect.y1, rect.y2 - size + offset]; retrieveRect _ NEW[CD.Rect _ [rect.x1, dist, rect.x2, rect.y2 + offset]]}; right => { size _ urObject.orgin.x - (llObject.orgin.x + llObject.size.x); dist _ MAX[rect.x2, size - offset]; retrieveRect _ NEW[CD.Rect _ [rect.x1 - offset, rect.y1, dist, rect.y2]]}; top => { size _ urObject.orgin.y - (llObject.orgin.y + llObject.size.y); dist _ MAX[rect.y2, size - offset]; retrieveRect _ NEW[CD.Rect _ [rect.x1, rect.y1 - offset, rect.x2, dist]]}; left => { size _ urObject.orgin.x - (llObject.orgin.x + llObject.size.x); dist _ MIN[rect.x1, rect.x2 - size + offset]; retrieveRect _ NEW[CD.Rect _ [dist, rect.y1, rect.x2 + offset, rect.y2]]}; ENDCASE; channel.object _ PWRoute.GetRouting[result, retrieveRect, parms.parms]; channel.size _ RTBasic.IRSize[channel.object]; channel.shell _ BuildChannelShell[handle, channel, parms]}; BuildObject: PROC [handle: CabbagePrivate.Handle, objectDes: CabbagePrivate.ObjectDescription, side: Route.Side, range: Connections.Range, rules: Route.DesignRules, opposingCell: Cabbage.Object] RETURNS [shell: Cabbage.Object _ CDCells.CreateEmptyCell[]] ~ { <> <> EachNet: Connections.EachNetAction ~ { EachSegment: Connections.EachSegmentAction ~ { IF (segment.object = objectDes.object AND segment.side = side) THEN { orgin: INT _ SELECT side FROM bottom, top => objectDes.orgin.x, right, left => objectDes.orgin.y, ENDCASE => Cabbage.Error[programmingError, "Not suppose to happen."]; adjustedRange: Connections.Range _ [orgin + segment.range.min, orgin + segment.range.max]; useThisOuter: BOOLEAN _ segment.object # handle.inner.object AND UseSegment[handle, segment, net] AND ~OverlapsOnOpposing[handle, opposingCell, adjustedRange, RTBasic.OtherSide[side], net.name]; IF useThisOuter AND CrossesBoundry[adjustedRange, range] THEN Cabbage.Signal[callingError, Rope.Cat["Segment on net: ", net.name, " crosses a seam between routing areas"]]; IF (useThisOuter OR objectDes.object = handle.inner.object) AND ProperSubset[adjustedRange, range] 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; [] _ Connections.EnumerateNets[handle.connections, EachNet]; SELECT side FROM bottom, top => interestRect _ [range.min, oldIR.y1, range.max, oldIR.y2]; left, right => interestRect _ [oldIR.x1, range.min, oldIR.x2, range.max]; ENDCASE; CDCells.SetInterestRect[design: NIL, cell: shell, r: interestRect]; RTBasic.RepositionCell[shell]}; BuildEnd: PROC [handle: CabbagePrivate.Handle, division: CabbagePrivate.Division, side: Route.Side, rules: Route.DesignRules] RETURNS [shell: Cabbage.Object _ CDCells.CreateEmptyCell[]] ~ { <> EachExit: EachExitAction ~ { 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]}; BuildChannelShell: PROC [handle: CabbagePrivate.Handle, channel: CabbagePrivate.Channel, parms: CabbagePrivate.ParmSet] RETURNS [shell: Cabbage.Object _ CDCells.CreateEmptyCell[]] ~ { <> ChanPublics: CoreGeometry.EachWirePinProc ~ { <> <> name: Rope.ROPE _ CoreOps.GetShortWireName[wire]; SELECT side FROM bottom => IncludePin[object: shell, name: name, denotes: [rect.x1+min, rect.y1, rect.x1+max, rect.y1+depth], layer: layer]; right => IncludePin[object: shell, name: name, denotes: [rect.x2-depth, rect.y1+min, rect.x2, rect.y1+max], layer: layer]; top => IncludePin[object: shell, name: name, denotes: [rect.x1+min, rect.y2-depth, rect.x1+max, rect.y2], layer: layer]; left => 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[parms.rules.technology]; cellType: Core.CellType _ NARROW [Sinix.Extract[channel.object, mode].result]; depth: Route.Number _ parms.rules.trunkWidth; rect: CD.Rect _ CD.InterestRect[channel.object]; [] _ CoreGeometry.EnumerateNonOverlappingSides[mode.decoration, cellType, ChanPublics]; CDCells.SetInterestRect[design: NIL, cell: shell, r: rect]; RTBasic.RepositionCell[shell]}; <> AdjustPositions: PROC [handle: CabbagePrivate.Handle] ~ { <> routeType: CabbagePrivate.RouteType _ handle.routeType; sizeBottomArea: INT _ handle.inner.orgin.y - (handle.bottom.orgin.y + handle.bottom.size.y); sizeBottomRouting: INT _ IF handle.routeType = normal THEN handle.detailedRouting.channels[bottom].size.y ELSE handle.detailedRoutingPL.switchBoxes[bottom].size.y; adjBottom: INT _ sizeBottomRouting - sizeBottomArea; sizeLeftArea: INT _ handle.inner.orgin.x - (handle.left.orgin.x + handle.left.size.x); sizeLeftRouting: INT _ IF handle.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.orgin _ CDBasics.AddPoints[handle.inner.orgin, [MAX[0, adjLeft], MAX[0, adjBottom]]]; handle.bottom.orgin _ CDBasics.AddPoints[handle.bottom.orgin, [MAX[0, adjLeft], 0]]; handle.right.orgin _ CDBasics.AddPoints[handle.right.orgin, [MAX[0, adjLeft], MAX[0, adjBottom]]]; handle.top.orgin _ CDBasics.AddPoints[handle.top.orgin, [MAX[0, adjLeft], MAX[0, adjBottom]]]; handle.left.orgin _ CDBasics.AddPoints[handle.left.orgin, [0, MAX[0, adjBottom]]]; sizeTopArea _ handle.top.orgin.y - (handle.inner.orgin.y + handle.inner.size.y); sizeTopRouting _ IF handle.routeType = normal THEN handle.detailedRouting.channels[top].size.y ELSE handle.detailedRoutingPL.switchBoxes[top].size.y; adjTop _ sizeTopRouting - sizeTopArea; sizeRightArea _ handle.right.orgin.x - (handle.inner.orgin.x + handle.inner.size.x); sizeRightRouting _ IF handle.routeType = normal THEN handle.detailedRouting.channels[right].size.x ELSE handle.detailedRoutingPL.channels[right].size.x; adjRight _ sizeRightRouting - sizeRightArea; handle.top.orgin _ CDBasics.AddPoints[handle.top.orgin, [0, MAX[0, adjTop]]]; handle.right.orgin _ CDBasics.AddPoints[handle.right.orgin, [MAX[0, adjRight], 0]]; [] _ GetSize[handle]; DoCorners[handle]; IF handle.routeType = normal THEN { handle.detailedRouting.channels[bottom].orgin _ [handle.inner.orgin.x, handle.inner.orgin.y - handle.detailedRouting.channels[bottom].size.y]; handle.detailedRouting.channels[right].orgin _ [handle.inner.orgin.x + handle.inner.size.x, handle.inner.orgin.y]; handle.detailedRouting.channels[top].orgin _ [handle.inner.orgin.x, handle.inner.orgin.y + handle.inner.size.y]; handle.detailedRouting.channels[left].orgin _ [handle.inner.orgin.x - handle.detailedRouting.channels[left].size.x, handle.inner.orgin.y]; handle.detailedRouting.switchBoxes[bottomLeft].orgin _ [handle.left.orgin.x + handle.left.size.x, handle.bottom.orgin.y + handle.bottom.size.y]; handle.detailedRouting.switchBoxes[bottomRight].orgin _ [handle.inner.orgin.x + handle.inner.size.x, handle.bottom.orgin.y + handle.bottom.size.y]; handle.detailedRouting.switchBoxes[topRight].orgin _ [handle.inner.orgin.x + handle.inner.size.x, handle.inner.orgin.y + handle.inner.size.y]; handle.detailedRouting.switchBoxes[topLeft].orgin _ [handle.left.orgin.x + handle.left.size.x, handle.inner.orgin.y + handle.inner.size.y]} ELSE { -- routeType = padLimited handle.detailedRoutingPL.channels[right].orgin _ [handle.inner.orgin.x + handle.inner.size.x, handle.inner.orgin.y]; handle.detailedRoutingPL.channels[left].orgin _ [handle.inner.orgin.x - handle.detailedRoutingPL.channels[left].size.x, handle.inner.orgin.y]; handle.detailedRoutingPL.switchBoxes[bottom].orgin _ [handle.left.orgin.x + handle.left.size.x, handle.bottom.orgin.y + handle.bottom.size.y]; handle.detailedRoutingPL.switchBoxes[top].orgin _ [handle.left.orgin.x + handle.left.size.x, handle.inner.orgin.y + handle.inner.size.y]}; }; <> RouteSwitchBoxes: PROC [handle: CabbagePrivate.Handle] ~ { horizParms: CabbagePrivate.ParmSet _ handle.rules.horizParms; leftHorizRange: Connections.Range _ [handle.left.orgin.x + handle.left.size.x, handle.inner.orgin.x]; rightHorizRange: Connections.Range _ [handle.inner.orgin.x + handle.inner.size.x, handle.right.orgin.x]; bottomVertRange: Connections.Range _ [handle.bottom.orgin.y + handle.bottom.size.y, handle.inner.orgin.y]; topVertRange: Connections.Range _ [handle.inner.orgin.y + handle.inner.size.y, handle.top.orgin.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; horizRange: Connections.Range _ [handle.left.orgin.x + handle.left.size.x, handle.right.orgin.x]; bottomVertRange: Connections.Range _ [handle.bottom.orgin.y + handle.bottom.size.y, handle.inner.orgin.y]; topVertRange: Connections.Range _ [handle.inner.orgin.y + handle.inner.size.y, handle.top.orgin.y]; 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}; GetWireWidth: PWRoute.WireWidthProc ~ { <> table: Connections.Table _ NARROW[context]; net: Connections.Net _ Connections.Fetch[table, netName].net; wireWidth _ net.width}; RouteSwitchBoxPL: PROC [handle: CabbagePrivate.Handle, side: RTBasic.TBSide, horizRange, vertRange: Connections.Range, parms: CabbagePrivate.ParmSet] RETURNS [switchBox: CabbagePrivate.SwitchBox] ~ { bottomObject, topObject: Cabbage.Object; leftObject: Cabbage.Object _ BuildObject[handle, handle.left, right, vertRange, parms.rules, NIL]; rightObject: Cabbage.Object _ BuildObject[handle, handle.right, left, vertRange, parms.rules, NIL]; innerRange: Connections.Range _ [handle.inner.orgin.x, handle.inner.orgin.x + handle.inner.size.x]; SELECT side FROM bottom => { innerObject: Cabbage.Object _ BuildObject[handle, handle.inner, bottom, innerRange, parms.rules, NIL]; topObject _ PW.AbutListX[LIST[handle.detailedRoutingPL.channels[left].shell, innerObject, handle.detailedRoutingPL.channels[right].shell]]; bottomObject _ BuildObject[handle, handle.bottom, top, horizRange, parms.rules, topObject]}; top => { innerObject: Cabbage.Object _ BuildObject[handle, handle.inner, top, innerRange, parms.rules, NIL]; bottomObject _ PW.AbutListX[LIST[handle.detailedRoutingPL.channels[left].shell, innerObject, handle.detailedRoutingPL.channels[right].shell]]; topObject _ BuildObject[handle, handle.top, bottom, horizRange, parms.rules, bottomObject]}; 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]}; RouteSwitchBox: PROC [handle: CabbagePrivate.Handle, corner: CabbagePrivate.Corners, horizRange, vertRange: Connections.Range, parms: CabbagePrivate.ParmSet] RETURNS [switchBox: CabbagePrivate.SwitchBox] ~ { bottomObject, topObject, leftObject, rightObject: Cabbage.Object; SELECT corner FROM bottomLeft => { topObject _ handle.detailedRouting.channels[left].shell; bottomObject _ BuildObject[handle, handle.bottom, top, horizRange, parms.rules, topObject]; leftObject _ BuildObject[handle, handle.left, right, vertRange, parms.rules, NIL]; rightObject _ handle.detailedRouting.channels[bottom].shell}; bottomRight => { topObject _ handle.detailedRouting.channels[right].shell; bottomObject _ BuildObject[handle, handle.bottom, top, horizRange, parms.rules, topObject]; rightObject _ BuildObject[handle, handle.right, left, vertRange, parms.rules, NIL]; leftObject _ handle.detailedRouting.channels[bottom].shell}; topRight => { bottomObject _ handle.detailedRouting.channels[right].shell; topObject _ BuildObject[handle, handle.top, bottom, horizRange, parms.rules, bottomObject]; rightObject _ BuildObject[handle, handle.right, left, vertRange, parms.rules, NIL]; leftObject _ handle.detailedRouting.channels[top].shell}; topLeft => { bottomObject _ handle.detailedRouting.channels[left].shell; topObject _ BuildObject[handle, handle.top, bottom, horizRange, parms.rules, bottomObject]; leftObject _ BuildObject[handle, handle.left, right, vertRange, parms.rules, NIL]; rightObject _ handle.detailedRouting.channels[top].shell}; 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]}; <> MakeChip: PUBLIC PROC [handle: CabbagePrivate.Handle] RETURNS [chip: Cabbage.Object] ~ { chip _ CDCells.CreateEmptyCell[]; IncludeObject[handle.inner.object, handle.inner.orgin, chip]; IncludeObject[handle.bottomLeft.object, handle.bottomLeft.orgin, chip]; IncludeObject[handle.bottom.object, handle.bottom.orgin, chip]; IncludeObject[handle.bottomRight.object, handle.bottomRight.orgin, chip]; IncludeObject[handle.right.object, handle.right.orgin, chip]; IncludeObject[handle.topRight.object, handle.topRight.orgin, chip]; IncludeObject[handle.top.object, handle.top.orgin, chip]; IncludeObject[handle.topLeft.object, handle.topLeft.orgin, chip]; IncludeObject[handle.left.object, handle.left.orgin, chip]; IF handle.routeType = normal THEN { IncludeObject[handle.detailedRouting.channels[bottom].object, handle.detailedRouting.channels[bottom].orgin, chip]; IncludeObject[handle.detailedRouting.channels[right].object, handle.detailedRouting.channels[right].orgin, chip]; IncludeObject[handle.detailedRouting.channels[top].object, handle.detailedRouting.channels[top].orgin, chip]; IncludeObject[handle.detailedRouting.channels[left].object, handle.detailedRouting.channels[left].orgin, chip]; IncludeObject[handle.detailedRouting.switchBoxes[bottomLeft].object, handle.detailedRouting.switchBoxes[bottomLeft].orgin, chip]; IncludeObject[handle.detailedRouting.switchBoxes[bottomRight].object, handle.detailedRouting.switchBoxes[bottomRight].orgin, chip]; IncludeObject[handle.detailedRouting.switchBoxes[topRight].object, handle.detailedRouting.switchBoxes[topRight].orgin, chip]; IncludeObject[handle.detailedRouting.switchBoxes[topLeft].object, handle.detailedRouting.switchBoxes[topLeft].orgin, chip]} ELSE { IncludeObject[handle.detailedRoutingPL.channels[right].object, handle.detailedRoutingPL.channels[right].orgin, chip]; IncludeObject[handle.detailedRoutingPL.channels[left].object, handle.detailedRoutingPL.channels[left].orgin, chip]; IncludeObject[handle.detailedRoutingPL.switchBoxes[bottom].object, handle.detailedRoutingPL.switchBoxes[bottom].orgin, chip]; IncludeObject[handle.detailedRoutingPL.switchBoxes[top].object, handle.detailedRoutingPL.switchBoxes[top].orgin, chip]}; [] _ RTBasic.RepositionCell[chip]; }; IncludeObject: PROC [object: Cabbage.Object, orgin: CD.Position, chip: Cabbage.Object] ~ { IF object # NIL THEN [] _ RouteUtil.Include[cell: chip, ob: object, position: CDOps.FitObjectI[ob: object, location: orgin, orientation: original].off, orientation: original]}; <> <> PosOf: PROC [handle: CabbagePrivate.Handle, net: Connections.Net, segment: Connections.Segment] RETURNS [INT] ~ { RETURN[MiddleOfRange[RangeOf[handle, net, segment]]]}; <> RangeOf: PROC [handle: CabbagePrivate.Handle, net: Connections.Net, segment: Connections.Segment] RETURNS [range: Connections.Range] ~ { SELECT TRUE FROM segment.object = handle.inner.object => range _ InnerRange[handle, net, segment]; segment.object = handle.bottom.object => range _ OuterRange[handle, net, segment, bottom]; segment.object = handle.right.object => range _ OuterRange[handle, net, segment, right]; segment.object = handle.top.object => range _ OuterRange[handle, net, segment, top]; segment.object = handle.left.object => range _ OuterRange[handle, net, segment, left]; ENDCASE => Cabbage.Signal[callingError, Rope.Cat["Invalid object in net: ", net.name]]}; <> MiddleOfRange: PROC [range: Connections.Range] RETURNS [INT] ~ { RETURN[(range.min+range.max)/2]}; InnerRange: PROC [handle: CabbagePrivate.Handle, net: Connections.Net, segment: Connections.Segment] RETURNS [range: Connections.Range] ~ { orgin: INT; SELECT segment.side FROM bottom => {orgin _ handle.inner.orgin.x; range _ [orgin + segment.range.min, orgin + segment.range.max]}; right => {orgin _ handle.size.x + handle.inner.orgin.y; range _ [orgin + segment.range.min, orgin + segment.range.max]}; top => {orgin _ handle.size.x +handle.size.y + (handle.size.x - handle.inner.orgin.x); range _ [orgin - segment.range.max, orgin - segment.range.min]}; left => {orgin _ 2*handle.size.x +handle.size.y + (handle.size.y - handle.inner.orgin.y); range _ [orgin - segment.range.max, orgin - segment.range.min]}; ENDCASE}; OuterRange: PROC [handle: CabbagePrivate.Handle, net: Connections.Net, segment: Connections.Segment, side: Route.Side] RETURNS [range: Connections.Range] ~ { orgin: INT; IF segment.side # RTBasic.OtherSide[side] THEN Cabbage.Signal[callingError, Rope.Cat["Invalid side in net: ", net.name]]; SELECT side FROM bottom => {orgin _ handle.bottom.orgin.x; range _ [orgin + segment.range.min, orgin + segment.range.max]}; right => {orgin _ handle.size.x + handle.right.orgin.y; range _ [orgin + segment.range.min, orgin + segment.range.max]}; top => {orgin _ handle.size.x +handle.size.y + (handle.size.x - handle.top.orgin.x); range _ [orgin - segment.range.max, orgin - segment.range.min]}; left => {orgin _ 2*handle.size.x +handle.size.y + (handle.size.y - handle.left.orgin.y); range _ [orgin - segment.range.max, orgin - segment.range.min]}; ENDCASE}; PosOfDivision: PROC [handle: CabbagePrivate.Handle, division: CabbagePrivate.Division] RETURNS [pos: INT] ~ { SELECT division FROM bottomLeft => pos _ handle.inner.orgin.x; bottomRight => pos _ handle.inner.orgin.x + handle.inner.size.x; rightBottom => pos _ handle.size.x + handle.inner.orgin.y; rightTop => pos _ handle.size.x + handle.inner.orgin.y + handle.inner.size.y; topRight => pos _ handle.size.x +handle.size.y + (handle.size.x - handle.inner.orgin.x - handle.inner.size.x); topLeft => pos _ handle.size.x +handle.size.y + (handle.size.x - handle.inner.orgin.x); leftTop => pos _ 2*handle.size.x +handle.size.y + (handle.size.y - handle.inner.orgin.y - handle.inner.size.y); leftBottom => pos _ 2*handle.size.x +handle.size.y + (handle.size.y - handle.inner.orgin.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; IF handle.routeType = normal THEN { vMiddle _ handle.bottom.size.y + handle.detailedRouting.channels[bottom].size.y + handle.inner.size.y + handle.detailedRouting.channels[top].size.y + handle.top.size.y; hMiddle _ handle.left.size.x + handle.detailedRouting.channels[left].size.x + handle.inner.size.x + handle.detailedRouting.channels[right].size.x + handle.right.size.x} ELSE { hCenter: INT _ handle.detailedRoutingPL.channels[left].size.x + handle.inner.size.x + handle.detailedRoutingPL.channels[right].size.x; hInner: INT _ MAX[hCenter, handle.detailedRoutingPL.switchBoxes[top].size.x, handle.detailedRoutingPL.switchBoxes[bottom].size.x]; vMiddle _ handle.bottom.size.y + handle.detailedRoutingPL.switchBoxes[bottom].size.y + handle.inner.size.y + handle.detailedRoutingPL.switchBoxes[top].size.y + 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.orgin _ [0, 0]; handle.bottomRight.orgin _ [handle.size.x - handle.bottomRight.size.x, 0]; handle.topRight.orgin _ [handle.size.x - handle.topRight.size.x, handle.size.y - handle.topRight.size.y]; handle.topLeft.orgin _ [0, handle.size.y - handle.topLeft.size.y]}; 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]; CDSymbolicObjects.SetName[pinInstance, name]; CDSymbolicObjects.SetLayer[pinInstance, layer]}; UseSegment: PROC [handle: CabbagePrivate.Handle, segment: Connections.Segment, net: Connections.Net] RETURNS [useIt: BOOLEAN _ TRUE] ~ { IF net = handle.vddNet AND segment.object # handle.inner.object AND SegsOverlap[handle, segment, net, handle.gndNet] THEN useIt _ FALSE ELSE IF net = handle.gndNet AND segment.object # handle.inner.object AND SegsOverlap[handle, segment, net, handle.vddNet] THEN useIt _ FALSE}; SegsOverlap: PROC [handle: CabbagePrivate.Handle, testSegment: Connections.Segment, testNet, net: Connections.Net] RETURNS [overlaps: BOOLEAN] ~ { <> EachSegment: Connections.EachSegmentAction ~ { IF Overlaps[expandedRange, RangeOf[handle, net, segment]] THEN quit _ TRUE}; testRange: Connections.Range _ RangeOf[handle, testNet, testSegment]; spacing: INT _ IF testSegment.side = top OR testSegment.side = bottom THEN handle.rules.vertParms.rules.branchToBranch ELSE handle.rules.horizParms.rules.branchToBranch; expandedRange: Connections.Range _ [testRange.min - spacing, testRange.max + spacing]; overlaps _ Connections.EnumerateSegments[net, EachSegment]}; Overlaps: PUBLIC PROC [r1, r2: Connections.Range] RETURNS [BOOL] = { RETURN [(r1.min<=r2.max) AND (r2.min<=r1.max)]}; OverlapsOnOpposing: PROC [handle: CabbagePrivate.Handle, opposingCell: Cabbage.Object, range: Connections.Range, side: Connections.Side, netName: Rope.ROPE] RETURNS [overlap: BOOLEAN _ FALSE] ~ { <> <> EachPin: PWPins.InstanceEnumerator ~ { IF pwSide = PWPins.GetSide[opposingCell, inst] AND ((Rope.Equal[netName, handle.vddNet.name] AND Rope.Equal[CDSymbolicObjects.GetName[inst], handle.gndNet.name]) OR (Rope.Equal[netName, handle.gndNet.name] AND Rope.Equal[CDSymbolicObjects.GetName[inst], handle.vddNet.name])) THEN { rect: CD.Rect _ CDBasics.MapRect[inst.ob.bbox, inst.trans]; pinRange: Connections.Range _ SELECT side FROM bottom, top => [rect.x1, rect.x2], right, left => [rect.y1, rect.y2], ENDCASE => Cabbage.Error[programmingError, "Not suppose to happen."]; quit _ Overlaps[pinRange, expandedRange]}}; pwSide: PWPins.Side _ SELECT side FROM bottom => bottom, right => right, top => top, left => left, ENDCASE => Cabbage.Error[programmingError, "Not suppose to happen."]; spacing: INT _ IF side = top OR side = bottom THEN handle.rules.vertParms.rules.branchToBranch ELSE handle.rules.horizParms.rules.branchToBranch; expandedRange: Connections.Range _ [range.min - spacing, range.max + spacing]; IF opposingCell # NIL THEN overlap _ PWPins.EnumerateEdgePins[opposingCell, EachPin]}; 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}; END.