GetRouting:
PUBLIC
PROCEDURE[routingArea: Route.RoutingArea,
rect: Route.Rect,
properties: Route.PropList,
EnumSegments: RouteChannel.EnumSegmentsProc,
EnumPins: RouteChannel.EnumPinsProc,
EnumVias: RouteChannel.EnumViasProc,
EnumExits: RouteChannel.EnumExitsProc,
EnumIncompletes: RouteChannel.EnumIncompletesProc] RETURNS [externalConnections: Route.PinList ← NIL] = {
Enumerate routing results entities
EachTrack: RouteChannel.EachTrackActionProc = {
run through the segments on the track
FOR seg: RouteChannel.Segment ← RouteChannel.TrackSegAbs[routingArea, trackIndex], seg.nextSeg
WHILE seg # NIL DO
AddInterval: PosSizeProc ~ {
thisRange: RoutePrivate.Range ← [pos - size/2, pos+size/2];
found: BOOLEAN ← FALSE;
list: RoutePrivate.RangeList ← NIL;
FOR l: RoutePrivate.RangeList ← intervalList, l.rest
WHILE l #
NIL
DO
currentRange: RoutePrivate.Range ← l.first;
IF RouteChannel.Overlaps[thisRange, currentRange]
THEN {
currentRange ← RouteChannel.Span[thisRange, currentRange];
found ← TRUE};
list ← CONS[currentRange, list];
ENDLOOP;
IF ~found THEN list ← CONS[thisRange, list];
intervalList ← list};
trackLoc: Route.Number ← RouteChannel.TrackLoc[routingArea, seg.trackNum];
leftPin: RouteChannel.ChanPin ← seg.exteriorPins[chanLeft];
rightPin: RouteChannel.ChanPin ← seg.exteriorPins[chanRight];
leftBranchWidth, rightBranchWidth: Route.Number ← 0;
segLayer: Route.Layer ← RouteUtil.RoutingLayerToLayer[routingArea, seg.routingLayer];
intervalList: RoutePrivate.RangeList ← NIL;
nextSeg: RouteChannel.Segment;
doRight: BOOLEAN;
audit the pins to which this segment point
RouteChannel.CheckPins[seg, leftPin, chanRight];
RouteChannel.CheckPins[seg, rightPin, chanLeft];
figure out the left branch
leftBranchWidth ← AnalyzeBranch[routingArea, seg.exteriorPins[chanLeft].pinPosition, seg, chanLeft, chanRight, AddInterval];
process the interior pins
FOR pinList: RouteChannel.ChanPinList ← seg.interiorPins, pinList.rest
WHILE pinList #
NIL
DO
pin: RouteChannel.ChanPin ← pinList.first;
[] ← AnalyzeBranch[routingArea, pin.pinPosition, seg, chanLeft, chanRight, AddInterval];
ENDLOOP;
do the right branch if no following segment in this track
nextSeg ← NextSegment[seg];
IF nextSeg # NIL THEN doRight ← seg.trackNum # nextSeg.trackNum
ELSE doRight ← TRUE;
IF doRight
THEN
rightBranchWidth ← AnalyzeBranch[routingArea, rightPin.pinPosition, seg, chanRight, chanLeft, AddInterval];
do the vias collected during the AnalyzeBranch Calls
DoVias[routingArea, seg, intervalList];
enumerate trunk segment
EnumSegments[routingArea, seg.net.name, seg.net.netPart,
RouteUtil.PQToXY[routingArea, [PinPos[leftPin] - leftBranchWidth/2, trackLoc]],
RouteUtil.PQToXY[routingArea, [PinPos[rightPin] + rightBranchWidth/2, trackLoc]],
seg.qWidth, segLayer];
ENDLOOP};
DoVias:
PROC [routingArea: Route.RoutingArea, seg: RouteChannel.Segment, intervalList: RoutePrivate.RangeList] ~ {
trunkL: Route.Layer ← RouteUtil.RoutingLayerToLayer[routingArea, trunk];
branchL: Route.Layer ← RouteUtil.RoutingLayerToLayer[routingArea, branch];
trackLoc: Route.Number ← RouteChannel.TrackLoc[routingArea, seg.trackNum];
FOR list: RoutePrivate.RangeList ← intervalList, list.rest
WHILE list #
NIL
DO
range: RoutePrivate.Range ← list.first;
EnumVias[routingArea, seg.net.name, seg.net.netPart, RouteUtil.PQToXY[routingArea, [(range.l+range.r)/2, trackLoc]], RouteUtil.PQToXY[routingArea, [range.r-range.l, seg.qWidth]], trunkL, branchL];
ENDLOOP};
PinPos:
PROCEDURE[pin: RouteChannel.ChanPin]
RETURNS [pos: Route.Number] = {
IF pin.kindOfPin # exitPin THEN pos ← pin.pinPosition.pLoc
ELSE {
pos ← IF pin.pinSide = chanLeft THEN pos1.p
ELSE IF pin.pinSide = chanRight THEN pos2.p
ELSE Route.Error[programmingError, "Invalid data. Call maintainer."]}};
ExitSegPos:
PROCEDURE[pin: RouteChannel.ChanPin, width: Route.Number]
RETURNS [pos: Route.Number] = {
pos ←
IF pin.pinSide = chanLeft
THEN pos1.p + width/2
ELSE IF pin.pinSide = chanRight THEN pos2.p - width/2
ELSE Route.Error[programmingError, "Invalid data. Call maintainer."]};
EachPin: RouteChannel.EachPinActionProc = {
IF pin #
NIL
THEN
IF pin.kindOfPin # noPin
THEN {
pin is present, look at the segments on the right side
seg: RouteChannel.Segment ← pin.conctSeg[chanRight];
IF seg #
NIL
THEN {
leftPinPosition: Route.Number ← seg.exteriorPins[chanLeft].pinPosition.pLoc;
rightPinPosition: Route.Number ← seg.exteriorPins[chanRight].pinPosition.pLoc;
RouteChannel.CheckSegs[seg, pin];
IF (seg.trackNum = 0
AND leftPinPosition # rightPinPosition)
OR seg.failed
THEN {
a routing failure
qLoc: Route.Number ←
IF seg.trackNum = 0
THEN 0
ELSE RouteChannel.TrackLoc[routingArea, seg.trackNum];
EnumIncompletes[routingArea, seg.net.name, seg.net.netPart,
RouteUtil.PQToXY[routingArea, [leftPinPosition, qLoc]],
RouteUtil.PQToXY[routingArea, [rightPinPosition, qLoc]]]}}}};
PosSizeProc: TYPE = PROC[pos, size: Route.Number];
AnalyzeBranch:
PROCEDURE[routingArea: Route.RoutingArea,
branchPos: RouteChannel.PinPosition,
segmentLink: RouteChannel.Segment,
branchSide, segmentSide: RouteChannel.ChanLRSide, callBack: PosSizeProc] RETURNS [branchWidth: Route.Number] = {
analyze the branch for this segment
problems with dogleg outside pin range
AnalyzeEachPin: RouteChannel.EachPinActionProc = {
IF pin #
NIL
THEN {
SELECT pin.kindOfPin
FROM
chanConnect, compPin => {
seg: RouteChannel.Segment ← pin.conctSeg[segmentSide];
IF seg #
NIL
THEN {
segLength: Route.Number ← RouteChannel.Length[seg];
IF seg = segmentLink
THEN
{trackLoc: Route.Number ← RouteChannel.TrackLoc[routingArea, seg.trackNum];
otherSeg: RouteChannel.Segment;
qLoc: Route.Number;
pLoc: Route.Number ← pin.pinPosition.pLoc;
newPin: Route.Pin;
SELECT pin.pinSide
FROM
chanTop => {
qLoc ← topLoc + pin.qLoc;
upperMaxQ ← MAX[upperMaxQ, qLoc];
upperMinQ ← MIN[upperMinQ, qLoc];
upperBranchWidth ← MAX[upperBranchWidth, pin.pWidth]};
chanBottom => {
qLoc ← bottomLoc + pin.qLoc;
lowerMaxQ ← MAX[lowerMaxQ, qLoc];
lowerMinQ ← MIN[lowerMinQ, qLoc];
lowerBranchWidth ← MAX[lowerBranchWidth, pin.pWidth]};
ENDCASE;
newPin ← BuildPin[routingArea, pin, seg, [pLoc, qLoc]];
EnumPins[routingArea, seg.net.name, seg.net.netPart, RouteUtil.PQToXY[routingArea, [pLoc, qLoc]], branchL, newPin];
IF seg.routingLayer = trunk
AND segLength > 0
THEN
callBack[pin.pinPosition.pLoc, pin.pWidth];
otherSeg ← pin.conctSeg[branchSide];
IF otherSeg #
NIL
THEN
IF otherSeg.trackNum # 0
THEN {
otherTrackLoc: Route.Number ← RouteChannel.TrackLoc[routingArea, otherSeg.trackNum];
IF (otherTrackLoc # 0)
AND (otherTrackLoc # trackLoc
OR otherSeg.routingLayer # segmentLink.routingLayer)
THEN {
otherSegLength: Route.Number ← RouteChannel.Length[otherSeg];
upperMaxQ ← MAX[upperMaxQ, otherTrackLoc + otherSeg.qWidth/2];
upperMinQ ← MIN[upperMinQ, otherTrackLoc - otherSeg.qWidth/2];
lowerMaxQ ← MAX[lowerMaxQ, otherTrackLoc + otherSeg.qWidth/2];
lowerMinQ ← MIN[lowerMinQ, otherTrackLoc - otherSeg.qWidth/2];
IF otherSeg.routingLayer = trunk
AND otherSegLength > 0
THEN
callBack[pin.pinPosition.pLoc, pin.pWidth];
}}}};
};
dogLeg => {
segList: RouteChannel.SegmentList ← RouteChannel.GetSegsOnPin[pin];
FOR segs: RouteChannel.SegmentList ← segList, segs.rest
WHILE segs #
NIL
DO
seg: RouteChannel.Segment ← segs.first;
IF seg.trackNum # 0
THEN {
trackLoc: Route.Number ← RouteChannel.TrackLoc[routingArea, seg.trackNum];
IF trackLoc # 0
THEN
{lowerBranchWidth ← MAX[lowerBranchWidth, pin.pWidth];
upperBranchWidth ← MAX[upperBranchWidth, pin.pWidth];
upperMaxQ ← MAX[upperMaxQ, trackLoc + seg.qWidth/2];
upperMinQ ← MIN[upperMinQ, trackLoc - seg.qWidth/2];
lowerMaxQ ← MAX[lowerMaxQ, trackLoc + seg.qWidth/2];
lowerMinQ ← MIN[lowerMinQ, trackLoc - seg.qWidth/2];
IF seg.routingLayer = trunk
AND seg = segmentLink
THEN
callBack[pin.pinPosition.pLoc, pin.pWidth];
}};
ENDLOOP};
exitPin => {
seg: RouteChannel.Segment ← pin.conctSeg[segmentSide];
IF seg #
NIL
THEN
IF seg = segmentLink
AND seg.trackNum # 0
THEN {
layer: Route.Layer ← RouteUtil.RoutingLayerToLayer[routingArea, seg.routingLayer];
exitP: Route.Number ← PinPos[pin];
trackQ: Route.Number ← RouteChannel.TrackLoc[routingArea, seg.trackNum];
exitQ: Route.Number;
exitPos: Route.Position;
newPin: Route.Pin;
IF parms.routerUsed = channel
THEN
exitQ ← trackQ
ELSE {
maxQ: Route.Number ← MAX[trackQ+seg.qWidth/2, pin.qLoc+seg.qWidth/2];
minQ: Route.Number ← MIN[trackQ-seg.qWidth/2, pin.qLoc-seg.qWidth/2];
pPos: Route.Number 𡤎xitSegPos[pin, routingArea.rules.trunkWidth];
EnumSegments[routingArea,
segmentLink.net.name, segmentLink.net.netPart,
RouteUtil.PQToXY[routingArea, [pPos, maxQ]],
RouteUtil.PQToXY[routingArea, [pPos, minQ]],
routingArea.rules.trunkWidth, layer];
exitQ ← pin.qLoc};
exitPos ← RouteUtil.PQToXY[routingArea, [exitP, exitQ]];
newPin ← BuildPin[routingArea, pin, seg, [exitP, exitQ]];
externalConnections ← CONS[newPin, externalConnections];
EnumExits[routingArea, seg.net.name, seg.net.netPart, exitPos, layer, newPin, seg.exitBreak]}};
ENDCASE}};
trackLoc: Route.Number ← RouteChannel.TrackLoc[routingArea, segmentLink.trackNum];
branchL: Route.Layer ← RouteUtil.RoutingLayerToLayer[routingArea, branch];
lowerMaxQ, upperMaxQ: Route.Number ← trackLoc + segmentLink.qWidth/2;
lowerMinQ, upperMinQ: Route.Number ← trackLoc - segmentLink.qWidth/2;
lowerBranchWidth, upperBranchWidth: Route.Number ← 0;
parms: RoutePrivate.RoutingAreaParms ← NARROW[routingArea.parms];
analyze component pin branches
[] ← RouteChannel.EnumPins[routingArea, branchPos, AnalyzeEachPin];
enumerate this branch segment
IF lowerMaxQ > lowerMinQ + segmentLink.qWidth
AND lowerBranchWidth > 0
THEN
EnumSegments[routingArea, segmentLink.net.name, segmentLink.net.netPart,
RouteUtil.PQToXY[routingArea, [branchPos.pLoc, lowerMinQ]],
RouteUtil.PQToXY[routingArea, [branchPos.pLoc, lowerMaxQ]],
lowerBranchWidth, branchL];
IF upperMaxQ > upperMinQ + segmentLink.qWidth
AND upperBranchWidth > 0
AND (lowerMaxQ # upperMaxQ
OR lowerMinQ # upperMinQ)
THEN
EnumSegments[routingArea, segmentLink.net.name, segmentLink.net.netPart,
RouteUtil.PQToXY[routingArea, [branchPos.pLoc, upperMinQ]],
RouteUtil.PQToXY[routingArea, [branchPos.pLoc, upperMaxQ]],
upperBranchWidth, branchL];
branchWidth ← MAX[lowerBranchWidth, upperBranchWidth];
}; -- AnalyzeBranch
chanData: RouteChannel.ChannelData ← NARROW[routingArea.privateData];
chanPins: RouteChannel.RoutingChannelPins ← chanData.chanPins;
nRect: Route.Rect ← CDBasics.NormalizeRect[rect];
pos1: RoutePrivate.PQPosition ← RouteUtil.XYToPQ[routingArea, [nRect.x1, nRect.y1]];
pos2: RoutePrivate.PQPosition ← RouteUtil.XYToPQ[routingArea, [nRect.x2, nRect.y2]];
bottomLoc: Route.Number ← pos1.q - chanData.chanSides[chanBottom].routeAreaCoord;
topLoc: Route.Number ← pos2.q;
[] ← RouteChannel.EnumTracks[routingArea, EachTrack];
enumerate the incompletes and audit the segments
FOR index: RouteChannel.MPinsOnCh
IN [1 .. chanPins.count]
DO
[] ← RouteChannel.EnumPins[routingArea, chanPins.sides[index], EachPin];
ENDLOOP};
BuildPin:
PROCEDURE[routingArea: Route.RoutingArea, iPin: RouteChannel.ChanPin, seg: RouteChannel.Segment, pos: RoutePrivate.PQPosition]
RETURNS [pin: Route.Pin] = {
build a pin record for the external exit
chanData: RouteChannel.ChannelData ← NARROW[routingArea.privateData];
chanPins: RouteChannel.RoutingChannelPins ← chanData.chanPins;
pinName: Rope.ROPE;
layer: Route.Layer;
loc: Route.Rect;
side: Route.Side;
cdPin: CD.Instance;
p1, p2: Route.Position;
p, q, pO, qO: Route.Number;
iSide: RouteChannel.ChanSide;
IF iPin.pin =
NIL
THEN {
-- this is a constructed pin
iSide ← IF pos.p <= chanPins.cEnd1 THEN chanLeft ELSE chanRight;
side ← RouteChannel.IntSideToExtSide[routingArea, iSide];
q ← seg.net.trunkWidth/2;
p ← routingArea.rules.CDLambda/2;
layer ← RouteUtil.RoutingLayerToLayer[routingArea, trunk];
pinName ← seg.net.name}
ELSE {
-- this exit came from the client
iSide ← iPin.pinSide;
IF iSide = chanBottom
OR iSide = chanTop
THEN
{p ← iPin.pWidth/2; q ← routingArea.rules.CDLambda/2}
ELSE {
p ← routingArea.rules.CDLambda/2; q ← seg.net.trunkWidth/2};
side ← RouteChannel.IntSideToExtSide[routingArea, iPin.pinSide];
layer ← RouteUtil.RoutingLayerToLayer[routingArea, iPin.pin.layer];
pinName ← iPin.pin.name};
SELECT iSide
FROM
chanBottom => {pO ← 0; qO ← q};
chanRight => {pO ← -p; qO ← 0};
chanTop => {pO ← 0; qO ← -q};
chanLeft => {pO ← p; qO ← 0};
ENDCASE;
p1 ← RouteUtil.PQToXY[routingArea, [pos.p - p + pO, pos.q - q + qO]];
p2 ← RouteUtil.PQToXY[routingArea, [pos.p + p + pO, pos.q + q + qO]];
loc ← [p1.x, p1.y, p2.x, p2.y];
cdPin ← RouteUtil.CreateCDPin[pinName, loc, layer];
pin ← NEW[Route.PinRec ← [cdPin, side]];
};
RetrieveSegments:
PUBLIC RouteChannel.EnumSegmentsProc = {
application: CD.Instance;
ob: CD.Object;
rectSize, position: CD.Position;
parms: RoutePrivate.RoutingAreaParms ← NARROW[routingArea.parms];
[position, rectSize] ←RouteUtil.LineToRect[pos1, pos2, width];
ob ← CDRects.CreateRect[rectSize, layer];
application ← RouteUtil.Include[parms.object, ob, position];
CDProperties.PutProp[application, $SignalName, name]};
}.