// PrintSlot.bcpl - SLOT printing code

// last modified by Ramshaw, November 29, 1983 10:27 AM
// - Added RavenPowerOnFlag hack

// last modified by Butterfield, October 6, 1980 5:10 PM
// - SetSCB, add .invert = InvertMode - 10/6/80

get "PressInternals.df"
get "PressParams.df"
get "SlotDefs.d"

//outgoing procedures
external
[ PSlot;SLOTInit
]

//outgoing statics
external [
SLOTScanLength//To give to 3100 interface
SLOTScanMarginAdjust//Adjustments to add to user input
SLOTBitMarginAdjust
SLOTDouble
SLOTTimeOut
]

static [
SLOTScanLength=384*11+48
SLOTScanMarginAdjust=36
SLOTBitMarginAdjust=12
SLOTDouble
SLOTTimeOut=10
]

//incoming procedures
external
[
//PRESSML
Ugt
//OS
Zero;MoveBlock;Timer;StartIO
//PRINT
PrintError
//WINDOW
FileVDA
//PRINTDISKTRIDENT
SetDA
]

//incoming statics
external
[
BitsFile
Report
InvertMode
RavenPowerOnFlag
]

//internal statics
static
[
bufferEmpty=0; PrintFail=0; IllegalState=0; readErrors=0
vDA
ReadNext; PrintNext
readCount; printCount
SectorsPerBuff
]

// S L O T Definitions:

structure RS [
blankbyte
Spare2bit
Waitbit//complement signal
PaperJambit//complement signal
AddPaperbit//complement signal
SelectBbit
Readybit
LineSyncbit
PageSync bit//complement signal
]
manifest NormalizeStatus = #161 //use to uncomplement above signals

structure SCB [
blankbit14
COMbit2//Command Beam On#0
//Command Status#1
//Command Reset#2
//Command Print#3
BlowUpbit// Make-one-bit-into-four; true select option
LastPagebit// Marks this command as the last page if true
invertbit// inverts the page
bitsPerLinebit13// Servo Count for number of bits per line
bitMarginword// Bottom Margin (bits)
scanLineWcword// Double Word Count
scanMarginword// Left Margin (bits before print in portrait)
scansPerPageword// Total number of Scan Lines per page
bufferPtrword// Print Buffer Base Address (first loc.)
scanLineWcIncword// Print Buffer Scan Line Increment
scansPerBuffword// Print-mode Buffer Length
currentBuffword// Current Buffer Address
currentLineword// Current Scan Address
SWword = @RS// Return Status Word
]

manifest lSCB = size SCB/16

manifest
[
SCBloc=#720

slotSIObit=4

BeamOnCommand=0
StatusCommand=1
ResetCommand=2
PrintCommand=3
]

// T R I D E N T D I S K defintions

structure DCB [

diskAddress word 2//DCB+0 & DCB+1
drive word//DCB+2
nextDC word //DCB+3
ID word//DCB+4

CommH word//DCB+5
CountH word//DCB+6
AddrH word//DCB+7
ECC0H word//DCB+8
ECC1H word//DCB+9
StatusH word//DCB+10

CommL word//DCB+11
CountL word//DCB+12
AddrL word//DCB+13
ECC0L word//DCB+14
ECC1L word//DCB+15
StatusL word//DCB+16

CommD word//DCB+17
CountD word//DCB+18
AddrD word//DCB+19
ECC0D word//DCB+20
ECC1D word//DCB+21
StatusD word//DCB+22
endWord word//DCB+23
]

manifest lDCB = size DCB/16

manifest
[
KBLK = #640;
diskWordsPerPage=1024
diskCheck = #4104; diskRead = #104; DCBseal = #122645
diskSIOStart=#40
RTC=#430
Active=#453
parityInterruptBit=1
WakeupsWaiting=#452
]

let SLOTInit() be
[
SLOTCommand(Reset)
SLOTCommand(BeamOn)
SlotReady()
]

and PSlot(pg, numBands, last, firstAdr, lastAdr) be
[
let oldActive=@Active
@Active=oldActive&(not parityInterruptBit)

let firstBuff=(firstAdr+2)&(-2)
let buffLen=nil
let da=nil
// Make an effort to print blank pages. Otherwise, color sync
// on 6500 will be screwed up.
test numBands gr 0 then
[
buffLen=1024*((pg>>PageG.BitWc*BANDWidth+1023)/1024)+2
da=FileVDA(BitsFile, pg>>PageG.BitPage)
] or [
buffLen=1024
da=-1
pg>>PageG.FirstBand=10
pg>>PageG.BitMargin=16*10
pg>>PageG.BitWc=4
numBands=1
]

let buff=firstBuff
for i=1 to 20 do
[
if Ugt(buff+buffLen, lastAdr) then break
let nb=buff+buffLen
if da eq -1 then Zero(buff, buffLen)
buff!-1=nb
buff=nb
]
buff!(-buffLen-1)=firstBuff
//On exit from loop, buff is just after last legal buffer

let v=vec lSlotStatus

[Retry
SLOTPrint( (last? LastPage,NormalPage), pg>>PageG.FirstBand*BANDWidth,
pg>>PageG.BitMargin, pg>>PageG.BitWc*16, numBands*BANDWidth,
BANDWidth, da, firstBuff, v)

let SlotError=(v!Ready eq 0)&((v!Wait % v!PaperJam % v!PaperOut % v!Illegal % v!PageNotPrinted) ne 0)
//Only worry about clearing or cleaning up Slot Errors (not disk errors)
test SlotError then
[
SLOTCommand(Reset)
SlotReady(v)
] or break
]Retry repeat

@WakeupsWaiting=@WakeupsWaiting&(not parityInterruptBit)
@Active=oldActive
]


and SlotReady(v; numargs n) be
[
let vv=vec 10
if n eq 0 then [ v=vv; SLOTStatus(v) ]
[checkStatus
if v!Ready then return
SLOTCommand(Reset)
//Kill print request

let i=0
if v!PaperOut then
[
i=1
compileif ReportSw then [ Report>>REP.PaperOut=true ]
]
if v!PaperJam then
[
i=2
compileif ReportSw then [ Report>>REP.Jams=Report>>REP.Jams+1 ]
]

test ((RavenPowerOnFlag ne 0) & (i eq 2))
ifso PrintError(2, 15000) //Signal error, wait for CR or timeout
ifnot PrintError(i)
//Signal error, wait for fix...

SLOTCommand(Reset)
SLOTCommand(BeamOn)
SLOTStatus(v)
]checkStatus repeat
]

// SLOT Procedures
and SLOTStatus(v) be
[
let scb=vec lSCB
scb=SetSCB(scb)
scb>>SCB.COM = StatusCommand
scb>>SCB.SW = NormalizeStatus
@SCBloc = scb
StartIO(slotSIObit)
MsWait(20)//give microcode long enough to see the new command

if scb>>SCB.SW eq NormalizeStatus then IllegalState = true
scb>>SCB.SW = scb>>SCB.SW xor NormalizeStatus
v!Wait = scb>>SCB.Wait
v!PaperJam = scb>>SCB.PaperJam
v!PaperOut = scb>>SCB.AddPaper
v!Illegal = IllegalState
v!PageNotPrinted = PrintFail
v!Overrun = bufferEmpty
v!DiskError = readErrors
v!Ready = scb>>SCB.Ready & ((v!Wait % v!PaperJam % v!PaperOut %
v!Illegal % v!PageNotPrinted % v!Overrun % v!DiskError) eq 0)
]

and SLOTCommand(comm) be
[
let scb=vec lSCB
scb=SetSCB(scb)
switchon comm into
[
case SetDensity:
case BeamOn:
[
scb>>SCB.COM = BeamOnCommand; endcase
]
case Reset:
[
IllegalState = false
PrintFail = false
bufferEmpty = false
readErrors = 0
]//!!! no endcase
case StopPrint:
case BeamOff:
[
scb>>SCB.COM = ResetCommand; endcase
]
default:
[ IllegalState = true;return ]
]
@ SCBloc = scb
StartIO(slotSIObit)
for i = 0 to 30000 do if scb>>SCB.SW then break
if scb>>SCB.SW eq 0 then IllegalState=true
if comm eq BeamOn then MsWait(1000)
]


and SLOTPrint(lastPage, scanMargin, bitMargin, scanLength, numScans, scansPerBuffer, DA, bufferList, V) be
[
vDA = DA
let useDisk = DA ne -1
readErrors = 0; PrintFail=0

let scb=vec lSCB
scb=SetSCB(scb)
scb>>SCB.COM = PrintCommand
scb>>SCB.LastPage = lastPage
scb>>SCB.bitMargin = bitMargin + SLOTBitMarginAdjust
scb>>SCB.scanLineWc = scanLength rshift 5
scb>>SCB.scanMargin = scanMargin + SLOTScanMarginAdjust
scb>>SCB.scansPerPage = numScans
let currentBuff = bufferList
scb>>SCB.bufferPtr = currentBuff
scb>>SCB.currentBuff = currentBuff
let numWords = scanLength rshift 4
scb>>SCB.scanLineWcInc = numWords
scb>>SCB.scansPerBuff = scansPerBuffer
rv SCBloc = scb

// Compute how many buffers to process before done
let BufferCount = (numScans+scansPerBuffer-1)/scansPerBuffer
printCount = BufferCount
readCount = BufferCount

//Now get the disk spinning:
SectorsPerBuff = (scansPerBuffer*numWords+1023)/1024
let labelBuff = vec 10
let dcbTable = vec 64*lDCB//Enough for all of memory!
dcbTable=(dcbTable+1)&(-2)
let dcb = dcbTable
let buff = bufferList
[
ReadNext = dcb
for cnt = 0 to SectorsPerBuff-1 do
[
Zero(dcb,lDCB)
dcb>>DCB.nextDC = dcb + lDCB
dcb>>DCB.CommH = diskCheck
dcb>>DCB.CountH = 2
dcb>>DCB.AddrH = lv dcb>>DCB.diskAddress
dcb>>DCB.CommL = diskRead
dcb>>DCB.AddrL = labelBuff
dcb>>DCB.CountL = 10
dcb>>DCB.CommD = diskRead
dcb>>DCB.CountD = diskWordsPerPage
dcb>>DCB.AddrD = buff + cnt*diskWordsPerPage
unless useDisk then dcb>>DCB.StatusD = 1
dcb = dcb>>DCB.nextDC
]
ReadBuffer(false)
buff=buff!-1
] repeatuntil buff eq bufferList
(dcb-lDCB)>>DCB.nextDC = dcbTable
ReadNext = dcbTable
PrintNext = dcbTable
if useDisk then
[
StartIO(diskSIOStart)
KBLK!2=-1; KBLK!3=-1//Reset track memory
@KBLK = dcbTable
]
Start:

//wait up to 10 seconds -- 2 page times for ’slow-to-grab’ 3100’s
let timeOut = @RTC + SLOTTimeOut*27

//Read in the first load from the disk:
until PrintBuffer() do
if @RTC ge timeOut then [ readErrors=-1; PrintFail=-1; break ]
bufferEmpty=0

//Now spin the Slot:
unless PrintFail then
[ml
StartIO(slotSIObit)
[
if scb>>SCB.currentBuff ne currentBuff then //started next buff
[
currentBuff = scb>>SCB.currentBuff
if useDisk then
[
unless PrintBuffer() then break //must be full
ReadBuffer(true) //read into emptied buff
]
]
if scb>>SCB.SW then break
if @RTC ge timeOut then [ PrintFail=1; break ]
] repeat
]ml

@ KBLK = 0//make sure disk wont start up
SLOTStatus(V)
if lastPage then [ MsWait(6000); SLOTCommand(Reset) ]
]

and PrintBuffer() = valof
[
if printCount eq 0 then resultis true
printCount = printCount-1
let dcb = PrintNext
for i = 1 to SectorsPerBuff do
[
unless dcb>>DCB.StatusD then [ bufferEmpty = true; resultis false ]
let status=dcb>>DCB.StatusH % dcb>>DCB.StatusL % dcb>>DCB.StatusD
if status ne 1 then
[
//
if status ne #11 then [ readErrors=-1; resultis 0 ]
readErrors = readErrors + 1
]
dcb = dcb>>DCB.nextDC
]
PrintNext = dcb
resultis true
]

and ReadBuffer(startUp) be if readCount then
[
readCount = readCount-1
let StartNext = ReadNext
for i = 1 to SectorsPerBuff do
[
SetDA(ReadNext, vDA); vDA=vDA+1
ReadNext>>DCB.StatusD = 0
ReadNext>>DCB.ID = DCBseal
ReadNext = ReadNext>>DCB.nextDC
]
if startUp ne 0 & @KBLK eq 0 then @KBLK = StartNext
]

and SetSCB(scb) = valof
[
Zero(scb, lSCB+1)
let p=(scb+1)&(-2)
p>>SCB.invert = InvertMode;
p>>SCB.bitsPerLine=SLOTScanLength
p>>SCB.BlowUp=SLOTDouble
resultis p
]

and MsWait(ms) be
[
let timeOut = @RTC + ms/37
until @RTC ge timeOut do loop
]