//routenet.bcpl
// Analyzes nets and prepares them for permutation
// last modified by E. McCreight, May 11, 1979 6:33 PM
get "route.defs"
let RouteEarlyNets(net) be if net>>net.wireEarly then RouteNet(net)
and RouteNetIfExternal(net) be
[
let pin = net>>net.pinList
while @pin ne mark do
[
let icinst = pin-offset icinst.pin↑1/16
let pinNo = 1
while icinst>>icinst.type ne typeIcinst do
[
icinst = icinst-1
pinNo = pinNo+1
]
if Icclass(icinst)>>icclass.isConnector then
[
RouteNet(net)
return
]
pin = @pin
]
]
and RouteNet(net) be
[
static [ currentNet; crucialNet = -1 ]
currentNet = net
if net eq crucialNet then CallSwat("Routing crucial net..")
if net>>net.isSame % net>>net.hasBeenRouted then return //net already done
if net>>net.isTraceWired then return // not suitable for routing
WeAre(doingRouting)
net>>net.hasBeenRouted = true
let xv = vec 100
let yv = vec 100
let permv = vec 100
let pointv = vec 100
let tpermv = vec 100
let isoutput = vec 100
let btnl = nil
let tbtnl = nil
let lp = net>>net.pinList
let nnodes = 0
let epcount = 0
let outcount = 0
let eclPins = false
let eclOutputs = false
let hasTWPin = false
let outnum = 0
let nterm = 0
let netString = FindNameesString(net)
let clusterBaseVec = vec 30
clusterBaseVec!0 = 29
ComputeClusters(clusterBaseVec, net)
let singleCluster = clusterBaseVec!0 eq 1
until (@lp) eq mark do
[
//set up argument vectors for the router
if nnodes ge 100 then
[
Warning("*nNet $S has too many nodes to route.",
netString)
return
]
nnodes = nnodes+1
pointv!nnodes = lp
isoutput!nnodes = false
let icinst = lp-offset icinst.pin↑1/16
let pin = 1
while icinst>>icinst.type ne typeIcinst do
[
icinst = icinst-1
pin = pin+1
]
GetPinCoord(icinst, pin, lv xv!nnodes, lv yv!nnodes)
let icclass = Icclass(icinst)
let pinAttributes = (icclass>>icclass.PinAttributes)(icinst, pin)
if pinAttributes<<pinattributes.isTerminator then nterm = nterm+1
if icclass>>icclass.isTraceWired then hasTWPin = true
if pinAttributes<<pinattributes.isEcl then
[
eclPins = true
if pinAttributes<<pinattributes.isOutput then eclOutputs = true
]
if pinAttributes<<pinattributes.isOutput then
[
if epcount eq 0 then outnum = nnodes
isoutput!nnodes = true
outcount = outcount+1
]
if icclass>>icclass.isConnector then
[
epcount = epcount+1
outnum = 1
if singleCluster then
MakeFirst(nnodes, xv, yv, pointv, isoutput)
]
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)
return
]
if nnodes eq 1 then
[
Warning("*nSingle Node Net: *"$S*"", netString)
return
]
if nnodes eq 2 then return // already routed
// First route the net as it is
Route(nnodes,xv,yv,permv,epcount ne 0,StandardMetric,
(singleCluster? empty, clusterBaseVec))
btnl = bestTotalNetLength
//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.
if (outcount eq 1)&(epcount eq 0)& eclPins & singleCluster then
[
// force the single output to the end of the net.
MakeFirst(outnum, xv, yv, pointv, isoutput)
outnum = 1
Route(nnodes,xv,yv,tpermv,true,StandardMetric)
// if this routing is at most 20%+2" worse than the
// unconstrained routing, use it.
if bestTotalNetLength le (btnl+btnl/5+80) then
[
btnl = bestTotalNetLength
permv = tpermv
]
]
//Reorder the list based on the permutation
net>>net.pinList = pointv!(permv!1) //list head
for j = 1 to nnodes-1 do @(pointv!(permv!j)) = pointv!(permv!(j+1))
@(pointv!(permv!nnodes)) = lp //last node
]
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
]
]
and ComputeLengths(net) be
[ // Compute the total net length and shortest arc length, or area for Multiwire
let shortestarc = infinity
let netlength = 0
let minx,miny = infinity,infinity
let maxx, maxy = 0,0
let pin = net>>net.pinList
if @pin ne mark then
[
let x1,y1 = nil,nil
GetPinCoord(0, pin, lv x1, lv y1)
if x1 ls minx then minx = x1
if x1 gr maxx then maxx = x1
if y1 ls miny then miny = y1
if y1 gr maxy then maxy = y1
pin = @pin
while @pin ne mark do
[
let x2,y2 = nil,nil
GetPinCoord(0, pin, lv x2, lv y2)
if x2 ls minx then minx = x2
if x2 gr maxx then maxx = x2
if y2 ls miny then miny = y2
if y2 gr maxy then maxy = y2
let arclength = StandardMetric(x1, y1, x2, y2)
netlength = netlength+arclength
if arclength ls shortestarc then shortestarc = arclength
pin = @pin
x1 = x2; y1 = y2
]
]
net>>net.shortestarc = shortestarc eq infinity? 0, // single-node net
(doMultiWire?
(((maxx-minx)/4)*((maxy-miny)/4)), // compute area of enclosing rectangle
shortestarc // shortest arc for Rosemary
)
net>>net.netlength = netlength
]