RouteChannelTopolImpl.mesa ///Route/RouteChannelTopolImpl.mesa
Bryan Preas February 27, 1986 11:20:46 am PST
Copyright © 1985 by Xerox Corporation. All rights reserved.
by Bryan Preas July 10, 1985 6:57:00 pm PDT
last edited by Bryan Preas July 10, 1985 6:57:07 pm PDT
DIRECTORY
Basics,
CD,
CDSymbolicObjects,
Convert,
Rope,
Route,
RouteChannel,
RouteDiGraph,
RoutePrivate,
RouteUtil,
TerminalIO;
RouteChannelTopolImpl: CEDAR PROGRAM
IMPORTS CD, CDSymbolicObjects, Convert, Rope, Route, RouteChannel, RouteDiGraph, RoutePrivate, RouteUtil, TerminalIO
EXPORTS RouteChannel
SHARES Route =
BEGIN
SegProc: TYPE = PROC[seg: RouteChannel.Segment, activeTrackSpec: RouteChannel.ActiveTrackSpec] RETURNS [quit: BOOLEANFALSE, segSpec: RouteChannel.ActiveSegSpec ← NIL];
debug: BOOLEANFALSE;
stopTrack: NAT ← 50;
TopoWiring: PUBLIC PROCEDURE[routingArea: Route.RoutingArea, opt: Route.Optimization] RETURNS [bestResult: Route.RoutingResult] = {
channel route the routing area
lastMethod: RouteChannel.Method ← NEW[RouteChannel.MethodRec];
bestMethod: RouteChannel.Method;
result: Route.RoutingResult;
parms: RoutePrivate.RoutingAreaParms ← NARROW[routingArea.parms];
start with a bad result
maxL: NAT = LAST[NAT];
bestResult ← NEW[Route.RoutingResultRec ← [routingArea, maxL, maxL, maxL, maxL, maxL, maxL, maxL, Route.Rect[maxL, maxL, maxL, maxL]]];
loop through the options
FOR method: RouteChannel.Method ← GetNextMethod[lastMethod], GetNextMethod[lastMethod] WHILE method # NIL DO
result ← RouteOneChan[routingArea, method];
lastMethod ← method;
IF debug THEN RouteChannel.WriteResult[result, method];
IF RouteUtil.CompareResult[result, bestResult] = less THEN
{bestResult ← result; bestMethod ← method};
IF opt = noIncompletes AND bestResult.numIncompletes = 0 THEN EXIT;
ENDLOOP;
restore results of the best method
IF bestMethod # lastMethod THEN
bestResult ← RouteOneChan[routingArea, bestMethod];
RouteChannel.WriteResult[bestResult, bestMethod]};
GetNextMethod: PROCEDURE [currentMethod: RouteChannel.Method]
RETURNS [nextMethod: RouteChannel.Method] = {
SELECT currentMethod.directionSequence FROM
start =>
nextMethod ← NEW[RouteChannel.MethodRec ← [outsideInTop, leftToRight]];
leftToRight =>
nextMethod ← NEW[RouteChannel.MethodRec ← [currentMethod.trackSequence, rightToLeft]];
rightToLeft =>
nextMethod ← NEW[RouteChannel.MethodRec ← [currentMethod.trackSequence, alternateLeft]];
alternateLeft =>
nextMethod ← NEW[RouteChannel.MethodRec ← [currentMethod.trackSequence, alternateRight]];
alternateRight =>
BEGIN
nextMethod ← NEW[RouteChannel.MethodRec ← [currentMethod.trackSequence, leftToRight]];
SELECT currentMethod.trackSequence FROM
start =>
nextMethod.trackSequence ← outsideInTop;
outsideInTop =>
nextMethod.trackSequence ← outsideInBottom;
outsideInBottom =>
nextMethod.trackSequence ← botToTop;
botToTop =>
nextMethod.trackSequence ← topToBot;
topToBot =>
nextMethod ← NIL;
ENDCASE;
END;
ENDCASE;
IF debug AND nextMethod # NIL THEN {
TerminalIO.WriteRope[Rope.Cat["\nNew method: ", RouteChannel.directionSequenceName[nextMethod.directionSequence], ", ", RouteChannel.trackSequenceName[nextMethod.trackSequence]]]};
};
RouteOneChan: PROCEDURE[routingArea: Route.RoutingArea, method: RouteChannel.Method]
RETURNS [result: Route.RoutingResult] = {
route this channel using the method described
InitOneChan[routingArea];
PreAssignSegs[routingArea, method];
AssignVariableSegs[routingArea, method];
result ← AnalyzeResult[routingArea];
}; -- RouteOneChan
InitOneChan: PROCEDURE[routingArea: Route.RoutingArea] = {
initialize for one channel routing
empty all of the tracks of their segments
SetTrackPos: RouteChannel.EachTrackActionProc = {
chanTracks.tracks[trackIndex].trackNum ← trackIndex;
chanTracks.tracks[trackIndex].firstSeg ← NIL;
chanTracks.tracks[trackIndex].keep ← FALSE};
ClearSegs: RouteChannel.EachPinActionProc = {
IF pin # NIL THEN
{FOR LRSide: RouteChannel.ChanLRSide IN RouteChannel.ChanLRSide DO
seg: RouteChannel.Segment ← pin.conctSeg[LRSide];
IF seg # NIL THEN
{seg.trackNum ← 0; seg.nextSeg ← NIL}
ENDLOOP}};
chanData: RouteChannel.ChannelData ← NARROW[routingArea.privateData];
chanPins: RouteChannel.RoutingChannelPins ← chanData.chanPins;
chanTracks: RouteChannel.RoutingChannelTracks ← chanData.chanTracks;
chanTracks.count ← chanTracks.maxCount;
[] ← RouteChannel.EnumTracks[routingArea, SetTrackPos];
empty the segments attached to the pins
FOR posIndex: RouteChannel.MPinsOnCh IN [1 .. chanPins.count] DO
pinPos: RouteChannel.PinPosition ← chanPins.sides[posIndex];
[] ← RouteChannel.EnumPins[routingArea, pinPos, ClearSegs]
ENDLOOP}; -- InitOneChan
PreAssignSegs: PROCEDURE[routingArea: Route.RoutingArea, method: RouteChannel.Method] = {
assign those segments that have fixed tracks
PreSegProc: SegProc = {
IF seg # NIL THEN
IF seg.trackNum = 0 AND seg.trackConstraint # 0 AND ~seg.failed THEN {
segSpec ← NEW[RouteChannel.ActiveSegSpecRec ← [seg: seg, segLayer: CanConvert[routingArea, seg]]];
quit ← FitSegment[routingArea, segSpec, activeTrackSpec, FALSE]};
};
chanData: RouteChannel.ChannelData ← NARROW[routingArea.privateData];
parms: RoutePrivate.RoutingAreaParms ← NARROW[routingArea.parms];
get next track to pack
FOR activeTrackSpec: RouteChannel.ActiveTrackSpec ← NextTrack[routingArea, NIL, method], NextTrack[routingArea, activeTrackSpec, method] WHILE activeTrackSpec # NIL DO
put segments on active track
FOR activeSegSpec: RouteChannel.ActiveSegSpec ← GetNextSegment[routingArea, NIL, activeTrackSpec, PreSegProc], GetNextSegment[routingArea, activeSegSpec, activeTrackSpec, PreSegProc] WHILE activeSegSpec # NIL DO
got segment, got track, place segment on track
PlaceSegment[routingArea, activeSegSpec, activeTrackSpec];
ENDLOOP; -- FOR GetNextSegment
ENDLOOP; -- FOR activeTrackSpec:
}; -- PreAssignSegs
AssignVariableSegs: PROCEDURE[routingArea: Route.RoutingArea, method: RouteChannel.Method] = {
route this channel using the method described
AsgnSegProc: SegProc = {
IF seg # NIL THEN
IF seg.trackNum = 0 AND ~seg.failed THEN {
segSpec ← NEW[RouteChannel.ActiveSegSpecRec ← [seg: seg, segLayer: CanConvert[routingArea, seg]]];
quit ← FitSegment[routingArea, segSpec, activeTrackSpec, TRUE]};
};
moreToDo: BOOLEANTRUE;
numTracksWOSegs: NAT ← 0;
chanData: RouteChannel.ChannelData ← NARROW[routingArea.privateData];
parms: RoutePrivate.RoutingAreaParms ← NARROW[routingArea.parms];
get next track to pack
FOR activeTrackSpec: RouteChannel.ActiveTrackSpec ← NextTrack[routingArea, NIL, method], NextTrack[routingArea, activeTrackSpec, method] WHILE moreToDo AND activeTrackSpec # NIL DO
segOnThisTrack: BOOLEANFALSE;
put segments on active track
FOR activeSegSpec: RouteChannel.ActiveSegSpec ← GetNextSegment[routingArea, NIL, activeTrackSpec, AsgnSegProc], GetNextSegment[routingArea, activeSegSpec, activeTrackSpec, AsgnSegProc] WHILE activeSegSpec # NIL DO
got segment, got track, place segment on track
stillGoing: BOOLEANTRUE;
nextSegSpec: RouteChannel.ActiveSegSpec;
PlaceSegment[routingArea, activeSegSpec, activeTrackSpec]; segOnThisTrack ← TRUE;
nextSegSpec ← FollowingSeg[routingArea, activeSegSpec, activeTrackSpec];
WHILE nextSegSpec # NIL AND stillGoing DO
nextSegSpec.segLayer ← CanConvert[routingArea, nextSegSpec.seg];
IF FitSegment[routingArea, nextSegSpec, activeTrackSpec, TRUE] THEN
{PlaceSegment[routingArea, nextSegSpec, activeTrackSpec];
nextSegSpec ← FollowingSeg[routingArea, nextSegSpec, activeTrackSpec]}
ELSE
stillGoing ← FALSE;
ENDLOOP; -- WHILE nextSeg # NIL
ENDLOOP; -- FOR GetNextSegment
check if we are finished
IF segOnThisTrack THEN {numTracksWOSegs ← 0; moreToDo ← TRUE}
ELSE {
numTracksWOSegs ← numTracksWOSegs+ 1;
IF parms.routerUsed = channel AND numTracksWOSegs >= chanData.chanParms.emptyTrackLimit THEN
moreToDo ← FALSE};
ENDLOOP; -- WHILE moreToDo
}; -- AssignVariableSegs
NextTrack: PROCEDURE[routingArea: Route.RoutingArea, activeTrackSpec: RouteChannel.ActiveTrackSpec, method: RouteChannel.Method]
RETURNS [nextTrackSpec: RouteChannel.ActiveTrackSpec] = {
determine the next track to pack into
OutsideInTopStop: PROCEDURE[track: RouteChannel.MaxTracks] RETURNS [BOOLEAN] = {
IF chanTracks.count MOD 2 # 0 THEN RETURN[track = chanTracks.count/2 + 1]
ELSE RETURN[track = chanTracks.count/2]};
OutsideInBottomStop: PROCEDURE[track: RouteChannel.MaxTracks] RETURNS [BOOLEAN] = {
RETURN[track = chanTracks.count/2 + 1]};
trialTrack: RouteChannel.ZMaxTracks;
freeArea: RouteChannel.AboveOrBelow;
going: RouteChannel.GoingDirection;
chanData: RouteChannel.ChannelData ← NARROW[routingArea.privateData];
chanTracks: RouteChannel.RoutingChannelTracks ← chanData.chanTracks;
IF activeTrackSpec = NIL THEN {
SELECT method.trackSequence FROM
outsideInTop => {trialTrack ← chanTracks.count; freeArea ← below};
outsideInBottom => {trialTrack ← 1; freeArea ← above};
botToTop => {trialTrack ← 1; freeArea ← above};
topToBot => {trialTrack ← chanTracks.count; freeArea ← below};
ENDCASE => Route.Error[programmingError, "Pack direction error"];
SELECT method.directionSequence FROM
leftToRight, alternateLeft => going ← leftToRight;
rightToLeft, alternateRight => going ← rightToLeft;
ENDCASE => Route.Error[programmingError, "Pack direction error"]}
ELSE { -- keep going
IF ~(activeTrackSpec.track IN RouteChannel.MaxTracks) THEN
Route.Error[programmingError, "Invalid track state"];
SELECT method.trackSequence FROM
outsideInTop =>
IF OutsideInTopStop[activeTrackSpec.track] THEN trialTrack ← 0
ELSE IF activeTrackSpec.track > chanTracks.count/2 THEN
{trialTrack ← chanTracks.count - activeTrackSpec.track + 1; freeArea ← above}
ELSE
{trialTrack ← chanTracks.count - activeTrackSpec.track; freeArea ← below};
outsideInBottom =>
IF OutsideInBottomStop[activeTrackSpec.track] THEN trialTrack ← 0
ELSE IF activeTrackSpec.track <= chanTracks.count/2 THEN
{trialTrack ← chanTracks.count - activeTrackSpec.track + 1; freeArea ← below}
ELSE
{trialTrack ← chanTracks.count - activeTrackSpec.track + 2; freeArea ← above};
botToTop =>
IF activeTrackSpec.track >= chanTracks.count THEN trialTrack ← 0
ELSE
{trialTrack ← activeTrackSpec.track + 1; freeArea ← above};
topToBot =>
IF activeTrackSpec.track <= 1 THEN trialTrack ← 0
ELSE
{trialTrack ← activeTrackSpec.track - 1; freeArea ← below};
ENDCASE => Route.Error[programmingError, "Pack direction error"];
SELECT method.directionSequence FROM
leftToRight => going ← leftToRight;
rightToLeft => going ← rightToLeft;
alternateLeft =>
IF activeTrackSpec.going = leftToRight THEN going ← rightToLeft
ELSE going ← leftToRight;
alternateRight =>
IF activeTrackSpec.going = rightToLeft THEN going ← leftToRight
ELSE going ← rightToLeft;
ENDCASE => Route.Error[programmingError, "Pack direction error"]};
generate return varables
IF ~(trialTrack IN [1 .. chanTracks.count]) THEN nextTrackSpec ← NIL
ELSE
{nextTrackSpec ← NEW[RouteChannel.ActiveTrackSpecRec];
BuildTrackSpec[routingArea, trialTrack, chanTracks.count, going, freeArea, nextTrackSpec];
IF debug THEN
{TerminalIO.WriteRope[Rope.Cat["\n New track: ", Convert.RopeFromInt[trialTrack], ", min Act: ", Convert.RopeFromInt[nextTrackSpec.minActTrack]]];
TerminalIO.WriteRope[Rope.Cat[", max Act: ", Convert.RopeFromInt[nextTrackSpec.maxActTrack]]];
TerminalIO.WriteRope[Rope.Cat["\n going: ", RouteChannel.GoingName[going], ", free area: ", RouteChannel.AboveOrBelowName[freeArea]]]}};
}; -- NextTrack
place this segment in this track
PlaceSegment: PROCEDURE[routingArea: Route.RoutingArea, activeSegSpec: RouteChannel.ActiveSegSpec, activeTrackSpec: RouteChannel.ActiveTrackSpec] = {
chanData: RouteChannel.ChannelData ← NARROW[routingArea.privateData];
chanTracks: RouteChannel.RoutingChannelTracks ← chanData.chanTracks;
track: RouteChannel.ZMaxTracks ← activeTrackSpec.track;
trackLoc: Route.Number ← RouteChannel.TrackLoc[routingArea, track];
mustKeep: RouteChannel.ZMaxTracks ← RouteChannel.InfluenceTracks[routingArea, activeSegSpec.seg.net.trunkWidth];
lowerTrack: RouteChannel.ZMaxTracks ← MAX[track - mustKeep, 1];
upperTrack: RouteChannel.ZMaxTracks ← MIN[track + mustKeep, chanTracks.count];
firstSeg: RouteChannel.Segment ← RouteChannel.TrackSeg[routingArea, track];
distance: Route.Number ← (MAX[routingArea.rules.contactSize, activeSegSpec.seg.net.trunkWidth] + routingArea.rules.trunkSpacing + routingArea.rules.trunkToTrunk)/2;
put track number in segment
IF activeSegSpec.seg.trackNum # 0 THEN Route.Error[programmingError, "Track state error"]
ELSE activeSegSpec.seg.trackNum ← track;
activeSegSpec.seg.routingLayer ← activeSegSpec.segLayer;
FOR keepTrack: RouteChannel.ZMaxTracks IN [lowerTrack .. upperTrack] DO
IF ABS[trackLoc - RouteChannel.TrackLoc[routingArea, keepTrack]] < distance THEN
chanTracks.tracks[keepTrack].keep ← TRUE
ENDLOOP;
link segment into list on track
IF firstSeg = NIL THEN {
no existing segments
activeSegSpec.seg.nextSeg ← NIL;
chanTracks.tracks[track].firstSeg ← activeSegSpec.seg}
ELSE IF activeSegSpec.seg.exteriorPins[chanRight].pinPosition.pLoc <= firstSeg.exteriorPins[chanLeft].pinPosition.pLoc THEN {
this segment goes before first segment
activeSegSpec.seg.nextSeg ← firstSeg;
chanTracks.tracks[track].firstSeg ← activeSegSpec.seg}
ELSE {
nextSeg: RouteChannel.Segment;
lastSeg: RouteChannel.Segment ← firstSeg;
FOR nextSeg ← lastSeg.nextSeg, lastSeg.nextSeg WHILE nextSeg # NIL DO
IF lastSeg.exteriorPins[chanRight].pinPosition.pLoc <= activeSegSpec.seg.exteriorPins[chanLeft].pinPosition.pLoc THEN
EXIT;
lastSeg ← nextSeg;
ENDLOOP;
lastSeg.nextSeg ← activeSegSpec.seg;
activeSegSpec.seg.nextSeg ← nextSeg}}; -- PlaceSegment
FitSegment: PROCEDURE[routingArea: Route.RoutingArea, nextSegSpec: RouteChannel.ActiveSegSpec, activeTrackSpec: RouteChannel.ActiveTrackSpec, useConstraints: BOOLEAN]
RETURNS [fitsSoFar: BOOLEANFALSE] = {
check if this segment fits and satisfies the constraints
chanData: RouteChannel.ChannelData ← NARROW[routingArea.privateData];
trackNum: RouteChannel.MaxTracks ← activeTrackSpec.track;
blocked: BOOLEAN ← chanData.chanTracks.tracks[trackNum].blocked;
trackConstraint: RouteChannel.ZMaxTracks ← nextSegSpec.seg.trackConstraint;
IF (trackConstraint # 0 AND trackConstraint # activeTrackSpec.track) OR blocked THEN
RETURN[fitsSoFar];
see if segments overlap in this track
fitsSoFar ← FitSegmentThisTrack[routingArea, nextSegSpec, activeTrackSpec];
see if segments interfere with each other
IF fitsSoFar THEN
fitsSoFar ← FitSegmentAdjTracks[routingArea, nextSegSpec, activeTrackSpec, chanData.chanTracks.count];
currently expanding up
IF fitsSoFar AND useConstraints THEN
fitsSoFar ← FitSegmentConstraints[routingArea, nextSegSpec, activeTrackSpec];
RETURN[fitsSoFar]}; -- FitSegment
FitSegmentThisTrack: PROCEDURE[routingArea: Route.RoutingArea, nextSegSpec: RouteChannel.ActiveSegSpec, activeTrackSpec: RouteChannel.ActiveTrackSpec]
RETURNS [fitsSoFar: BOOLEANTRUE] = {
check if this segment fits on this track
chanData: RouteChannel.ChannelData ← NARROW[routingArea.privateData];
chanTracks: RouteChannel.RoutingChannelTracks ← chanData.chanTracks;
rules: Route.DesignRules ← routingArea.rules;
trialSeg: RouteChannel.Segment ← nextSegSpec.seg;
trackNum: RouteChannel.MaxTracks ← activeTrackSpec.track;
segLayer: RoutePrivate.RoutingLayerOrNone ← nextSegSpec.segLayer;
see if seg fits on this track
FOR existingSeg: RouteChannel.Segment ← RouteChannel.TrackSeg[routingArea, trackNum], existingSeg.nextSeg
WHILE existingSeg # NIL AND fitsSoFar DO
IF existingSeg.net.netNum # trialSeg.net.netNum OR
existingSeg.net.netPart # trialSeg.net.netPart THEN {
trunkTrunk: Route.Number ← rules.contactToContact - rules.branchSpacing;
trunkBranch: Route.Number ← rules.branchToContact - rules.branchSpacing;
branchBranch: Route.Number ← rules.branchSpacing;
SELECT TRUE FROM
segLayer = trunk AND existingSeg.routingLayer = trunk =>
fitsSoFar ← ~OverlapCheck[existingSeg, trialSeg, trunkTrunk];
segLayer = trunk AND existingSeg.routingLayer = branch =>
fitsSoFar ← ~EndOverlapCheck[routingArea, existingSeg, trialSeg, trunkBranch];
segLayer = branch AND existingSeg.routingLayer = trunk =>
fitsSoFar ← ~EndOverlapCheck[routingArea, trialSeg, existingSeg, trunkBranch];
segLayer = branch AND existingSeg.routingLayer = branch =>
fitsSoFar ← ~OverlapCheck[existingSeg, trialSeg, branchBranch];
ENDCASE};
ENDLOOP}; -- FitSegmentThisTrack
FitSegmentAdjTracks: PROCEDURE[routingArea: Route.RoutingArea, nextSegSpec: RouteChannel.ActiveSegSpec, activeTrackSpec: RouteChannel.ActiveTrackSpec, maxTrack: RouteChannel.ZMaxTracks]
RETURNS [fitsSoFar: BOOLEANTRUE] = {
check if this segment fits on the adjacent tracks
chanData: RouteChannel.ChannelData ← NARROW[routingArea.privateData];
chanTracks: RouteChannel.RoutingChannelTracks ← chanData.chanTracks;
firstPass: BOOLEANTRUE;
rules: Route.DesignRules ← routingArea.rules;
trialSeg: RouteChannel.Segment ← nextSegSpec.seg;
pinsOnTrialSeg: RouteChannel.ChanPinList;
trackNum: RouteChannel.MaxTracks ← activeTrackSpec.track;
trialPos: Route.Number ← RouteChannel.TrackLoc[routingArea, trackNum];
edgeSpacing: Route.Number ← rules.trunkSpacing;
maxPos: Route.Number ← RouteChannel.TrackLoc[routingArea, maxTrack] + rules.trunkToEdge - edgeSpacing;
minPos: Route.Number ← RouteChannel.TrackLoc[routingArea, 1] - rules.trunkToEdge + edgeSpacing;
segLayer: RoutePrivate.RoutingLayerOrNone ← nextSegSpec.segLayer;
qTrunkTrunk: Route.Number ← rules.trunkSpacing;
check to see if wire interferes with edges
IF maxPos < trialPos + trialSeg.qWidth/2 OR trialPos - trialSeg.qWidth/2 < minPos THEN
fitsSoFar ← FALSE;
see if segments interfere with each other
FOR adjTrack: RouteChannel.MaxTracks IN [activeTrackSpec.minActTrack .. activeTrackSpec.maxActTrack] WHILE fitsSoFar DO
IF adjTrack # activeTrackSpec.track THEN {
adjTrackPos: Route.Number ← RouteChannel.TrackLoc[routingArea, adjTrack];
contactToContact: Route.Number ← rules.contactToContact;
IF firstPass THEN { -- don't get pinsOnTrialSeg until needed
firstPass ← FALSE;
pinsOnTrialSeg ← RouteChannel.GetPinsOnSeg[trialSeg]};
FOR existingSeg: RouteChannel.Segment ← RouteChannel.TrackSeg[routingArea, adjTrack], existingSeg.nextSeg
WHILE existingSeg # NIL AND fitsSoFar DO
IF existingSeg.net.netNum # trialSeg.net.netNum OR
existingSeg.net.netPart # trialSeg.net.netPart THEN
{-- check to see if contacts interfere with each other
IF segLayer = trunk AND existingSeg.routingLayer = trunk THEN {
pinsOnExistSeg: RouteChannel.ChanPinList ← RouteChannel.GetPinsOnSeg[existingSeg];
FOR trialPins: RouteChannel.ChanPinList ← pinsOnTrialSeg, trialPins.rest WHILE trialPins # NIL AND fitsSoFar DO
trialPin: RouteChannel.ChanPin ← trialPins.first;
FOR existPins: RouteChannel.ChanPinList ← pinsOnExistSeg, existPins.rest WHILE existPins # NIL AND fitsSoFar DO
existPin: RouteChannel.ChanPin ← existPins.first;
fitsSoFar ← ~ContactCheck[trialPin, trialPos, existPin, adjTrackPos, contactToContact];
ENDLOOP;
ENDLOOP};
check to see if wires interfere with each other
IF ABS[trialPos - adjTrackPos] < trialSeg.qWidth/2 + qTrunkTrunk + existingSeg.qWidth/2 THEN
fitsSoFar ← ~OverlapCheck[existingSeg, trialSeg, qTrunkTrunk]};
ENDLOOP};
ENDLOOP}; -- FitSegmentAdjTracks
FitSegmentConstraints: PROCEDURE[routingArea: Route.RoutingArea, nextSegSpec: RouteChannel.ActiveSegSpec, activeTrackSpec: RouteChannel.ActiveTrackSpec]
RETURNS [fitsSoFar: BOOLEANTRUE] = {
check if this segment satisfies the constraints
see if segments overlap in this track
chanData: RouteChannel.ChannelData ← NARROW[routingArea.privateData];
graph: RouteDiGraph.Graph ← chanData.constraints;
trialSeg: RouteChannel.Segment ← nextSegSpec.seg;
currently expanding up
IF activeTrackSpec.freeArea = above THEN {
see if constraints below are satisfied: lower segs MUST be placed
IF fitsSoFar THEN
fitsSoFar ← ~ConstraintCheck[graph, trialSeg, below, activeTrackSpec.track, TRUE];
if upper segments are placed, they must be above
IF fitsSoFar THEN
fitsSoFar ← ~ConstraintCheck[graph, trialSeg, above, activeTrackSpec.track, FALSE]};
currently expanding down
IF activeTrackSpec.freeArea = below THEN {
see if constraints above are satisfied: upper segs MUST be placed
IF fitsSoFar THEN
fitsSoFar ← ~ConstraintCheck[graph, trialSeg, above, activeTrackSpec.track, TRUE];
if lower segments are placed, they must be below
IF fitsSoFar THEN
fitsSoFar ← ~ConstraintCheck[graph, trialSeg, below, activeTrackSpec.track, FALSE]};
RETURN[fitsSoFar]}; -- FitSegmentConstraints
EndOverlapCheck: PROCEDURE[routingArea: Route.RoutingArea, branchSeg, trunkSeg: RouteChannel.Segment, dist: Route.Number]
RETURNS [overlap: BOOLEAN] = {
EachPin: RouteChannel.EachPinActionProc ~ {
leftTrunkPinLoc: Route.Number ← pin.pinPosition.pLoc - pin.pWidth/2;
rightTrunkPinLoc: Route.Number ← pin.pinPosition.pLoc + pin.pWidth/2;
gap: RoutePrivate.Range ← RouteChannel.Gap[[leftBranchLoc, rightBranchLoc], [leftTrunkPinLoc, rightTrunkPinLoc]];
IF gap.l > gap.r THEN overlap ← TRUE
ELSE overlap ← gap.r - gap.l < dist
};
leftBranchPin: RouteChannel.ChanPin ← branchSeg.exteriorPins[chanLeft];
leftBranchLoc: Route.Number ← leftBranchPin.pinPosition.pLoc - leftBranchPin.pWidth/2;
rightBranchPin: RouteChannel.ChanPin ← branchSeg.exteriorPins[chanRight];
rightBranchLoc: Route.Number ← rightBranchPin.pinPosition.pLoc + rightBranchPin.pWidth/2;
overlap ← RouteChannel.EnumPinsOnSeg[routingArea, trunkSeg, EachPin]};
HalfOverlapCheck: PROCEDURE[seg1, seg2: RouteChannel.Segment, dist: Route.Number]
RETURNS [overlap: BOOLEAN] = {
leftPin1: RouteChannel.ChanPin ← seg1.exteriorPins[chanLeft];
left1Loc: Route.Number ← leftPin1.pinPosition.pLoc - leftPin1.pWidth/2;
rightPin1: RouteChannel.ChanPin ← seg1.exteriorPins[chanRight];
right1Loc: Route.Number ← rightPin1.pinPosition.pLoc + rightPin1.pWidth/2;
leftPin2: RouteChannel.ChanPin ← seg2.exteriorPins[chanLeft];
left2Loc: Route.Number ← leftPin2.pinPosition.pLoc - leftPin2.pWidth/2;
rightPin2: RouteChannel.ChanPin ← seg2.exteriorPins[chanRight];
right2Loc: Route.Number ← rightPin2.pinPosition.pLoc + rightPin2.pWidth/2;
gap: RoutePrivate.Range ← RouteChannel.Gap[[left1Loc, right1Loc], [left2Loc, right2Loc]];
IF gap.l > gap.r THEN overlap ← TRUE
ELSE overlap ← gap.r - gap.l < dist};
OverlapCheck: PROCEDURE[seg1, seg2: RouteChannel.Segment, dist: Route.Number]
RETURNS [overlap: BOOLEAN] = {
overlap ← HalfOverlapCheck[seg1, seg2, dist] OR HalfOverlapCheck[seg2, seg1, dist]};
ContactCheck: PROCEDURE[pin1: RouteChannel.ChanPin, qPos1: Route.Number, pin2: RouteChannel.ChanPin, qPos2, dist: Route.Number] RETURNS [overlap: BOOLEANFALSE] =
BEGIN
IF ABS[qPos1 - qPos2] < dist THEN {
left1Loc: Route.Number ← pin1.pinPosition.pLoc - pin1.pWidth/2;
right1Loc: Route.Number ← pin1.pinPosition.pLoc + pin1.pWidth/2;
left2Loc: Route.Number ← pin2.pinPosition.pLoc - pin2.pWidth/2;
right2Loc: Route.Number ← pin2.pinPosition.pLoc + pin2.pWidth/2;
gap: RoutePrivate.Range ← RouteChannel.Gap[[left1Loc, right1Loc], [left2Loc, right2Loc]];
IF gap.l > gap.r THEN overlap ← TRUE
ELSE overlap ← gap.r - gap.l < dist};
END; -- ContactCheck
ConstraintCheck: PROCEDURE[graph: RouteDiGraph.Graph, segment: RouteChannel.Segment,
direction: RouteChannel.AboveOrBelow, track: RouteChannel.MaxTracks, mustBePlaced: BOOLEAN]
RETURNS [constrained: BOOLEANFALSE] = {
recursively go through the constraints
CheckConstraints: RouteDiGraph.EnumArcsFromNodeProc = {
nextNode: RouteDiGraph.Node ← IF direction = in THEN arc.inferiorNode ELSE arc.superiorNode;
nodeInfo: RouteChannel.SegmentConstraint ← NARROW[nextNode.nodeInfo];
segment: RouteChannel.Segment ← nodeInfo.segment;
IF segment.trackNum = 0 THEN {
IF mustBePlaced THEN quit ← TRUE} -- segment must be placed
ELSE {
IF direction = out THEN
quit ← track >= segment.trackNum
ELSE
quit ← track <= segment.trackNum};
IF ~quit THEN
quit ← RouteDiGraph.EnumArcsFromNode[graph, nextNode, direction, CheckConstraints]};
node: RouteDiGraph.Node ← segment.constraintNode;
gDirection: RouteDiGraph.Direction ← IF direction = above THEN out ELSE in;
constrained ← RouteDiGraph.EnumArcsFromNode[graph, node, gDirection, CheckConstraints];
};
GetNextSegment: PROCEDURE[routingArea: Route.RoutingArea, activeSegSpec: RouteChannel.ActiveSegSpec, activeTrackSpec: RouteChannel.ActiveTrackSpec, segProc: SegProc]
RETURNS [nextSegSpec: RouteChannel.ActiveSegSpec ← NIL] = {
return the next segment that fits and satisfies the constraints
CheckSegs: RouteChannel.EachPinActionProc = {
IF pin # NIL THEN {
[quit, trialSegSpec] ← segProc[pin.conctSeg[whichSide], activeTrackSpec];
IF ~quit THEN [quit, trialSegSpec] ← segProc[pin.altConctSeg[whichSide], activeTrackSpec]}};
found: BOOLEANFALSE;
whichSide: RouteChannel.ChanLRSide;
pinPos: RouteChannel.ZMPinsOnCh;
chanData: RouteChannel.ChannelData ← NARROW[routingArea.privateData];
lastIndex: RouteChannel.ZMPinsOnCh ← chanData.chanPins.count;
trialSegSpec: RouteChannel.ActiveSegSpec;
got starting pin, scan the track
SELECT activeTrackSpec.going FROM
leftToRight => {
IF activeSegSpec = NIL THEN pinPos ← 1
ELSE pinPos ← activeSegSpec.seg.exteriorPins[chanLeft].pinPosition.pinIndex;
whichSide ← chanRight;
FOR posIndex: RouteChannel.MPinsOnCh IN [pinPos .. lastIndex] WHILE ~ found DO
pinPosition: RouteChannel.PinPosition ← chanData.chanPins.sides[posIndex];
found ← RouteChannel.EnumPins[routingArea, pinPosition, CheckSegs]
ENDLOOP}; -- posIndex
rightToLeft => {
IF activeSegSpec = NIL THEN pinPos ← lastIndex
ELSE pinPos ← activeSegSpec.seg.exteriorPins[chanRight].pinPosition.pinIndex;
whichSide ← chanLeft;
FOR posIndex: RouteChannel.MPinsOnCh DECREASING IN [1 .. pinPos] WHILE ~ found DO
pinPosition: RouteChannel.PinPosition ← chanData.chanPins.sides[posIndex];
found ← RouteChannel.EnumPins[routingArea, pinPosition, CheckSegs]
ENDLOOP}; -- posIndex
ENDCASE;
IF found THEN nextSegSpec ← trialSegSpec;
IF debug AND nextSegSpec # NIL THEN
IF nextSegSpec.seg # NIL THEN
{TerminalIO.WriteRope[Rope.Cat["\n New segment: ", nextSegSpec.seg.net.name, ", ", RoutePrivate.RoutingLayerName[nextSegSpec.segLayer]]]};
}; -- GetNextSegment
FollowingSeg: PROCEDURE [routingArea: Route.RoutingArea, activeSegSpec: RouteChannel.ActiveSegSpec,
activeTrackSpec: RouteChannel.ActiveTrackSpec]
RETURNS [nextSegSpec: RouteChannel.ActiveSegSpec ← NIL] = {
return the following segment in the current direction
tracknum must be 0
CheckFitSegs: RouteChannel.EachPinActionProc = {
IF pin # NIL THEN
{seg: RouteChannel.Segment ← pin.conctSeg[existingSide];
IF seg # NIL THEN
IF seg = activeSegSpec.seg THEN
{trialSegSpec: RouteChannel.ActiveSegSpec ← NEW[RouteChannel.ActiveSegSpecRec ← [seg: pin.conctSeg[newSide]]];
IF trialSegSpec.seg # NIL THEN
IF trialSegSpec.seg.trackNum = 0 THEN nextSegSpec ← trialSegSpec;
quit ← TRUE}}};
existingSide, newSide: RouteChannel.ChanLRSide;
pinPos: RouteChannel.PinPosition;
found: BOOLEANFALSE;
SELECT activeTrackSpec.going FROM
leftToRight =>
{pinPos ← activeSegSpec.seg.exteriorPins[chanRight].pinPosition;
existingSide ← chanLeft;
newSide ← chanRight};
rightToLeft =>
{pinPos ← activeSegSpec.seg.exteriorPins[chanLeft].pinPosition;
existingSide ← chanRight;
newSide ← chanLeft};
ENDCASE;
check the next seg basie on existingSide and newSide
found ← RouteChannel.EnumPins[routingArea, pinPos, CheckFitSegs]
}; -- FollowingSeg
AnalyzeResult: PROCEDURE[routingArea: Route.RoutingArea] RETURNS [result: Route.RoutingResult] = {
RemoveTrackIfPossible: PROCEDURE[routingArea: Route.RoutingArea, track, oldNumTracks: RouteChannel.MaxTracks]
RETURNS [numTracks: RouteChannel.ZMaxTracks] = {
check for design rule violations if track is removed
chanData: RouteChannel.ChannelData ← NARROW[routingArea.privateData];
chanTracks: RouteChannel.RoutingChannelTracks ← chanData.chanTracks;
IF track = stopTrack THEN track ← stopTrack;
IF ~chanTracks.tracks[track].blocked AND ~chanTracks.tracks[track].keep THEN
numTracks ← RemoveTrack[routingArea, track, oldNumTracks] -- assume track can be removed
ELSE numTracks ← oldNumTracks};
EnumExits: RouteChannel.EnumExitsProc = {
do nothing, dont care about exits
IF constructedExit THEN
IF ~RouteChannel.MembRopeList[name, breakAtExitList] THEN
breakAtExitList ← CONS[name, breakAtExitList]};
EnumSegments: RouteChannel.EnumSegmentsProc = {
length: Route.Number ← RouteUtil.Length[pos1, pos2];
SELECT TRUE FROM
layer = metalLayer => metal1length ← metal1length + length;
layer = metal2Layer => metal2length ← metal2length + length;
layer = polyLayer => polyLength ← polyLength + length;
ENDCASE => otherLength ← otherLength + length};
EnumPins: RouteChannel.EnumPinsProc = {
count the vias
pinLayer: Route.Layer ← CDSymbolicObjects.GetLayer[pin.pin];
IF layer = polyLayer AND pinLayer = metalLayer OR layer = metalLayer AND pinLayer = polyLayer THEN
polyToMetal ← polyToMetal +1
ELSE IF layer = metalLayer AND pinLayer = metal2Layer OR layer = metal2Layer AND pinLayer = metalLayer THEN
metalToMetal2 ← metalToMetal2 +1};
EnumVias: RouteChannel.EnumViasProc = {
count the vias
IF layer1 = polyLayer AND layer2 = metalLayer OR layer1 = metalLayer AND layer2 = polyLayer THEN
polyToMetal ← polyToMetal +1
ELSE IF layer1 = metalLayer AND layer2 = metal2Layer OR layer1 = metal2Layer AND layer2 = metalLayer THEN
metalToMetal2 ← metalToMetal2 +1};
EnumIncompletes: RouteChannel.EnumIncompletesProc = {
count the incompletes
numIncompletes ← numIncompletes +1;
IF ~RouteChannel.MembRopeList[name, incompleteList] THEN
incompleteList ← CONS[name, incompleteList]};
ElimUselessTracks: RouteChannel.EachTrackActionProc = {
remove empty tracks if no design rule violation is created
IF RouteChannel.TrackSeg[routingArea, trackIndex] = NIL THEN -- this track has no segments
numTracks ← RemoveTrackIfPossible[routingArea, trackIndex, numTracks]};
AnalyzeResult
chanData: RouteChannel.ChannelData ← NARROW[routingArea.privateData];
chanTracks: RouteChannel.RoutingChannelTracks ← chanData.chanTracks;
parms: RoutePrivate.RoutingAreaParms ← NARROW[routingArea.parms];
metal1length, metal2length, polyLength, otherLength: Route.Number ← 0;
polyToMetal, metalToMetal2, numIncompletes: NAT ← 0;
technology: CD.Technology ← NARROW[routingArea.rules.technology];
metalLayer: Route.Layer ← CD.FetchLayer[technology, $met];
metal2Layer: Route.Layer ← CD.FetchLayer[technology, $met2];
polyLayer: Route.Layer ← CD.FetchLayer[technology, $pol];
rect: Route.Rect;
loc1, loc2: Route.Position;
incompleteList: LIST OF Rope.ROPENIL;
breakAtExitList: LIST OF Rope.ROPENIL;
numTracks: RouteChannel.ZMaxTracks ← chanTracks.count;
lowerTrackSpec: RouteChannel.ActiveTrackSpec ← NEW[RouteChannel.ActiveTrackSpecRec];
upperTrackSpec: RouteChannel.ActiveTrackSpec ← NEW[RouteChannel.ActiveTrackSpecRec];
segSpec: RouteChannel.ActiveSegSpec ← NEW[RouteChannel.ActiveSegSpecRec];
remove useless tracks
later I need to add ability to do wiring improvements:
reduce poly length, reduce number of vias
IF parms.routerUsed = channel THEN {
[] ← RouteChannel.EnumTracks[routingArea, ElimUselessTracks];
chanTracks.count ← numTracks};
loc1 ← RouteUtil.PQToXY[routingArea, [chanData.chanPins.cEnd1, chanData.chanSides[chanBottom].routeAreaCoord]];
IF parms.routerUsed = channel THEN {
thisChanWidth: Route.Number ← RouteChannel.ChannelWidth[routingArea];
loc2 ← RouteUtil.PQToXY[routingArea, [chanData.chanPins.cEnd2, chanData.chanSides[chanBottom].routeAreaCoord + thisChanWidth]]}
ELSE IF parms.routerUsed = switchBox THEN
loc2 ← RouteUtil.PQToXY[routingArea, [chanData.chanPins.cEnd2, chanData.chanSides[chanTop].routeAreaCoord]];
rect ← [loc1.x, loc1.y, loc2.x, loc2.y];
[] ← RouteChannel.GetRouting[routingArea, rect, NIL, EnumSegments,
EnumPins, EnumVias, EnumExits, EnumIncompletes];
result ← NEW[Route.RoutingResultRec ← [routingArea, polyLength, metal1length, metal2length, polyToMetal, metalToMetal2, chanTracks.count, numIncompletes, rect, FALSE, incompleteList, breakAtExitList]];
}; -- AnalyzeResult
CanConvert: PROCEDURE[routingArea: Route.RoutingArea, seg: RouteChannel.Segment]
RETURNS [segLayer: RoutePrivate.RoutingLayerOrNone ← trunk] = {
-- see if this trunk routingLayer seg can be pulled down onto the branch routingLayer
chanData: RouteChannel.ChannelData ← NARROW[routingArea.privateData];
leftPin: RouteChannel.ChanPin ← seg.exteriorPins[chanLeft];
rightPin: RouteChannel.ChanPin ← seg.exteriorPins[chanRight];
leftPinPosition: RouteChannel.PinPosition ← leftPin.pinPosition;
rightPinPosition: RouteChannel.PinPosition ← rightPin.pinPosition;
segLength: Route.Number ← rightPinPosition.pLoc - leftPinPosition.pLoc;
IF leftPin.kindOfPin = exitPin OR rightPin.kindOfPin = exitPin THEN RETURN;
IF segLength <= chanData.chanParms.maxToConvert AND ABS[leftPinPosition.pinIndex - rightPinPosition.pinIndex] <= 1 THEN segLayer ← branch};
RemoveTrack: PROCEDURE [routingArea: Route.RoutingArea, track, oldNumTracks: RouteChannel.ZMaxTracks] RETURNS [numTracks: RouteChannel.ZMaxTracks] = {
move tracks above this one down
chanData: RouteChannel.ChannelData ← NARROW[routingArea.privateData];
chanTracks: RouteChannel.RoutingChannelTracks ← chanData.chanTracks;
trackNum, oldTrackNum: RouteChannel.MaxTracks;
FOR upperTrack: RouteChannel.MaxTracks DECREASING IN [track+1 .. chanTracks.count] DO
chanTracks.tracks[upperTrack].oldTrackNum ← chanTracks.tracks[upperTrack].trackNum;
chanTracks.tracks[upperTrack].trackNum ← chanTracks.tracks[upperTrack-1].trackNum;
ENDLOOP;
IF track # 1 THEN chanTracks.tracks[track].trackNum ← chanTracks.tracks[track-1].trackNum;
FOR upperTrack: RouteChannel.MaxTracks IN [track+1 .. chanTracks.count] DO
trackNum ← chanTracks.tracks[upperTrack].trackNum;
oldTrackNum ← chanTracks.tracks[upperTrack].oldTrackNum;
chanTracks.tracks[trackNum].firstSeg ← chanTracks.tracks[oldTrackNum].firstSeg;
ENDLOOP;
IF track # chanTracks.count THEN {
oldTrackNum ← chanTracks.tracks[chanTracks.count].oldTrackNum;
chanTracks.tracks[oldTrackNum].firstSeg ← NIL};
numTracks ← oldNumTracks - 1};
BuildTrackSpec: PROCEDURE [routingArea: Route.RoutingArea, track, maxTracks: RouteChannel.ZMaxTracks, going: RouteChannel.GoingDirection, freeArea: RouteChannel.AboveOrBelow, trackSpec: RouteChannel.ActiveTrackSpec] = {
chanData: RouteChannel.ChannelData ← NARROW[routingArea.privateData];
chanTracks: RouteChannel.RoutingChannelTracks ← chanData.chanTracks;
parms: RoutePrivate.RoutingAreaParms ← NARROW[routingArea.parms];
influence: Route.Number ← RouteChannel.InfluenceTracks[routingArea, parms.widestTrunk];
trackSpec.minActTrack ← MAX[track - influence, 1];
trackSpec.maxActTrack ← MIN[track + influence, maxTracks];
trackSpec.track ← track;
trackSpec.going ← going;
trackSpec.freeArea ← freeArea};
END.