//routeb.bcpl

// Output module

// last modified by E. McCreight, May 11, 1979 6:25 PM

get "route.defs"

static
[
netnumber = 0
outcount; nodecount; headingpresent; currentFile
baseNetNumber; netCount
zeroPending; currentlevel; noseName
]

let MakeOutputFile(file, isADFile) be
[
currentFile = file
baseNetNumber = 1
PutTemplate(file, "$S*n", ZeroTablePoint(0))
let comments = GetFile(nlFileName,".comments")
until Endofs(comments) do Puts(file, Gets(comments))
Closes(comments)
unless isADFile do DoInSortOrder(typeIcinst, NameCompareFn, OutputUsedIC)
Wss(currentFile, "*n@")

currentlevel = 1
let levelName, pullComponents, wire = nil,nil,nil
while LevelTransform(currentlevel, 0, 0, 0, 0, lv levelName,
lv pullComponents, lv wire) do
[
zeroPending = true
noseName = "welder"
if isADFile then
[
if pullComponents then PullComponents()
if wire then
[
netCount = 0
DeleteNets()
baseNetNumber = baseNetNumber+netCount
]
]

zeroPending = true
noseName = "cutter"
test isADFile
ifso [ ReportPins(ReportRepairedPins); ReportPins(ReportNewCutPins) ]
ifnot ReportPins(ReportCutPins)

if wire then
[
zeroPending = true
noseName = "welder"
netCount = 0
DoInSortOrder(typeNet, NameCompareFn,
(isADFile? PrintNewNet, PrintNet))
baseNetNumber = baseNetNumber+netCount
]
currentlevel = currentlevel lshift 1
]
]
and ReportPins(Routine) be
[
headingpresent = false
DoInSortOrder(typeIcclass, NameCompareFn, Routine)
]

and NLCompFn(net1,net2) = valof //sort function for net routing. First nets wired
// are those that will appear in the .AD file. Within that, sort by "wireEarly".
// Within that, sort by shortest arcs. Within that, sort by net length.
[
if net1>>net.hasNetnum then resultis -1
if net2>>net.hasNetnum then resultis 1
// because AssignNetNumber
// clobbers the shortestarc field with the netnum field
// we have to give NextBatchToHeap some explicit help. The
// -1 says that net1 is already done. The 1 says that net1
// still needs doing.

let same1 = net1>>net.isSame
let same2 = net2>>net.isSame
if same1 ne same2 then resultis same1? 1, -1

let we1 = net1>>net.wireEarly
let we2 = net2>>net.wireEarly
if doMultiWire then if we1 ne we2 then resultis we1? -1, 1

let sa1 = net1>>net.shortestarc
let sa2 = net2>>net.shortestarc

if sa1 ne sa2 then resultis sa1-sa2

resultis net1>>net.netlength-net2>>net.netlength
]

and AssignNetNumber(net) be
[
net>>net.hasNetnum = true
let firstpin = net>>net.pinList
if @firstpin eq mark then return // empty pin list
netnumber = netnumber+1
net>>net.netnum = netnumber
]

and OutputUsedIC(icinst) be
[
WeAre(doingOutput)
unless Icclass(icinst)>>icclass.printUsedList do return
PutTemplate(OutFile, "*n$S: ($S) ; ", FindNameesString(icinst),
FindNameesString(icinst>>icinst.ictype))
let commaNeeded = false
let x,y = nil,nil
for pin=1 to Npins(icinst) do
[
if GetPinCoord(icinst, pin, lv x, lv y) &
icinst>>icinst.pin↑pin eq empty then
[
if commaNeeded then PutTemplate(OutFile, ",")
PutTemplate(OutFile, "$D", pin)
commaNeeded = true
]
]
]


and ZeroTheTable() be
[
unless zeroPending do return
zeroPending = false
let levelName = nil
let xtable = vec 5
let ytable = vec 5
let x, y = nil,nil
let cornertable = vec 5
for point = 1 to 4 do
[
GetPatternCoord(ZeroTablePoint(point), lv x, lv y)
LevelTransform(currentlevel, x, y, lv xtable!point, lv ytable!point,
lv levelName)
]

PermuteCorners(xtable, ytable, cornertable)

PutTemplate(currentFile, "*n*nCALIBRATE: <$D> ; INSTALL $S nose, board $S up ...", baseNetNumber, noseName, levelName)
baseNetNumber = baseNetNumber+1
outcount = 0
for corner = 1 to 4 do
[
let point = cornertable!corner
GetPatternCoord(ZeroTablePoint(point), lv x, lv y)
PrintBasicPin(ZeroTablePoint(point), x, y)
]
]

and PermuteCorners(xtable, ytable, cornertable) be
[
// find center of mass

let cx,cy = 0,0
for i=1 to 4 do
[
cx = cx+xtable!i
cy = cy+ytable!i
]
cx = cx/4
cy = cy/4
for corner = 1 to 4 do
[
for point = 1 to 4 do
[
// identify point toward origin from center of mass

if xtable!point ls cx & ytable!point ls cy then
cornertable!corner = point

// rotate point ccw 90 degrees about center of mass

let newx = cx-(ytable!point-cy)
ytable!point = cy+(xtable!point-cx)
xtable!point = newx
]
]
]

and ReportCutPins(icclass) be
[
unless icclass>>icclass.isTraceWired do return
let cutPins = icclass>>icclass.cutPins
if cutPins eq empty then CallSwat()
for i=1 to Npins(icclass) do
[
if GetBit(cutPins, i) eq 0 then loop
let x,y,info = nil,nil,nil
if (icclass>>icclass.PinOffset)(0, i, lv x, lv y, lv info) ne absolute then
CallSwat()
if (info<<info.level & currentlevel) eq 0 then loop
Heading("DISCONNECT")
PrintPin(icclass, i, currentFile)
]
]

and Heading(str) be
[
unless headingpresent & nodecount le 59 do
[
ZeroTheTable()
PutTemplate(currentFile, "*n*n$S: <$D>", str, baseNetNumber)
baseNetNumber = baseNetNumber+1
headingpresent = true
outcount = 0
nodecount = 0
]
]

and PrintNet(net, netnum; numargs na) be //print all nodes associated with net
[
DefaultArgs(lv na, -1, net>>net.netnum)
let pin = net>>net.pinList
if @pin eq mark then return

ZeroTheTable()
netCount = netCount+1
WeAre(currentFile eq OutFile? doingOutput, doingADFile)
PutTemplate(currentFile, "*n*n$S: <$D> ($D)", FindNameesString(net),
netnum+baseNetNumber-1, net>>net.netlength)
outcount = 0
until @pin eq mark do
[
PrintPin(0, pin, currentFile)
pin = @pin
]
]


and PrintPin(icinst, pin, file, skipFormatting; numargs na) be //print a single pin
[
DefaultArgs(lv na, -2, currentFile, false)

if icinst eq 0 then
[
icinst = pin-offset icinst.pin↑1/16
pin = 1
while icinst>>icinst.type ne typeIcinst do
[
pin = pin+1
icinst = icinst-1
]
]

let x,y = nil,nil
GetPinCoord(icinst, pin, lv x, lv y)
let icclass = Icclass(icinst)
let pa = (icclass>>icclass.PinAttributes)(icinst,pin)

let iostr = ""
let ictype = icinst>>icinst.ictype
if ictype>>namee.type eq typeIctype then
iostr = pa<<pinattributes.isOutput? "o", "i"

let pnv = vec 40
ExpandTemplate(pnv, "$S$S$D$S",
FindNameesString(icinst),
(icclass>>icclass.isTraceWired%icclass>>icclass.isConnector? "", "."),
pin, iostr)
PrintBasicPin(pnv, x, y, file, skipFormatting)
]

and PrintBasicPin(pinstring, x, y, file, skipFormatting; numargs na) be
[
static [ lastPinLen ]
DefaultArgs(lv na, -3, currentFile, false)

LevelTransform(currentlevel, x, y, lv x, lv y)

unless skipFormatting do
[
test outcount eq 0 % outcount gr 3
ifso [ outcount = 0; Wss(file, "*n ") ]
ifnot for i=1 to 22-lastPinLen do Puts(file, $*s)
]

let pnv = vec 40
ExpandTemplate(pnv, "$S {$D,$D}", pinstring, x, y)
Wss(file, pnv)
lastPinLen = pnv>>str.length

outcount = outcount+1
nodecount = nodecount+1
]