RouteChannelInitImpl:
CEDAR
PROGRAM
IMPORTS CDBasics, CDSymbolicObjects, List, Rope, Route, RouteChannel, RouteUtil
EXPORTS RouteChannel
BEGIN
ChanSideName: PUBLIC ARRAY RouteChannel.ChanSide OF Rope.ROPE ← ["chanBottom", "chanTop", "chanLeft", "chanRight"];
AboveOrBelowName: PUBLIC ARRAY RouteChannel.AboveOrBelow OF Rope.ROPE ← ["above", "below"];
GoingName:
PUBLIC
ARRAY RouteChannel.GoingDirection
OF Rope.
ROPE ← ["leftToRight", "rightToLeft"];
InitChannel:
PUBLIC
PROCEDURE[routingArea: Route.RoutingArea, sideOrgins: Route.PositionVec, routingRect: Route.Rect, routerUsed: RoutePrivate.RouterUsed, signalSinglePinNets, signalCoincidentPins, okToDiddleLLPins, okToDiddleURPins:
BOOLEAN] = {
Initialize for channel routing
netTab: RoutePrivate.NetTab;
parms: RoutePrivate.RoutingAreaParms ← NARROW[routingArea.parms];
nRect: Route.Rect ← CDBasics.ReInterpreteRect[routingRect];
lowPos: RoutePrivate.PQPosition ← RouteUtil.XYToPQ[routingArea, [nRect.x1, nRect.y1]];
upPos: RoutePrivate.PQPosition ← RouteUtil.XYToPQ[routingArea, [nRect.x2, nRect.y2]];
rRect: RoutePrivate.PQRect ← [lowPos, upPos];
build the channel routing area; privatePart.constraints initialized in RouteChannelConstraintsImpl
channelData: RouteChannel.ChannelData ← NEW[RouteChannel.ChannelDataRec];
channelData.constraints ← NIL;
channelData.chanSides[chanTop] ← NEW[RouteChannel.RoutingChannelSidesRec];
channelData.chanSides[chanBottom] ← NEW[RouteChannel.RoutingChannelSidesRec];
channelData.chanSides[chanLeft] ← NEW[RouteChannel.RoutingChannelSidesRec];
channelData.chanSides[chanRight] ← NEW[RouteChannel.RoutingChannelSidesRec];
channelData.chanTracks ← NEW[RouteChannel.RoutingChannelTracksRec];
channelData.chanPins ← NEW[RouteChannel.RoutingChannelPinsRec];
channelData.chanParms ← NEW[RouteChannel.ChanParmsRec];
routingArea.privateData ← channelData;
parms.routerUsed ← routerUsed;
channelData.chanParms.emptyTrackLimit ← MAX[2, RouteChannel.InfluenceTracks[routingArea, parms.widestTrunk]];
channelData.chanParms.maxToConvert ← 10*routingArea.rules.branchToBranch;
convert sides to p-q space and build side data structures
ConvertSide[routingArea, chanBottom, sideOrgins, rRect];
ConvertSide[routingArea, chanTop, sideOrgins, rRect];
ConvertEnd[routingArea, chanLeft, sideOrgins, rRect];
ConvertEnd[routingArea, chanRight, sideOrgins, rRect];
fix up the routing area orgins
FixOrgins[routingArea, rRect];
convert the nets from x-y space to p-q space
netTab ← NARROW[routingArea.nets, RoutePrivate.NetTab];
FOR netIndex: RoutePrivate.ZMaxNets
IN [1 .. netTab.count]
DO
InitNet[routingArea, netTab.n[netIndex], signalSinglePinNets, signalCoincidentPins];
ENDLOOP;
IF parms.routerUsed = switchBox THEN MakeSBTracks[routingArea, okToDiddleLLPins, okToDiddleURPins]
ELSE MakeCRTracks[routingArea, parms.numTracksToUse];
DoTBBarriers[routingArea, chanBottom];
DoTBBarriers[routingArea, chanTop];
DoLRBarriers[routingArea, chanLeft];
DoLRBarriers[routingArea, chanRight]};
ConvertSide:
PROCEDURE[routingArea: Route.RoutingArea, chanSide: RouteChannel.ChanSide, sideOrgins: Route.PositionVec, routingRect: RoutePrivate.PQRect] = {
Convert a channel side to p-q space and set up side data
chanData: RouteChannel.ChannelData ← NARROW[routingArea.privateData];
activeSide: RouteChannel.RoutingChannelSides ← chanData.chanSides[chanSide];
chanPins: RouteChannel.RoutingChannelPins ← chanData.chanPins;
extSide: Route.Side ← RouteChannel.IntSideToExtSide[routingArea, chanSide];
extSidesData: RoutePrivate.RoutingAreaSides ← NARROW[routingArea.routingSides];
extSideData: RoutePrivate.RoutingAreaSide ← extSidesData[extSide];
activeSide.enclosingBarrier ← [[0, 0], [0, 0]];
activeSide.extSide ← extSide;
activeSide.sideOrg ← RouteUtil.XYToPQ[routingArea, sideOrgins[extSide]];
chanPins.cEnd1 ← routingRect.c1.p; chanPins.cEnd2 ← routingRect.c2.p;
IF extSideData #
NIL
THEN {
encloseBranch: RoutePrivate.PQRect ← TranslateBarriers[routingArea, activeSide, branch];
encloseTrunk: RoutePrivate.PQRect ← TranslateBarriers[routingArea, activeSide, trunk];
activeSide.enclosingBarrier ← Surround[encloseBranch, encloseTrunk];
activeSide.sideFiducial ← RouteUtil.XYToPQ[routingArea, extSideData.sideFiducial];
activeSide.properties ← extSideData.properties}};
TranslateBarriers:
PROCEDURE[routingArea: Route.RoutingArea, activeSide: RouteChannel.RoutingChannelSides, rLayer: RoutePrivate.RoutingLayer]
RETURNS [enclosingRect: RoutePrivate.PQRect ← [[0, 0], [0, 0]]] = {
convert routing barriers for a side
extSidesData: RoutePrivate.RoutingAreaSides ← NARROW[routingArea.routingSides];
extSide: Route.Side ← activeSide.extSide;
extSideData: RoutePrivate.RoutingAreaSide ← extSidesData[extSide];
chanDirection: Route.Direction ← routingArea.rules.trunkDirection;
IF extSideData #
NIL
THEN {
FOR bList: Route.RoutingBarrierList ← extSideData.barrierList, bList.rest
WHILE bList #
NIL
DO
barrierItem: Route.RoutingBarrier ← bList.first;
generalLayer: Route.Layer ← barrierItem.layer;
IF generalLayer =
CD.undefLayer
OR RouteUtil.LayerToRoutingLayer[routingArea, generalLayer] = rLayer
THEN {
FOR rList: Route.RectList ← barrierItem.barrier, rList.rest
WHILE rList #
NIL
DO
cleanRectangle: RoutePrivate.PQRectRef ← CheckRect[routingArea, rList.first, activeSide];
IF cleanRectangle #
NIL
THEN {
enclosingRect ← Surround[enclosingRect, cleanRectangle^];
activeSide.barrierList[rLayer] ← CONS[cleanRectangle^, activeSide.barrierList[rLayer]]};
ENDLOOP}
ENDLOOP}};
CheckRect:
PROC [routingArea: Route.RoutingArea, rect: Route.Rect, activeSide: RouteChannel.RoutingChannelSides]
RETURNS[cleanRect: RoutePrivate.PQRectRef] = {
clean up the rectangle and return it.
chanDirection: Route.Direction ← routingArea.rules.trunkDirection;
c1: RoutePrivate.PQPosition ← RouteUtil.XYToPQ[routingArea, [rect.x1, rect.y1]];
c2: RoutePrivate.PQPosition ← RouteUtil.XYToPQ[routingArea, [rect.x2, rect.y2]];
t1: RoutePrivate.PQPosition ← [c1.p - activeSide.sideFiducial.p + activeSide.sideOrg.p, c1.q - activeSide.sideFiducial.q + activeSide.sideOrg.q];
t2: RoutePrivate.PQPosition ← [c2.p - activeSide.sideFiducial.p + activeSide.sideOrg.p, c2.q - activeSide.sideFiducial.q + activeSide.sideOrg.q];
RETURN[NEW[RoutePrivate.PQRect ← [t1, t2]]]};
ConvertEnd:
PROCEDURE[routingArea: Route.RoutingArea, chanSide: RouteChannel.ChanSide, sideOrgins: Route.PositionVec, routingRect: RoutePrivate.PQRect] = {
convert a channel end to p-q space and set up side data
chanData: RouteChannel.ChannelData ← NARROW[routingArea.privateData];
activeSide: RouteChannel.RoutingChannelSides ← chanData.chanSides[chanSide];
extSide: Route.Side ← RouteChannel.IntSideToExtSide[routingArea, chanSide];
extSidesData: RoutePrivate.RoutingAreaSides ← NARROW[routingArea.routingSides];
extSideData: RoutePrivate.RoutingAreaSide ← extSidesData[extSide];
activeSide.extSide ← extSide;
activeSide.enclosingBarrier ← [[0, 0], [0, 0]];
activeSide.sideOrg ← RouteUtil.XYToPQ[routingArea, sideOrgins[extSide]];
IF extSideData #
NIL
THEN {
encloseBranch: RoutePrivate.PQRect ← TranslateBarriers[routingArea, activeSide, branch];
encloseTrunk: RoutePrivate.PQRect ← TranslateBarriers[routingArea, activeSide, trunk];
activeSide.sideFiducial ← RouteUtil.XYToPQ[routingArea, extSideData.sideFiducial];
activeSide.enclosingBarrier ← Surround[encloseBranch, encloseTrunk];
activeSide.properties ← extSideData.properties}};
FixOrgins:
PROCEDURE[routingArea: Route.RoutingArea, routingRect: RoutePrivate.PQRect] = {
now that all side data is available, compute the routing area
chanData: RouteChannel.ChannelData ← NARROW[routingArea.privateData];
chanPins: RouteChannel.RoutingChannelPins ← chanData.chanPins;
leftSide: RouteChannel.RoutingChannelSides ← chanData.chanSides[chanLeft];
rightSide: RouteChannel.RoutingChannelSides ← chanData.chanSides[chanRight];
bottomSide: RouteChannel.RoutingChannelSides ← chanData.chanSides[chanBottom];
topSide: RouteChannel.RoutingChannelSides ← chanData.chanSides[chanTop];
zero: Route.Number ← 0; -- don't laugh
fix up the routing area
leftSide.routeAreaCoord ← chanPins.cEnd1;
rightSide.routeAreaCoord ← chanPins.cEnd2;
chanPins.cEnd1 ← chanPins.cEnd1 + MAX[zero, leftSide.enclosingBarrier.c2.p];
chanPins.cEnd2 ← chanPins.cEnd2 + MAX[zero, rightSide.enclosingBarrier.c1.p];
bottomSide.routeAreaCoord ← routingRect.c1.q;
topSide.routeAreaCoord ← routingRect.c2.q};
InitNet:
PROCEDURE[routingArea: Route.RoutingArea, net: RoutePrivate.Net, signalSinglePinNets, signalCoincidentPins:
BOOLEAN] = {
Initialize for channel routing
PPinCompare: List.CompareProc = {
p1: Route.Number ← NARROW[ref1, RouteChannel.InternPin].location.p;
p2: Route.Number ← NARROW[ref2, RouteChannel.InternPin].location.p;
RETURN[
IF p1 < p2
THEN Basics.Comparison.less
ELSE IF p1 = p2 THEN Basics.Comparison.equal
ELSE Basics.Comparison.greater]};
mungedPinList, sortedPinList: List.LORA;
parms: RoutePrivate.RoutingAreaParms ← NARROW[routingArea.parms];
chanDirection: Route.Direction ← routingArea.rules.trunkDirection;
net.internPinList ← FixPins[routingArea, net.pinList, chanDirection];
mungedPinList ← ConvertToLORA[NARROW[net.internPinList]];
sortedPinList ← List.Sort[mungedPinList, PPinCompare];
IF CheckChanPins[routingArea, net, sortedPinList, signalSinglePinNets, signalCoincidentPins]
THEN
BuildChanPin[routingArea, net, sortedPinList]};
FixPins:
PROC [routingArea: Route.RoutingArea, pList: Route.PinList, chanDirection: Route.Direction]
RETURNS [fixedPins:
-- List.LORA ← NIL -- RouteChannel.InternPinList ←
NIL ] = {
Translate the pin coordinates from x-y space to p-q space.
chanData: RouteChannel.ChannelData ← NARROW[routingArea.privateData];
chanPins: RouteChannel.RoutingChannelPins ← chanData.chanPins;
parms: RoutePrivate.RoutingAreaParms ← NARROW[routingArea.parms];
FOR list: Route.PinList ← pList, list.rest
WHILE list #
NIL
DO
old: Route.Pin ← list.first;
loc: RoutePrivate.PQPosition;
oldWidth, width: Route.Number;
new: RouteChannel.InternPin;
oldPinSize: CD.Position ← CDBasics.OrientedSize[CDBasics.SizeOfRect[old.pin.ob.bbox], old.pin.trans.orient];
oldPinPos: CD.Position ← CDBasics.BaseOfRect[CDBasics.MapRect[old.pin.ob.bbox, old.pin.trans]];
chanSide: RouteChannel.ChanSide ← RouteChannel.ExtSideToIntSide[routingArea, old.side];
activeSide: RouteChannel.RoutingChannelSides ← chanData.chanSides[chanSide];
layer: Route.Layer ← CDSymbolicObjects.GetLayer[old.pin];
rLayer: RoutePrivate.RoutingLayer ← RouteUtil.LayerToRoutingLayer[routingArea, layer];
name: Rope.ROPE ← CDSymbolicObjects.GetName[old.pin];
sideFiducial: RoutePrivate.PQPosition ← activeSide.sideFiducial;
sideOrg: RoutePrivate.PQPosition ← activeSide.sideOrg;
SELECT old.side
FROM
bottom => {
oldWidth ← oldPinSize.x;
oldLoc ← [oldPinPos.x + oldPinSize.x/2, oldPinPos.y + oldPinSize.y]};
top => {
oldWidth ← oldPinSize.x;
oldLoc ← [oldPinPos.x + oldPinSize.x/2, oldPinPos.y]};
left => {
oldWidth ← oldPinSize.y;
oldLoc ← [oldPinPos.x + oldPinSize.x, oldPinPos.y + oldPinSize.y/2]};
right => {
oldWidth ← oldPinSize.y;
oldLoc ← [oldPinPos.x, oldPinPos.y + oldPinSize.y/2]};
ENDCASE;
SELECT chanSide
FROM
chanBottom, chanTop => {
loc ← RouteChannel.SubPoints[RouteUtil.XYToPQ[routingArea, oldLoc], sideFiducial];
loc ← RouteChannel.AddPoints[loc, sideOrg];
loc.q ← loc.q - activeSide.routeAreaCoord;
width ← oldWidth};
chanLeft => {
IF parms.routerUsed = channel THEN {loc ← [chanPins.cEnd1, 0]; width ← 0}
ELSE
IF parms.routerUsed = switchBox
THEN {
loc ← RouteChannel.SubPoints[RouteUtil.XYToPQ[routingArea, oldLoc], sideFiducial];
loc ← RouteChannel.AddPoints[loc, sideOrg];
loc.p ← chanPins.cEnd1;
width ← oldWidth}};
chanRight => {
IF parms.routerUsed = channel THEN {loc ← [chanPins.cEnd2, 0]; width ← 0}
ELSE
IF parms.routerUsed = switchBox
THEN
{loc ← RouteChannel.SubPoints[RouteUtil.XYToPQ[routingArea, oldLoc], sideFiducial];
loc ← RouteChannel.AddPoints[loc, sideOrg];
loc.p ← chanPins.cEnd2;
width ← oldWidth}};
ENDCASE;
new ← NEW[RouteChannel.InternPinRec ← [name, chanSide, loc, width, rLayer, old]];
fixedPins ← CONS[new, fixedPins];
ENDLOOP};
CheckChanPins:
PROC [routingArea: Route.RoutingArea, net: RoutePrivate.Net, pinList: List.
LORA
-- RouteChannel.InternPinList --, signalSinglePinNets, signalCoincidentPins:
BOOLEAN]
RETURNS [ok:
BOOLEAN ←
TRUE] = {
Check the pins for this net.
-- number of pins > 1
-- pins within range
-- pin overlap
-- pin spacing
-- max number of pins
chanData: RouteChannel.ChannelData ← NARROW[routingArea.privateData];
chanPins: RouteChannel.RoutingChannelPins ← chanData.chanPins;
netTab: RoutePrivate.NetTab ← NARROW[routingArea.nets, RoutePrivate.NetTab];
numPins, numOverlaps: NAT ← 0;
leftExit, rightExit: BOOLEAN ← FALSE;
branchLayer: CD.Layer ← routingArea.rules.branchLayer;
trunkLayer: CD.Layer ← routingArea.rules.trunkLayer;
previousPin: RouteChannel.InternPin ←
NIL;
FOR pList: List.
LORA
-- RouteChannel.InternPinList -- ← pinList, pList.rest
WHILE pList #
NIL
DO
this: RouteChannel.InternPin ← NARROW[pList.first];
pinLayer: CD.Layer ← CDSymbolicObjects.GetLayer[this.pin.pin];
numPins ← numPins + 1;
IF previousPin #
NIL
THEN {
-- check for overlapping pins.
IF previousPin.chanSide = this.chanSide
THEN {
rLast, rThis: RoutePrivate.Range;
IF previousPin.chanSide = chanBottom OR previousPin.chanSide = chanTop
THEN {
rLast ← [previousPin.location.p - previousPin.pWidth/2, previousPin.location.p + previousPin.pWidth/2];
rThis ← [this.location.p - this.pWidth/2, this.location.p + this.pWidth/2]}
ELSE {
-- chanSide = chanLeft OR chanSide = chanRight
rLast ← [previousPin.location.q - previousPin.pWidth/2, previousPin.location.q + previousPin.pWidth/2];
rThis ← [this.location.q - this.pWidth/2, this.location.q + this.pWidth/2]};
IF RouteChannel.Overlaps[rLast, rThis]
THEN {
numOverlaps ← numOverlaps + 1;
IF signalCoincidentPins
OR ~(previousPin.location = this.location
AND previousPin.pWidth = this.pWidth)
THEN
Route.Signal[callingError, Rope.Cat[Rope.Cat["Pins overlap, net: ", net.name, ", pins: "], Rope.Cat[this.name, ", ", previousPin.name]]]; ok ← FALSE}}
};
SELECT this.chanSide
FROM
chanBottom, chanTop => {
pos: Route.Number ← this.location.p;
IF chanPins.cEnd1 > pos
OR chanPins.cEnd2 < pos
THEN {
Route.Signal[callingError, Rope.Cat["Pin location out of range, net: ", net.name, ", pin: ", this.name]]; ok ← FALSE};
IF pinLayer # branchLayer
THEN {
Route.Signal[callingError, Rope.Cat["Pin not on branch layer, net: ", net.name, ", pin: ", this.name]]; ok ← FALSE}};
chanLeft => {
IF pinLayer # trunkLayer
THEN {
Route.Signal[callingError, Rope.Cat["Pin not on trunk layer, net: ", net.name, ", pin: ", this.name]]; ok ← FALSE};
IF leftExit
THEN {
Route.Signal[callingError, Rope.Cat["Multiple channel exits: ", net.name, ", pin: ", this.name]]; ok ← FALSE};
leftExit ← TRUE};
chanRight => {
IF pinLayer # trunkLayer
THEN {
Route.Signal[callingError, Rope.Cat["Pin not on trunk layer, net: ", net.name, ", pin: ", this.name]]; ok ← FALSE};
IF rightExit
THEN {
Route.Signal[callingError, Rope.Cat["Multiple channel exits: ", net.name, ", pin: ", this.name]]; ok ← FALSE};
rightExit ← TRUE};
ENDCASE;
previousPin ← this;
ENDLOOP;
IF numPins - numOverlaps <= 1
THEN {
IF signalSinglePinNets THEN Route.Signal[callingError, Rope.Cat["Too few pins for net: ", net.name]];
ok ← FALSE};
IF netTab.count + numPins > netTab.size
THEN {
Route.Signal[noResource, "Net table is too small"]; ok ← FALSE}};
BuildChanPin:
PROC [routingArea: Route.RoutingArea, net: RoutePrivate.Net, pinList: List.
LORA
-- RouteChannel.InternPinList -- ] = {
build the channel pins data structure for this net.
NOTE: this assumes that CheckChanPins has been invoked and that the inputs are valid!!!
chanData: RouteChannel.ChannelData ← NARROW[routingArea.privateData];
chanPins: RouteChannel.RoutingChannelPins ← chanData.chanPins;
interiorPins: RouteChannel.ChanPinList ← NIL;
rightInternPin: RouteChannel.InternPin ← NARROW[List.NthElement[pinList, -1]];
previousPin: RouteChannel.InternPin ← NIL;
leftPin, rightPin: RouteChannel.ChanPin ← NIL;
allPinsOverlap: BOOLEAN ← TRUE;
seg: RouteChannel.Segment ←
NEW[RouteChannel.SegmentRec ← [net: net]];
FOR pList: List.
LORA
-- RouteChannel.InternPinList -- ← pinList, pList.rest
WHILE pList #
NIL
DO
pinIndex: RouteChannel.ZMPinsOnCh;
pinPosition: RouteChannel.PinPosition;
chanPin: RouteChannel.ChanPin;
this: RouteChannel.InternPin ← NARROW[pList.first];
useThisOne: BOOLEAN ← TRUE;
IF previousPin #
NIL
THEN {
-- This is a crock! If Bertrand checked for overlapping pins wouldn't be necessary!!
rLast, rThis: RoutePrivate.Range;
IF previousPin.chanSide = chanBottom OR previousPin.chanSide = chanTop
THEN {
rLast ← [previousPin.location.p - previousPin.pWidth/2, previousPin.location.p + previousPin.pWidth/2];
rThis ← [this.location.p - this.pWidth/2, this.location.p + this.pWidth/2]}
ELSE {
-- chanSide = chanLeft OR chanSide = chanRight
rLast ← [previousPin.location.q - previousPin.pWidth/2, previousPin.location.q + previousPin.pWidth/2];
rThis ← [this.location.q - this.pWidth/2, this.location.q + this.pWidth/2]};
IF previousPin.chanSide = this.chanSide
AND RouteChannel.Overlaps[rLast, rThis]
THEN
useThisOne ← FALSE;
IF this.chanSide = chanLeft
OR this.chanSide = chanRight
THEN
allPinsOverlap ← FALSE;
IF this.chanSide # chanLeft
AND this.chanSide # chanRight
THEN
allPinsOverlap ← allPinsOverlap AND RouteChannel.Equal[rLast, rThis]
};
IF useThisOne
THEN {
pinIndex ← FindPinPos[routingArea, this.location.p];
pinPosition ← chanPins.sides[pinIndex];
chanPin ← BuildPin[routingArea, this, pinPosition, routingArea.rules.branchWidth];
SELECT this.chanSide
FROM
chanBottom, chanTop =>
IF ~PinViolation[routingArea, chanPin, net]
THEN
pinPosition.pins[chanPin.pinSide] ← chanPin;
chanLeft, chanRight =>
pinPosition.innerPins ← CONS[chanPin, pinPosition.innerPins];
ENDCASE;
IF leftPin =
NIL
THEN {
leftPin ← chanPin; chanPin.conctSeg[chanLeft] ← NIL; chanPin.conctSeg[chanRight] ← seg}
ELSE
IF this = rightInternPin
THEN {
rightPin ← chanPin; chanPin.conctSeg[chanRight] ← NIL; chanPin.conctSeg[chanLeft] ← seg}
ELSE {
interiorPins ← CONS[chanPin, interiorPins]; chanPin.conctSeg[chanRight] ← seg; chanPin.conctSeg[chanLeft] ← seg}};
previousPin ← this;
ENDLOOP;
now update the segment
seg.exteriorPins[chanLeft] ← leftPin;
seg.exteriorPins[chanRight] ← rightPin;
seg.interiorPins ← interiorPins;
seg.qWidth ← IF allPinsOverlap THEN routingArea.rules.trunkWidth ELSE net.trunkWidth};
FindPinPos:
PUBLIC
PROC [routingArea: Route.RoutingArea, thisPLoc: Route.Number]
RETURNS [index: RouteChannel.ZMPinsOnCh ← 0] = {
build the PinPosition data structure for this pin at thisPLoc.
NOTE: this assumes that CheckChanPins has been invoked and that the inputs are valid!!!
chanData: RouteChannel.ChannelData ← NARROW[routingArea.privateData];
chanPins: RouteChannel.RoutingChannelPins ← chanData.chanPins;
found: BOOLEAN ← FALSE;
FOR pIndex: RouteChannel.ZMPinsOnCh
IN [1 .. chanPins.count]
WHILE ~found
DO
pLoc: Route.Number ← chanPins.sides[pIndex].pLoc;
IF pLoc > thisPLoc
THEN
{ -- add a new pinPosition
found ← TRUE;
MovePins[chanPins, pIndex];
index ← pIndex;
chanPins.sides[pIndex] ← NEW[RouteChannel.PinPositionRec ← [index, thisPLoc]]}
ELSE
IF pLoc = thisPLoc
THEN
{ -- pin position already taken, use it
found ← TRUE;
index ← pIndex};
ENDLOOP;
IF ~found
THEN {
-- this pin goes after the last pin
chanPins.count ← chanPins.count +1;
index ← chanPins.count;
chanPins.sides[index] ← NEW[RouteChannel.PinPositionRec ← [index, thisPLoc]]};
};
MovePins:
PROC [chanPins: RouteChannel.RoutingChannelPins, pIndex: RouteChannel.ZMPinsOnCh] = {
chanPins.count ← chanPins.count +1;
FOR index: RouteChannel.ZMPinsOnCh
DECREASING
IN [pIndex+1 .. chanPins.count]
DO
pinPos: RouteChannel.PinPosition ← chanPins.sides[index-1];
pinPos.pinIndex ← index;
chanPins.sides[index] ← pinPos;
ENDLOOP};
BuildPin:
PROC [routingArea: Route.RoutingArea, iPin: RouteChannel.InternPin, pinPosition: RouteChannel.PinPosition, pinWidth: Route.Number]
RETURNS [pin: RouteChannel.ChanPin] = {
build the channel segment data structure for this net.
parms: RoutePrivate.RoutingAreaParms ← NARROW[routingArea.parms];
kindOfPin: RouteChannel.ChanPinType ←
IF iPin.chanSide = chanLeft OR iPin.chanSide = chanRight THEN exitPin
ELSE compPin;
thisPinWidth: Route.Number ←
IF kindOfPin = exitPin THEN iPin.pWidth
ELSE MAX[pinWidth, iPin.pWidth];
parms.widestPin ← MAX[thisPinWidth, parms.widestPin];
pin ← NEW[RouteChannel.ChanPinRec ← [pinSide: iPin.chanSide, qLoc: iPin.location.q, pWidth: thisPinWidth, kindOfPin: kindOfPin, pinPosition: pinPosition, pin: iPin]]};
PinViolation:
PROC [routingArea: Route.RoutingArea, pin: RouteChannel.ChanPin, net: RoutePrivate.Net]
RETURNS [violation:
BOOLEAN ←
FALSE] = {
check for pin to pin violations.
LimitProc: RouteChannel.EachPinActionProc = {
IF pin #
NIL
THEN
IF pin.pinSide = pinSide
THEN
{width: Route.Number ← RouteUtil.GetWidthWithContact[routingArea, pin.pWidth]/2;
pinPos: Route.Number ← pin.pinPosition.pLoc;
IF pinPos < pLoc
THEN
quit ← pinPos + width + routingArea.rules.branchSpacing > pLoc - pWidth
ELSE
-- pinPos >= pLoc
quit ← pLoc + pWidth + routingArea.rules.branchSpacing > pinPos - width};
IF quit THEN violationPin ← pin.pin};
chanData: RouteChannel.ChannelData ← NARROW[routingArea.privateData];
chanPins: RouteChannel.RoutingChannelPins ← chanData.chanPins;
parms: RoutePrivate.RoutingAreaParms ← NARROW[routingArea.parms];
pinSide: RouteChannel.ChanSide ← pin.pinSide;
pinIndex: RouteChannel.ZMPinsOnCh ← pin.pinPosition.pinIndex;
pLoc: Route.Number ← pin.pinPosition.pLoc;
pWidth: Route.Number ← RouteUtil.GetWidthWithContact[routingArea, pin.pWidth]/2;
testWidth: Route.Number ← RouteUtil.GetWidthWithContact[routingArea, parms.widestPin] + routingArea.rules.branchSpacing;
violationPin: RouteChannel.InternPin ← NIL;
count down from index to find the pin that can still effect index
iPos: Route.Number ← chanPins.sides[pinIndex].pLoc;
FOR limitIndex: RouteChannel.MPinsOnCh
DECREASING
IN [1 .. pinIndex]
WHILE chanPins.sides[limitIndex].pLoc + testWidth > iPos
AND ~violation
DO
violation ← RouteChannel.EnumPins[routingArea, chanPins.sides[limitIndex], LimitProc];
IF violation
THEN
Route.Signal[callingError, Rope.Cat[Rope.Cat["Pins are too close. net 1: ", net.name, ", pin 1: ", pin.pin.name], Rope.Cat[ ", pin 2: ", violationPin.name]]];
ENDLOOP;
count up from index to find the pin that can still effect index
iPos ← chanPins.sides[pinIndex].pLoc;
FOR limitIndex: RouteChannel.MPinsOnCh
IN [pinIndex .. chanPins.count]
WHILE chanPins.sides[limitIndex].pLoc - testWidth < iPos
AND ~violation
DO
violation ← RouteChannel.EnumPins[routingArea, chanPins.sides[limitIndex], LimitProc];
IF violation
THEN
Route.Signal[callingError, Rope.Cat[Rope.Cat["Pins are too close. net 1: ", net.name, ", pin 1: ", pin.pin.name], Rope.Cat[ ", pin 2: ", violationPin.name]]];
ENDLOOP};
GetExitPins:
PROC [routingArea: Route.RoutingArea]
RETURNS [exitPins: List.
LORA ←
NIL] = {
get the exit pins for this net.
NOTE: this assumes that CheckChanPins has been invoked and that the inputs are valid!!!
ReallyGetExits:
PROC [pinPos: RouteChannel.PinPosition] = {
IF pinPos #
NIL
THEN {
FOR pList: RouteChannel.ChanPinList ← pinPos.innerPins, pList.rest
WHILE pList #
NIL
DO
this: RouteChannel.ChanPin ← pList.first;
SELECT this.pin.chanSide
FROM
chanLeft, chanRight => exitPins ← CONS[this, exitPins];
ENDCASE;
ENDLOOP}};
chanData: RouteChannel.ChannelData ← NARROW[routingArea.privateData];
chanPins: RouteChannel.RoutingChannelPins ← chanData.chanPins;
ReallyGetExits[chanPins.sides[1]];
IF chanPins.count > 0 THEN ReallyGetExits[chanPins.sides[chanPins.count]]};
MakeSBTracks:
PROC [routingArea: Route.RoutingArea, okToDiddleLLPins, okToDiddleURPins:
BOOLEAN] = {
find the track positions
ExitPinCompare: List.CompareProc = {
q1: Route.Number ← NARROW[ref1, RouteChannel.ChanPin].pin.location.q;
q2: Route.Number ← NARROW[ref2, RouteChannel.ChanPin].pin.location.q;
RETURN[
IF q1 < q2
THEN Basics.Comparison.less
ELSE IF q1 = q2 THEN Basics.Comparison.equal
ELSE Basics.Comparison.greater]};
DoUp:
PROC [thisPos: Route.Number]~ {
FOR trackPos: Route.Number ← lastPos + trackDist, trackPos + trackDist
WHILE trackPos <= thisPos - trackDist
DO
[] ← AddTrack[routingArea, trackPos];
lastPos ← trackPos;
ENDLOOP};
ClosestTrack:
PROC [thisPos: Route.Number]
RETURNS [track: RouteChannel.Track ←
NIL] ~ {
dist: INT ← LAST[INT];
FOR trackNum:
INT
IN [1 .. chanTracks.count]
DO
trialTrack: RouteChannel.Track ← chanTracks.tracks[trackNum];
trialDist: INT ← ABS[trialTrack.trackPos - thisPos];
IF trialDist < dist
THEN {
track ← trialTrack;
dist ← trialDist}
ENDLOOP;
};
chanData: RouteChannel.ChannelData ← NARROW[routingArea.privateData];
chanTracks: RouteChannel.RoutingChannelTracks ← chanData.chanTracks;
exitPinList: List.LORA ← GetExitPins[routingArea];
sortedExitPinList: List.LORA ← List.Sort[exitPinList, ExitPinCompare];
lastPos: Route.Number ← chanData.chanSides[chanBottom].routeAreaCoord;
previousPin: RouteChannel.ChanPin ← NIL;
trackDist: Route.Number ← routingArea.rules.trunkToTrunk;
lastTrack: RouteChannel.Track ← NIL;
the complexity of this code comes from the requirement to move pins on the end of a switchbox under certain conditions (okToDiddleLLPins or okToDiddleURPins).
FOR pList: List.
LORA
-- RouteChannel.InternPinList -- ← sortedExitPinList, pList.rest
WHILE pList #
NIL
DO
this: RouteChannel.ChanPin ← NARROW[pList.first];
thisPos: Route.Number ← this.pin.location.q;
pin2Name: Rope.ROPE ← IF previousPin = NIL THEN "none" ELSE previousPin.pin.name;
track: RouteChannel.Track ← NIL;
SELECT
TRUE
FROM
~okToDiddleLLPins
AND ~okToDiddleURPins => {
-- can't move any pins
IF thisPos = lastPos
THEN
-- already have a track here
track ← lastTrack
ELSE
IF thisPos >= lastPos + trackDist
THEN {
-- lots of room here
DoUp[thisPos];
track ← AddTrack[routingArea, thisPos]}
ELSE {
Route.Signal[callingError, Rope.Cat["Pins too close on ends of switchbox, pin 1: ", this.pin.name, ", pin 2: ", pin2Name]];
track ← AddTrack[routingArea, thisPos]};
BindPinToTrack[this, track];
previousPin ← this;
lastTrack ← track;
lastPos ← thisPos};
okToDiddleLLPins
AND okToDiddleURPins => {
-- can move pins on both sides
IF thisPos = lastPos
THEN
-- already have a track here
track ← lastTrack
ELSE
IF thisPos >= lastPos + trackDist
THEN {
-- lots of room here
DoUp[thisPos];
track ← AddTrack[routingArea, thisPos]}
ELSE {
thisPos ← lastPos + trackDist;
track ← AddTrack[routingArea, thisPos]};
BindPinToTrack[this, track];
previousPin ← this;
lastTrack ← track;
lastPos ← thisPos};
okToDiddleLLPins => {
-- can move only pins on the left
IF this.pin.chanSide = chanRight
THEN {
-- this pin is on the right
IF thisPos >= lastPos + trackDist
THEN
-- lots of room here
DoUp[thisPos]
ELSE
-- not enough room, error
Route.Signal[callingError, Rope.Cat["Pins too close on ends of switchbox, pin 1: ", this.pin.name, ", pin 2: ", pin2Name]];
track ← AddTrack[routingArea, thisPos];
BindPinToTrack[this, track];
previousPin ← this;
lastTrack ← track;
lastPos ← thisPos}};
okToDiddleURPins => {
-- can move only pins on the right
IF this.pin.chanSide = chanLeft
THEN {
-- this pin is on the left
IF thisPos >= lastPos + trackDist
THEN
-- lots of room here
DoUp[thisPos]
ELSE
-- not enough room, error
Route.Signal[callingError, Rope.Cat["Pins too close on ends of switchbox, pin 1: ", this.pin.name, ", pin 2: ", pin2Name]];
track ← AddTrack[routingArea, thisPos];
BindPinToTrack[this, track];
previousPin ← this;
lastTrack ← track;
lastPos ← thisPos}};
ENDCASE;
ENDLOOP;
run the tracks to the top of the switchbox
IF previousPin #
NIL
AND lastPos > chanData.chanSides[chanTop].routeAreaCoord - trackDist
THEN {
Route.Signal[callingError, Rope.Cat["Pins too close on ends of switchbox, pin : ", previousPin.pin.name]]};
FOR trackPos: Route.Number ← lastPos + trackDist, trackPos + trackDist
WHILE trackPos < chanData.chanSides[chanTop].routeAreaCoord - trackDist
DO
[] ← AddTrack[routingArea, trackPos];
lastPos ← trackPos;
ENDLOOP;
chanTracks.maxCount ← chanTracks.count;
IF okToDiddleLLPins # okToDiddleURPins
THEN {
fix up the other side now
FOR pList: List.
LORA
-- RouteChannel.InternPinList -- ← sortedExitPinList, pList.rest
WHILE pList #
NIL
DO
this: RouteChannel.ChanPin ← NARROW[pList.first];
thisPos: Route.Number ← this.pin.location.q;
pin2Name: Rope.ROPE ← IF previousPin = NIL THEN "none" ELSE previousPin.pin.name;
track: RouteChannel.Track;
SELECT
TRUE
FROM
okToDiddleLLPins => {
-- can move only pins on the left
IF this.pin.chanSide = chanLeft
THEN {
-- this pin is on the left
track ← ClosestTrack[thisPos];
BindPinToTrack[this, track]};
};
okToDiddleURPins => {
-- can move only pins on the right
IF this.pin.chanSide = chanRight
THEN {
-- this pin is on the right
track ← ClosestTrack[thisPos];
BindPinToTrack[this, track]};
};
ENDCASE;
ENDLOOP};
};
MakeCRTracks:
PROC [routingArea: Route.RoutingArea, maxTracksRequired:
NAT] = {
find the track positions
chanData: RouteChannel.ChannelData ← NARROW[routingArea.privateData];
chanTracks: RouteChannel.RoutingChannelTracks ← chanData.chanTracks;
trackLimit: RouteChannel.ZMaxTracks ← MIN[chanTracks.size, maxTracksRequired];
FOR trackIndex: RouteChannel.ZMaxTracks
IN [1 .. trackLimit]
DO
loc: Route.Number ← routingArea.rules.trunkToEdge + (trackIndex - 1) * routingArea.rules.trunkToTrunk;
[] ← AddTrack[routingArea, loc];
ENDLOOP;
chanTracks.maxCount ← chanTracks.count};
AddTrack:
PROC [routingArea: Route.RoutingArea, trackPos: Route.Number]
RETURNS [track: RouteChannel.Track] = {
insert a track at the position
chanData: RouteChannel.ChannelData ← NARROW[routingArea.privateData];
chanTracks: RouteChannel.RoutingChannelTracks ← chanData.chanTracks;
IF chanTracks.count >= RouteChannel.maxTrack
THEN
Route.Signal[noResource, "Too many tracks needed, call implementor"];
chanTracks.count ← chanTracks.count + 1;
track ← chanTracks.tracks[chanTracks.count] ← NEW[RouteChannel.TrackRec ← [trackNum: chanTracks.count, trackPos: trackPos]]};
BindPinToTrack:
PROC [pin: RouteChannel.ChanPin, track: RouteChannel.Track] ~ {
IF pin #
NIL
THEN {
update the track constraints for the segments attached to the pin
sList: RouteChannel.SegmentList ← RouteChannel.GetSegsOnPin[pin];
pin.trackConstraint ← track.trackNum;
FOR segs: RouteChannel.SegmentList ← sList, segs.rest
WHILE segs #
NIL
DO
seg: RouteChannel.Segment ← segs.first;
IF seg #
NIL
THEN {
IF seg.trackConstraint = 0 THEN seg.trackConstraint ← track.trackNum
ELSE seg.secTrackConstraint ← track.trackNum};
ENDLOOP;
}};
DoTBBarriers:
PROC [routingArea: Route.RoutingArea, chanSide: RouteChannel.ChanSide] = {
Block the tracks covered by the layer.
chanData: RouteChannel.ChannelData ← NARROW[routingArea.privateData];
activeSide: RouteChannel.RoutingChannelSides ← chanData.chanSides[chanSide];
chanPins: RouteChannel.RoutingChannelPins ← chanData.chanPins;
trackDist: Route.Number ← routingArea.rules.trunkToTrunk;
FOR rlayer: RoutePrivate.RoutingLayer
IN [trunk .. branch]
DO
FOR bList: RoutePrivate.PQRectList ← activeSide.barrierList[rlayer], bList.rest
WHILE bList #
NIL
DO
BlockProc: RouteChannel.EachTrackActionProc = {
trackPos: Route.Number ← RouteChannel.TrackLoc[routingArea, trackIndex];
IF minQ < trackPos - trackDist
AND trackPos + trackDist < maxQ
THEN
track.blocked ← TRUE};
barrierItem: RoutePrivate.PQRect ← bList.first;
minQ: Route.Number ← MIN[barrierItem.c1.q, barrierItem.c2.q];
maxQ: Route.Number ← MAX[barrierItem.c1.q, barrierItem.c2.q];
[] ← RouteChannel.EnumTracks[routingArea, BlockProc];
ENDLOOP;
ENDLOOP};
DoLRBarriers:
PROC [routingArea: Route.RoutingArea, chanSide: RouteChannel.ChanSide] = {
Block the tracks covered by the layer.
chanData: RouteChannel.ChannelData ← NARROW[routingArea.privateData];
activeSide: RouteChannel.RoutingChannelSides ← chanData.chanSides[chanSide];
FOR rlayer: RoutePrivate.RoutingLayer
IN [trunk .. branch]
DO
FOR bList: RoutePrivate.PQRectList ← activeSide.barrierList[rlayer], bList.rest
WHILE bList #
NIL
DO
BlockProc: RouteChannel.EachTrackActionProc = {
NULL };
barrierItem: RoutePrivate.PQRect ← bList.first;
minQ: Route.Number ← MIN[barrierItem.c1.q, barrierItem.c2.q];
maxQ: Route.Number ← MAX[barrierItem.c1.q, barrierItem.c2.q];
[] ← RouteChannel.EnumTracks[routingArea, BlockProc];
ENDLOOP;
ENDLOOP};
Surround:
PROC [r1, r2: RoutePrivate.PQRect]
RETURNS [RoutePrivate.PQRect] =
INLINE {
RETURN [RoutePrivate.PQRect[
[MIN[r1.c1.p, r2.c1.p], MIN[r1.c1.q, r2.c1.q]],
[MAX[r1.c2.p, r2.c2.p], MAX[r1.c2.q, r2.c2.q]]]]};
ConvertToLORA:
PROC [list: RouteChannel.InternPinList]
RETURNS[val: List.
LORA] = {
val ← NIL;
UNTIL list =
NIL
DO
val ← CONS[list.first, val];
list ← list.rest;
ENDLOOP;
RETURN[val];
}; -- of ConvertToLORA
END.