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
Jean-Marc Frailong October 11, 1987 10:14:56 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: BOOLEANFALSE] = {
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: BOOLEANFALSE] = {
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: BOOLEANFALSE;
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.
GetANetSegInChan: PUBLIC PROC [handle: SC.Handle, rowChan: SCPrivate.RowChan, net: SCPrivate.Net, segProc: SCNewRoutePinsUtil.SegProc, 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;
didLeftPin: BOOLFALSE;
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]; didLeftPin ← TRUE};
IF chanNetDat.exits[right] # NIL AND rightPin # minPin[top] AND rightPin # minPin[bottom] AND ~didLeftPin 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 GetANetSegInChan
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]};
chanNetDat.exits[left] # NIL AND chanNetDat.exits[right] # NIL =>
{DoExit[chanNetDat, left]; DoExit[chanNetDat, right]};
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]]]}};
GetAllNetSegInChan: PUBLIC PROC [handle: SC.Handle, rowChan: SCPrivate.RowChan, segProc: SCNewRoutePinsUtil.SegProc, pinProc: SCNewRoutePinsUtil.PinProc, exitProc: SCNewRoutePinsUtil.ExitProc] ~ {
enter all net segment into the netDats, and enter pin connection info.
EachNet: SCNetUtil.EachNetProc ~ {
PROC [net: SCPrivate.Net] RETURNS [quit: BOOLFALSE];
IF net.netDat # NIL THEN
GetANetSegInChan[handle, rowChan, net, segProc, 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]};
}.