//routenetswap.bcpl

// Analyzes nets and prepares them for permutation

// last modified by E. McCreight, July 27, 1981 6:04 PM

get "route.defs"

static [ pointV ]

let RouteNetSwap(net, poutnum, plp) = valof
[
WeAre(doingRouting)

net>>net.hasBeenRouted = true

NewSwapZone((5+4)*maxNets+memoTableEntries*(size MEMO/16)+100)
X = Allocate(swapZone, maxNets)
Y = Allocate(swapZone, maxNets)
Perm = Allocate(swapZone, maxNets)
pointV = Allocate(swapZone, maxNets)

let lp = net>>net.pinList
let nnodes = 0
let epcount = 0
let outcount = 0
let isOutput = Allocate(swapZone, maxNets)
let eclPins = false
let eclOutputs = false
let hasTWPin = false
let nterm = 0
let netString = FindNameesString(net)

let cbv = Allocate(swapZone, maxNets+1)
cbv!0 = maxNets
ComputeClusters(cbv, net)
let singleCluster = cbv!0 eq 1

until (@lp) eq mark do
[
//set up argument vectors for the router
if nnodes ge maxNets then
[
Warning("*nNet $S has too many nodes to route.",
netString)
n = nnodes
resultis false
]
nnodes = nnodes+1

pointV!nnodes = lp
isOutput!nnodes = false

let icinst, pin = nil,lp
FindIcinst(lv icinst, lv pin)
GetPinCoord(icinst, pin, lv X!nnodes, lv Y!nnodes)

let icclass = Icclass(icinst)
let pinAttributes = (icclass>>icclass.PinAttributes)(icinst, pin)

if pinAttributes<<pinattributes.isTerminator then nterm = nterm+1
if pinAttributes<<pinattributes.isEcl then
[
eclPins = true
if pinAttributes<<pinattributes.isOutput then eclOutputs = true
]

if pinAttributes<<pinattributes.isOutput then
[
if epcount eq 0 then @poutnum = nnodes
isOutput!nnodes = true
outcount = outcount+1
]
if icclass>>icclass.isConnector then
[
epcount = epcount+1
@poutnum = 1
if singleCluster then
MakeFirst(nnodes, X, Y, pointV, isOutput)
]

let twclass, twpin = empty,nil
let index = FindIndexFromCoord(X!nnodes, Y!nnodes, lv twclass, lv twpin)
if index ne 0 & twclass ne empty &
GetBit(twclass>>icclass.cutPins, twpin) eq 0 then
hasTWPin = true

lp = @lp
]

//do a little checking on the validity of the net

unless hasTWPin do
[
let incount = nnodes-outcount-epcount
if (incount eq 0)&(epcount eq 0) then
[
Warning( "*nNet $S consists of outputs exclusively.",netString)
]
if (outcount eq 0)&(epcount eq 0) then
[
Warning( "*nNet $S consists of inputs exclusively.",netString)
]
if (outcount eq 0)&(incount eq 0) then
[
Warning( "*nNet $S consists of edge pins exclusively.",netString)
]

if epcount gr 1 then
[
Warning( "*nNet *"$S*" has more than one off-board connector pin",
netString)
]
]

if nnodes le 0 then
[
unless net>>net.isTraceWired % net eq dontCareNet do
Serious("*nEmpty net: *"$S*"", netString)
]

if nnodes eq 1 then
[
Warning("*nSingle Node Net: *"$S*"", netString)
]

// Set up for the wire routers...
n = nnodes
forceFirstNodeToEnd = epcount ne 0
DistFn = StandardMetric
clusterBaseVec = singleCluster? empty, cbv
@plp = lp // tell caller where net ends

// set up for the memo-using arc-length function
memoTable = Allocate(swapZone, memoTableEntries*(size MEMO/16))
Zero(memoTable, memoTableEntries*(size MEMO/16))

Free(swapZone, isOutput)

//for ECL nets, if outcount = 1 and epcount = 0,
//we route the net two ways, one with the output forced to the
//end of the net, once with it unconstrained. If the constrained
//length is less then 1.2x the unconstrained length+2", the constrained
//form of the net is used. This puts the output at the end of the net.

resultis (outcount eq 1)&(epcount eq 0)& eclPins & singleCluster
]

and HasExternalConnection(net) = valof
[
let lp = net>>net.pinList
until (@lp) eq mark do
[

let icinst, pin = nil,lp
FindIcinst(lv icinst, lv pin)
if Icclass(icinst)>>icclass.isConnector then resultis true
lp = @lp
]
resultis false
]

and MakeFirst(i, v0, v1, v2, v3, v4, v5; numargs na) be
[
for j=0 to na-2 do
[
let v = (lv v0)!j
let t = v!1
v!1 = v!i
v!i = t
]
]