SCNewRoutePinsUtilImpl.mesa
Copyright Ó 1987 by Xerox Corporation. All rights reserved.
Jason Cong, August 22, 1987 10:54:38 am PDT
last edited by Preas, August 4, 1987 10:59:25 am PDT
Bryan Preas August 14, 1987 3:21:11 pm PDT
DIRECTORY
DABasics, Convert, Rope, RTBasic, SC, SCNetUtil, SCPrivate, SCNewRoutePinsUtil;
SCNewRoutePinsUtilImpl:
CEDAR
PROGRAM
IMPORTS Convert, Rope, RTBasic, SC, SCNetUtil
EXPORTS SCNewRoutePinsUtil
SHARES SC = {
initialize for determining the width of a channel
InitGetChanPins:
PUBLIC
PROCEDURE [handle:
SC.Handle, rowChan: SCPrivate.RowChan] = {
InitNet: SCNetUtil.EachNetProc = {net.netDat ← NIL};
chanDat: SCNewRoutePinsUtil.ChanDat ← NEW[SCNewRoutePinsUtil.ChanDatRec];
chanDat.head ← chanDat.tail ← NEW[SCNewRoutePinsUtil.PinInChanRec ← [min: FIRST[INT], max: FIRST[INT], depth: 0, layer: 0]];
rowChan.chanDat ← chanDat;
rowChan.wireLength ← rowChan.chanDensity ← rowChan.chanWidth ← 0;
[] ← SCNetUtil.EnumerateNets[handle, InitNet]};
terminate determining the width of a channel
TermGetChanPins:
PUBLIC
PROCEDURE [handle:
SC.Handle, rowChan: SCPrivate.RowChan] = {
TermNet: SCNetUtil.EachNetProc = {
netDat: SCNewRoutePinsUtil.NetDat ← NARROW[net.netDat];
IF netDat #
NIL
THEN {
chanNetDat: SCNewRoutePinsUtil.ChanNetDat ← netDat[rowChan.chanNum];
IF chanNetDat #
NIL
THEN
chanNetDat.firstPin ← chanNetDat.lastPin ← chanNetDat.leftmost ← chanNetDat.rightmost ← chanNetDat.exits[left] ← chanNetDat.exits[right] ← NIL;
net.netDat ← NIL}};
EachPin: SCNewRoutePinsUtil.EachPinProc = {
PROC[rowChan: SCPrivate.RowChan, pin: PinInChan];
pin.prevPinInChan ← pin.nextPinInNet ← NIL};
EnumPinsInChan[rowChan, EachPin];
[] ← SCNetUtil.EnumerateNets[handle, TermNet];
rowChan.chanDat ← NIL};
enter a net on a channel into data structure
EnterPin:
PUBLIC
PROCEDURE[rowChan: SCPrivate.RowChan, min, max, depth:
SC.Number, layer:
SC.Layer, net: SCPrivate.Net, side: DABasics.TBSide, alwaysUse:
BOOLEAN]
RETURNS[pinInChan: SCNewRoutePinsUtil.PinInChan] = {
chanDat: SCNewRoutePinsUtil.ChanDat ← NARROW[rowChan.chanDat];
tail: SCNewRoutePinsUtil.PinInChan ← chanDat.tail;
chanDat.tail ← tail.nextPinInChan ← pinInChan ←
NEW[SCNewRoutePinsUtil.PinInChanRec ← [
layer: layer,
net: net,
chanNet: NIL,
min: min, max: max, depth: depth,
pinClass: isPin,
chanSide: side,
nextPinInChan: NIL,
prevPinInChan: tail,
pinConn: unconnected,
nextPinInNet: NIL, prevPinInNet: NIL,
localDensity: 0 ,
alwaysUse: alwaysUse,
chanNum: rowChan.chanNum]];
rowChan.chanDat ← chanDat};
enter exit data for a channel into routing data base
EnterExit:
PUBLIC
PROCEDURE[rowChan: SCPrivate.RowChan, pos:
SC.Number, layer:
SC.Layer, net: SCPrivate.Net, side: DABasics.LRSide]
RETURNS[pinInChan: SCNewRoutePinsUtil.PinInChan] = {
chanDat: SCNewRoutePinsUtil.ChanDat ← NARROW[rowChan.chanDat];
tail: SCNewRoutePinsUtil.PinInChan ← chanDat.tail;
chanDat.tail ← tail.nextPinInChan ← pinInChan ←
NEW[SCNewRoutePinsUtil.PinInChanRec ← [
layer: layer,
net: net,
chanNet: NIL,
min: pos, max: pos, depth: 0,
pinClass: isExit,
chanSide: side,
nextPinInChan: NIL,
prevPinInChan: tail,
pinConn: unconnected,
nextPinInNet: NIL, prevPinInNet: NIL,
localDensity: 0 ,
alwaysUse: TRUE,
chanNum: rowChan.chanNum]];
rowChan.chanDat ← chanDat};
NoChange:
PROCEDURE[mpin, pin: SCNewRoutePinsUtil.PinInChan]
RETURNS[yes:
BOOLEAN ←
FALSE] = {
IF mpin.nextPinInNet #
NIL
THEN
yes ← (mpin.nextPinInNet.min = pin.min) AND (mpin.nextPinInNet.pinConn #unconnected);
IF mpin.prevPinInNet #
NIL
THEN
yes ← yes OR (mpin.prevPinInNet.min = pin.min) AND (mpin.prevPinInNet.pinConn # unconnected) };
MoveAPinInChan:
PUBLIC
PROCEDURE[rowChan: SCPrivate.RowChan, pin: SCNewRoutePinsUtil.PinInChan, deltaX:
SC.Number]
RETURNS[scan:
BOOLEAN ←
FALSE] = {
next: SCNewRoutePinsUtil.PinInChan ← pin;
prev: SCNewRoutePinsUtil.PinInChan ← pin;
origX, currX, dX: SC.Number;
origX ← currX ← pin.min;
pin.min ← pin.min + deltaX;
pin.max ← pin.max + deltaX;
IF pin.min = rowChan.chanDensity THEN scan ← TRUE;
IF deltaX > 0
THEN {
prev ← pin.prevPinInChan;
IF (prev #
NIL)
AND (prev.min = currX)
AND (pin.pinConn = left)
THEN
prev.localDensity ← prev.localDensity - 1;
WHILE (pin.nextPinInChan #
NIL)
AND (pin.nextPinInChan.min <= pin.min)
DO
next ← pin.nextPinInChan;
IF next.localDensity = rowChan.chanDensity THEN scan ← TRUE;
dX ← next.min - currX;
currX ← next.min;
SwapTwoPins[pin, next];
SELECT pin.pinConn
FROM
left => {
IF pin.net = next.net
THEN {
SELECT next.pinConn
FROM
interior => {
pin.pinConn ← interior;
next.pinConn ← left;
pin.chanNet.leftmost ← next};
right => {
pin.pinConn ← right;
next.pinConn ← left;
pin.chanNet.leftmost ← next;
pin.chanNet.rightmost ← pin};
ENDCASE};
rowChan.wireLength ← rowChan.wireLength - dX};
interior => {
IF pin.net = next.net
THEN
IF next.pinConn = right
THEN {
next.pinConn ← interior;
pin.pinConn ← right;
pin.chanNet.rightmost ← pin}};
right => {
rowChan.wireLength ← rowChan.wireLength + dX};
ENDCASE;
IF pin.net = next.net
THEN
SwapTwoPinsInNet[pin, next];
ENDLOOP;
dX ← pin.min - currX;
IF pin.pinConn = right
THEN
rowChan.wireLength ← rowChan.wireLength + dX;
IF pin.pinConn = left
THEN
rowChan.wireLength ← rowChan.wireLength - dX;
next ← pin.nextPinInChan}
ELSE
IF deltaX < 0
THEN {
next ← pin.nextPinInChan;
IF (next #
NIL)
AND (next.min = currX)
AND (pin.pinConn = right)
THEN
next.localDensity ← next.localDensity - 1;
WHILE (pin.prevPinInChan #
NIL)
AND (pin.prevPinInChan.min >= pin.min)
DO
prev ← pin.prevPinInChan;
IF prev.localDensity = rowChan.chanDensity THEN scan ← TRUE;
dX ← currX - prev.min;
currX ← prev.min;
SwapTwoPins[prev, pin];
SELECT pin.pinConn
FROM
right => {
IF pin.net = prev.net
THEN {
SELECT prev.pinConn
FROM
interior => {
pin.pinConn ← interior;
prev.pinConn ← right;
pin.chanNet.rightmost ← prev};
left => {
pin.pinConn ← left;
prev.pinConn ← right;
pin.chanNet.leftmost ← pin;
pin.chanNet.rightmost ← prev};
ENDCASE};
rowChan.wireLength ← rowChan.wireLength - dX};
interior => {
IF pin.net = prev.net
THEN
IF prev.pinConn = left
THEN {
prev.pinConn ← interior;
pin.pinConn ← left;
pin.chanNet.leftmost ← pin}};
left => {
rowChan.wireLength ← rowChan.wireLength + dX};
ENDCASE;
IF pin.net = prev.net
THEN
SwapTwoPinsInNet[prev, pin];
ENDLOOP;
dX ← currX - pin.min;
IF pin.pinConn = left
THEN
rowChan.wireLength ← rowChan.wireLength + dX;
IF pin.pinConn = right
THEN
rowChan.wireLength ← rowChan.wireLength - dX}};
SortPins:
PROCEDURE[chanDat: SCNewRoutePinsUtil.ChanDat] = {
stop: BOOLEAN ← FALSE;
temp: SCNewRoutePinsUtil.PinInChan;
head: SCNewRoutePinsUtil.PinInChan ← chanDat.head;
WHILE ~stop
DO
rList: SCNewRoutePinsUtil.PinInChan ← head;
stop ← TRUE;
WHILE rList.nextPinInChan #
NIL
DO
temp ← rList.nextPinInChan;
IF rList.min > temp.min
THEN {
stop ← FALSE;
SwapTwoPins[rList, temp]};
rList ← temp;
ENDLOOP;
ENDLOOP};
SwapTwoPins:
PROCEDURE[pin1, pin2: SCNewRoutePinsUtil.PinInChan] = {
IF pin2.nextPinInChan #
NIL
THEN
pin2.nextPinInChan.prevPinInChan ← pin1;
IF pin1.prevPinInChan #
NIL
THEN
pin1.prevPinInChan.nextPinInChan ← pin2;
pin1.nextPinInChan ← pin2.nextPinInChan;
pin2.prevPinInChan ← pin1.prevPinInChan;
pin1.prevPinInChan ← pin2;
pin2.nextPinInChan ← pin1};
SwapTwoPinsInNet:
PROCEDURE[pin1, pin2: SCNewRoutePinsUtil.PinInChan] = {
chanNetDat: SCNewRoutePinsUtil.ChanNetDat ← pin1.chanNet;
IF pin2.nextPinInNet #
NIL
THEN
pin2.nextPinInNet.prevPinInNet ← pin1;
IF pin1.prevPinInNet #
NIL
THEN
pin1.prevPinInNet.nextPinInNet ← pin2;
pin1.nextPinInNet ← pin2.nextPinInNet;
pin2.prevPinInNet ← pin1.prevPinInNet;
pin1.prevPinInNet ← pin2;
pin2.nextPinInNet ← pin1;
IF chanNetDat.firstPin = pin1 THEN chanNetDat.firstPin ← pin2;
IF chanNetDat.lastPin = pin2 THEN chanNetDat.lastPin ← pin1};
enumerate all the pins on this channel (all nets)
EnumPinsInChan:
PUBLIC
PROCEDURE[rowChan: SCPrivate.RowChan, doEachPin: SCNewRoutePinsUtil.EachPinProc] = {
chanDat: SCNewRoutePinsUtil.ChanDat ← NARROW[rowChan.chanDat];
IF chanDat #
NIL
THEN {
head: SCNewRoutePinsUtil.PinInChan ← chanDat.head;
FOR chanPin: SCNewRoutePinsUtil.PinInChan ← head.nextPinInChan, chanPin.nextPinInChan
WHILE chanPin #
NIL
DO
doEachPin[rowChan, chanPin];
ENDLOOP}};
enumerate the pins on this net on this channel (including exits)
EnumAllPinsInNetChan:
PUBLIC
PROCEDURE[chanNetDat: SCNewRoutePinsUtil.ChanNetDat, doEachNetPin: SCNewRoutePinsUtil.EachNetPinProc] = {
IF chanNetDat #
NIL
THEN {
FOR chanPin: SCNewRoutePinsUtil.PinInChan ← chanNetDat.firstPin, chanPin.nextPinInNet
WHILE chanPin #
NIL
DO
doEachNetPin[chanNetDat, chanPin];
ENDLOOP}};
enumerate the pins on this net on this channel on side (including exits)
EnumPinsInNetChan:
PUBLIC
PROCEDURE[chanNetDat: SCNewRoutePinsUtil.ChanNetDat, side: DABasics.Side, doEachNetPin: SCNewRoutePinsUtil.EachNetPinProc] = {
IF chanNetDat #
NIL
THEN {
FOR chanPin: SCNewRoutePinsUtil.PinInChan ← chanNetDat.firstPin, chanPin.nextPinInNet
WHILE chanPin #
NIL
DO
IF chanPin.chanSide = side OR chanPin.pinClass = isExit THEN doEachNetPin[chanNetDat, chanPin];
ENDLOOP}};
initialize the data for a channel
CreateNetDat:
PUBLIC
PROCEDURE[handle:
SC.Handle, rowChan: SCPrivate.RowChan] = {
DoEachPin: SCNewRoutePinsUtil.EachPinProc = {
EachPinProc: TYPE = PROC[rowChan: SCPrivate.RowChan, pin:PinInChan];
net: SCPrivate.Net ← pin.net;
netDat: SCNewRoutePinsUtil.NetDat ← NARROW[net.netDat];
chanNum: NAT ← rowChan.chanNum;
chanNetDat: SCNewRoutePinsUtil.ChanNetDat ← NIL;
IF netDat =
NIL
THEN
net.netDat ← netDat ← NARROW[NEW[SCNewRoutePinsUtil.NetDatRec ← ALL[NIL]]];
IF netDat[chanNum] =
NIL
THEN
netDat[chanNum] ← NEW[SCNewRoutePinsUtil.ChanNetDatRec];
chanNetDat ← netDat[chanNum];
IF pin.pinClass = isExit
THEN {
IF chanNetDat.exits[pin.chanSide] #
NIL
THEN
SC.Error[programmingError, "More than two exits for a net one side of a channel"]
ELSE chanNetDat.exits[pin.chanSide] ← pin};
IF chanNetDat.firstPin =
NIL
THEN {
chanNetDat.firstPin ← (chanNetDat.lastPin ← pin);
chanNetDat.net ← net}
ELSE {
pin.prevPinInNet ← chanNetDat.lastPin;
chanNetDat.lastPin.nextPinInNet ← pin;
chanNetDat.lastPin ← pin};
chanNetDat.pinCount ← chanNetDat.pinCount + 1;
pin.chanNet ← chanNetDat};
main body of 'CreateNetDat'
SortPins[NARROW[rowChan.chanDat]];
EnumPinsInChan[rowChan, DoEachPin]};
enter a net segment into chanNetDat, and enter pin connection info in pin.
EnterANetSegInChan:
PUBLIC
PROC [handle:
SC.Handle, rowChan: SCPrivate.RowChan, net: SCPrivate.Net, pinProc: SCNewRoutePinsUtil.PinProc, exitProc: SCNewRoutePinsUtil.ExitProc] ~ {
process an exit pin
DoExit:
PROCEDURE[chanNetDat: SCNewRoutePinsUtil.ChanNetDat, side: DABasics.LRSide] = {
exit: SCNewRoutePinsUtil.PinInChan ← chanNetDat.exits[side];
IF exit #
NIL
THEN {
IF side = left THEN exit.pinConn ← interior
ELSE IF side = right THEN exit.pinConn ← interior;
IF exitProc # NIL THEN exitProc[side, exit.layer, exit.net];
numPinsUsed ← numPinsUsed + 1}};
process an channel pin that is to be connected
DoPin: SCNewRoutePinsUtil.EachNetPinProc = {
PROC[chanNetDat: ChanNetDat, pin: PinInChan];
IF (chanNetDat.pinCount > 1
OR pin.alwaysUse)
AND pin.pinClass = isPin
THEN {
pin.pinConn ← interior;
IF pinProc # NIL THEN pinProc[pin.min, pin.max, pin.depth, pin.chanSide, pin.layer, pin.net];
numPinsUsed ← numPinsUsed + 1}};
process all channel pin that are to be connected that are on side
DoAllPins:
PROCEDURE[chanNetDat: SCNewRoutePinsUtil.ChanNetDat, side: DABasics.TBSide] = {
EnumPinsInNetChan[chanNetDat, side, DoPin]};
enter at most one pin from minSide; that pin ads the shortest wire segment to the pins on the fullside
DoFullMin:
PROC [chanNetDat: SCNewRoutePinsUtil.ChanNetDat, fullSide, minSide: DABasics.TBSide] ~ {
find the range of pins on fullSide
DoRange: SCNewRoutePinsUtil.EachNetPinProc = {fullRange ← RTBasic.Span[fullRange, [pin.min, pin.max]]};
PROC[chanNetDat: ChanNetDat, pin: PinInChan];
find the pin on minSide that adds smallest length to fullSide
DoMinPins: SCNewRoutePinsUtil.EachNetPinProc = {
PROC[chanNetDat: ChanNetDat, pin: PinInChan];
IF pin.pinClass = isPin
THEN {
trialRange: RTBasic.Range ← RTBasic.Span[fullRange, [pin.min, pin.max]];
trialLength: SC.Number ← trialRange.r - trialRange.l;
IF trialLength < maxLength THEN {maxLength ← trialLength; minPin ← pin}}};
maxLength: SC.Number ← LAST[INT];
minPin: SCNewRoutePinsUtil.PinInChan ← NIL;
compute span of pins that must be connected
fullRange: RTBasic.Range ← [LAST[INT], FIRST[INT]];
EnumPinsInNetChan[chanNetDat, fullSide, DoRange];
IF fullRange.l <= fullRange.r
THEN {
EnumPinsInNetChan[chanNetDat, minSide, DoMinPins];
IF minPin # NIL THEN DoPin[chanNetDat, minPin]}};
enter at most one pin from both channel sides; those pins define the shortest segment that crosses the channel
DoMinMin:
PROC [chanNetDat: SCNewRoutePinsUtil.ChanNetDat] ~ {
DoMinPins: SCNewRoutePinsUtil.EachNetPinProc = {
PROC[chanNetDat: ChanNetDat, pin: PinInChan];
IF pin.pinClass = isPin
THEN {
IF leftPin # NIL THEN leftPin ← pin;
rightPin ← pin;
lastPin[pin.chanSide] ← pin;
IF lastPin[RTBasic.OtherSide[pin.chanSide]] #
NIL
THEN {
trialLength: SC.Number;
trialRange: RTBasic.Range ← RTBasic.Span[[lastPin[top].min, lastPin[top].max], [lastPin[bottom].min, lastPin[bottom].max]];
IF chanNetDat.exits[left] #
NIL
THEN {
min: SC.Number ← lgRows.horzRowOrg;
trialRange ← RTBasic.Span[trialRange, [min, min]]};
IF chanNetDat.exits[right] #
NIL
THEN {
max: SC.Number ← lgRows.horzRowOrg + lgRows.maxRowWidth;
trialRange ← RTBasic.Span[trialRange, [max, max]]};
trialLength ← trialRange.r - trialRange.l;
IF trialLength < maxLength
THEN {
maxLength ← trialLength;
minPin[top]← lastPin[top];
minPin[bottom]← lastPin[bottom]}}}};
maxLength: SC.Number ← LAST[INT];
lastPin: ARRAY DABasics.TBSide OF SCNewRoutePinsUtil.PinInChan ← [NIL, NIL];
minPin: ARRAY DABasics.TBSide OF SCNewRoutePinsUtil.PinInChan ← [NIL, NIL];
leftPin: SCNewRoutePinsUtil.PinInChan ← NIL;
rightPin: SCNewRoutePinsUtil.PinInChan ← NIL;
EnumAllPinsInNetChan[chanNetDat, DoMinPins];
IF minPin[top] # NIL THEN DoPin[chanNetDat, minPin[top]];
IF minPin[bottom] # NIL THEN DoPin[chanNetDat, minPin[bottom]];
IF chanNetDat.exits[left] #
NIL
AND leftPin # minPin[top]
AND leftPin # minPin[bottom]
THEN
DoPin[chanNetDat, leftPin];
IF chanNetDat.exits[right] #
NIL
AND rightPin # minPin[top]
AND rightPin # minPin[bottom]
THEN
DoPin[chanNetDat, rightPin]};
clear connections for this net
ClearPin: SCNewRoutePinsUtil.EachNetPinProc = {
PROC[chanNetDat: ChanNetDat, pin: PinInChan];
pin.pinConn ← unconnected};
set connections for this net
FixUpAndCheck: SCNewRoutePinsUtil.EachNetPinProc = {
PROC[chanNetDat: ChanNetDat, pin: PinInChan];
pinState ← pin.pinConn ← NextPinState[pinState, pin];
IF pinState = left THEN chanNetDat.leftmost ← pin;
IF pinState = interior THEN lastConnectedPin ← pin};
main body of EnterANetSegInChan
numPinsUsed: INT ← 0;
layoutData: SCPrivate.LayoutData ← NARROW[handle.layoutData];
lgRows: SCPrivate.LgRows ← layoutData.lgRows;
netDat: SCNewRoutePinsUtil.NetDat ← NARROW[net.netDat];
chan: SCPrivate.ZMaxChanSr ← rowChan.chanNum;
chanNetDat: SCNewRoutePinsUtil.ChanNetDat ← netDat[chan];
pinState: SCNewRoutePinsUtil.ConnectionType ← unconnected;
lastConnectedPin: SCNewRoutePinsUtil.PinInChan ← NIL;
EnumAllPinsInNetChan[chanNetDat, ClearPin];
IF chanNetDat #
NIL
THEN {
SELECT
TRUE
FROM
chan = 0 =>
-- this is a side
{DoAllPins[chanNetDat, top]; DoAllPins[chanNetDat, bottom]};
net.routeTopology[chan].upper = full
AND net.routeTopology[chan].lower = full =>
{DoExit[chanNetDat, left]; DoExit[chanNetDat, right];
DoAllPins[chanNetDat, top]; DoAllPins[chanNetDat, bottom]};
net.routeTopology[chan].upper = full
AND net.routeTopology[chan].lower = min =>
{DoExit[chanNetDat, left]; DoExit[chanNetDat, right];
DoFullMin[chanNetDat, top, bottom]; DoAllPins[chanNetDat, top]};
net.routeTopology[chan].upper = min
AND net.routeTopology[chan].lower = full =>
{DoExit[chanNetDat, left]; DoExit[chanNetDat, right];
DoFullMin[chanNetDat, bottom, top]; DoAllPins[chanNetDat, bottom]};
net.routeTopology[chan].upper = min
AND net.routeTopology[chan].lower = min =>
{DoExit[chanNetDat, left]; DoExit[chanNetDat, right]; DoMinMin[chanNetDat]};
net.routeTopology[chan].upper = full =>
-- lower must be none
{DoExit[chanNetDat, left]; DoExit[chanNetDat, right]; DoAllPins[chanNetDat, top]};
net.routeTopology[chan].lower = full =>
-- upper must be none
{DoExit[chanNetDat, left]; DoExit[chanNetDat, right]; DoAllPins[chanNetDat, bottom]};
ENDCASE =>
check for unconnected exits
IF chanNetDat.exits[left] #
NIL
OR chanNetDat.exits[right] #
NIL
THEN
SC.Signal[callingError, "Unconnected public wire; make sure all publics hanve more than one pin"];
fix up the net connections; make sure left and right pins are done correctly
EnumAllPinsInNetChan[chanNetDat, FixUpAndCheck];
IF lastConnectedPin # NIL
THEN
{lastConnectedPin.pinConn ← right; chanNetDat.rightmost ← lastConnectedPin};
IF numPinsUsed = 1 AND chan # 1 AND chan # layoutData.rowChans.count THEN SC.Signal[callingError, Rope.Cat["Too few pins for wire: ", net.name, " on channel: ", Convert.RopeFromInt[chan]]]}};
EnterAllNetSegInChan:
PUBLIC
PROC [handle:
SC.Handle, rowChan: SCPrivate.RowChan, pinProc: SCNewRoutePinsUtil.PinProc, exitProc: SCNewRoutePinsUtil.ExitProc] ~ {
enter all net segment into the netDats, and enter pin connection info.
EachNet: SCNetUtil.EachNetProc ~ {
PROC [netIndex: NAT, net: SCPrivate.Net] RETURNS [quit: BOOL ← FALSE];
IF net.netDat #
NIL
THEN
EnterANetSegInChan[handle, rowChan, net, pinProc, exitProc]};
[] ← SCNetUtil.EnumerateNets[handle, EachNet]};
NextPinState:
PROC [pinState: SCNewRoutePinsUtil.ConnectionType, pin: SCNewRoutePinsUtil.PinInChan]
RETURNS [newPinState: SCNewRoutePinsUtil.ConnectionType] ~ {
compute connection of this pin as a function of its position and the previous state
IF pin.pinConn = unconnected
THEN { -- this pin is unconnected
newPinState ← unconnected;
IF pin.pinClass = isExit
THEN
SC.Signal[programmingError, Rope.Cat["Exit is unconnected for wire: ", pin.net.name, ". Call maintainer"]]}
ELSE
IF pin.pinConn = interior
THEN { -- this pin is unconnected; determine which type
IF pinState = unconnected
THEN -- fitst pin we have come to
newPinState ← left
ELSE newPinState ← interior}};
PosOfPin:
PROC [chanPin: SCNewRoutePinsUtil.PinInChan]
RETURNS [
INT] ~
INLINE{
RETURN[(chanPin.min+chanPin.max)/2]};