<> <> <> <> <> DIRECTORY Basics, CD, CDBasics, DABasics, List, Rope, Route, RouteChannel, RoutePrivate, RouteUtil, RTBasic; RouteChannelInitImpl: CEDAR PROGRAM IMPORTS CDBasics, List, Rope, Route, RouteChannel, RouteUtil, RTBasic EXPORTS RouteChannel = { ChanSideName: PUBLIC ARRAY RouteChannel.ChanSide OF Rope.ROPE _ ["chanBottom", "chanTop", "chanLeft", "chanRight"]; AboveOrBelowName: PUBLIC ARRAY RouteChannel.AboveOrBelow OF Rope.ROPE _ ["above", "below"]; GoingName: PUBLIC ARRAY RouteChannel.GoingDirection OF Rope.ROPE _ ["leftToRight", "rightToLeft"]; InitChannel: PUBLIC PROC [extSidesData: RoutePrivate.RoutingAreaSides, parms: RoutePrivate.RoutingAreaParms, rules: Route.DesignRules, netTab: RoutePrivate.NetTab, signalSinglePinNets, signalCoincidentPins, okToDiddleLLPins, okToDiddleURPins: BOOLEAN] RETURNS [chanData: RouteChannel.ChannelData] = { <> <<>> nRect: DABasics.Rect _ CDBasics.ReInterpreteRect[parms.routingRect]; lowPos: RTBasic.PQPos _ RouteUtil.XYToPQ[rules, [nRect.x1, nRect.y1]]; upPos: RTBasic.PQPos _ RouteUtil.XYToPQ[rules, [nRect.x2, nRect.y2]]; rRect: RTBasic.PQRect _ [lowPos, upPos]; <> chanData _ NEW[RouteChannel.ChannelDataRec]; chanData.constraints _ NIL; chanData.chanSides[chanTop] _ NEW[RouteChannel.RoutingChannelSidesRec]; chanData.chanSides[chanBottom] _ NEW[RouteChannel.RoutingChannelSidesRec]; chanData.chanSides[chanLeft] _ NEW[RouteChannel.RoutingChannelSidesRec]; chanData.chanSides[chanRight] _ NEW[RouteChannel.RoutingChannelSidesRec]; chanData.chanTracks _ NEW[RouteChannel.RoutingChannelTracksRec]; chanData.chanPins _ NEW[RouteChannel.RoutingChannelPinsRec]; chanData.chanParms _ NEW[RouteChannel.ChanParmsRec]; chanData.chanParms.emptyTrackLimit _ MAX[2, RouteChannel.InfluenceTracks[rules, parms.widestTrunk]]; chanData.chanParms.maxToConvert _ 10*rules.branchToBranch; <> ConvertSide[chanData, extSidesData, rules, chanBottom, rRect]; ConvertSide[chanData, extSidesData, rules, chanTop, rRect]; ConvertEnd[chanData, extSidesData, rules, chanLeft, rRect]; ConvertEnd[chanData, extSidesData, rules, chanRight, rRect]; <> FixOrigins[chanData, rRect]; <> FOR netIndex: RoutePrivate.ZMaxNets IN [1 .. netTab.count] DO InitNet[chanData, parms, rules, netTab, netTab.n[netIndex], signalSinglePinNets, signalCoincidentPins]; ENDLOOP; SELECT parms.routerUsed FROM switchBox => MakeSBTracks[chanData, rules, okToDiddleLLPins, okToDiddleURPins]; channel => MakeCRTracks[chanData.chanTracks, rules, parms.numTracksToUse]; ENDCASE => ERROR; --may be channel should be the default ? <> <> <<>> DoTBBarriers[chanData, parms, rules, chanBottom]; DoTBBarriers[chanData, parms, rules, chanTop]; DoLRBarriers[chanData, chanLeft]; DoLRBarriers[chanData, chanRight]; }; ConvertSide: PROC [chanData: RouteChannel.ChannelData, extSidesData: RoutePrivate.RoutingAreaSides, rules: Route.DesignRules, chanSide: RouteChannel.ChanSide, routingRect: RTBasic.PQRect] = { <> <<>> activeSide: RouteChannel.RoutingChannelSides _ chanData.chanSides[chanSide]; chanPins: RouteChannel.RoutingChannelPins _ chanData.chanPins; extSide: DABasics.Side _ RouteChannel.IntSideToExtSide[rules, chanSide]; extSideData: RoutePrivate.RoutingAreaSide _ extSidesData[extSide]; activeSide.enclosingBarrier _ [[0, 0], [0, 0]]; activeSide.extSide _ extSide; chanPins.cEnd1 _ routingRect.c1.p; chanPins.cEnd2 _ routingRect.c2.p; IF extSideData # NIL THEN { encloseBranch: RTBasic.PQRect _ TranslateBarriers[extSidesData, rules, activeSide, branch]; encloseTrunk: RTBasic.PQRect _ TranslateBarriers[extSidesData, rules, activeSide, trunk]; activeSide.enclosingBarrier _ Surround[encloseBranch, encloseTrunk]; }; }; TranslateBarriers: PROC [extSidesData: RoutePrivate.RoutingAreaSides, rules: Route.DesignRules, activeSide: RouteChannel.RoutingChannelSides, rLayer: RoutePrivate.RoutingLayer] RETURNS [enclosingRect: RTBasic.PQRect _ [[0, 0], [0, 0]]] = { <> <<>> extSide: DABasics.Side _ activeSide.extSide; extSideData: RoutePrivate.RoutingAreaSide _ extSidesData[extSide]; <> IF extSideData # NIL THEN { FOR bList: RoutePrivate.RoutingBarrierList _ extSideData.barrierList, bList.rest WHILE bList # NIL DO barrierItem: RoutePrivate.RoutingBarrier _ bList.first; generalLayer: CD.Layer _ barrierItem.layer; IF generalLayer = CD.undefLayer OR RouteUtil.LayerToRoutingLayer[rules, generalLayer] = rLayer THEN { FOR rList: LIST OF DABasics.Rect _ barrierItem.barrier, rList.rest WHILE rList # NIL DO cleanRectangle: RTBasic.PQRectRef _ CheckRect[rules, rList.first, activeSide]; IF cleanRectangle # NIL THEN { enclosingRect _ Surround[enclosingRect, cleanRectangle^]; activeSide.barrierList[rLayer] _ CONS[cleanRectangle^, activeSide.barrierList[rLayer]]}; ENDLOOP; } ENDLOOP; }; }; CheckRect: PROC [rules: Route.DesignRules, rect: DABasics.Rect, activeSide: RouteChannel.RoutingChannelSides] RETURNS[cleanRect: RTBasic.PQRectRef] = { <> <<*** CHECK THAT PROC... ***>> <<>> <> c1: RTBasic.PQPos _ RouteUtil.XYToPQ[rules, [rect.x1, rect.y1]]; c2: RTBasic.PQPos _ RouteUtil.XYToPQ[rules, [rect.x2, rect.y2]]; RETURN[NEW[RTBasic.PQRect _ [c1, c2]]]; }; ConvertEnd: PROC [chanData: RouteChannel.ChannelData, extSidesData: RoutePrivate.RoutingAreaSides, rules: Route.DesignRules, chanSide: RouteChannel.ChanSide, routingRect: RTBasic.PQRect] = { <> <<>> activeSide: RouteChannel.RoutingChannelSides _ chanData.chanSides[chanSide]; extSide: DABasics.Side _ RouteChannel.IntSideToExtSide[rules, chanSide]; extSideData: RoutePrivate.RoutingAreaSide _ extSidesData[extSide]; activeSide.extSide _ extSide; activeSide.enclosingBarrier _ [[0, 0], [0, 0]]; IF extSideData # NIL THEN { encloseBranch: RTBasic.PQRect _ TranslateBarriers[extSidesData, rules, activeSide, branch]; encloseTrunk: RTBasic.PQRect _ TranslateBarriers[extSidesData, rules, activeSide, trunk]; activeSide.enclosingBarrier _ Surround[encloseBranch, encloseTrunk]; }; }; FixOrigins: PROC [chanData: RouteChannel.ChannelData, routingRect: RTBasic.PQRect] = { <> <<>> chanPins: RouteChannel.RoutingChannelPins _ chanData.chanPins; leftSide: RouteChannel.RoutingChannelSides _ chanData.chanSides[chanLeft]; rightSide: RouteChannel.RoutingChannelSides _ chanData.chanSides[chanRight]; bottomSide: RouteChannel.RoutingChannelSides _ chanData.chanSides[chanBottom]; topSide: RouteChannel.RoutingChannelSides _ chanData.chanSides[chanTop]; zero: DABasics.Number _ 0; -- don't laugh <> leftSide.routeAreaCoord _ chanPins.cEnd1; rightSide.routeAreaCoord _ chanPins.cEnd2; chanPins.cEnd1 _ chanPins.cEnd1 + MAX[zero, leftSide.enclosingBarrier.c2.p]; chanPins.cEnd2 _ chanPins.cEnd2 + MAX[zero, rightSide.enclosingBarrier.c1.p]; bottomSide.routeAreaCoord _ routingRect.c1.q; topSide.routeAreaCoord _ routingRect.c2.q; }; InitNet: PROC [chanData: RouteChannel.ChannelData, parms: RoutePrivate.RoutingAreaParms, rules: Route.DesignRules, netTab: RoutePrivate.NetTab, net: RoutePrivate.Net, signalSinglePinNets, signalCoincidentPins: BOOLEAN] = { <> <<>> PPinCompare: List.CompareProc = { p1: DABasics.Number _ NARROW[ref1, RouteChannel.InternPin].location.p; p2: DABasics.Number _ NARROW[ref2, RouteChannel.InternPin].location.p; RETURN[IF p1 < p2 THEN Basics.Comparison.less ELSE IF p1 = p2 THEN Basics.Comparison.equal ELSE Basics.Comparison.greater]; }; mungedPinList, sortedPinList: List.LORA; <> chanPins: RouteChannel.RoutingChannelPins _ chanData.chanPins; net.internPinList _ FixPins[chanData, parms, rules, net.pinList]; mungedPinList _ ConvertToLORA[NARROW[net.internPinList]]; sortedPinList _ List.Sort[mungedPinList, PPinCompare]; IF CheckChanPins[chanPins, rules, netTab, net, sortedPinList, signalSinglePinNets, signalCoincidentPins] THEN BuildChanPinForDogleg[chanPins, parms, rules, net, sortedPinList]; -- Multiple segments per net <> }; FixPins: PROC [chanData: RouteChannel.ChannelData, parms: RoutePrivate.RoutingAreaParms, rules: Route.DesignRules, pList: Route.PinList] RETURNS [fixedPins: -- List.LORA _ NIL -- RouteChannel.InternPinList _ NIL ] = { <> chanPins: RouteChannel.RoutingChannelPins _ chanData.chanPins; routingRect: DABasics.Rect _ parms.routingRect; FOR list: Route.PinList _ pList, list.rest WHILE list # NIL DO old: Route.Pin _ list.first; loc: RTBasic.PQPos; new: RouteChannel.InternPin; chanSide: RouteChannel.ChanSide _ RouteChannel.ExtSideToIntSide[rules, old.side]; activeSide: RouteChannel.RoutingChannelSides _ chanData.chanSides[chanSide]; rLayer: RoutePrivate.RoutingLayer _ RouteUtil.LayerToRoutingLayer[rules, old.layer]; width: DABasics.Number _ old.max - old.min; oldLoc: DABasics.Position _ SELECT old.side FROM bottom => [old.min + width/2, routingRect.y1 - old.depth], top => [old.min + width/2, routingRect.y2 + old.depth], left => [routingRect.x1 - old.depth, old.min + width/2], right => [routingRect.x2 + old.depth, old.min + width/2], ENDCASE => Route.Error[programmingError, "not suppose to happen."]; SELECT chanSide FROM chanBottom, chanTop => { loc _ RouteUtil.XYToPQ[rules, oldLoc]; loc.q _ loc.q - activeSide.routeAreaCoord}; chanLeft => { SELECT parms.routerUsed FROM channel => { loc _ [chanPins.cEnd1, 0]; width _ 0; }; switchBox => { loc _ RouteUtil.XYToPQ[rules, oldLoc]; loc.p _ chanPins.cEnd1}; ENDCASE => ERROR; }; chanRight => { SELECT parms.routerUsed FROM channel => { loc _ [chanPins.cEnd2, 0]; width _ 0; }; switchBox => { loc _ RouteUtil.XYToPQ[rules, oldLoc]; loc.p _ chanPins.cEnd2; }; ENDCASE => ERROR; }; ENDCASE; new _ NEW[RouteChannel.InternPinRec _ [NIL, chanSide, loc, width, rLayer, old]]; fixedPins _ CONS[new, fixedPins]; ENDLOOP; }; CheckChanPins: PROC [chanPins: RouteChannel.RoutingChannelPins, rules: Route.DesignRules, netTab: RoutePrivate.NetTab, net: RoutePrivate.Net, pinList: List.LORA -- RouteChannel.InternPinList --, signalSinglePinNets, signalCoincidentPins: BOOLEAN] RETURNS [ok: BOOLEAN _ TRUE] = { <> <<-- number of pins > 1>> <<-- pins within range>> <<-- pin overlap>> <<-- pin spacing>> <<-- max number of pins>> <<>> numPins, numOverlaps: NAT _ 0; leftExit, rightExit: BOOLEAN _ FALSE; branchLayer: CD.Layer _ rules.branchLayer; trunkLayer: CD.Layer _ rules.trunkLayer; previousPin: RouteChannel.InternPin _ NIL; FOR pList: List.LORA -- RouteChannel.InternPinList -- _ pinList, pList.rest WHILE pList # NIL DO this: RouteChannel.InternPin _ NARROW[pList.first]; numPins _ numPins + 1; IF previousPin # NIL THEN { -- check for overlapping pins. IF previousPin.chanSide = this.chanSide THEN { rLast, rThis: RTBasic.Range; IF previousPin.chanSide = chanBottom OR previousPin.chanSide = chanTop THEN { rLast _ [previousPin.location.p - previousPin.pWidth/2, previousPin.location.p + previousPin.pWidth/2]; rThis _ [this.location.p - this.pWidth/2, this.location.p + this.pWidth/2]} ELSE { -- chanSide = chanLeft OR chanSide = chanRight rLast _ [previousPin.location.q - previousPin.pWidth/2, previousPin.location.q + previousPin.pWidth/2]; rThis _ [this.location.q - this.pWidth/2, this.location.q + this.pWidth/2]}; IF RTBasic.Overlaps[rLast, rThis] THEN { numOverlaps _ numOverlaps + 1; IF signalCoincidentPins OR ~(previousPin.location = this.location AND previousPin.pWidth = this.pWidth) THEN Route.Signal[callingError, Rope.Cat[Rope.Cat["Pins overlap, net: ", net.name, ", pins: "], Rope.Cat[this.name, ", ", previousPin.name]]]; ok _ FALSE}} }; SELECT this.chanSide FROM chanBottom, chanTop => { pos: DABasics.Number _ this.location.p; IF chanPins.cEnd1 > pos OR chanPins.cEnd2 < pos THEN { Route.Signal[callingError, Rope.Cat["Pin location out of range, net: ", net.name, ", pin: ", this.name]]; ok _ FALSE}; IF this.pin.layer # branchLayer THEN { Route.Signal[callingError, Rope.Cat["Pin not on branch layer, net: ", net.name, ", pin: ", this.name]]; ok _ FALSE}}; chanLeft => { IF this.pin.layer # trunkLayer THEN { Route.Signal[callingError, Rope.Cat["Pin not on trunk layer, net: ", net.name, ", pin: ", this.name]]; ok _ FALSE}; IF leftExit THEN { Route.Signal[callingError, Rope.Cat["Multiple channel exits: ", net.name, ", pin: ", this.name]]; ok _ FALSE}; leftExit _ TRUE}; chanRight => { IF this.pin.layer # trunkLayer THEN { Route.Signal[callingError, Rope.Cat["Pin not on trunk layer, net: ", net.name, ", pin: ", this.name]]; ok _ FALSE}; IF rightExit THEN { Route.Signal[callingError, Rope.Cat["Multiple channel exits: ", net.name, ", pin: ", this.name]]; ok _ FALSE}; rightExit _ TRUE}; ENDCASE; previousPin _ this; ENDLOOP; IF numPins - numOverlaps <= 1 THEN { IF signalSinglePinNets THEN Route.Signal[callingError, Rope.Cat["Too few pins for net: ", net.name]]; ok _ FALSE}; IF netTab.count + numPins > netTab.size THEN { Route.Signal[noResource, "Net table is too small"]; ok _ FALSE}; }; BuildChanPinForDogleg: PROC [chanPins: RouteChannel.RoutingChannelPins, parms: RoutePrivate.RoutingAreaParms, rules: Route.DesignRules, net: RoutePrivate.Net, pinList: List.LORA -- RouteChannel.InternPinList -- ] = { <> <> <> <> previousSeg: RouteChannel.Segment _ NIL; previousPin: RouteChannel.InternPin _ NARROW[pinList.first]; previousPinPosition: RouteChannel.PinPosition _ chanPins.sides[FindPinPos[chanPins, previousPin.location.p]]; previousChanPin: RouteChannel.ChanPin _ BuildPin[parms, previousPin, previousPinPosition, rules.branchWidth]; SELECT previousPin.chanSide FROM chanBottom, chanTop => IF ~PinViolation[chanPins, parms, rules, previousChanPin, net] THEN previousPinPosition.pins[previousChanPin.pinSide] _ previousChanPin; chanLeft, chanRight => previousPinPosition.innerPins _ CONS[previousChanPin, previousPinPosition.innerPins]; ENDCASE; FOR pList: List.LORA -- RouteChannel.InternPinList -- _ pinList.rest, pList.rest WHILE pList # NIL DO this: RouteChannel.InternPin _ NARROW[pList.first]; allPinsOverlap: BOOLEAN _ TRUE; useThisOne: BOOLEAN _ TRUE; rLast, rThis: RTBasic.Range; IF previousPin.chanSide = chanBottom OR previousPin.chanSide = chanTop THEN { rLast _ [previousPin.location.p - previousPin.pWidth/2, previousPin.location.p + previousPin.pWidth/2]; rThis _ [this.location.p - this.pWidth/2, this.location.p + this.pWidth/2]} ELSE { -- chanSide = chanLeft OR chanSide = chanRight rLast _ [previousPin.location.q - previousPin.pWidth/2, previousPin.location.q + previousPin.pWidth/2]; rThis _ [this.location.q - this.pWidth/2, this.location.q + this.pWidth/2]}; IF previousPin.chanSide = this.chanSide AND RTBasic.Overlaps[rLast, rThis] THEN useThisOne _ FALSE; IF this.chanSide = chanLeft OR this.chanSide = chanRight THEN allPinsOverlap _ FALSE ELSE allPinsOverlap _ allPinsOverlap AND RTBasic.Equal[rLast, rThis]; IF useThisOne THEN { -- this pin is not a duplicate seg: RouteChannel.Segment _ NEW[RouteChannel.SegmentRec _ [net: net]]; pinPosition: RouteChannel.PinPosition _ chanPins.sides[FindPinPos[chanPins, this.location.p]]; chanPin: RouteChannel.ChanPin _ BuildPin[parms, this, pinPosition, rules.branchWidth]; SELECT this.chanSide FROM chanBottom, chanTop => IF ~PinViolation[chanPins, parms, rules, chanPin, net] THEN pinPosition.pins[chanPin.pinSide] _ chanPin; chanLeft, chanRight => pinPosition.innerPins _ CONS[chanPin, pinPosition.innerPins]; ENDCASE; previousChanPin.conctSeg[chanLeft] _ previousSeg; previousChanPin.conctSeg[chanRight] _ seg; chanPin.conctSeg[chanLeft] _ seg; chanPin.conctSeg[chanRight] _ NIL; <<>> <> seg.exteriorPins[chanLeft] _ previousChanPin; seg.exteriorPins[chanRight] _ chanPin; seg.interiorPins _ NIL; <> seg.qWidth _ IF allPinsOverlap THEN rules.trunkWidth ELSE net.trunkWidth; previousChanPin _ chanPin; previousSeg _ seg; }; previousPin _ this; ENDLOOP; }; BuildChanPin: PROC [chanPins: RouteChannel.RoutingChannelPins, parms: RoutePrivate.RoutingAreaParms, rules: Route.DesignRules, net: RoutePrivate.Net, pinList: List.LORA -- RouteChannel.InternPinList -- ] = { <> <> interiorPins: RouteChannel.ChanPinList _ NIL; rightInternPin: RouteChannel.InternPin _ NARROW[List.NthElement[pinList, -1]]; previousPin: RouteChannel.InternPin _ NIL; leftPin, rightPin: RouteChannel.ChanPin _ NIL; allPinsOverlap: BOOLEAN _ TRUE; seg: RouteChannel.Segment _ NEW[RouteChannel.SegmentRec _ [net: net]]; FOR pList: List.LORA -- RouteChannel.InternPinList -- _ pinList, pList.rest WHILE pList # NIL DO pinIndex: RouteChannel.ZMPinsOnCh; pinPosition: RouteChannel.PinPosition; chanPin: RouteChannel.ChanPin; this: RouteChannel.InternPin _ NARROW[pList.first]; useThisOne: BOOLEAN _ TRUE; IF previousPin # NIL THEN { rLast, rThis: RTBasic.Range; IF previousPin.chanSide = chanBottom OR previousPin.chanSide = chanTop THEN { rLast _ [previousPin.location.p - previousPin.pWidth/2, previousPin.location.p + previousPin.pWidth/2]; rThis _ [this.location.p - this.pWidth/2, this.location.p + this.pWidth/2]} ELSE { -- chanSide = chanLeft OR chanSide = chanRight rLast _ [previousPin.location.q - previousPin.pWidth/2, previousPin.location.q + previousPin.pWidth/2]; rThis _ [this.location.q - this.pWidth/2, this.location.q + this.pWidth/2]}; IF previousPin.chanSide = this.chanSide AND RTBasic.Overlaps[rLast, rThis] THEN useThisOne _ FALSE; IF this.chanSide = chanLeft OR this.chanSide = chanRight THEN allPinsOverlap _ FALSE ELSE -- make a narrow trunk if pins overlap allPinsOverlap _ allPinsOverlap AND RTBasic.Equal[rLast, rThis] }; IF useThisOne THEN { pinIndex _ FindPinPos[chanPins, this.location.p]; pinPosition _ chanPins.sides[pinIndex]; chanPin _ BuildPin[parms, this, pinPosition, rules.branchWidth]; SELECT this.chanSide FROM chanBottom, chanTop => IF ~PinViolation[chanPins, parms, rules, chanPin, net] THEN pinPosition.pins[chanPin.pinSide] _ chanPin; chanLeft, chanRight => pinPosition.innerPins _ CONS[chanPin, pinPosition.innerPins]; ENDCASE; IF leftPin = NIL THEN { leftPin _ chanPin; chanPin.conctSeg[chanLeft] _ NIL; chanPin.conctSeg[chanRight] _ seg} ELSE IF this = rightInternPin THEN { rightPin _ chanPin; chanPin.conctSeg[chanRight] _ NIL; chanPin.conctSeg[chanLeft] _ seg} ELSE { interiorPins _ CONS[chanPin, interiorPins]; chanPin.conctSeg[chanRight] _ seg; chanPin.conctSeg[chanLeft] _ seg}}; previousPin _ this; ENDLOOP; <> seg.exteriorPins[chanLeft] _ leftPin; seg.exteriorPins[chanRight] _ rightPin; seg.interiorPins _ interiorPins; seg.qWidth _ IF allPinsOverlap THEN rules.trunkWidth ELSE net.trunkWidth; }; FindPinPos: PUBLIC PROC [chanPins: RouteChannel.RoutingChannelPins, thisPLoc: DABasics.Number] RETURNS [index: RouteChannel.ZMPinsOnCh _ 0] = { <> <> found: BOOLEAN _ FALSE; FOR pIndex: RouteChannel.ZMPinsOnCh IN [1 .. chanPins.count] WHILE ~found DO pLoc: DABasics.Number _ chanPins.sides[pIndex].pLoc; IF pLoc > thisPLoc THEN { -- add a new pinPosition found _ TRUE; MovePins[chanPins, pIndex]; index _ pIndex; chanPins.sides[pIndex] _ NEW[RouteChannel.PinPositionRec _ [index, thisPLoc]]} ELSE IF pLoc = thisPLoc THEN { -- pin position already taken, use it found _ TRUE; index _ pIndex}; ENDLOOP; IF ~found THEN { -- this pin goes after the last pin chanPins.count _ chanPins.count +1; index _ chanPins.count; chanPins.sides[index] _ NEW[RouteChannel.PinPositionRec _ [index, thisPLoc]]}; }; MovePins: PROC [chanPins: RouteChannel.RoutingChannelPins, pIndex: RouteChannel.ZMPinsOnCh] = { chanPins.count _ chanPins.count +1; FOR index: RouteChannel.ZMPinsOnCh DECREASING IN [pIndex+1 .. chanPins.count] DO pinPos: RouteChannel.PinPosition _ chanPins.sides[index-1]; pinPos.pinIndex _ index; chanPins.sides[index] _ pinPos; ENDLOOP; }; BuildPin: PROC [parms: RoutePrivate.RoutingAreaParms, iPin: RouteChannel.InternPin, pinPosition: RouteChannel.PinPosition, pinWidth: DABasics.Number] RETURNS [pin: RouteChannel.ChanPin] = { <> kindOfPin: RouteChannel.ChanPinType _ IF iPin.chanSide = chanLeft OR iPin.chanSide = chanRight THEN exitPin ELSE compPin; thisPinWidth: DABasics.Number _ IF kindOfPin = exitPin THEN iPin.pWidth ELSE MAX[pinWidth, iPin.pWidth]; parms.widestPin _ MAX[thisPinWidth, parms.widestPin]; pin _ NEW[RouteChannel.ChanPinRec _ [ pinSide: iPin.chanSide, qLoc: iPin.location.q, pWidth: thisPinWidth, kindOfPin: kindOfPin, pinPosition: pinPosition, pin: iPin ]]; }; PinViolation: PROC [chanPins: RouteChannel.RoutingChannelPins, parms: RoutePrivate.RoutingAreaParms, rules: Route.DesignRules, pin: RouteChannel.ChanPin, net: RoutePrivate.Net] RETURNS [violation: BOOLEAN _ FALSE] = { <> LimitProc: RouteChannel.EachPinActionProc = { IF pin # NIL THEN IF pin.pinSide = pinSide THEN {width: DABasics.Number _ RouteUtil.GetWidthWithContact[rules, pin.pWidth]/2; pinPos: DABasics.Number _ pin.pinPosition.pLoc; IF pinPos < pLoc THEN quit _ pinPos + width + rules.branchSpacing > pLoc - pWidth ELSE -- pinPos >= pLoc quit _ pLoc + pWidth + rules.branchSpacing > pinPos - width}; IF quit THEN violationPin _ pin.pin}; pinSide: RouteChannel.ChanSide _ pin.pinSide; pinIndex: RouteChannel.ZMPinsOnCh _ pin.pinPosition.pinIndex; pLoc: DABasics.Number _ pin.pinPosition.pLoc; pWidth: DABasics.Number _ RouteUtil.GetWidthWithContact[rules, pin.pWidth]/2; testWidth: DABasics.Number _ RouteUtil.GetWidthWithContact[rules, parms.widestPin] + rules.branchSpacing; violationPin: RouteChannel.InternPin _ NIL; <<>> <> iPos: DABasics.Number _ chanPins.sides[pinIndex].pLoc; FOR limitIndex: RouteChannel.MPinsOnCh DECREASING IN [1 .. pinIndex] WHILE chanPins.sides[limitIndex].pLoc + testWidth > iPos AND ~violation DO violation _ RouteChannel.EnumPins[chanPins.sides[limitIndex], LimitProc]; IF violation THEN Route.Signal[callingError, Rope.Cat[Rope.Cat["Pins are too close. net 1: ", net.name, ", pin 1: ", pin.pin.name], Rope.Cat[ ", pin 2: ", violationPin.name]]]; ENDLOOP; <> iPos _ chanPins.sides[pinIndex].pLoc; FOR limitIndex: RouteChannel.MPinsOnCh IN [pinIndex .. chanPins.count] WHILE chanPins.sides[limitIndex].pLoc - testWidth < iPos AND ~violation DO violation _ RouteChannel.EnumPins[chanPins.sides[limitIndex], LimitProc]; IF violation THEN Route.Signal[callingError, Rope.Cat[Rope.Cat["Pins are too close. net 1: ", net.name, ", pin 1: ", pin.pin.name], Rope.Cat[ ", pin 2: ", violationPin.name]]]; ENDLOOP; }; GetExitPins: PROC [chanPins: RouteChannel.RoutingChannelPins] RETURNS [exitPins: List.LORA _ NIL] = { <> <> ReallyGetExits: PROC [pinPos: RouteChannel.PinPosition] = { IF pinPos # NIL THEN { FOR pList: RouteChannel.ChanPinList _ pinPos.innerPins, pList.rest WHILE pList # NIL DO this: RouteChannel.ChanPin _ pList.first; SELECT this.pin.chanSide FROM chanLeft, chanRight => exitPins _ CONS[this, exitPins]; ENDCASE; ENDLOOP; }; }; ReallyGetExits[chanPins.sides[1]]; IF chanPins.count > 0 THEN ReallyGetExits[chanPins.sides[chanPins.count]]; }; MakeSBTracks: PROC [chanData: RouteChannel.ChannelData, rules: Route.DesignRules, okToDiddleLLPins, okToDiddleURPins: BOOLEAN] = { <> ExitPinCompare: List.CompareProc = { q1: DABasics.Number _ NARROW[ref1, RouteChannel.ChanPin].pin.location.q; q2: DABasics.Number _ NARROW[ref2, RouteChannel.ChanPin].pin.location.q; RETURN[IF q1 < q2 THEN Basics.Comparison.less ELSE IF q1 = q2 THEN Basics.Comparison.equal ELSE Basics.Comparison.greater]; }; DoUp: PROC [thisPos: DABasics.Number]~ { FOR trackPos: DABasics.Number _ lastPos + trackDist, trackPos + trackDist WHILE trackPos <= thisPos - trackDist DO [] _ AddTrack[chanTracks, trackPos]; lastPos _ trackPos; ENDLOOP; }; ClosestTrack: PROC [thisPos: DABasics.Number] RETURNS [track: RouteChannel.Track _ NIL] ~ { dist: INT _ LAST[INT]; FOR trackNum: INT IN [1 .. chanTracks.count] DO trialTrack: RouteChannel.Track _ chanTracks.tracks[trackNum]; trialDist: INT _ ABS[trialTrack.trackPos - thisPos]; IF trialDist < dist THEN { track _ trialTrack; dist _ trialDist} ENDLOOP; }; chanPins: RouteChannel.RoutingChannelPins _ chanData.chanPins; chanTracks: RouteChannel.RoutingChannelTracks _ chanData.chanTracks; exitPinList: List.LORA _ GetExitPins[chanPins]; sortedExitPinList: List.LORA _ List.Sort[exitPinList, ExitPinCompare]; lastPos: DABasics.Number _ chanData.chanSides[chanBottom].routeAreaCoord; previousPin: RouteChannel.ChanPin _ NIL; trackDist: DABasics.Number _ rules.trunkToTrunk; lastTrack: RouteChannel.Track _ NIL; <> <<>> FOR pList: List.LORA -- RouteChannel.InternPinList -- _ sortedExitPinList, pList.rest WHILE pList # NIL DO this: RouteChannel.ChanPin _ NARROW[pList.first]; thisPos: DABasics.Number _ this.pin.location.q; pin2Name: Rope.ROPE _ IF previousPin = NIL THEN "none" ELSE previousPin.pin.name; track: RouteChannel.Track _ NIL; SELECT TRUE FROM ~okToDiddleLLPins AND ~okToDiddleURPins => { -- can't move any pins IF thisPos = lastPos THEN -- already have a track here track _ lastTrack ELSE IF thisPos >= lastPos + trackDist THEN { -- lots of room here DoUp[thisPos]; track _ AddTrack[chanTracks, thisPos]} ELSE { Route.Signal[callingError, Rope.Cat["Pins too close on ends of switchbox, pin 1: ", this.pin.name, ", pin 2: ", pin2Name]]; track _ AddTrack[chanTracks, thisPos]}; BindPinToTrack[this, track]; previousPin _ this; lastTrack _ track; lastPos _ thisPos}; okToDiddleLLPins AND okToDiddleURPins => { -- can move pins on both sides IF thisPos = lastPos THEN -- already have a track here track _ lastTrack ELSE IF thisPos >= lastPos + trackDist THEN { -- lots of room here DoUp[thisPos]; track _ AddTrack[chanTracks, thisPos]} ELSE { thisPos _ lastPos + trackDist; track _ AddTrack[chanTracks, thisPos]}; BindPinToTrack[this, track]; previousPin _ this; lastTrack _ track; lastPos _ thisPos}; okToDiddleLLPins => { -- can move only pins on the left IF this.pin.chanSide = chanRight THEN { -- this pin is on the right IF thisPos >= lastPos + trackDist THEN -- lots of room here DoUp[thisPos] ELSE -- not enough room, error Route.Signal[callingError, Rope.Cat["Pins too close on ends of switchbox, pin 1: ", this.pin.name, ", pin 2: ", pin2Name]]; track _ AddTrack[chanTracks, thisPos]; BindPinToTrack[this, track]; previousPin _ this; lastTrack _ track; lastPos _ thisPos; }; }; okToDiddleURPins => { -- can move only pins on the right IF this.pin.chanSide = chanLeft THEN { -- this pin is on the left IF thisPos >= lastPos + trackDist THEN -- lots of room here DoUp[thisPos] ELSE -- not enough room, error Route.Signal[callingError, Rope.Cat["Pins too close on ends of switchbox, pin 1: ", this.pin.name, ", pin 2: ", pin2Name]]; track _ AddTrack[chanTracks, thisPos]; BindPinToTrack[this, track]; previousPin _ this; lastTrack _ track; lastPos _ thisPos; }; }; ENDCASE; ENDLOOP; <> IF previousPin # NIL AND lastPos > chanData.chanSides[chanTop].routeAreaCoord - trackDist THEN { Route.Signal[callingError, Rope.Cat["Pins too close on ends of switchbox, pin : ", previousPin.pin.name]]}; FOR trackPos: DABasics.Number _ lastPos + trackDist, trackPos + trackDist WHILE trackPos < chanData.chanSides[chanTop].routeAreaCoord - trackDist DO [] _ AddTrack[chanTracks, trackPos]; lastPos _ trackPos; ENDLOOP; chanTracks.maxCount _ chanTracks.count; IF okToDiddleLLPins # okToDiddleURPins THEN { <> FOR pList: List.LORA -- RouteChannel.InternPinList -- _ sortedExitPinList, pList.rest WHILE pList # NIL DO this: RouteChannel.ChanPin _ NARROW[pList.first]; thisPos: DABasics.Number _ this.pin.location.q; pin2Name: Rope.ROPE _ IF previousPin = NIL THEN "none" ELSE previousPin.pin.name; track: RouteChannel.Track; SELECT TRUE FROM okToDiddleLLPins => { -- can move only pins on the left IF this.pin.chanSide = chanLeft THEN { -- this pin is on the left track _ ClosestTrack[thisPos]; BindPinToTrack[this, track]}; }; okToDiddleURPins => { -- can move only pins on the right IF this.pin.chanSide = chanRight THEN { -- this pin is on the right track _ ClosestTrack[thisPos]; BindPinToTrack[this, track]}; }; ENDCASE; ENDLOOP; }; }; MakeCRTracks: PROC [chanTracks: RouteChannel.RoutingChannelTracks, rules: Route.DesignRules, maxTracksRequired: NAT] = { <> trackLimit: RouteChannel.ZMaxTracks _ MIN[chanTracks.size, maxTracksRequired]; loc: DABasics.Number _ rules.trunkToEdge; FOR trackIndex: RouteChannel.ZMaxTracks IN [1 .. trackLimit] DO <> [] _ AddTrack[chanTracks, loc]; loc _ loc + rules.trunkToTrunk; ENDLOOP; chanTracks.maxCount _ chanTracks.count; }; AddTrack: PROC [chanTracks: RouteChannel.RoutingChannelTracks, trackPos: DABasics.Number] RETURNS [track: RouteChannel.Track] = { <> IF chanTracks.count >= RouteChannel.maxTrack THEN Route.Signal[noResource, "Too many tracks needed, call implementor"]; chanTracks.count _ chanTracks.count + 1; track _ chanTracks.tracks[chanTracks.count] _ NEW[RouteChannel.TrackRec _ [trackNum: chanTracks.count, trackPos: trackPos]]}; BindPinToTrack: PROC [pin: RouteChannel.ChanPin, track: RouteChannel.Track] ~ { IF pin # NIL THEN { <> sList: RouteChannel.SegmentList _ RouteChannel.GetSegsOnPin[pin]; pin.trackConstraint _ track.trackNum; FOR segs: RouteChannel.SegmentList _ sList, segs.rest WHILE segs # NIL DO seg: RouteChannel.Segment _ segs.first; IF seg # NIL THEN { IF seg.trackConstraint = 0 THEN seg.trackConstraint _ track.trackNum ELSE seg.secTrackConstraint _ track.trackNum}; ENDLOOP; }; }; DoTBBarriers: PROC [chanData: RouteChannel.ChannelData, parms: RoutePrivate.RoutingAreaParms, rules: Route.DesignRules, chanSide: RouteChannel.ChanSide] = { <> <<>> chanTracks: RouteChannel.RoutingChannelTracks _ chanData.chanTracks; activeSide: RouteChannel.RoutingChannelSides _ chanData.chanSides[chanSide]; chanPins: RouteChannel.RoutingChannelPins _ chanData.chanPins; trackDist: DABasics.Number _ rules.trunkToTrunk; FOR rlayer: RoutePrivate.RoutingLayer IN [trunk .. branch] DO FOR bList: RTBasic.PQRectList _ activeSide.barrierList[rlayer], bList.rest WHILE bList # NIL DO BlockProc: RouteChannel.EachTrackActionProc = { trackPos: DABasics.Number _ RouteChannel.TrackLoc[chanTracks, parms, rules, trackIndex]; IF minQ < trackPos - trackDist AND trackPos + trackDist < maxQ THEN track.blocked _ TRUE}; barrierItem: RTBasic.PQRect _ bList.first; minQ: DABasics.Number _ MIN[barrierItem.c1.q, barrierItem.c2.q]; maxQ: DABasics.Number _ MAX[barrierItem.c1.q, barrierItem.c2.q]; [] _ RouteChannel.EnumTracks[chanTracks, BlockProc]; ENDLOOP; ENDLOOP; }; DoLRBarriers: PROC [chanData: RouteChannel.ChannelData, chanSide: RouteChannel.ChanSide] = { <> <<>> activeSide: RouteChannel.RoutingChannelSides _ chanData.chanSides[chanSide]; FOR rlayer: RoutePrivate.RoutingLayer IN [trunk .. branch] DO FOR bList: RTBasic.PQRectList _ activeSide.barrierList[rlayer], bList.rest WHILE bList # NIL DO BlockProc: RouteChannel.EachTrackActionProc = { NULL }; barrierItem: RTBasic.PQRect _ bList.first; minQ: DABasics.Number _ MIN[barrierItem.c1.q, barrierItem.c2.q]; maxQ: DABasics.Number _ MAX[barrierItem.c1.q, barrierItem.c2.q]; [] _ RouteChannel.EnumTracks[chanData.chanTracks, BlockProc]; ENDLOOP; ENDLOOP; }; Surround: PROC [r1, r2: RTBasic.PQRect] RETURNS [RTBasic.PQRect] = INLINE { RETURN [RTBasic.PQRect[ [MIN[r1.c1.p, r2.c1.p], MIN[r1.c1.q, r2.c1.q]], [MAX[r1.c2.p, r2.c2.p], MAX[r1.c2.q, r2.c2.q]]]]}; ConvertToLORA: PROC [list: RouteChannel.InternPinList] RETURNS[val: List.LORA] = { val _ NIL; UNTIL list = NIL DO val _ CONS[list.first, val]; list _ list.rest; ENDLOOP; RETURN[val]; }; -- of ConvertToLORA }.