-- File: PrintSlot.mesa.
--edit history at bottom of file
-- Last Edited: February 19, 1982 3:41 PM By: GWilliams
--added totalBufferLength to PSlot to guard against overflows

DIRECTORY
AltoDefs USING [PageSize],
FSPDefs USING[ZoneTooLarge],
InlineDefs USING[BITAND, BITNOT, BITOR, BITSHIFT, BITXOR],
IODefs USING[CR, ReadChar,
--ReadDecimal,-- WriteChar, WriteDecimal, WriteLine, WriteString],
MiscDefs USING [--CallDebugger,-- Zero],
PressDefs USING [abortFile, invertMode, PageG, PageGptr, SLOTScanLength, SLOTScanMarginAdjust, SLOTBitMarginAdjust, SLOTDouble, SLOTTimeOut],
RamDefs USING[StartIO],
SegmentDefs USING[DataSegmentAddress, DataSegmentHandle, DefaultBase, DeleteDataSegment, InsufficientVM, NewDataSegment],
StringDefs USING [UpperCase],
Storage USING[FreeWords, Words],
SystemDefs USING [Even],
TridentDefs USING[DA, diskCheck, diskRead, dlPtr, dstDone, dstZeroStatus, FP, kcbPtr, lKCB, Mstatus, PAGE, ptr, statusptr, Status, tfsdskPtr, TfsRealDA, TFSwordsPerPage, track];
PrintSlot: PROGRAM
IMPORTS FSPDefs, InlineDefs, IODefs, MiscDefs, PressDefs, RamDefs, SegmentDefs, Storage, StringDefs, SystemDefs, TridentDefs--, FSPDefs
EXPORTS PressDefs=
BEGIN OPEN AltoDefs, FSPDefs, InlineDefs, IODefs, MiscDefs, PressDefs, RamDefs, SegmentDefs, StringDefs, Storage, SystemDefs, TridentDefs;

-- Types
PError: TYPE = {noPaper, jam, firstFillFailed, firstFillTimeOut, pageTimeOut, overRan, scannerOverRan, readError, illegal, notSure};
SlotCommand: TYPE = {setDensity, beamOn, reset, stopPrint, beamOff};
--SCB: TYPE = MACHINE DEPENDENT RECORD
--
[
--
blank:[0..37777B],- -14 bits worth
--
com:[0..3],- -Beam On =0, Status = 1, Reset = 2, Print = 3
--
blowup:[0..1),- -True: make one bit into 4
--
lastPage:[0..1),- -Marks this command as the last page if true
--
invert:[0..1),- -invert this page
--
bitsPerLine:[0..17777B],- -servo count for number of bits per line
--
bitMargin:CARDINAL,- -bottom margin in bits
--
scanLineWc:CARDINAL,- -double of the word count
--
scanMargin:CARDINAL,- -left margin (bits before print in portrait)
--
scansPerPage:CARDINAL,- -total number of scan lines per page
--
bufferPtr:POINTER,- -print buffer base address (first loc.)
--
scanLineWcInc:CARDINAL,- -print buffer scan line increment
--
scansPerBuff:CARDINAL,- -print-mode buffer length
--
currentBuf:POINTER,- -current buffer address
--
currentLine:CARDINAL,- -current scan address
--
status:ReturnStatus,- -return status
--
filler:CARDINAL];- -in case SetSCB adds one to base address
SCB: TYPE = MACHINE DEPENDENT RECORD
[
blank:[0..37777B],--14 bits worth
com:[0..3],--Beam On =0, Status = 1, Reset = 2, Print = 3
blowup:[0..1),--True: make one bit into 4
lastPage:[0..1),--Marks this command as the last page if true
invert:[0..1),--invert this page
slug:[0..17777B],--13 bits of filler. Was bitsPerLine.
bitMargin:CARDINAL,--bottom margin in bits
scanLineWc:CARDINAL,--double of the word count
scanMargin:CARDINAL,--left margin (bits before print in portrait)
scansPerPage:CARDINAL,--total number of scan lines per page
bufferPtr:POINTER,--print buffer base address (first loc.)
scanLineWcInc:CARDINAL,--print buffer scan line increment
scansPerBuff:CARDINAL,--print-mode buffer length
bitsPerLine:CARDINAL,--servo count for number of bits per line
currentBuf:POINTER,--current buffer address
currentLine:CARDINAL,--current scan address
status:ReturnStatus,--return status
debuggingSpace0: CARDINAL,
debuggingSpace1: CARDINAL,
debuggingSpace2: CARDINAL,
debuggingSpace3: CARDINAL,
debuggingSpace4: CARDINAL,
debuggingSpace5: CARDINAL,
debuggingSpace6: CARDINAL,
debuggingSpace7: CARDINAL,
filler:CARDINAL--in case SetSCB adds one to base address
];
ReturnStatus: TYPE = MACHINE DEPENDENT RECORD
[
blank:[0..377B],
spare2:[0..1],
wait:[0..1],
paperJam:[0..1],
addPaper:[0..1],
selectB:[0..1],
ready:[0..1],
lineSync:[0..1],
pageSync:[0..1]--complemented signal
];
normalizedStatus: ReturnStatus ← [0,0,1,1,1,0,0,0,1];
--161B

MetaStat: TYPE = POINTER TO AqMetaStat;
AqMetaStat: TYPE = MACHINE DEPENDENT RECORD
[wait:BOOLEAN,--from uCode
paperJam:BOOLEAN,--from uCode
paperOut:BOOLEAN,--from uCode
illegal:BOOLEAN,--from IllegalState
ready:BOOLEAN,--"OR" of various bits and variables
overRun:BOOLEAN,--from "bufferEmpty"
--
fill:[0..1777B],----filler
fill:[0..0777B],--filler
scannerOverRun: BOOLEAN,--scanner got >1 buffers ahead
pageNotPrinted: CARDINAL,--from PrintFail
diskError:CARDINAL--from "readErrors"
];

-- Public Pack Variables EXPORTED to PressDefs
--EXPORTED to PressDefs
--Private Pack Variables
scannerOverRun, overRun, illegalState: BOOLEAN;--these are initialized by SlotInit
printFail, readErrors: CARDINAL;
slotCommandBlock: POINTER TO POINTER = LOOPHOLE[720B];
slotSIObit: CARDINAL = 4;

--debugging switches
useSLOT: BOOLEAN ← TRUE;
debug: BOOLEAN ← FALSE;
noDisplay: BOOLEAN ← TRUE;
diskRetries: CARDINAL ← 20B;
testDiskOnly: BOOLEAN ← FALSE;
checkBufs: BOOLEAN ← TRUE;

da: PAGE;
--used by SLOTPrint and ReadBuffer
readNext, printNext: kcbPtr;
printCount, readCount: CARDINAL;
--
global names for variables that will be initialized in ReadBuffer for PrintSlot
gTrack: INTEGER;
gHead, gSector: INTEGER;

active: POINTER TO CARDINAL = LOOPHOLE[453B];
--for turning off memory parity interrrupts
wakeupsWaiting: POINTER TO CARDINAL = LOOPHOLE[452B];
RTC: POINTER TO CARDINAL = LOOPHOLE[430B];
Display: POINTER = LOOPHOLE [420B];
DisplayOn: BOOLEAN ← TRUE;
savedDisplay: WORD;

parityInterruptBit: CARDINAL = 1;

bandWidth: CARDINAL = 16;


beamOnCommand: CARDINAL = 0;
statusCommand: CARDINAL = 1;
resetCommand: CARDINAL = 2;
printCommand: CARDINAL = 3;


--Signals and Errors

--
Procs

OriginalSlotInit: PUBLIC PROC []=
{
SLOTCommand[reset];
SLOTCommand[beamOn];
SlotReady[];
};--
SlotInit
SlotInit: PUBLIC PROC []=
{
SLOTCommand[reset];
--SLOTCommand[beamOn];
SlotReady[];
};--
SlotInit

OriginalSLOTCommand: PROC[cmd: SlotCommand]=
BEGIN
i: CARDINAL;
sCB:SCB;
scb: POINTER TO SCB ← @sCB;

scb ← SetSCB[scb];--align to even word boundary and init some fields.
SELECT cmd FROM
setDensity, beamOn =>scb.com ← beamOnCommand;
reset =>{overRun ← scannerOverRun ← illegalState ← FALSE; printFail ← readErrors ← 0;
scb.com ← resetCommand;};
stopPrint, beamOff =>scb.com ← resetCommand;
ENDCASE =>{illegalState ← TRUE; GOTO done};
slotCommandBlock↑ ← LOOPHOLE[scb];
IF useSLOT THEN
{[] ← StartIO[slotSIObit];
FOR i IN [0..30000]
DO
IF scb. status # ReturnStatus[0,0,0,0,0,0,0,0,0] THEN EXIT;
ENDLOOP;

IF scb.status = ReturnStatus[0,0,0,0,0,0,0,0,0] THEN illegalState ← TRUE;
IF cmd = beamOn THEN MsWait[1000];
};
EXITS
done => NULL;
END;
--SlotCommand
SLOTCommand: PROC[cmd: SlotCommand]=
BEGIN
i: CARDINAL;
sCB:SCB;
scb: POINTER TO SCB ← @sCB;

scb ← SetSCB[scb];--align to even word boundary and init some fields.
SELECT cmd FROM
setDensity, beamOn =>scb.com ← beamOnCommand;
reset =>{overRun ← scannerOverRun ← illegalState ← FALSE; printFail ← readErrors ← 0;
scb.com ← resetCommand;};
stopPrint, beamOff =>scb.com ← resetCommand;
ENDCASE =>{illegalState ← TRUE; GOTO done};
slotCommandBlock↑ ← LOOPHOLE[scb];
IF useSLOT THEN
{[] ← StartIO[slotSIObit];
FOR i IN [0..30000]
DO
IF scb. status # ReturnStatus[0,0,0,0,0,0,0,0,0] THEN EXIT;
ENDLOOP;

IF scb.status = ReturnStatus[0,0,0,0,0,0,0,0,0] THEN illegalState ← TRUE;
IF cmd = beamOn THEN MsWait[1000];
};
EXITS
done => NULL;
END;
--SlotCommand

SlotStatus
: PROC[metaStat: MetaStat]=
{
sCB:SCB;
scb: POINTER TO SCB ← @sCB;

IF useSLOT THEN
{scb ← SetSCB[scb];
scb.com ← statusCommand;
scb.status ← normalizedStatus;--some dummy bits
slotCommandBlock↑ ← scb;
[] ← StartIO[slotSIObit];
MsWait[37];--give microcode time to see new command

IF scb.status = normalizedStatus THEN illegalState ← TRUE;
scb.status ← BITXOR[scb.status, normalizedStatus];

metaStat.wait ← scb.status.wait # 0;
metaStat.paperJam ← scb.status.paperJam # 0;
metaStat.paperOut ← scb.status.addPaper # 0;
metaStat.illegal ← illegalState;
metaStat.pageNotPrinted ← printFail;
metaStat.overRun ← overRun;
metaStat.scannerOverRun ← scannerOverRun;
metaStat.diskError ← readErrors;
metaStat.ready ← scb.status.ready = 1 AND NOT(metaStat.wait OR metaStat.paperJam OR metaStat.paperOut OR metaStat.illegal OR metaStat.pageNotPrinted # 0 OR metaStat.overRun OR metaStat.scannerOverRun OR metaStat.diskError # 0);
}
ELSE metaStat.ready ← TRUE;
};--SlotStatus

PrintError
: PROC[err: PError, num: CARDINAL]=
--This routine should turn the display on if it was off and type appropriate message, then turn the display back off to continue.
--if the error is notSure, display the whole slotStats structure
{displayWasOn: BOOLEAN ← DisplayOn;
continue: BOOLEAN ← FALSE;
canContinue: BOOLEAN ← FALSE;

IF ~DisplayOn THEN
{Display↑ ← savedDisplay; DisplayOn ← TRUE};
SELECT err FROM
noPaper => {WriteLine["Reload printer with paper. Type any key to continue."L];
[]←ReadChar[];
continue ← TRUE;
IF ~displayWasOn THEN
{savedDisplay ← Display↑; Display↑ ←0; DisplayOn ← FALSE};
GOTO getOut;
};
jam => {WriteLine["Printer jammed. Fix, then type any key to continue."L];
[]←ReadChar[];
continue ← TRUE;
IF ~displayWasOn THEN
{savedDisplay ← Display↑; Display↑ ←0; DisplayOn ← FALSE};
GOTO getOut;
};
firstFillFailed, firstFillTimeOut=>
WriteLine["Trident didn’t get off the ground."L];
pageTimeOut=>WriteLine["Page took too long to print."L];
overRan=>{WriteLine["Disk Overran "L]; canContinue ← TRUE};
scannerOverRan=>{WriteLine["Slot Overran"L]; canContinue ← TRUE};
readError=>{WriteDecimal[num]; WriteLine[" readErrors."L];};
illegal =>WriteLine["Illegal state"L];
notSure =>{WriteLine["Unknown Error"L];};
ENDCASE;

IF canContinue THEN
{WriteString["Type Y to continue, anything else to exit: "L];
IF (UpperCase[ReadChar[]] = ’Y) THEN continue ← TRUE; WriteChar[CR]};
IF ~continue THEN abortFile;

EXITS
getOut=> NULL;

};
--PrintError

SlotReady: PROC [metaStat: MetaStat ← NIL]=
{
aqMetaStat: AqMetaStat;
mStat: MetaStat ← @aqMetaStat;

IF metaStat = NIL THEN
{metaStat ← mStat;
SlotStatus[metaStat];};
IF ~useSLOT THEN metaStat.ready ← TRUE;
IF ~metaStat.ready THEN
{SLOTCommand[reset];
SELECT TRUE FROM
metaStat.paperOut => PrintError[noPaper, 0];
metaStat.paperJam => PrintError[jam, 0];
metaStat.illegal => PrintError[illegal, 0];
metaStat.pageNotPrinted # 0 =>
SELECT metaStat.pageNotPrinted FROM
1 => PrintError[firstFillFailed, 0];
2 => PrintError[firstFillTimeOut, 0];
3 => PrintError[pageTimeOut, 0];--took too long to print entire page
ENDCASE;
metaStat.overRun => PrintError[overRan, 0];
metaStat.scannerOverRun => PrintError[scannerOverRan, 0];
metaStat.diskError # 0 => PrintError[readError, metaStat.diskError]
ENDCASE => PrintError[notSure, 0];
SLOTCommand[reset];
SLOTCommand[beamOn];
};
};
--SlotReady

MsWait
: PROC[ms: CARDINAL]=
{
timeOut: CARDINAL ← RTC↑ + ms/37;--RTC runs at ~38 uSec/click, but clicks are measured at a scale of ~1024 uSec/click
UNTIL RTC↑ >= timeOut DO ENDLOOP;
};
--MsWait

--Pslot grabs as much storage as it can for buffers of scan lines. Each buffer holds a multiple of TfsWordsPerPage
--The buffers are arranged in a ring, with @buffer-1 holding the address of the next buffer. The storage is grabbed from the system as
-- one large segment if it can get it, and then divided into the buffers.
--The display machinery is turned off here in the final product. It is turned back on if there is an eror.
--SLOTPrint is then called to print the page by filling the buffers and passing them to the microcode.
--
November 10, 1981 1:47 PM: no longer get as much storage as possible. Just get 2 buffers and go with them
PSlot: PUBLIC PROC[disk: tfsdskPtr, pageG: PageGptr, lastPage: BOOLEAN, firstVDA: PAGE, filePtr: POINTER TO FP] =
BEGIN
i, nBufs, oldActive: CARDINAL;
zoneBase, firstBuf, buf: POINTER ← NIL;
aqMetaStat: AqMetaStat;
dcbSegment: DataSegmentHandle;
dcbTab: POINTER ← NIL;
totalBufferLength: LONG CARDINAL;--added this to catch possible overflows

BEGIN ENABLE UNWIND => {IF zoneBase # NIL THEN FreeWords[zoneBase];
IF dcbTab # NIL THEN DeleteDataSegment[dcbSegment]};

firstBitPageDA: PAGE ← pageG.BitPage + firstVDA;--assume a contiguous file for now
metaStat: MetaStat ← @ aqMetaStat;
buffLen: CARDINAL ← (1024*((pageG.BitWc*bandWidth+1023)/1024))+2;

--get enough room for 64 buffers of 1024 words each
dcbSegment ← NewDataSegment[DefaultBase, ((64*lKCB)/(PageSize))+1];
dcbTab ← DataSegmentAddress[dcbSegment];

nBufs ← 5;--now get the scan buffers
IF ~debug THEN
{oldActive ← active↑;
active↑ ← BITAND[oldActive, BITNOT[parityInterruptBit]]};

totalBufferLength ← nBufs * buffLen;
WHILE totalBufferLength > LAST[CARDINAL] DO
nBufs ← nBufs - 1; totalBufferLength ← nBufs * buffLen;
ENDLOOP;
zoneBase ← Words[nBufs * buffLen!
InsufficientVM, ZoneTooLarge =>
{nBufs ← nBufs - 1; RETRY}];
IF nBufs < 2 THEN
{active↑ ← oldActive;
FreeWords[zoneBase];
WriteLine["Not Enough Memory. Type any char to continue"L];
[]←ReadChar[];
RETURN;};

--the microcode requires the bit array to begin on an even word boundary AND bit array[-1] must be available for linking the pointers.
--Since MakeNode has a bookkeeping word at ptr-1, we must round up. Hence the +2 in the original calc.
buf ← firstBuf ← (IF BITAND[zoneBase, 1] THEN zoneBase+1 ELSE zoneBase + 2);
FOR i IN [0..nBufs)
DO
(buf-1)↑ ← buf+buffLen;
buf ← buf+buffLen;
ENDLOOP;
(buf-(buffLen+1))↑ ← firstBuf;--backup to fix up last pointer & complete the ring.

DO
SLOTPrint[disk, lastPage, pageG.FirstBand*bandWidth, pageG.BitMargin, pageG.BitWc*16, (pageG.LastBand-pageG.FirstBand+1)*bandWidth, bandWidth, firstBuf, firstBitPageDA, metaStat, dcbTab];--print this page till it’s printed without errors.
IF (~metaStat.ready AND (metaStat.wait OR metaStat.paperJam OR metaStat.paperOut OR metaStat.illegal OR metaStat.pageNotPrinted#0))
THEN
{SLOTCommand[reset];--only clear Slot Errors (not disk errors)
SlotReady[metaStat];}
ELSE
EXIT;
ENDLOOP;

DeleteDataSegment[dcbSegment];
dcbTab ← NIL;
FreeWords[zoneBase];
zoneBase ← NIL;
IF ~debug THEN
{wakeupsWaiting↑ ← BITAND[wakeupsWaiting↑, BITNOT[parityInterruptBit]];
active↑ ← oldActive;};

END;
--of UNWIND
END;--PSlot
SLOTPrint: PROC[disk: tfsdskPtr, lastPage: BOOLEAN, scanMargin, bitMargin, scanLength, numScans, scansPerBuffer: CARDINAL, firstBuf: POINTER, FirstDA: PAGE, metaStat: MetaStat, dcbTable: POINTER]=
{i, timeOut: CARDINAL;--i is used in two loops
dontUseTrident: BOOLEAN ← FALSE;
buf, currentBuf: POINTER;
dcb: kcbPtr ← LOOPHOLE[dcbTable];--used in first half of code and in inner loop
--dcbTable: POINTER;
labelBuf: ARRAY [0..10) OF WORD;
tridentStart: CARDINAL = 40B;
tridentStop: CARDINAL = 20B;
sCB:SCB;
scb: POINTER TO SCB ← @sCB;
numWords: CARDINAL ← BITSHIFT[scanLength, -4];
sectorsPerBuffer: CARDINAL ← (scansPerBuffer * numWords+1023)/1024;
--
these vars were in PrintBuffer and ReadBuffer
--status: Status;
DCBseal: CARDINAL = 122645B;
startNext: kcbPtr ← NIL;
daPtr: POINTER TO DA;

--vars that are needed by TfsRealDA replacement

nSectors: CARDINAL ← disk.tfskd.kdh.nSectors;
nHeads: CARDINAL ← disk.tfskd.kdh.nHeads;
--quotient: CARDINAL;

--
vars for timeout book keeping
subInterval, timeLeft: CARDINAL;
subIntervalSeconds: CARDINAL = 3;
subIntervalQuantum: CARDINAL = 78;--3 * 26 * .039 = 3 seconds

--local vars for printing
printCt, readCt: CARDINAL;
--locals for readNext and printNext
pNext, rNext, kcbHead, newKcbTail, kcbTail: kcbPtr;
--
locals for reading trident
trackNum: INTEGER;
sector, head: INTEGER;

da ← FirstDA;
printCount ← readCount ← (numScans+scansPerBuffer-1)/scansPerBuffer;
scb ← SetSCB[scb];

--must init buf etc. here to avoid "warning: multiple initialization with a pointer"
scb.currentBuf ← scb.bufferPtr ← buf ← currentBuf ← firstBuf;
scb.com ← printCommand;
scb.lastPage ← IF lastPage THEN 1 ELSE 0;
scb.bitMargin ← bitMargin + SLOTBitMarginAdjust;
scb.scanLineWc ← BITSHIFT[scanLength, -5];--shift right 5 bits
scb.scanMargin ← scanMargin + SLOTScanMarginAdjust;
scb.scansPerPage ← numScans;
scb.scanLineWcInc ← numWords;
scb.scansPerBuff ← scansPerBuffer;

slotCommandBlock↑ ← scb;--give microcode the pointer, (uCode not running yet).

DO
readNext ← dcb;
FOR i IN [0..sectorsPerBuffer) DO
Zero[dcb, lKCB];
dcb.nextKCB ← dcb + lKCB;
dcb.blockH.comm ← diskCheck;
dcb.blockH.count ← 2;
dcb.blockH.addr ← LOOPHOLE[@dcb.diskAddress, dlPtr];--disk label pointer
dcb.blockL.comm ← diskRead;
dcb.blockL.addr ← LOOPHOLE[@labelBuf, dlPtr];
dcb.blockL.count ← 10;
dcb.blockD.comm ← diskRead;
dcb.blockD.count ← TFSwordsPerPage;
dcb.blockD.addr ← (buf+i*TFSwordsPerPage);
dcb ← dcb.nextKCB;
ENDLOOP;
ReadBuffer[FALSE, sectorsPerBuffer, disk];
buf ← (buf-1)↑;
IF buf = firstBuf THEN EXIT;
ENDLOOP;--buffers filled

--(dcb-lKCB).nextKCB ← dcbTable;
dcb ← (dcb-lKCB);
dcb.nextKCB ← NIL;
kcbTail ← dcb;
readNext ← printNext ← dcbTable;

IF noDisplay THEN
{savedDisplay ← Display↑;
DisplayOn ← FALSE;
Display↑ ← 0;};

IF ~dontUseTrident THEN
{[] ← StartIO[tridentStart];
track↑ ← 177777B;
statusptr↑ ← Mstatus[1,1,1,1,1,1,1,1,1,1,1,1, 17B];
ptr↑ ← dcbTable;
};

timeOut ← RTC↑ + 5*27;--give us 5 seconds to read disk

--
PrintBuffer will return true as soon as the first buffer is filled (with or w/o errors)
UNTIL PrintBuffer[sectorsPerBuffer] DO
IF RTC↑ >= timeOut THEN printFail ← (IF printNext = firstBuf THEN 1 ELSE 2);
ENDLOOP;

timeLeft ← SLOTTimeOut / subIntervalSeconds;--# of sub intervals
overRun ← FALSE;
printCt ← printCount;--get globals into locals for speed
readCt ← readCount;
pNext ← printNext;
kcbHead ← readNext;
trackNum ← gTrack; sector ← gSector; head ← gHead;

IF printFail = 0 THEN--start the SLOT!
{IF useSLOT THEN
[]←StartIO[slotSIObit];
subInterval ← RTC↑ + subIntervalQuantum;--subIntervalSeconds * 26 * .039 = 3 seconds

DO
IF scb.currentBuf # currentBuf THEN--uCode started outputting next buf
{currentBuf ← scb.currentBuf;
-------------- ReadBuffer code ------------------------------------------------
rNext ← startNext ← kcbHead;
FOR i IN [1..sectorsPerBuffer] DO
daPtr ← LOOPHOLE[rNext];
-------------- ~TfsRealDA code ------------------------------------------------
IF (sector ← sector+1) > 8 THEN
{sector ← 0;
IF (head ← head + 1) > 18 THEN
{head ← 0;
trackNum ← trackNum + 1;
};
};
daPtr↑ ← DA[trackNum, head, sector]; --store the new values
-------------- End TfsRealDA code --------------------------------------------
rNext.blockD.status ← dstZeroStatus;
rNext.id ← DCBseal;
IF i=sectorsPerBuffer THEN
{kcbHead ← rNext.nextKCB;
newKcbTail ← rNext;
rNext.nextKCB ← NIL;
} ELSE
rNext ← rNext.nextKCB;
ENDLOOP;
--IF ptr↑ = NIL THEN ptr↑ ← startNext;
--seems I can eliminate the first test on IF ptr↑ # 0, but will try it once.
IF ptr↑ # NIL THEN {kcbTail.nextKCB ← startNext; kcbTail ← newKcbTail;}
ELSE {kcbTail.nextKCB ← startNext; kcbTail ← newKcbTail};
IF ptr↑ = NIL THEN ptr↑ ← startNext;
-------------- End ReadBuffer code --------------------------------------------
};
IF scb.status # LOOPHOLE[0, ReturnStatus] THEN EXIT;
IF RTC↑ > subInterval THEN
{IF (timeLeft ← timeLeft - 1) = 0 THEN {printFail ← 3; EXIT} ELSE subInterval ← RTC↑ + subIntervalQuantum};
ENDLOOP;--DO above IF scb.currentBuf #
};--IF printFail = 0 THEN

ptr↑ ← NIL;--quiet disk
IF ~DisplayOn THEN
{Display↑ ← savedDisplay;
DisplayOn ← TRUE;
};
SlotStatus[metaStat];--return final status
IF lastPage THEN {MsWait[6000]; SLOTCommand[reset];};
--CallDebugger["check scb for uCode Status"L];

};
--SLOTPrint
PrintBuffer: PROC[sectorsPerBuffer: CARDINAL] RETURNS[ok: BOOLEAN ← TRUE]=
{
i: CARDINAL;
dcb: kcbPtr ← printNext;
status: Status;

IF printCount = 0 THEN RETURN;
FOR i IN [1..sectorsPerBuffer] DO
IF dcb.blockD.status = dstZeroStatus THEN {overRun ← TRUE; RETURN [FALSE];};
status ← BITOR[BITOR[dcb.blockH.status, dcb.blockD.status], dcb.blockL.status];
IF status # dstDone THEN
readErrors ← readErrors + 1;
dcb ← dcb.nextKCB;
ENDLOOP;

printCount ← printCount - 1;
printNext ← dcb;
};
--PrintBuffer

ReadBuffer
: PROC[startUp: BOOLEAN, sectorsPerBuffer: CARDINAL, disk: tfsdskPtr ]=
{
i: CARDINAL;
DCBseal: CARDINAL = 122645B;
startNext: kcbPtr ← readNext;
daPtr: POINTER TO DA;

readCount ← readCount - 1;
FOR i IN [1..sectorsPerBuffer] DO
daPtr ← LOOPHOLE[readNext];
daPtr↑ ← TfsRealDA[disk, da];--returns a DA record (2 words)
da ← da + 1;
readNext.blockD.status ← dstZeroStatus;
readNext.id ← DCBseal;
readNext ← readNext.nextKCB;
ENDLOOP;
gTrack ← daPtr.track; gSector ← daPtr.sector; gHead ← daPtr.head;

IF startUp AND ptr↑ = NIL THEN ptr↑ ← startNext;
};
--ReadBuffer

SetSCB: PROC[scb: POINTER TO SCB] RETURNS[newSCBadr: POINTER TO SCB]=
{
Zero[scb, SIZE[SCB]];
newSCBadr ← Even[scb];
newSCBadr.invert ← IF invertMode THEN 1 ELSE 0;
newSCBadr.bitsPerLine ← SLOTScanLength;
newSCBadr.blowup ← IF SLOTDouble=0 THEN 0 ELSE 1;
};
--SetSCB
END.--PrintSlot
-- Last Edited: September 15, 1981 6:19 PM By: GWilliams
--noDisplay=FALSE (i.e., leave it on) and useSlot=FALSE, debug=FALSE(do timeouts)
--October 26, 1981 2:36 PM By: GWilliams
--cause PSlot to clear disk errors (& print a goofed-up page) a few times before erroring.

-- Last Edited: October 27, 1981 1:32 PM By: GWilliams
--SLOTPrint runs too slow dat 384 spi. Put PrintBuffer and ReadBuffer inline in inner loop
-- Last Edited: October 28, 1981 11:34 AM By: GWilliams
--a 4K buffer load is dropped sporatically, added one line in inner loop to zero status on dequeing (@inline PrintBuffer code). This is to observe it.
-- Last Edited: October 28, 1981 3:01 PM By: GWilliams
--moved printCount test to bottom of PrintBuffer routine..
-- Last Edited: October 29, 1981 9:38 AM By: GWilliams
--Added code to see whether uCode is getting two buffers ahead.
-- Last Edited: October 30, 1981 5:16 PM By: GWilliams
--Added code to allow me to set # of buffers in PSlot for debugging.
-- Last Edited: November 4, 1981 11:10 AM By: GWilliams
--Changed calculation of buffLen to include the +2 inside brackets.
--also now allocate the dcbTable at PSlot instead of SLOTPrint to make sure there’s space for it.
-- Last Edited: November 10, 1981 2:17 PM By: GWilliams
--New amalgam that asks for two buffers only and doesn’t get storage for the dcbs from local frame.
-- Last Edited: November 11, 1981 2:11 PM By: GWilliams
--changed def of SCB to allow for change in uCode to have 64K bits per scan line.
-- Last Edited: December 3, 1981 11:42 AM By: GWilliams
--Used PrintSlot of Nov 81 but plugged in the original SCB def.
-- Last Edited: January 14, 1982 4:14 PM By: GWilliams
--The plate maket needs extremely long timeouts, whereas a fast device needs relatively short ones. The RTC wraps around at 40 minute intervals. I changed the code to minimize false timeouts caused by adding large numbers to the RTC value when it is near wrap-around state.
-- Last Edited: January 15, 1982 2:49 PM By: GWilliams
--This is a speed-up attempt on PrintSlotGary: copy globals into local frame.
-- Last Edited: January 26, 1982 11:47 AM By: GWilliams
--Last attempt to speed up process didn’t work. Seem not to be setting the dcb’s correctly. This is an experiment to see whether it is only the dropping of the MOD’s and /’s, or whether it was a bug introduced elsewhere. In other words, I’m changing back to using the MOD’s and /’s, but leaving all other code that was changed, in.
-- Last Edited: January 26, 1982 1:55 PM By: GWilliams
--OK, this one should work, no MOD’s or /’s.
-- Last Edited: January 27, 1982 10:46 AM By: GWilliams
--The code works ok, but didn’t fix the problem. This version tries a new scheme with running the disk.
-- Last Edited: January 27, 1982 10:46 AM By: GWilliams
--Added more buffers in case we’ve run out.
-- Last Edited: January 27, 1982 10:46 AM By: GWilliams
--Adding more buffers didn’t help. Try waiting for the disk to be idle.
-- Last Edited: January 27, 1982 1:10 PM By: GWilliams
-- Last Edited: January 28, 1982 2:34 PM By: GWilliams
--Turns out this version doesn’t work. There is a race in the original coding of the BCPL version of this code that I hope to rectify. Briefly, the trident controller should not be run with rings of control blocks.
-- Last Edited: February 19, 1982 11:13 AM By: GWilliams
--Running the Trident with lists rather than a ring wins.
--Adding fix to get some space in PSlot that I know I’ll need in SLOTPrint before getting the buffers.