RouteChannelInitImpl.mesa
Copyright © 1985 by Xerox Corporation. All rights reserved.
by Bryan Preas July 10, 1985 6:57:00 pm PDT
last edited by Bryan Preas December 18, 1986 2:33:43 pm PST
DIRECTORY
Basics, CD, CDBasics, CDSymbolicObjects, List, Rope, Route, RouteChannel, RoutePrivate, RouteUtil;
RouteChannelInitImpl: CEDAR PROGRAM
IMPORTS CDBasics, CDSymbolicObjects, List, Rope, Route, RouteChannel, RouteUtil
EXPORTS RouteChannel
SHARES Route =
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;
oldLoc: Route.Position;
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: BOOLEANTRUE] = {
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: BOOLEANFALSE;
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: BOOLEANTRUE;
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: BOOLEANTRUE;
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: BOOLEANFALSE;
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: BOOLEANFALSE] = {
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.LORANIL] = {
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: INTLAST[INT];
FOR trackNum: INT IN [1 .. chanTracks.count] DO
trialTrack: RouteChannel.Track ← chanTracks.tracks[trackNum];
trialDist: INTABS[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.ROPEIF 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.ROPEIF 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.