RouteChannelConstraintsImpl.mesa
Copyright Ó 1985, 1986, 1987, 1989 by Xerox Corporation. All rights reserved.
by Bryan Preas July 10, 1985 6:57:00 pm PDT
last edited by Bryan Preas July 16, 1987 8:36:23 pm PDT
Christian Le Cocq January 11, 1988 12:45:14 pm PST
Altered version for improved dogleg routes
DIRECTORY
Basics, CD, DABasics, List, IO, Rope, Route, RouteChannel, RouteDiGraph, RoutePrivate, RouteUtil, RTBasic, TerminalIO;
RouteChannelConstraintsImpl: CEDAR PROGRAM
IMPORTS Basics, List, IO, Rope, Route, RouteChannel, RouteDiGraph, RouteUtil, RTBasic, TerminalIO
EXPORTS RouteChannel = {
SegBreakType: TYPE = {dogLeg, exit}; -- should add pinDogLeg sometime
SegBreakSpec: TYPE = REF SegBreakSpecRec;
SegBreakSpecRec: TYPE = RECORD [
pos: DABasics.Number ← 0,
type: SegBreakType ← dogLeg,
chainLength: INT ← 0];
Lmr: TYPE = {left, middle, right};
FullSegBreakSpec: TYPE = RECORD [
seg: RouteChannel.Segment ←NIL,
breaks: ARRAY Lmr OF SegBreakSpec ← ALL[NIL]];
BreakResult: TYPE = RECORD [
deltaDensity: DABasics.Number,
duplicateLength: DABasics.Number,
numDogLegs: DABasics.Number,
chainLength: DABasics.Number];
RangeWithDirList: TYPE = LIST OF RangeWithDir;
RangeWithDir: TYPE = RECORD [
range: RTBasic.Range,
dir: RouteChannel.GoingDirection];
ChanPinListSet: TYPE = RECORD [
leftExit, rightExit: RouteChannel.ChanPin ← NIL,
bottomList, topList: RouteChannel.ChanPinList ← NIL];
ChanPinListPair: TYPE = RECORD [
list1, list2: RouteChannel.ChanPinList ← NIL];
TestPins: TYPE = REF TestPinsRec;
TestPinsRec: TYPE = RECORD [
trialPin, leftExitPin, rightExitPin: RouteChannel.ChanPin ← NIL];
GenerateConstraints: PUBLIC PROC [chanData: RouteChannel.ChannelData,
parms: RoutePrivate.RoutingAreaParms,
rules: Route.DesignRules,
routerUsed: RoutePrivate.RouterUsed]
RETURNS [anythingToDo: BOOLEAN] ~ {
run through the pins on the channel,
create segment constraints from the pin to pin relationships
return if no pins
chanPins: RouteChannel.RoutingChannelPins ← chanData.chanPins;
graphName: Rope.ROPE ← "Vertical Constraints";
segBroken: BOOLEANTRUE;
trialPinPosition: RouteChannel.PinPosition ← NEW[RouteChannel.PinPositionRec ← [pinIndex: 0, pLoc: 0]];
trialPin: RouteChannel.ChanPin ← NEW[RouteChannel.ChanPinRec ← [pinSide: none, qLoc: 0, pWidth: 0, kindOfPin: dogLeg, pinPosition: trialPinPosition]];
leftExitPosition: RouteChannel.PinPosition ← NEW[RouteChannel.PinPositionRec ← [pinIndex: 0, pLoc: chanPins.cEnd1]];
leftExitPin: RouteChannel.ChanPin ← NEW[RouteChannel.ChanPinRec ← [pinSide: none, qLoc: 0, pWidth: 0, kindOfPin: exitPin, pinPosition: leftExitPosition]];
rightExitPosition: RouteChannel.PinPosition ← NEW[RouteChannel.PinPositionRec ← [pinIndex: 0, pLoc: chanPins.cEnd2]];
rightExitPin: RouteChannel.ChanPin ← NEW[RouteChannel.ChanPinRec ← [pinSide: none, qLoc: 0, pWidth: 0, kindOfPin: exitPin, pinPosition: rightExitPosition]];
pins: TestPins ← NEW[TestPinsRec ← [trialPin, leftExitPin, rightExitPin]];
IF chanPins.count = 0 THEN RETURN[FALSE];
WHILE segBroken DO
outer loop can be removed whe constraints by seg is added
segBroken ← FALSE;
IF chanData.constraints # NIL THEN DestroyOldConstraints[chanData]; -- unlink the old graph
chanData.constraints ← RouteDiGraph.CreateGraph[graphName];
FOR index: RouteChannel.MPinsOnCh IN [1 .. chanPins.count] DO
WidestPinProc: RouteChannel.EachPinActionProc = {
IF pin # NIL THEN
widestPinD2 ← MAX[widestPinD2, RouteUtil.GetWidthWithContact[rules, pin.pWidth]/2]};
LimitProc: RouteChannel.EachPinActionProc = {
IF pin # NIL THEN
{width: DABasics.Number ← RouteUtil.GetWidthWithContact[rules, pin.pWidth]/2;
pinPos: DABasics.Number ← pin.pinPosition.pLoc;
IF pinPos = pLoc THEN
quit ← TRUE
ELSE IF pinPos < pLoc THEN
quit ← pinPos + width + rules.branchSpacing > pLoc - widestPinD2
ELSE -- pinPos >= pLoc
quit ← pLoc + widestPinD2 + rules.branchSpacing > pinPos - width}};
pinPosition: RouteChannel.PinPosition ← chanPins.sides[index];
testPin: RouteChannel.ChanPin ← pinPosition.pins[chanBottom];
pLoc: DABasics.Number ← pinPosition.pLoc;
widestPinD2: DABasics.Number ← RouteUtil.GetWidthWithContact[rules, rules.branchWidth]/2;
minLimit, maxLimit: RouteChannel.MPinsOnCh;
generate constraints for this coordinate, if any
[] ← RouteChannel.EnumPins[pinPosition, WidestPinProc];
[minLimit, maxLimit] ← RouteChannel.FindConstraintLimits[chanPins, parms, rules, index, index, LimitProc];
FOR upperIndex: RouteChannel.MPinsOnCh IN [minLimit .. maxLimit] DO
upperPinPosition: RouteChannel.PinPosition ← chanPins.sides[upperIndex];
upperPin: RouteChannel.ChanPin ← upperPinPosition.pins[chanTop];
lowerPin: RouteChannel.ChanPin ← upperPinPosition.pins[chanBottom];
IF ProcessConstraints[chanData, parms, rules, upperPin, testPin, middle, pins] THEN GOTO GoRound;
now do constraints for doglegs and exits wrt the upper pins
FOR innerPins: RouteChannel.ChanPinList ← pinPosition.innerPins, innerPins.rest WHILE innerPins # NIL DO
innerPin: RouteChannel.ChanPin ← innerPins.first;
first the upper pin, if any
IF ProcessConstraints[chanData, parms, rules, upperPin, innerPin, middle, pins] THEN GOTO GoRound;
IF ProcessConstraints[chanData, parms, rules, innerPin, lowerPin, middle, pins] THEN GOTO GoRound;
ENDLOOP; -- FOR innerPins
ENDLOOP; -- FOR upperIndex
do the exits wrt each other if this is a switchBox and a channel end
IF routerUsed = switchBox AND (index = 1 OR index = chanPins.count) THEN {
QPinCompare: List.CompareProc = {
p1: DABasics.Number ← NARROW[ref1, RouteChannel.ChanPin].qLoc;
p2: DABasics.Number ← NARROW[ref2, RouteChannel.ChanPin].qLoc;
RETURN[IF p1 < p2 THEN Basics.Comparison.less
ELSE IF p1 = p2 THEN Basics.Comparison.equal
ELSE Basics.Comparison.greater]};
whichEnd: Lmr ← IF index = 1 THEN left ELSE right;
mungedPinList: List.LORA ← ConvertToLORA[pinPosition.innerPins];
sortedPinList: List.LORA ← List.Sort[mungedPinList, QPinCompare];
FOR pList: List.LORA -- RouteChannel.ChanPinList -- ← sortedPinList, pList.rest WHILE pList # NIL DO
lowerPin: RouteChannel.ChanPin ← NARROW[pList.first];
sList: RouteChannel.SegmentList ← RouteChannel.GetSegsOnPin[lowerPin];
process pin to pin constraints
IF pList.rest # NIL THEN {
upperPin: RouteChannel.ChanPin ← NARROW[pList.rest.first];
IF ProcessConstraints[chanData, parms, rules, upperPin, lowerPin, whichEnd, pins] THEN GOTO GoRound};
break any segments that must be in 2 tracks
FOR segs: RouteChannel.SegmentList ← sList, segs.rest WHILE segs # NIL DO
seg: RouteChannel.Segment ← segs.first;
IF seg.trackConstraint # 0 AND seg.secTrackConstraint # 0 AND seg.trackConstraint # seg.secTrackConstraint AND ~seg.failed THEN {
break: FullSegBreakSpec ← BreakOneSeg[chanData, parms, rules, seg, NIL, whichEnd, pins];
IF BreaksFound[break] > 0 THEN {
DoBreak[chanData, parms, break]; GOTO GoRound}
ELSE { -- mark seg as failed --
seg.failed ← TRUE;
Route.Signal[noResource, Rope.Cat["\nunable to find a place to dogleg, net: ", seg.net.name, " failed"]]}};
IF index = chanPins.count THEN {
Must resolve constraints accross the ends of the switchbox. If there is a constraint from a segment on one end to a segment on the other, it must be resolved.
leftPinPosition: RouteChannel.PinPosition ← chanPins.sides[1];
leftPinList: RouteChannel.ChanPinList ← leftPinPosition.innerPins;
these are the pins on the left side of the channel
FOR lPList: RouteChannel.ChanPinList ← leftPinList, lPList.rest WHILE lPList # NIL DO
leftPin: RouteChannel.ChanPin ← NARROW[lPList.first];
lSList: RouteChannel.SegmentList ← RouteChannel.GetSegsOnPin[leftPin];
these are the segments on the left pin
FOR lSegs: RouteChannel.SegmentList ← lSList, lSegs.rest WHILE lSegs # NIL DO
graph: RouteDiGraph.Graph ← chanData.constraints;
leftSeg: RouteChannel.Segment ← lSegs.first;
leftSegNode: RouteDiGraph.Node ← leftSeg.constraintNode;
rightSegNode: RouteDiGraph.Node ← seg.constraintNode;
leftToRightSegList: RouteChannel.SegmentList ← SegsInCycle[graph, leftSegNode, rightSegNode];
rightToLeftSegList: RouteChannel.SegmentList;
IF leftToRightSegList # NIL THEN
choose a segment to break and the position to dogleg
{density: RouteChannel.Density ← RouteChannel.ComputeDensity[chanPins, rules];
segBreak: FullSegBreakSpec ← FindBreak[chanData, parms, rules, leftToRightSegList, density, whichEnd, pins];
IF BreaksFound[segBreak] > 0 THEN DoBreak[chanData, parms, segBreak]
ELSE { -- choose a victim --
lSegs.first.failed ← TRUE;
Route.Signal[noResource, Rope.Cat["\nnet: ", lSegs.first.net.name, " failed, unable to find a place to dogleg"]]};
segBroken ← TRUE; GOTO GoRound};
rightToLeftSegList ← SegsInCycle[graph, rightSegNode, leftSegNode];
IF rightToLeftSegList # NIL THEN
choose a segment to break and the position to dogleg
{density: RouteChannel.Density ← RouteChannel.ComputeDensity[chanPins, rules];
segBreak: FullSegBreakSpec ← FindBreak[chanData, parms, rules, rightToLeftSegList, density, whichEnd, pins];
IF BreaksFound[segBreak] > 0 THEN DoBreak[chanData, parms, segBreak]
ELSE { -- choose a victim --
lSegs.first.failed ← TRUE;
Route.Signal[noResource, Rope.Cat["\nnet: ", lSegs.first.net.name, " failed, unable to find a place to dogleg"]]};
segBroken ← TRUE; GOTO GoRound};
next check if the external segments are in the same track, they overlap, and they are in different nets
IF seg.trackConstraint = leftSeg.trackConstraint AND RTBasic.Overlaps[RouteChannel.SegRange[seg], RouteChannel.SegRange[leftSeg]] AND seg.net # leftSeg.net THEN
choose a segment to break and the position to dogleg
{density: RouteChannel.Density ← RouteChannel.ComputeDensity[chanPins, rules];
segBreak: FullSegBreakSpec ← FindBreak[chanData, parms, rules, LIST[seg, leftSeg], density, whichEnd, pins];
IF BreaksFound[segBreak] > 0 THEN DoBreak[chanData, parms, segBreak]
ELSE { -- choose a victim --
seg.failed ← TRUE;
Route.Signal[noResource, Rope.Cat["\nnet: ", seg.net.name, " failed, unable to find a place to dogleg"]]};
segBroken ← TRUE; GOTO GoRound};
ENDLOOP;
ENDLOOP;
};
ENDLOOP;
ENDLOOP};
REPEAT GoRound => segBroken ← TRUE;
ENDLOOP; -- WHILE index
ENDLOOP; -- WHILE segBroken
RETURN[TRUE]}; -- GenerateConstraints
DestroyOldConstraints: PUBLIC PROC [chanData: RouteChannel.ChannelData] = {
must explicitly destroy the old data
chanPins: RouteChannel.RoutingChannelPins ← chanData.chanPins;
DestroyGraph: RouteDiGraph.EnumGraphProc = {NULL};
DestroyArc: RouteDiGraph.EnumArcProc = {NULL};
DestroyNode: RouteDiGraph.EnumNodeProc = {
nodeInfo: RouteChannel.SegmentConstraint ← NARROW[node.nodeInfo];
nodeInfo.segment ← NIL};
ClearConstraints: RouteChannel.EachPinActionProc = {
leftSeg: RouteChannel.Segment ← pin.conctSeg[chanLeft];
rightSeg: RouteChannel.Segment ← pin.conctSeg[chanRight];
IF leftSeg # NIL THEN leftSeg.constraintNode ← NIL;
IF rightSeg # NIL THEN rightSeg.constraintNode ← NIL};
FOR index: RouteChannel.MPinsOnCh IN [1 .. chanPins.count] DO
pinPosition: RouteChannel.PinPosition ← chanPins.sides[index];
[] ← RouteChannel.EnumPins[pinPosition, ClearConstraints];
ENDLOOP;
RouteDiGraph.DestroyGraph[chanData.constraints, DestroyGraph, DestroyNode, DestroyArc]};
ProcessConstraints: PROC [chanData: RouteChannel.ChannelData, parms: RoutePrivate.RoutingAreaParms, rules: Route.DesignRules, upperPin, lowerPin: RouteChannel.ChanPin, whichEnd: Lmr, pins: TestPins] RETURNS [segBroken: BOOLEANFALSE] = {
add a segment constraint if it does not create a loop
do upper to lower pin constraint
IF upperPin # NIL AND lowerPin # NIL THEN
IF upperPin.kindOfPin # noPin AND lowerPin.kindOfPin # noPin THEN
IF (upperPin.kindOfPin # exitPin AND lowerPin.kindOfPin # exitPin) OR (whichEnd # middle AND upperPin.kindOfPin = exitPin AND lowerPin.kindOfPin = exitPin) THEN
IF Constraining[rules, upperPin, lowerPin] THEN
generate pin to pin constraints, process all segments attached to these pins
FOR lowerSegIndex: RouteChannel.ChanLRSide IN [chanLeft .. chanRight] WHILE ~segBroken DO
FOR upperSegIndex: RouteChannel.ChanLRSide IN [chanLeft .. chanRight] WHILE ~segBroken DO
lowerSeg: RouteChannel.Segment ← lowerPin.conctSeg[lowerSegIndex];
upperSeg: RouteChannel.Segment ← upperPin.conctSeg[upperSegIndex];
lowerAltSeg: RouteChannel.Segment ← lowerPin.altConctSeg[lowerSegIndex];
upperAltSeg: RouteChannel.Segment ← upperPin.altConctSeg[upperSegIndex];
IF HackedDoConstraint[chanData, parms, rules, lowerSeg, upperSeg, whichEnd, pins] THEN segBroken ← TRUE;
IF HackedDoConstraint[chanData, parms, rules, lowerSeg, upperAltSeg, whichEnd, pins] THEN segBroken ← TRUE;
IF HackedDoConstraint[chanData, parms, rules, lowerAltSeg, upperSeg, whichEnd, pins] THEN segBroken ← TRUE;
IF HackedDoConstraint[chanData, parms, rules, lowerAltSeg, upperAltSeg, whichEnd, pins] THEN segBroken ← TRUE;
ENDLOOP; -- FOR upperSegIndex
ENDLOOP; -- FOR lowerSegIndex
};
Constraining: PROC [rules: Route.DesignRules, pin1, pin2: RouteChannel.ChanPin] RETURNS [constraining: BOOLEANFALSE] = {
determining if pin1 actually constrains pin2
IF pin1 # NIL AND pin2 # NIL THEN
{p1: DABasics.Number ← pin1.pinPosition.pLoc;
w1WContact: DABasics.Number ← RouteUtil.GetWidthWithContact[rules, pin1.pWidth]/2;
w1: DABasics.Number ← pin1.pWidth/2;
p2: DABasics.Number ← pin2.pinPosition.pLoc;
w2WContact: DABasics.Number ← RouteUtil.GetWidthWithContact[rules, pin2.pWidth]/2;
w2: DABasics.Number ← pin2.pWidth/2;
IF p1 = p2 THEN
constraining ← TRUE
ELSE IF p1 < p2 THEN
constraining ← (p1 + w1WContact + rules.branchSpacing > p2 - w2)
OR (p1 + w1 + rules.branchSpacing > p2 - w2WContact)
ELSE -- p1 > p2
constraining ← (p2 + w2WContact + rules.branchSpacing > p1 - w1)
OR (p2 + w2 + rules.branchSpacing > p1 - w1WContact)}};
DoConstraint: PROC [chanData: RouteChannel.ChannelData, parms: RoutePrivate.RoutingAreaParms, rules: Route.DesignRules, lowerSeg, upperSeg: RouteChannel.Segment, whichEnd: Lmr, pins: TestPins] RETURNS [segBroken: BOOLEANFALSE] = {
add a segment constraint if it does not create a loop
IF lowerSeg # NIL AND upperSeg # NIL AND lowerSeg # upperSeg THEN
IF ~lowerSeg.failed AND ~upperSeg.failed AND lowerSeg.net.num # upperSeg.net.num THEN {
segList: RouteChannel.SegmentList;
chanPins: RouteChannel.RoutingChannelPins ← chanData.chanPins;
graph: RouteDiGraph.Graph ← chanData.constraints;
lowerNode: RouteDiGraph.Node ← lowerSeg.constraintNode;
upperNode: RouteDiGraph.Node ← upperSeg.constraintNode;
IF lowerNode = NIL THEN
{constraint: RouteChannel.SegmentConstraint ← NEW[RouteChannel.SegmentConstraintRec ← [lowerSeg.net.name, lowerSeg]];
lowerNode ← RouteDiGraph.AddNewNode[graph, constraint];
lowerSeg.constraintNode ← lowerNode};
IF upperNode = NIL THEN
{constraint: RouteChannel.SegmentConstraint ← NEW[RouteChannel.SegmentConstraintRec ← [upperSeg.net.name, upperSeg]];
upperNode ← RouteDiGraph.AddNewNode[graph, constraint];
upperSeg.constraintNode ← upperNode};
segList ← SegsInCycle[graph, lowerNode, upperNode];
IF segList # NIL THEN {
choose a segment to break and the position to dogleg
density: RouteChannel.Density ← RouteChannel.ComputeDensity[chanPins, rules];
segBreak: FullSegBreakSpec ← FindBreak[chanData, parms, rules, segList, density, whichEnd, pins];
IF BreaksFound[segBreak] > 0 THEN DoBreak[chanData, parms, segBreak]
ELSE { -- choose a victim --
segList.first.failed ← TRUE;
Route.Signal[noResource, Rope.Cat["net: ", segList.first.net.name, " failed, unable to find a place to dogleg"]]};
segBroken ← TRUE}
ELSE { -- add a segment constraint
need to change so I don't add duplicate constraints
constrain Upper above Lower
IF ~RouteDiGraph.PathExists[graph, upperNode, lowerNode] THEN
arcName: Rope.ROPE ← Rope.Cat[upperSeg.net.name,"-above-", lowerSeg.net.name];
[] ← RouteDiGraph.AddNewArc[graph, NIL, upperNode, lowerNode]}}};
SegsInCycle: PROCEDURE[graph: RouteDiGraph.Graph, lowerNode, upperNode: RouteDiGraph.Node]
RETURNS [segList: RouteChannel.SegmentList ← NIL] = {
recursively go through the constraints
ArcProc: RouteDiGraph.EnumArcsFromNodeProc = {
-- PROC[graph: Graph, arc: Arc, node: Node, direction: Direction] RETURNS [quit: BOOLEANFALSE];
IF arc.inferiorNode = upperNode THEN
{nodeInfo: RouteChannel.SegmentConstraint ← NARROW[upperNode.nodeInfo];
segList ← CONS[nodeInfo.segment, segList];
quit ← TRUE}
ELSE {
IF ~List.Memb[arc.inferiorNode, visitedNodes] THEN {
visitedNodes ← CONS[arc.inferiorNode, visitedNodes];
quit ← RouteDiGraph.EnumArcsFromNode[graph, arc.inferiorNode, in, ArcProc]}};
IF quit THEN
{nodeInfo: RouteChannel.SegmentConstraint ← NARROW[node.nodeInfo];
segList ← CONS[nodeInfo.segment, segList]}};
visitedNodes: RouteDiGraph.ArcList ← NIL;
[] ← RouteDiGraph.EnumArcsFromNode[graph, lowerNode, in, ArcProc]};
PrintSegs: PROC [
segList: RouteChannel.SegmentList] = {
print segments on list
FOR segs: RouteChannel.SegmentList ← segList, segs.rest WHILE segs # NIL DO
seg: RouteChannel.Segment ← segs.first;
range: RTBasic.Range ← RouteChannel.SegRange[seg];
TerminalIO.PutF["\n\tnet: %g at %g , %g ( %g, %g )", IO.rope[seg.net.name], IO.int[range.l], IO.int[range.r], IO.int[range.l/8], IO.int[range.r/8]];
ENDLOOP};
FindBreak: PROC [chanData: RouteChannel.ChannelData,
parms: RoutePrivate.RoutingAreaParms,
rules: Route.DesignRules,
segList: RouteChannel.SegmentList,
density: RouteChannel.Density,
whichEnd: Lmr,
pins: TestPins] RETURNS [bestBreak: FullSegBreakSpec ← [NIL, [NIL, NIL, NIL]]] = {
decide on which segment to divide and the position
chanPins: RouteChannel.RoutingChannelPins ← chanData.chanPins;
bestResult: BreakResult ← [LAST[INT], LAST[INT], LAST[INT], LAST[INT]];
run through the segs in the cycle. find the best
TerminalIO.PutRope["\nSegements in Cycle:"];
FOR segs: RouteChannel.SegmentList ← segList, segs.rest WHILE segs # NIL DO
seg: RouteChannel.Segment ← segs.first;
break: FullSegBreakSpec ← BreakOneSeg[chanData, parms, rules, seg, density, whichEnd, pins];
result: BreakResult ← EvalBreak[chanPins, parms, break, density];
range: RTBasic.Range ← RouteChannel.SegRange[seg];
TerminalIO.PutF["\n\tnet: %g at %g , %g ( %g, %g )", IO.rope[seg.net.name], IO.int[range.l], IO.int[range.r], IO.int[range.l/8], IO.int[range.r/8]];
TerminalIO.PutF["\n\t\tdeltaDensity: %g duplicateLength: %g numDogLegs: %g , chainLength: %g", IO.int[result.deltaDensity], IO.int[result.duplicateLength], IO.int[result.numDogLegs], IO.int[result.chainLength]];
-- try breaks at ALL places as an experiment
IF BreaksFound[break] > 0 THEN HackedDoBreak[chanData, parms, rules, break];
IF CompareResult[result, bestResult] = less THEN
{bestResult ← result; bestBreak ← break};
ENDLOOP;
IF bestBreak.seg = NIL THEN RETURN[[NIL, [NIL, NIL, NIL]]]};
BreakOneSeg: PROC [chanData: RouteChannel.ChannelData,
parms: RoutePrivate.RoutingAreaParms,
rules: Route.DesignRules,
seg: RouteChannel.Segment,
density: RouteChannel.Density,
whichEnd: Lmr,
pins: TestPins]
RETURNS [break: FullSegBreakSpec] = {
find the best position to break this seg
chanPins: RouteChannel.RoutingChannelPins ← chanData.chanPins;
exitsSeparate: BOOLEANIF parms.routerUsed = channel THEN FALSE ELSE TRUE;
pinLists: ChanPinListSet ← GetPins[exitsSeparate, seg];
rangeList: RangeWithDirList ← SegRanges[chanPins, pinLists];
break ← [seg, [NIL, NIL, NIL]];
IF ~HasDogleg[seg] THEN {
SELECT parms.routerUsed FROM
channel => {
FOR ranges: RangeWithDirList ← rangeList, ranges.rest WHILE ranges # NIL DO
break.breaks[middle] ← HackedBreakWithInRange[chanData, parms, rules, seg, ranges.first, pins];
IF break.breaks[middle] # NIL THEN EXIT;
ENDLOOP;
IF break.breaks[middle] = NIL AND seg.net.mayExit THEN
break.breaks[middle] ← BreakAtExit[chanPins, parms, seg, density]};
switchBox => {
DoMiddle: PROC [] ~ {
IF top AND bottom AND BreaksFound[break] = 0 THEN {
FOR ranges: RangeWithDirList ← rangeList, ranges.rest WHILE ranges # NIL DO
break.breaks[middle] ← BreakWithInRange[chanData, parms, rules, seg, ranges.first, pins];
IF break.breaks[middle] # NIL THEN EXIT;
ENDLOOP;
};
};
DoLeft: PROC [] ~ {
IF left AND (top OR right OR bottom) AND BreaksFound[break] = 0 THEN {
leftRange: RangeWithDir ← [[cEnd1, cEnd2], leftToRight];
break.breaks[left] ← BreakWithInRange[chanData, parms, rules, seg, leftRange, pins];
};
};
DoRight: PROC [] ~ {
IF right AND (top OR left OR bottom) AND BreaksFound[break] = 0 THEN {
rightRange: RangeWithDir ← [[cEnd1, cEnd2], rightToLeft];
break.breaks[right] ← BreakWithInRange[chanData, parms, rules, seg, rightRange, pins];
};
};
cEnd1: DABasics.Number ← chanPins.cEnd1;
cEnd2: DABasics.Number ← chanPins.cEnd2;
left, top, right, bottom: BOOLEAN;
[left, top, right, bottom] ← RouteChannel.PinsOnSide[seg];
SELECT TRUE FROM
whichEnd = left => {DoLeft; DoRight; DoMiddle};
whichEnd = right => {DoRight; DoLeft; DoMiddle};
seg.trackConstraint # 0 => {DoRight; DoLeft; DoMiddle};
ENDCASE => {DoMiddle; DoRight; DoLeft}};
ENDCASE => Route.Error[programmingError, "Invalid router being used."]
}};
HasDogleg: PROC [seg: RouteChannel.Segment] RETURNS [hasDogleg: BOOLEANFALSE] ~ {
returns TRUE if seg has a dogleg
EachPin: RouteChannel.EachPinActionProc ~ {
PROC[pinPosition: PinPosition, pin: ChanPin] RETURNS [quit: BOOLEANFALSE];
IF pin.kindOfPin = dogLeg THEN quit ← TRUE};
hasDogleg ← RouteChannel.EnumPinsOnSeg[seg, EachPin]};
BreakWithInRange: PROC [chanData: RouteChannel.ChannelData,
parms: RoutePrivate.RoutingAreaParms,
rules: Route.DesignRules,
seg: RouteChannel.Segment,
range: RangeWithDir,
pins: TestPins]
RETURNS [break: SegBreakSpec ← NIL] = {
find the best position to break this seg within this range
WidestPinProc: RouteChannel.EachPinActionProc = {
IF pin # NIL THEN
widestPinD2 ← MAX[widestPinD2, RouteUtil.GetWidthWithContact[rules, pin.pWidth]/2]};
NextPosToRight: PROC [pinIndex: RouteChannel.ZMPinsOnCh] RETURNS[pos: DABasics.Number] ~ {
IF pinIndex = 0 THEN
pos ← chanPins.cEnd1 + rules.branchSpacing + seg.net.branchWidth
ELSE IF pinIndex >= chanPins.count+1 THEN
pos ← LAST[INT]
ELSE {
pinPosition: RouteChannel.PinPosition ← chanPins.sides[pinIndex];
widestPinD2 ← minPinD2;
[] ← RouteChannel.EnumPins[pinPosition, WidestPinProc];
pos ← pinPosition.pLoc + widestPinD2 + rules.branchSpacing + RouteUtil.GetWidthWithContact[rules, seg.net.branchWidth]/2}};
NextPosToLeft: PROC [pinIndex: RouteChannel.ZMPinsOnCh] RETURNS[pos: DABasics.Number] ~ {
IF pinIndex <= 0 THEN
pos ← FIRST[INT]
ELSE IF pinIndex = chanPins.count THEN
pos ← chanPins.cEnd2 - rules.branchSpacing - seg.net.branchWidth
ELSE {
pinPosition: RouteChannel.PinPosition ← chanPins.sides[pinIndex];
widestPinD2 ← minPinD2;
[] ← RouteChannel.EnumPins[pinPosition, WidestPinProc];
pos ← pinPosition.pLoc - widestPinD2 - rules.branchSpacing - RouteUtil.GetWidthWithContact[rules, seg.net.branchWidth]/2}};
minPinD2: DABasics.Number ← RouteUtil.GetWidthWithContact[routingArea, routingArea.rules.branchWidth]/2;
chanPins: RouteChannel.RoutingChannelPins ← chanData.chanPins;
minPinD2: DABasics.Number ← rules.branchWidth/2;
widestPinD2: DABasics.Number;
SELECT range.dir FROM
leftToRight => {
nextLower: RouteChannel.ZMPinsOnCh ← ClosestPins[chanPins, range.range.l].nextLower;
IF ~DogLegNotAllowed[chanPins, parms, rules, seg, range.range.l, pins] THEN
break ← NEW[SegBreakSpecRec ← [range.range.l, dogLeg]];
FOR pos: DABasics.Number ← NextPosToRight[nextLower], NextPosToRight[nextLower] WHILE pos <= range.range.r AND break = NIL DO
IF ~DogLegNotAllowed[chanPins, parms, rules, seg, pos, pins] THEN
break ← NEW[SegBreakSpecRec ← [pos, dogLeg]];
nextLower ← MIN[chanPins.count+1, nextLower + 1];
ENDLOOP};
rightToLeft => {
nextHigher: RouteChannel.ZMPinsOnCh ← ClosestPins[chanPins, range.range.r].nextHigher;
IF ~DogLegNotAllowed[chanPins, parms, rules, seg, range.range.r, pins] THEN
break ← NEW[SegBreakSpecRec ← [range.range.r, dogLeg]];
FOR pos: DABasics.Number ← NextPosToLeft[nextHigher], NextPosToLeft[nextHigher] WHILE pos >= range.range.l AND break = NIL DO
IF ~DogLegNotAllowed[chanPins, parms, rules, seg, pos, pins] THEN
break ← NEW[SegBreakSpecRec ← [pos, dogLeg]];
nextHigher ← MAX[0, nextHigher - 1];
ENDLOOP};
ENDCASE};
DogLegNotAllowed: PROC [chanPins: RouteChannel.RoutingChannelPins,
parms: RoutePrivate.RoutingAreaParms,
rules: Route.DesignRules,
seg: RouteChannel.Segment,
pos: DABasics.Number,
pins: TestPins]
RETURNS [notAllowed: BOOLEANFALSE] = {
see if a dogleg is allowed here
FindConnectedNet: PROC [pin: RouteChannel.ChanPin] RETURNS [net: RoutePrivate.Net ← NIL] =
{IF pin # NIL THEN
{s1: RouteChannel.Segment ← pin.conctSeg[chanLeft];
s2: RouteChannel.Segment ← pin.conctSeg[chanRight];
IF s1 # NIL THEN net ← s1.net
ELSE IF s2 # NIL THEN net ← s2.net
ELSE Route.Error[programmingError, "Pin not connected to a segment."]}};
CheckInner: RouteChannel.EachPinActionProc = {
IF pin # NIL THEN
IF pin.kindOfPin = exitPin OR pin.kindOfPin = dogLeg THEN
IF Constraining[rules, pin, pins.trialPin] THEN quit ← TRUE};
OuterConstraints: RouteChannel.EachPinActionProc = {
IF pin # NIL THEN
IF pin.kindOfPin = chanConnect OR pin.kindOfPin = compPin THEN
IF Constraining[rules, pin, pins.trialPin] THEN quit ← TRUE};
minLimit, maxLimit, leftIndex, rightIndex: RouteChannel.ZMPinsOnCh;
width: DABasics.Number ← MAX[seg.net.trunkWidth, seg.net.branchWidth];
pins.trialPin.pinPosition.pLoc ← pos;
pins.trialPin.pWidth ← width;
pins.leftExitPin.pWidth ← width;
pins.rightExitPin.pWidth ← width;
[leftIndex, rightIndex] ← ClosestPins[chanPins, pos];
must reserve place for future exits
IF Constraining[rules, pins.trialPin, pins.leftExitPin] THEN notAllowed ← TRUE;
IF Constraining[rules, pins.trialPin, pins.rightExitPin] THEN notAllowed ← TRUE;
see if inner pins interfere
[minLimit, maxLimit] ← RouteChannel.FindConstraintLimits[chanPins, parms, rules, leftIndex, rightIndex, CheckInner];
FOR index: RouteChannel.MPinsOnCh IN [minLimit .. maxLimit] WHILE ~notAllowed DO
see if there are existing dog legs
pinPosition: RouteChannel.PinPosition ← chanPins.sides[index];
notAllowed ← RouteChannel.EnumPins[pinPosition, CheckInner];
ENDLOOP;
see if outer pins interfere
[minLimit, maxLimit] ← RouteChannel.FindConstraintLimits[chanPins, parms, rules, leftIndex, rightIndex, OuterConstraints];
FOR index: RouteChannel.MPinsOnCh IN [minLimit .. maxLimit] WHILE ~notAllowed DO
pinPosition: RouteChannel.PinPosition ← chanPins.sides[index];
bottomPin: RouteChannel.ChanPin ← pinPosition.pins[chanBottom];
topPin: RouteChannel.ChanPin ← pinPosition.pins[chanTop];
bottomNet: RoutePrivate.Net ← FindConnectedNet[bottomPin];
topNet: RoutePrivate.Net ← FindConnectedNet[topPin];
constrainTop: BOOLEAN ← Constraining[rules, topPin, pins.trialPin];
constrainBottom: BOOLEAN ← Constraining[rules, bottomPin, pins.trialPin];
see if any nets within th range cross the channels
FOR i: RouteChannel.MPinsOnCh IN [minLimit .. maxLimit] WHILE ~notAllowed DO
pP: RouteChannel.PinPosition ← chanPins.sides[i];
bP: RouteChannel.ChanPin ← pP.pins[chanBottom];
tP: RouteChannel.ChanPin ← pP.pins[chanTop];
bN: RoutePrivate.Net ← FindConnectedNet[bP];
tN: RoutePrivate.Net ← FindConnectedNet[tP];
IF bottomNet = tN AND Constraining[rules, topPin, bP] AND constrainTop AND constrainBottom THEN notAllowed ← TRUE;
IF topNet = bN AND Constraining[rules, bottomPin, tP] AND constrainTop AND constrainBottom THEN notAllowed ← TRUE;
ENDLOOP;
see if a constraint loop is created
later -- for now dont use pin positions that could cause constraint loops
IF constrainTop OR constrainBottom THEN notAllowed ← TRUE;
ENDLOOP};
BreakAtExit: PROC [chanPins: RouteChannel.RoutingChannelPins, parms: RoutePrivate.RoutingAreaParms, seg: RouteChannel.Segment, density: RouteChannel.Density] RETURNS [break: SegBreakSpec] = {
find the best exit to break this seg
leftBreak: SegBreakSpec ← NEW[SegBreakSpecRec ← [chanPins.cEnd1, exit]];
leftFullBreak: FullSegBreakSpec ← [seg, [leftBreak, NIL, NIL]];
rightBreak: SegBreakSpec ← NEW[SegBreakSpecRec ← [chanPins.cEnd2, exit]];
rightFullBreak: FullSegBreakSpec ← [seg, [NIL, NIL, rightBreak]];
leftResult: BreakResult ← EvalBreak[chanPins, parms, leftFullBreak, density];
rightResult: BreakResult ← EvalBreak[chanPins, parms, rightFullBreak, density];
IF CompareResult[leftResult, rightResult] = less THEN RETURN [leftBreak]
ELSE RETURN [rightBreak]};
EvalBreak: PROC [chanPins: RouteChannel.RoutingChannelPins, parms: RoutePrivate.RoutingAreaParms, break: FullSegBreakSpec, density: RouteChannel.Density] RETURNS [result: BreakResult] = {
evaluate the break of ths seg at break
maxDensity: DABasics.Number;
lowerRange, upperRange, overlap: RTBasic.Range;
exitsSeparate: BOOLEANIF parms.routerUsed = channel THEN FALSE ELSE TRUE;
pinLists: ChanPinListSet ← GetPins[exitsSeparate, break.seg];
chain: INTLAST[INT];
IF BreaksFound[break] = 0 THEN RETURN[[LAST[INT], LAST[INT], LAST[INT], LAST[INT]]];
IF break.breaks[middle] # NIL THEN {
lowerRange ← RTBasic.Span[[break.breaks[middle].pos, break.breaks[middle].pos], RouteChannel.GetRange[pinLists.bottomList]];
upperRange ← RTBasic.Span[[break.breaks[middle].pos, break.breaks[middle].pos], RouteChannel.GetRange[pinLists.topList]];
overlap ← RTBasic.Overlap[lowerRange, upperRange];
IF overlap.l > overlap.r THEN Route.Error[programmingError, "overlap should not be NIL."];
chain ← break.breaks[middle].chainLength}
ELSE overlap ← [0,0];
maxDensity ← AddSeg[chanPins, density, overlap, break.seg.qWidth];
result.deltaDensity ← maxDensity - density.maxDensity;
result.duplicateLength ← overlap.r - overlap.l;
result.numDogLegs ← 0;
result.chainLength ← chain;
FOR lmr: Lmr IN Lmr DO
IF break.breaks[lmr] # NIL THEN result.numDogLegs ← result.numDogLegs + 1;
ENDLOOP};
DoBreak: PROC [chanData: RouteChannel.ChannelData, parms: RoutePrivate.RoutingAreaParms, fullSegBreak: FullSegBreakSpec] = {
break the segment at position:
add pin position at fullSegBreak.breaks[mumble].pos
unlink segBreak
create 2 new segments
link in the pins
UnlinkSegFromPins: RouteChannel.EachPinActionProc ~ {
IF pin.conctSeg[chanLeft] = oldSeg THEN pin.conctSeg[chanLeft] ← NIL;
IF pin.conctSeg[chanRight] = oldSeg THEN pin.conctSeg[chanRight] ← NIL;
IF pin.altConctSeg[chanLeft] = oldSeg THEN pin.altConctSeg[chanLeft] ← NIL;
IF pin.altConctSeg[chanRight] = oldSeg THEN pin.altConctSeg[chanRight] ← NIL;
};
chanPins: RouteChannel.RoutingChannelPins ← chanData.chanPins;
oldSeg: RouteChannel.Segment ← fullSegBreak.seg;
branchWidth: DABasics.Number ← oldSeg.net.branchWidth;
trunkWidth: DABasics.Number ← oldSeg.net.trunkWidth;
IF BreaksFound[fullSegBreak] # 1 THEN
Route.Error[programmingError, "Not suppose to happen"];
[] ← RouteChannel.EnumPinsOnSeg[oldSeg, UnlinkSegFromPins];
FOR lmr: Lmr IN Lmr DO
segBreak: SegBreakSpec ← fullSegBreak.breaks[lmr];
IF segBreak # NIL THEN {
pinIndex: RouteChannel.ZMPinsOnCh ← RouteChannel.FindPinPos[chanPins, segBreak.pos];
pinPosition: RouteChannel.PinPosition ← chanPins.sides[pinIndex];
upperPin, lowerPin: RouteChannel.ChanPin ← NIL;
pinListPair: ChanPinListPair;
seg1: RouteChannel.Segment ← NEW[RouteChannel.SegmentRec ← [net: oldSeg.net, qWidth: trunkWidth, exitBreak: oldSeg.exitBreak]];
seg2: RouteChannel.Segment ← NEW[RouteChannel.SegmentRec ← [net: oldSeg.net, qWidth: trunkWidth, exitBreak: oldSeg.exitBreak]];
SELECT segBreak.type FROM
dogLeg => {
exitsSeparate: BOOLEANIF parms.routerUsed = channel THEN FALSE ELSE TRUE;
pinLists: ChanPinListSet ← GetPins[exitsSeparate, oldSeg];
parms.widestPin ← MAX[branchWidth, parms.widestPin];
upperPin ← lowerPin ← NEW[RouteChannel.ChanPinRec ← [pinSide: none, qLoc: 0, pWidth: branchWidth, kindOfPin: dogLeg, pinPosition: pinPosition]];
pinPosition.innerPins ← CONS[upperPin, pinPosition.innerPins];
pinListPair ← DividePins[lmr, pinLists, lowerPin, upperPin]};
exit => {
pinSide: RouteChannel.ChanLRSide ←
IF segBreak.pos <= chanPins.cEnd1 THEN chanLeft
ELSE IF segBreak.pos >= chanPins.cEnd2 THEN chanRight
ELSE Route.Error[programmingError, "Invalid data. Call maintainer."];
pinLists: ChanPinListSet ← GetPins[TRUE, oldSeg];
seg1.exitBreak ← TRUE; seg1.part ← 1;
seg2.exitBreak ← TRUE; seg2.part ← 2;
upperPin ← NEW[RouteChannel.ChanPinRec ← [pinSide: pinSide, qLoc: 0, pWidth: 0, kindOfPin: exitPin, pinPosition: pinPosition]];
pinPosition.innerPins ← CONS[upperPin, pinPosition.innerPins];
if this segment already has an exit on this side, then use that one, otherwise make a new pin
lowerPin ← IF pinSide = chanRight THEN pinLists.rightExit ELSE pinLists.leftExit;
IF lowerPin = NIL THEN {
lowerPin ← NEW[RouteChannel.ChanPinRec ← [pinSide: pinSide, qLoc: 0, pWidth: 0, kindOfPin: exitPin, pinPosition: pinPosition]];
pinPosition.innerPins ← CONS[lowerPin, pinPosition.innerPins]}
ELSE {
};
pinListPair ← DividePins[lmr, pinLists, lowerPin, upperPin]};
ENDCASE;
LinkSegsToPins[seg1, pinListPair.list1, lowerPin];
LinkSegsToPins[seg2, pinListPair.list2, upperPin];
SetTrackConstraints[seg1, oldSeg.trackConstraint];
SetTrackConstraints[seg2, oldSeg.trackConstraint];
TerminalIO.PutRope[Rope.Cat["\ntrunk segment for net: ", fullSegBreak.seg.net.name, ]];
TerminalIO.PutF1[" divided at: %g", IO.int[chanPins.sides[pinIndex].pLoc/8]];
remove these statments for production
RouteChannel.AuditPins[chanPins]};
ENDLOOP;
};
DividePins: PROC [which: Lmr, pinLists: ChanPinListSet, pin1, pin2: RouteChannel.ChanPin] RETURNS [pinListPair: ChanPinListPair ← [NIL, NIL]] = {
SELECT which FROM
left => {
IF pinLists.leftExit = NIL THEN Route.Error[programmingError, "exit dogleg with no exit"];
pinListPair.list1 ← LIST[pin1, pinLists.leftExit];
pinListPair.list2 ← RouteChannel.Combine[pinLists.bottomList, pinLists.topList, LIST[pinLists.rightExit, pin2]]};
middle => {
pinListPair.list1 ← RouteChannel.Combine[LIST[pin1], pinLists.bottomList, NIL];
pinListPair.list2 ← RouteChannel.Combine[LIST[pin2], pinLists.topList, NIL];
pinListPair ← AddToClosestList[pinListPair, pinLists.leftExit];
pinListPair ← AddToClosestList[pinListPair, pinLists.rightExit]};
right => {
IF pinLists.rightExit = NIL THEN Route.Error[programmingError, "exit dogleg with no exit"];
pinListPair.list1 ← LIST[pin1, pinLists.rightExit];
pinListPair.list2 ← RouteChannel.Combine[pinLists.bottomList, pinLists.topList, LIST[pinLists.leftExit, pin2]]};
ENDCASE;
};
SetTrackConstraints: PROC [seg: RouteChannel.Segment, trackConstraint: DABasics.Number] = {
EachPin: RouteChannel.EachPinActionProc = {
IF pin # NIL THEN {
IF pin.trackConstraint # 0 THEN
seg.trackConstraint ← pin.trackConstraint;
};
};
[] ← RouteChannel.EnumPinsOnSeg[seg, EachPin];
};
AddToClosestList: PROC [pinListPair: ChanPinListPair, pin: RouteChannel.ChanPin] RETURNS [result: ChanPinListPair] ~ {
l1Range: RTBasic.Range ← RouteChannel.GetRange[pinListPair.list1];
l2Range: RTBasic.Range ← RouteChannel.GetRange[pinListPair.list2];
IF pin # NIL THEN {
pLoc: DABasics.Number ← pin.pinPosition.pLoc;
IF l1Range.l <= pLoc AND pLoc <= l1Range.r THEN RETURN[[CONS[pin, pinListPair.list1], pinListPair.list2]]
ELSE IF l2Range.l <= pLoc AND pLoc <= l2Range.r THEN RETURN[[pinListPair.list1, CONS[pin, pinListPair.list2]]]
ELSE {
distToL1: DABasics.Number ← MIN[ABS[pLoc - l1Range.l], ABS[pLoc - l1Range.r]];
distToL2: DABasics.Number ← MIN[ABS[pLoc - l2Range.l], ABS[pLoc - l2Range.r]];
IF distToL1 < distToL2 THEN RETURN[[CONS[pin, pinListPair.list1], pinListPair.list2]]
ELSE RETURN[[pinListPair.list1, CONS[pin, pinListPair.list2]]]}}
ELSE RETURN[pinListPair]};
LinkSegsToPins: PROC [seg: RouteChannel.Segment, pinList: RouteChannel.ChanPinList, newPin: RouteChannel.ChanPin] = {
link the segment to the pin in the list and vice versa
PinCompare: List.CompareProc = {
p1: DABasics.Number ← NARROW[ref1, RouteChannel.ChanPin].pinPosition.pLoc;
p2: DABasics.Number ← NARROW[ref2, RouteChannel.ChanPin].pinPosition.pLoc;
RETURN[IF p1 < p2 THEN Basics.Comparison.less
ELSE IF p1 = p2 THEN Basics.Comparison.equal
ELSE Basics.Comparison.greater]};
mungedPinList: List.LORA ← ConvertToLORA[pinList];
sortedPinList: List.LORA ← List.Sort[mungedPinList, PinCompare];
rightPin: RouteChannel.ChanPin ← NARROW[List.NthElement[sortedPinList, -1]];
leftPin: RouteChannel.ChanPin ← NARROW[List.NthElement[sortedPinList, 1]];
FOR pList: List.LORA -- RouteChannel.ChanPinList -- ← sortedPinList, pList.rest WHILE pList # NIL DO
chanPin: RouteChannel.ChanPin ← NARROW[pList.first];
IF chanPin = leftPin THEN {
update old seg pointer
{IF chanPin.conctSeg[chanRight] = NIL THEN chanPin.conctSeg[chanRight] ← seg
ELSE chanPin.altConctSeg[chanRight] ← seg};
IF chanPin # newPin THEN {chanPin.conctSeg[chanRight] ← seg}
chanPin.conctSeg[chanLeft] ← NIL
ELSE
no old seg pointer, but make sure both segs on new pin are initialized
{IF chanPin.conctSeg[chanRight] = NIL THEN chanPin.conctSeg[chanRight] ← seg
ELSE chanPin.altConctSeg[chanRight] ← seg};
BTP August 1, 1988 6:37:29 pm PDT
seg.exteriorPins[chanLeft] ← chanPin}
ELSE IF chanPin = rightPin THEN {
update old seg pointer
{IF chanPin.conctSeg[chanLeft] = NIL THEN chanPin.conctSeg[chanLeft] ← seg
ELSE chanPin.altConctSeg[chanLeft] ← seg};
IF chanPin # newPin THEN
{chanPin.conctSeg[chanLeft] ← seg; -- chanPin.conctSeg[chanRight] ← NIL -- }
ELSE
no old seg pointer, but make sure both segs on new pin are initialized
{IF chanPin.conctSeg[chanLeft] = NIL THEN chanPin.conctSeg[chanLeft] ← seg
ELSE chanPin.altConctSeg[chanLeft] ← seg};
BTP August 1, 1988 6:37:29 pm PDT
seg.exteriorPins[chanRight] ← chanPin}
ELSE {seg.interiorPins ← CONS[chanPin, seg.interiorPins];
SELECT chanPin.kindOfPin FROM
chanConnect, compPin => {
chanPin.conctSeg[chanRight] ← seg; chanPin.conctSeg[chanLeft] ← seg};
dogLeg => {
IF chanPin.conctSeg[chanRight] = NIL AND chanPin.conctSeg[chanLeft] = NIL THEN
{chanPin.conctSeg[chanRight] ← seg; chanPin.conctSeg[chanLeft] ← seg}
ELSE
{chanPin.altConctSeg[chanLeft] ← seg; chanPin.altConctSeg[chanRight] ← seg}};
exitPin => Route.Error[programmingError, "Exit pin not on end of segment"];
ENDCASE};
ENDLOOP};
AddSeg: PROC [chanPins: RouteChannel.RoutingChannelPins, density: RouteChannel.Density, r: RTBasic.Range, width: DABasics.Number] RETURNS [maxDensity: DABasics.Number ← 0] = {
compute the track density when this range is added
IF density # NIL THEN
FOR index: RouteChannel.MPinsOnCh IN [1 .. chanPins.count] DO
pos: DABasics.Number ← chanPins.sides[index].pLoc;
thisDensity: DABasics.Number ← IF r.l <= pos AND pos <= r.r THEN density.values[index] + width
ELSE density.values[index];
maxDensity ← MAX[maxDensity, thisDensity];
ENDLOOP};
CompareResult: PROC [r1, r2: BreakResult] RETURNS [result: Basics.Comparison] = {
compare r1 and r2
result ← Basics.CompareInt[r1.chainLength, r2.chainLength];
IF result # equal THEN RETURN;
result ← Basics.CompareInt[r1.numDogLegs, r2.numDogLegs];
IF result # equal THEN RETURN;
result ← Basics.CompareInt[r1.deltaDensity, r2.deltaDensity];
IF result # equal THEN RETURN;
result ← Basics.CompareInt[r1.duplicateLength, r2.duplicateLength];
RETURN};
ClosestPins: PROC [chanPins: RouteChannel.RoutingChannelPins, target: DABasics.Number] RETURNS [nextLower, nextHigher: RouteChannel.ZMPinsOnCh ← 0] = {
find the PinPosition closest to target.
trial: RouteChannel.ZMPinsOnCh;
nextHigher ← chanPins.count;
nextLower ← 1;
WHILE ABS[nextHigher - nextLower] > 1 DO
trial ←(nextHigher + nextLower)/2;
IF target < chanPins.sides[trial].pLoc THEN nextHigher ← trial
ELSE IF target > chanPins.sides[trial].pLoc THEN nextLower ← trial
ELSE nextLower ← nextHigher ← trial;
ENDLOOP};
GetPins: PROC [exitsSeparate: BOOLEAN, seg: RouteChannel.Segment] RETURNS [pinLists: ChanPinListSet ← [NIL, NIL, NIL, NIL]] = {
get the pins attached to the segment on the indicated side
bottomList == lowerPinList and topList == upperPinList
IncludePin: PROC [pin: RouteChannel.ChanPin] = {
IF pin.pinSide = chanBottom THEN pinLists.bottomList ← CONS[pin, pinLists.bottomList]
ELSE IF pin.pinSide = chanTop THEN pinLists.topList ← CONS[pin, pinLists.topList]
ELSE IF pin.kindOfPin = dogLeg THEN dogLegList ← CONS[pin, dogLegList]};
IncludeExit: PROC [pin: RouteChannel.ChanPin, chanSide: RouteChannel.ChanSide] = {
IF pin.kindOfPin = exitPin THEN
{SELECT exitsSeparate FROM
FALSE => {
Compiler problem: [pinLists.bottomList, pinLists.topList] ← AddToClosestList[[pinLists.bottomList, pinLists.topList], pin]};
result: ChanPinListPair ← AddToClosestList[[pinLists.bottomList, pinLists.topList], pin];
pinLists.bottomList ← result.list1;
pinLists.topList ← result.list2};
TRUE => {
IF pin.pinPosition.pLoc = leftPin.pinPosition.pLoc THEN pinLists.leftExit ← pin
ELSE pinLists.rightExit ← pin};
ENDCASE => Route.Error[programmingError, "Invalid Router."]};
};
first include the obvious pins: top, bottom and dogleg
dogLegList: RouteChannel.ChanPinList ← NIL;
leftPin: RouteChannel.ChanPin ← seg.exteriorPins[chanLeft];
rightPin: RouteChannel.ChanPin ← seg.exteriorPins[chanRight];
IncludePin[leftPin];
IncludePin[rightPin];
FOR list: RouteChannel.ChanPinList ← seg.interiorPins, list.rest WHILE list # NIL DO
IncludePin[list.first];
ENDLOOP;
next decide which segments the exit pins go in
IncludeExit[leftPin, chanLeft];
IncludeExit[rightPin, chanRight];
next decide which segments the dogleg pins go in
FOR list: RouteChannel.ChanPinList ← dogLegList, list.rest WHILE list # NIL DO
Compiler problem: [pinLists.bottomList, pinLists.topList] ← AddToClosestList[[pinLists.bottomList, pinLists.topList], list.first];
result: ChanPinListPair ← AddToClosestList[[pinLists.bottomList, pinLists.topList], list.first];
pinLists.bottomList ← result.list1;
pinLists.topList ← result.list2;
ENDLOOP;
};
SegRanges: PROC [chanPins: RouteChannel.RoutingChannelPins, pinLists: ChanPinListSet] RETURNS [rangeList: RangeWithDirList] = {
find distinct ranges for this seg, use enumeration
lr: RTBasic.Range ← RouteChannel.GetRange[pinLists.bottomList];
ur: RTBasic.Range ← RouteChannel.GetRange[pinLists.topList];
ce1: DABasics.Number ← chanPins.cEnd1;
ce2: DABasics.Number ← chanPins.cEnd2;
min: DABasics.Number ← MIN[lr.l, ur.l];
max: DABasics.Number ← MAX[lr.r, ur.r];
left: RangeWithDir ← IF ce1 < min THEN [[ce1, min], rightToLeft] ELSE [[ce1, ce1], rightToLeft];
right: RangeWithDir ← IF ce2 > max THEN [[max, ce2], leftToRight] ELSE [[ce2, ce2], leftToRight];
SELECT TRUE FROM
lr.r < lr.l OR ur.r < ur.l =>
rangeList ← LIST[RangeWithDir[[ce1, ce2], leftToRight]];
lr.r < ur.l =>
-- ur: ———————
-- lr: —————
{gap: RangeWithDir ← [[lr.r, ur.l], leftToRight];
rangeList ← LIST[gap, [lr, rightToLeft], [ur, leftToRight], left, right]};
(lr.l <= ur.l AND ur.l <= lr.r) AND (ur.l <= lr.r AND lr.r <= ur.r) =>
-- ur: ———————
-- lr: ———————
{dual: RangeWithDir ← [[ur.l, lr.r], leftToRight];
ls: RangeWithDir ← [[lr.l, dual.range.l], rightToLeft];
rs: RangeWithDir ← [[dual.range.r, ur.r], leftToRight];
rangeList ← LIST[dual, ls, rs, left, right]};
(lr.l <= ur.l AND ur.l < lr.r) AND (lr.l <= ur.r AND ur.r <= lr.r) =>
-- ur: ———————
lr: ————————————
{ls: RangeWithDir ← [[lr.l, ur.l], rightToLeft];
rs: RangeWithDir ← [[ur.r, lr.r], leftToRight];
rangeList ← LIST[[ur, leftToRight], ls, rs, left, right]};
(ur.l <= lr.l AND lr.l <= ur.r) AND (ur.l <= lr.r AND lr.r <= ur.r) =>
ur: ————————————
-- lr: ———————
{ls: RangeWithDir ← [[ur.l, lr.l], rightToLeft];
rs: RangeWithDir ← [[lr.r, ur.r], leftToRight];
rangeList ← LIST[[lr, leftToRight], ls, rs, left, right]};
(ur.l <= lr.l AND lr.l <= ur.r) AND (lr.l <= ur.r AND ur.r <= lr.r) =>
-- ur: ———————
-- lr: ————————————
{dual: RangeWithDir ← [[lr.l, ur.r], leftToRight];
ls: RangeWithDir ← [[ur.l, dual.range.l], rightToLeft];
rs: RangeWithDir ← [[dual.range.r, lr.r], leftToRight];
rangeList ← LIST[dual, ls, rs, left, right]};
ur.r < lr.l =>
-- ur: ———————
-- lr: ———————
{gap: RangeWithDir ← [[ur.r, lr.l], leftToRight];
rangeList ← LIST[gap, [lr, leftToRight], [ur, rightToLeft], left, right]};
ENDCASE => Route.Error[programmingError, "Not suppose to happen."]};
BreaksFound: PROCEDURE [break: FullSegBreakSpec] RETURNS [numBreaks: INT ← 0] = {
FOR lmr: Lmr IN Lmr DO
IF break.breaks[lmr] # NIL THEN numBreaks ← numBreaks + 1;
ENDLOOP};
ConvertToLORA: PROC [list: RouteChannel.ChanPinList] RETURNS[val: List.LORA] = {
val ← NIL;
UNTIL list = NIL DO
val ← CONS[list.first, val];
list ← list.rest;
ENDLOOP;
RETURN[val];
}; -- of ConvertToLORA
Code for improved dogleg routes. Should be made permenent or deleted
BTP April 18, 1989 11:32:59 am PDT
this code taken from this module or from RouteChannelInitImpl.mesa
HackedBreakWithInRange: PROC [chanData: RouteChannel.ChannelData,
parms: RoutePrivate.RoutingAreaParms,
rules: Route.DesignRules,
seg: RouteChannel.Segment,
range: RangeWithDir,
pins: TestPins]
RETURNS [break: SegBreakSpec ← NIL] = {
find the best position to break this seg within this range
Special for DDE: don't try dogleg positions between pins positions
BTP: April 17, 1989 3:27:49 pm PDT
minPinD2: DABasics.Number ← RouteUtil.GetWidthWithContact[routingArea, routingArea.rules.branchWidth]/2;
chanPins: RouteChannel.RoutingChannelPins ← chanData.chanPins;
minPinD2: DABasics.Number ← rules.branchWidth/2;
chainLength: INT;
notAllowed: BOOLEAN;
SELECT range.dir FROM
leftToRight => {
FOR pos: DABasics.Number ← range.range.l, pos + 4*11 WHILE pos <= range.range.r AND break = NIL DO
[notAllowed, chainLength] ← NewDogLegNotAllowed[chanData, parms, rules, seg, pos, pins];
IF ~notAllowed THEN
break ← NEW[SegBreakSpecRec ← [pos, dogLeg, chainLength]];
ENDLOOP};
rightToLeft => {
FOR pos: DABasics.Number ← range.range.r, pos- 4*11 WHILE pos >= range.range.l AND break = NIL DO
[notAllowed, chainLength] ← NewDogLegNotAllowed[chanData, parms, rules, seg, pos, pins];
IF ~notAllowed THEN
break ← NEW[SegBreakSpecRec ← [pos, dogLeg, chainLength]];
ENDLOOP};
ENDCASE};
NewDogLegNotAllowed: PROC [chanData: RouteChannel.ChannelData,
parms: RoutePrivate.RoutingAreaParms,
rules: Route.DesignRules,
seg: RouteChannel.Segment,
pos: DABasics.Number,
pins: TestPins]
RETURNS [notAllowed: BOOLEANFALSE, chainLength: INTLAST[INT]] = {
BTP April 13, 1989 3:18:33 pm PDT
Implements dogleg rules in ICCAD paper
see if a dogleg is allowed here
FindConnectedNet : PROC [pin: RouteChannel.ChanPin] RETURNS [net: RoutePrivate.Net ← NIL] =
{IF pin # NIL THEN
{s1: RouteChannel.Segment ← pin.conctSeg[chanLeft];
s2: RouteChannel.Segment ← pin.conctSeg[chanRight];
IF s1 # NIL THEN net ← s1.net
ELSE IF s2 # NIL THEN net ← s2.net
ELSE Route.Error[programmingError, "Pin not connected to a segment."]}};
CheckInner: RouteChannel.EachPinActionProc = {
IF pin # NIL THEN
IF pin.kindOfPin = exitPin OR pin.kindOfPin = dogLeg THEN
IF Constraining[rules, pin, pins.trialPin] THEN quit ← TRUE};
OuterConstraints: RouteChannel.EachPinActionProc = {
IF pin # NIL THEN
IF pin.kindOfPin = chanConnect OR pin.kindOfPin = compPin THEN
IF Constraining[rules, pin, pins.trialPin] THEN quit ← TRUE};
chanPins: RouteChannel.RoutingChannelPins ← chanData.chanPins;
minLimit, maxLimit, leftIndex, rightIndex: RouteChannel.ZMPinsOnCh;
width: DABasics.Number ← MAX[seg.net.trunkWidth, seg.net.branchWidth];
graph: RouteDiGraph.Graph ← chanData.constraints;
pins.trialPin.pinPosition.pLoc ← pos;
pins.trialPin.pWidth ← width;
pins.leftExitPin.pWidth ← width;
pins.rightExitPin.pWidth ← width;
[leftIndex, rightIndex] ← ClosestPins[chanPins, pos];
must reserve place for future exits (Rule 0: unstated, but obvious)
IF Constraining[rules, pins.trialPin, pins.leftExitPin] THEN notAllowed ← TRUE;
IF Constraining[rules, pins.trialPin, pins.rightExitPin] THEN notAllowed ← TRUE;
see if inner pins interfere (Rule 2)
[minLimit, maxLimit] ← RouteChannel.FindConstraintLimits[chanPins, parms, rules, leftIndex, rightIndex, CheckInner];
FOR index: RouteChannel.MPinsOnCh IN [minLimit .. maxLimit] WHILE ~notAllowed DO
see if there are existing dog legs
pinPosition: RouteChannel.PinPosition ← chanPins.sides[index];
notAllowed ← RouteChannel.EnumPins[pinPosition, CheckInner];
ENDLOOP;
IF ~notAllowed THEN {
-- see if this dogleg position participates in a cycle
originalNode: RouteDiGraph.Node ← seg.constraintNode;
originalArcs: RouteDiGraph.ArcList ← RouteDiGraph.RemoveNode[graph, seg.constraintNode];
upperSeg: RouteChannel.Segment ← NEW[RouteChannel.SegmentRec ← [net: seg.net, qWidth: seg.qWidth, exitBreak: seg.exitBreak]];
upperConstraint: RouteChannel.SegmentConstraint ← NEW[RouteChannel.SegmentConstraintRec ← [Rope.Cat[upperSeg.net.name, "-upperSegment"], upperSeg]];
newUpperConstraintNode: RouteDiGraph.Node ← RouteDiGraph.AddNewNode[graph, upperConstraint];
lowerSeg: RouteChannel.Segment ← NEW[RouteChannel.SegmentRec ← [net: seg.net, qWidth: seg.qWidth, exitBreak: seg.exitBreak]];
lowerConstraint: RouteChannel.SegmentConstraint ← NEW[RouteChannel.SegmentConstraintRec ← [Rope.Cat[lowerSeg.net.name, "-lowerSegment"], lowerSeg]];
newLowerConstraintNode: RouteDiGraph.Node ← RouteDiGraph.AddNewNode[graph, lowerConstraint];
TransferConstraints[graph, originalArcs, originalNode, newUpperConstraintNode, newLowerConstraintNode];
see if outer pins can cross the channel
[minLimit, maxLimit] ← RouteChannel.FindConstraintLimits[chanPins, parms, rules, leftIndex, rightIndex, OuterConstraints];
FOR index: RouteChannel.MPinsOnCh IN [minLimit .. maxLimit] WHILE ~notAllowed DO
pinPosition: RouteChannel.PinPosition ← chanPins.sides[index];
bottomPin: RouteChannel.ChanPin ← pinPosition.pins[chanBottom];
bottomNet: RoutePrivate.Net ← FindConnectedNet[bottomPin];
constrainBottom: BOOLEAN ← Constraining[rules, bottomPin, pins.trialPin];
IF constrainBottom THEN {
IF bottomNet = seg.net THEN notAllowed ← TRUE; -- Don't let a dogleg constratin its own net
add constraints for new trial segments
AddConstraintsToPin[graph, newLowerConstraintNode, bottomPin]};
Check if bottom and top pins constrain each other (Rule 1)
Check if bottom and top pins belong to the same net (Rule 3)
see if any nets within the range cross the channels
FOR i: RouteChannel.MPinsOnCh IN [minLimit .. maxLimit] WHILE ~notAllowed DO
pP: RouteChannel.PinPosition ← chanPins.sides[i];
topPin: RouteChannel.ChanPin ← pP.pins[chanTop];
topNet: RoutePrivate.Net ← FindConnectedNet[topPin];
constrainTop: BOOLEAN ← Constraining[rules, topPin, pins.trialPin];
IF constrainTop THEN {
IF topNet = seg.net THEN notAllowed ← TRUE; -- Don't let a dogleg constratin its own net
add constraints for new trial segments
AddConstraintsFromPin[graph, topPin, newUpperConstraintNode]};
IF constrainBottom AND constrainTop THEN {
IF bottomNet = topNet THEN notAllowed ← TRUE; -- Rule 1
};
ENDLOOP;
ENDLOOP;
check Rule 3
IF ~RouteDiGraph.PathExists[graph, newUpperConstraintNode, newLowerConstraintNode] THEN
[] ← RouteDiGraph.AddNewArc[graph, NIL, newUpperConstraintNode, newLowerConstraintNode];
IF notAllowed OR SegsInCycle[graph, newLowerConstraintNode, newUpperConstraintNode] # NIL THEN notAllowed ← TRUE;
IF notAllowed OR SegsInCycle[graph, newUpperConstraintNode, newUpperConstraintNode] # NIL THEN notAllowed ← TRUE;
IF notAllowed OR SegsInCycle[graph, newLowerConstraintNode, newLowerConstraintNode] # NIL THEN notAllowed ← TRUE;
IF ~notAllowed THEN
chainLength ← UpperConstrainedNodes[graph, newUpperConstraintNode] + LowerConstrainedNodes[graph, newLowerConstraintNode];
put things back the way they were
[] ← RouteDiGraph.RemoveNode[graph, newUpperConstraintNode];
[] ← RouteDiGraph.RemoveNode[graph, newLowerConstraintNode];
RouteDiGraph.IncludeNode[graph, originalNode];
RouteDiGraph.IncludeArcs[graph, originalArcs]};
};
GetBreakSpec: PROC [break: FullSegBreakSpec] RETURNS [segBreak: SegBreakSpec ← NIL] ~ {
extract the break spec for the full break
FOR lmr: Lmr IN Lmr DO
IF break.breaks[lmr] # NIL THEN segBreak ← break.breaks[lmr];
ENDLOOP;
};
GetLmr: PROC [break: FullSegBreakSpec] RETURNS [lmr: Lmr ← middle] ~ {
extract the Lmr spec for the full break
FOR where: Lmr IN Lmr DO
IF break.breaks[where] # NIL THEN lmr ← where;
ENDLOOP;
};
HackedDoBreak: PROC [chanData: RouteChannel.ChannelData, parms: RoutePrivate.RoutingAreaParms, rules: Route.DesignRules, fullSegBreak: FullSegBreakSpec] = {
break the segment at position:
add pin position at fullSegBreak.breaks[mumble].pos
unlink segBreak
create 2 new segments
link in the pins
UnlinkSegFromPins: RouteChannel.EachPinActionProc ~ {
IF pin.conctSeg[chanLeft] = oldSeg THEN pin.conctSeg[chanLeft] ← NIL;
IF pin.conctSeg[chanRight] = oldSeg THEN pin.conctSeg[chanRight] ← NIL;
IF pin.altConctSeg[chanLeft] = oldSeg THEN pin.altConctSeg[chanLeft] ← NIL;
IF pin.altConctSeg[chanRight] = oldSeg THEN pin.altConctSeg[chanRight] ← NIL;
};
chanPins: RouteChannel.RoutingChannelPins ← chanData.chanPins;
oldSeg: RouteChannel.Segment ← fullSegBreak.seg;
branchWidth: DABasics.Number ← oldSeg.net.branchWidth;
trunkWidth: DABasics.Number ← oldSeg.net.trunkWidth;
segBreak: SegBreakSpec ← GetBreakSpec[fullSegBreak];
lmr: Lmr ← GetLmr[fullSegBreak];
pinIndex: RouteChannel.ZMPinsOnCh ← RouteChannel.FindPinPos[chanPins, segBreak.pos];
pinPosition: RouteChannel.PinPosition ← chanPins.sides[pinIndex];
upperPin, lowerPin: RouteChannel.ChanPin ← NIL;
pinListPair: ChanPinListPair;
segRange: RTBasic.Range ← RouteChannel.SegRange[oldSeg];
seg1: RouteChannel.Segment ← NEW[RouteChannel.SegmentRec ← [net: oldSeg.net, qWidth: trunkWidth, exitBreak: oldSeg.exitBreak]];
seg2: RouteChannel.Segment ← NEW[RouteChannel.SegmentRec ← [net: oldSeg.net, qWidth: trunkWidth, exitBreak: oldSeg.exitBreak]];
IF (segRange.l < pinPosition.pLoc AND pinPosition.pLoc < segRange.r) OR segBreak.type = exit THEN {
break this one segment
[] ← RouteChannel.EnumPinsOnSeg[oldSeg, UnlinkSegFromPins];
SELECT segBreak.type FROM
dogLeg => {
exitsSeparate: BOOLEANIF parms.routerUsed = channel THEN FALSE ELSE TRUE;
pinLists: ChanPinListSet ← GetPins[exitsSeparate, oldSeg];
parms.widestPin ← MAX[branchWidth, parms.widestPin];
upperPin ← lowerPin ← NEW[RouteChannel.ChanPinRec ← [pinSide: none, qLoc: 0, pWidth: rules.branchWidth, kindOfPin: dogLeg, pinPosition: pinPosition]];
pinPosition.innerPins ← CONS[upperPin, pinPosition.innerPins];
pinListPair ← DividePins[lmr, pinLists, lowerPin, upperPin]};
exit => {
pinSide: RouteChannel.ChanLRSide ←
IF segBreak.pos <= chanPins.cEnd1 THEN chanLeft
ELSE IF segBreak.pos >= chanPins.cEnd2 THEN chanRight
ELSE Route.Error[programmingError, "Invalid data. Call maintainer."];
pinLists: ChanPinListSet ← GetPins[TRUE, oldSeg];
seg1.exitBreak ← TRUE; seg1.part ← 1;
seg2.exitBreak ← TRUE; seg2.part ← 2;
upperPin ← NEW[RouteChannel.ChanPinRec ← [pinSide: pinSide, qLoc: 0, pWidth: 0, kindOfPin: exitPin, pinPosition: pinPosition]];
pinPosition.innerPins ← CONS[upperPin, pinPosition.innerPins];
if this segment already has an exit on this side, then use that one, otherwise make a new pin
lowerPin ← IF pinSide = chanRight THEN pinLists.rightExit ELSE pinLists.leftExit;
IF lowerPin = NIL THEN {
lowerPin ← NEW[RouteChannel.ChanPinRec ← [pinSide: pinSide, qLoc: 0, pWidth: 0, kindOfPin: exitPin, pinPosition: pinPosition]];
pinPosition.innerPins ← CONS[lowerPin, pinPosition.innerPins]}
ELSE {
};
pinListPair ← DividePins[lmr, pinLists, lowerPin, upperPin]};
ENDCASE;
LinkSegsToPins[seg1, pinListPair.list1, lowerPin];
LinkSegsToPins[seg2, pinListPair.list2, upperPin];
SetTrackConstraints[seg1, oldSeg.trackConstraint];
SetTrackConstraints[seg2, oldSeg.trackConstraint];
TerminalIO.PutRope[Rope.Cat["\ntrunk segment for net: ", fullSegBreak.seg.net.name, ]];
TerminalIO.PutF1[" divided at: %g", IO.int[chanPins.sides[pinIndex].pLoc/8]];
}
ELSE { -- replace all segments for net with one segment
net: RoutePrivate.Net ← oldSeg.net;
pinLists: ChanPinListSet ← GetPinsOnNet[chanPins, net];
parms.widestPin ← MAX[rules.branchWidth, parms.widestPin];
upperPin ← lowerPin ← NEW[RouteChannel.ChanPinRec ← [pinSide: none, qLoc: 0, pWidth: rules.branchWidth, kindOfPin: dogLeg, pinPosition: pinPosition]];
pinPosition.innerPins ← CONS[upperPin, pinPosition.innerPins];
pinListPair ← DividePins[middle, pinLists, lowerPin, upperPin];
UnlinkPinsOnNet[chanPins, net]; -- unlink the old segments
LinkSegsToPins[seg1, pinListPair.list1, lowerPin];
LinkSegsToPins[seg2, pinListPair.list2, upperPin];
SetTrackConstraints[seg1, oldSeg.trackConstraint];
SetTrackConstraints[seg2, oldSeg.trackConstraint];
TerminalIO.PutRope[Rope.Cat["\ntrunk segment divided for net: ", fullSegBreak.seg.net.name ]];
TerminalIO.PutF1[" dogleg at: %g", IO.int[chanPins.sides[pinIndex].pLoc/8]];
};
remove this statment for production
RouteChannel.AuditPins[chanPins]
};
GetPinsOnNet: PROC [chanPins: RouteChannel.RoutingChannelPins, net: RoutePrivate.Net] RETURNS [pinLists: ChanPinListSet← [NIL, NIL, NIL, NIL]] ~ {
get the pins attached to the net on the indicated side
bottomList == lowerPinList and topList == upperPinList
this is a heavy duty way to perform this action; needs to be improved
EachPinPosition: RouteChannel.EachPinPositionActionProc ~ {
PROC[pinPosition: PinPosition, pinIndex: MPinsOnCh] RETURNS [quit: BOOLEANFALSE];
EachPin: RouteChannel.EachPinActionProc ~ {
PROC[pinPosition: PinPosition, pin: ChanPin] RETURNS [quit: BOOLEANFALSE];
IF OnNet[net, pin] THEN {
SELECT pin.pinSide FROM
chanBottom => pinLists.bottomList ← CONS[pin, pinLists.bottomList];
chanTop => pinLists.topList ← CONS[pin, pinLists.topList];
chanLeft => leftPin ← pin;
chanRight => rightPin ← pin;
ENDCASE => Route.Error[programmingError, "Invalid pin on net."];
}
};
[] ← RouteChannel.EnumPins[pinPosition, EachPin]};
leftPin, rightPin: RouteChannel.ChanPin;
[] ← RouteChannel.EnumPinPositions[chanPins, EachPinPosition];
IF leftPin # NIL THEN {
result: ChanPinListPair ← AddToClosestList[[pinLists.bottomList, pinLists.topList], leftPin];
pinLists.bottomList ← result.list1;
pinLists.topList ← result.list2};
IF rightPin # NIL THEN {
result: ChanPinListPair ← AddToClosestList[[pinLists.bottomList, pinLists.topList], rightPin];
pinLists.bottomList ← result.list1;
pinLists.topList ← result.list2};
};
UnlinkPinsOnNet: PROC [chanPins: RouteChannel.RoutingChannelPins, net: RoutePrivate.Net] ~ {
Unlink the old segments for Garbage collection
EachPinPosition: RouteChannel.EachPinPositionActionProc ~ {
PROC[pinPosition: PinPosition, pinIndex: MPinsOnCh] RETURNS [quit: BOOLEANFALSE];
EachPin: RouteChannel.EachPinActionProc ~ {
PROC[pinPosition: PinPosition, pin: ChanPin] RETURNS [quit: BOOLEANFALSE];
IF OnNet[net, pin] THEN {
pin.conctSeg[chanLeft] ← NIL;
pin.conctSeg[chanRight] ← NIL;
pin.altConctSeg[chanLeft] ← NIL;
pin.altConctSeg[chanRight] ← NIL;
}};
[] ← RouteChannel.EnumPins[pinPosition, EachPin]};
[] ← RouteChannel.EnumPinPositions[chanPins, EachPinPosition]};
OnNet: PROC [net: RoutePrivate.Net, pin: RouteChannel.ChanPin] RETURNS [onNet: BOOLEANFALSE] ~ {
Returns TRUE if pin is connected to net
IF pin # NIL THEN {
IF pin.conctSeg[chanLeft] # NIL AND pin.conctSeg[chanLeft].net = net THEN onNet ← TRUE;
IF pin.conctSeg[chanRight] # NIL AND pin.conctSeg[chanRight].net = net THEN onNet ← TRUE;
IF pin.altConctSeg[chanLeft] # NIL AND pin.altConctSeg[chanLeft].net = net THEN onNet ← TRUE;
IF pin.altConctSeg[chanRight] # NIL AND pin.altConctSeg[chanRight].net = net THEN onNet ← TRUE;
}};
CycleFromPins: PROC [chanData: RouteChannel.ChannelData, lowerPin, upperPin: RouteChannel.ChanPin] RETURNS [cycleExists: BOOLEANFALSE] ~ {
graph: RouteDiGraph.Graph ← chanData.constraints;
FOR lowerSegIndex: RouteChannel.ChanLRSide IN [chanLeft .. chanRight] WHILE ~cycleExists DO
FOR upperSegIndex: RouteChannel.ChanLRSide IN [chanLeft .. chanRight] WHILE ~cycleExists DO
IF lowerPin # NIL AND upperPin # NIL THEN {
lowerSeg: RouteChannel.Segment ← lowerPin.conctSeg[lowerSegIndex];
upperSeg: RouteChannel.Segment ← upperPin.conctSeg[upperSegIndex];
IF lowerSeg # NIL AND upperSeg # NIL AND lowerSeg # upperSeg THEN
IF ~lowerSeg.net.num # upperSeg.net.num THEN {
lowerNode: RouteDiGraph.Node ← lowerSeg.constraintNode;
upperNode: RouteDiGraph.Node ← upperSeg.constraintNode;
IF SegsInCycle[graph, lowerNode, upperNode] # NIL THEN cycleExists ← TRUE}};
ENDLOOP; -- FOR upperSegIndex
ENDLOOP; -- FOR lowerSegIndex
};
HackedDoConstraint: PROC [chanData: RouteChannel.ChannelData, parms: RoutePrivate.RoutingAreaParms, rules: Route.DesignRules, lowerSeg, upperSeg: RouteChannel.Segment, whichEnd: Lmr, pins: TestPins] RETURNS [segBroken: BOOLEANFALSE] = {
add a segment constraint if it does not create a loop
IF lowerSeg # NIL AND upperSeg # NIL AND lowerSeg # upperSeg THEN
IF ~lowerSeg.failed AND ~upperSeg.failed AND lowerSeg.net.num # upperSeg.net.num THEN {
segList: RouteChannel.SegmentList;
chanPins: RouteChannel.RoutingChannelPins ← chanData.chanPins;
graph: RouteDiGraph.Graph ← chanData.constraints;
lowerNode: RouteDiGraph.Node ← lowerSeg.constraintNode;
upperNode: RouteDiGraph.Node ← upperSeg.constraintNode;
IF lowerNode = NIL THEN
{constraint: RouteChannel.SegmentConstraint ← NEW[RouteChannel.SegmentConstraintRec ← [lowerSeg.net.name, lowerSeg]];
lowerNode ← RouteDiGraph.AddNewNode[graph, constraint];
lowerSeg.constraintNode ← lowerNode};
IF upperNode = NIL THEN
{constraint: RouteChannel.SegmentConstraint ← NEW[RouteChannel.SegmentConstraintRec ← [upperSeg.net.name, upperSeg]];
upperNode ← RouteDiGraph.AddNewNode[graph, constraint];
upperSeg.constraintNode ← upperNode};
segList ← SegsInCycle[graph, lowerNode, upperNode];
IF segList # NIL THEN {
choose a segment to break and the position to dogleg
add constraint that caused this
dummy: RouteDiGraph.Arc ← RouteDiGraph.AddNewArc[graph, NIL, upperNode, lowerNode];
density: RouteChannel.Density ← RouteChannel.ComputeDensity[chanPins, rules];
segBreak: FullSegBreakSpec ← FindBreak[chanData, parms, rules, segList, density, whichEnd, pins];
IF BreaksFound[segBreak] > 0 THEN HackedDoBreak[chanData, parms, rules, segBreak]
ELSE { -- choose a victim --
segList.first.failed ← TRUE;
Route.Signal[noResource, Rope.Cat["net: ", segList.first.net.name, " failed, unable to find a place to dogleg"]]};
segBroken ← TRUE}
ELSE { -- add a segment constraint
constrain Upper above Lower
IF ~RouteDiGraph.PathExists[graph, upperNode, lowerNode] THEN
arcName: Rope.ROPE ← Rope.Cat[upperSeg.net.name,"-above-", lowerSeg.net.name];
[] ← RouteDiGraph.AddNewArc[graph, NIL, upperNode, lowerNode]}}};
AddConstraintsToPin: PROC [graph: RouteDiGraph.Graph, constraintNode: RouteDiGraph.Node, pin: RouteChannel.ChanPin] ~ {
add constraints from the constraint node to the segments on the pin
segList: RouteChannel.SegmentList ← RouteChannel.GetSegsOnPin[pin];
FOR segs: RouteChannel.SegmentList ← segList, segs.rest WHILE segs # NIL DO
lowerNode: RouteDiGraph.Node ← segs.first.constraintNode;
IF lowerNode = NIL THEN {
constraint: RouteChannel.SegmentConstraint ← NEW[RouteChannel.SegmentConstraintRec ← [segs.first.net.name, segs.first]];
lowerNode ← RouteDiGraph.AddNewNode[graph, constraint];
segs.first.constraintNode ← lowerNode};
IF ~RouteDiGraph.PathExists[graph, constraintNode, lowerNode] THEN
[] ← RouteDiGraph.AddNewArc[graph, NIL, constraintNode, lowerNode];
ENDLOOP;
};
AddConstraintsFromPin: PROC [graph: RouteDiGraph.Graph, pin: RouteChannel.ChanPin, constraintNode: RouteDiGraph.Node] ~ {
add constraints from the constraint node to the segments on the pin
segList: RouteChannel.SegmentList ← RouteChannel.GetSegsOnPin[pin];
FOR segs: RouteChannel.SegmentList ← segList, segs.rest WHILE segs # NIL DO
upperNode: RouteDiGraph.Node ← segs.first.constraintNode;
IF upperNode = NIL THEN {
constraint: RouteChannel.SegmentConstraint ← NEW[RouteChannel.SegmentConstraintRec ← [segs.first.net.name, segs.first]];
upperNode ← RouteDiGraph.AddNewNode[graph, constraint];
segs.first.constraintNode ← upperNode};
IF ~RouteDiGraph.PathExists[graph, upperNode, constraintNode] THEN
[] ← RouteDiGraph.AddNewArc[graph, NIL, upperNode, constraintNode];
ENDLOOP;
};
TransferConstraints: PROC [graph: RouteDiGraph.Graph, originalArcs: RouteDiGraph.ArcList, originalNode, newUpperConstraintNode, newLowerConstraintNode: RouteDiGraph.Node] ~ {
transfer constraints from removed arcs to new nodes
FOR aList: RouteDiGraph.ArcList ← originalArcs, aList.rest WHILE aList # NIL DO
arc: RouteDiGraph.Arc ← NARROW[aList.first];
IF arc.superiorNode = originalNode THEN [] ← RouteDiGraph.AddNewArc[graph, NIL, newUpperConstraintNode, arc.inferiorNode]
ELSE IF arc.inferiorNode = originalNode THEN [] ← RouteDiGraph.AddNewArc[graph, NIL, arc.superiorNode, newLowerConstraintNode]
ELSE Route.Error;
ENDLOOP;
};
LowerConstrainedNodes: PROCEDURE[graph: RouteDiGraph.Graph, node: RouteDiGraph.Node]
RETURNS [constrainedNodes: INT ← 0] = {
recursively go through the constraints
ArcProc: RouteDiGraph.EnumArcsFromNodeProc = {
PROC[graph: Graph, arc: Arc, node: Node, direction: Direction] RETURNS [quit: BOOLEANFALSE];
IF ~List.Memb[arc.inferiorNode, visitedNodes] THEN {
visitedNodes ← CONS[arc.inferiorNode, visitedNodes];
constrainedNodes ← constrainedNodes + 1;
quit ← RouteDiGraph.EnumArcsFromNode[graph, arc.inferiorNode, in, ArcProc]}};
visitedNodes: RouteDiGraph.NodeList ← NIL;
[] ← RouteDiGraph.EnumArcsFromNode[graph, node, in, ArcProc]};
UpperConstrainedNodes: PROCEDURE[graph: RouteDiGraph.Graph, node: RouteDiGraph.Node]
RETURNS [constrainedNodes: INT ← 0] = {
recursively go through the constraints
ArcProc: RouteDiGraph.EnumArcsFromNodeProc = {
PROC[graph: Graph, arc: Arc, node: Node, direction: Direction] RETURNS [quit: BOOLEANFALSE];
IF ~List.Memb[arc.superiorNode, visitedNodes] THEN {
visitedNodes ← CONS[arc.superiorNode, visitedNodes];
constrainedNodes ← constrainedNodes + 1;
quit ← RouteDiGraph.EnumArcsFromNode[graph, arc.superiorNode, out, ArcProc]}};
visitedNodes: RouteDiGraph.NodeList ← NIL;
[] ← RouteDiGraph.EnumArcsFromNode[graph, node, out, ArcProc]};
}.