%
*** *** *** *** *** *** *** Revision 1 March 26, 1980 *** *** *** *** *** *** ***

****************************************************************************************
*** EDRDCD.mc : Rigid Disk Controller Diagnostic microcode
*** Purpose : This test exercises the Rigid Disk Controller and the Rigid Disk.
*** Minimum Hardware : Standard 4 CPU boards, one 96K Storage Module, an RDC disk drive
and a RDC Controller Module.
*** Approximate Run Time : One hour if default parameters are used.
*** Written by Jim Katsiroumbas, Obtained March 14, 1980
*** Modified by : T. Henning, March 26, 1980
Added title page and reformated for readability.
Renamed R registers to delete the RDC prefix so that names on Midas are more
readable. However, those R registers are doubly defined so that they can still
be referred to by the RDC prefix.
Added the Extract routine to extract the last IOCB cylinder, head, and sector info.
*** WARNING: EDRDCD is not compatible with Super which runs three controllers at once.
To run Super, it is necessary to get RDCD, not EDRDCD.
*** NOTE: EDRDCD assembly procedure:
1) micro/o/u EDRDC
2) micro/o/u EDRDCD
3) microd EDRDC EDRDCD
****************************************************************************************

****************************************************************************************
* Phases Description:
* Phase 0: Seek only phase. Seek all selected sectors, heads, cylinders, and disks.
* Phase 1: Header verify, label write, data write. Do this for all selected sectors,
heads, cylinders, disks.
* Phase 2: Header verify, label read, data read. Do this for all selected sectors,
heads, cylinders, disks.
* Phase 3: Header verify, label write, data write, then do command pointed to by
command pointer. Do this for all selected sectors, heads, cylinders, disks.
* Phase 4: Do command in PHASE4COMMAND register. Do this for all selected sectors,
heads, cylinders, disks.
* Phase 5: Header write, label nop, data nop. Do this for all selected sectors,
heads, cylinders, disks.
* Phase 6: Header verify, label nop, data nop. Do this for all selected sectors,
heads, cylinders, disks.
****************************************************************************************

****************************************************************************************
* Special Midas Screen Feature:
*
*
The EDRDCD test has many parameters useful to the operator at different stages of
*
testing. Since they would clutter up the Midas screen if they all appeared at the
*
same time, the screen is controlled to give the more important data as it is needed.
*
*
Essentially, there are two screens available: the DEBUG screen and the SET screen.
*
*
1) The DEBUG screen will display the last disk, cylinder, head, and sector
*
as specified in the last IOCB that was involved in an error breakpoint.
*
To get this screen, bug Read-Cmds, then bug RDCDEBUG.
*
*
2) The SET screen displays parameters for running the EDRDCD test.
*
To get this screen, bug Read-Cmds, then bug RDCSET.
*
****************************************************************************************

****************************************************************************************
* Theory of Operation:
*
*
The D(0) rigid disk is the Shugart SA4000 rigid disk. It has 312 cylinders, 8 heads,
*
and 28 sectors per track. Each sector has 2 words of Header, 8 words of Label,
*
and 256 words of Data. The EDRDCD diagnostic code controls the RDC task through
*
the use of Controller Status Blocks (CSB’s) and Input Output Controller Blocks (IOCB’s).
*
The command and status blocks are executed by the EDRDC firmware driver which has
*
control of the rigid disk drive.
*
****************************************************************************************

****************************************************************************************
* SPECIAL FEATURES:

* Data Generation: Data generation and checking are controlled by ’DTYPE’ and ’SEED’.

If DTYPE=0, then the data pattern will be SEED, 2 times SEED, 3 times SEED,
4 times SEED, 5 times SEED, etc.
Example:SEED=0 generates all zeros pattern;
SEED=1 generates 1,2,3,4,5...;
SEED=5 generates 5,10,15,20,15...
If DTYPE=1, then the data pattern will be SEED, 0, SEED, 0, SEED, 0, etc.

As data blocks are being generated, the first block uses ’SEED’ for data generation,
but the second block uses the two’s complement of ’SEED’ for data generation,
the third block uses ’SEED’ for data generation, the fourth block uses the two’s
complement of ’SEED’ for data generation, etc. The data starts at VM 10000.

* The cylinders to be ignored in the test may be written into VM 310, 311, 312, and 313.

* PHASE4COMD: The special command as indicated in PHASE4COMD is executed in phase 4.
A 3 digit code is to be entered:
The most significant digit controls the Header:
2 for write, 1 for read and verify
The middle digit controls the Label:
4 for write, 2 for read, 1 for verify, 0 for nop
The least significant digit controls the Data:
4 for write, 2 for read, 1 for verify, 0 for nop
Thus a 112 is verify Header, verify Label, and read Data. It is not possible
to execute all combinations of 3 digits, the user is responsible for putting in
a correct and logical code.

* RANDOMC: In each phase, the operation is done on random cylinders, then the phase is
done sequentially to all selected cylinders. RANDOMC is the number of random
operations to be done. A zero in RANDOMC indicates no random operations. The
register RANDOM indicates how many random operations are left.
****************************************************************************************

****************************************************************************************
* BREAKPOINTS TABLE:

* DATAERROR: THIS IS A DIAGNOSTIC DETECTED ERROR WITH NO ERROR REPORTED FROM THE
CONTROLLER OR THE FIRMWARE.A REG ’EXPECTED’ HAS THE EXPECTED DATA,’OBSERVED’
HAS THE BAD DATA,AND ’ADDRESS’ HAS THE ADDRESS OF THE BAD DATA.THIS CAN BE EITHER
IN THE IOCB OR THE MEMORY BLOCK.THE REG ’BLOCK’ POINTS TO THE FIRST WORD OF
THE BLOCK.TO GO ON TO CHECK THE NEXT BLOCK, BUG ’CONTINUE’.

* DEVICEERROR: THIS IS A CONTROLLER ERROR DETECTED BY THE CONTROLLER OR THE FIRMWARE.
A REG ’ERRORF’ CONTAINS THE STATUS AND OPS WORD OF THE CSB CONTAINS THE ERROR CODE.
THE ’OLD IOCB LINK’ OF THE CSB POINTS TO THE IOCB.TO RETRY THE CHAIN OF IOCB’S,
BUG ’CONTINUE’.

* TIMERHALT: A DISK OPERATION WAS STARTED BUT NEVER COMPLETED.BUG ’CONTINUE’ AND THE
PROGRAM WILL HALT AT ’DEVICEERROR’.BUG ’CONTINUE’ AGAIN AND THE OPERATION WILL
BE RETRYED.

* NOIDHERE: THE ID FOR THE DEVICE WAS NOT FOUND.IF THE DEVICE IS THE FIRST ONE IN THE
CHAIN THEN A REGISTER ’EXPECTED’ CONTAINS WHAT YOU SHOULD HAVE RECEIVED AND ’OBSERVED’
CONTAINS WHAT YOU DID RECEIVE. TO RETRY, BUG ’CONTINUE’.

* IDER: THE ID FOUND WAS NOT THE SAME AS THE ONE EXPECTED. TO RETRY, BUG ’CONTINUE’.

* NOPHASE: THE VALUE IN ’RUNPHASE’ IS NOT IN THE VALID RANGE. SET ’RUNPHASE’ AGAIN.

* BADPHASE: THE VALUE IN ’PHASE’ IS NOT IN THE VALID RANGE AFTER IOCB’S HAVE EXECUTED.

* PASSED-EDRDCD-TEST: ALL PHASES SELECTED WERE RUN FOR THE NUMBER OF PASSES
SPECIFIED IN ’PASSCOUNT’. BUG ’CONTINUE’ TO START ANOTHER PASS.

* SETPARAMETERS: THIS IS TO ALLOW YOU TO CHANGE PARAMETERS.THEN BUG ’CONTINUE’.
****************************************************************************************

****************************************************************************************
* CONTROLLER STATUS BLOCK (CSB) DEFINITIONS:
*
*
NOTE: The CSB block begins at virtual memory address 300 in EDRDCD.

VM 300, WORD 00: IOCB LINK
VM 301, WORD 01: SYNCH
VM 302, WORD 02: CURRENT STATUS
VM 303, WORD 03: OPERATIONAL STATUS WORD (bits 14-17, get STP error code on error)
VM 304, WORD 04: OLDDISK ADDRESS, DISK 1, (-1, RECAL NECESSARY) (bit 0, seek in progress, sip)
VM 305, WORD 05: OLDDISK ADDRESS, DISK 2, (-1, RECAL NECESSARY) (bit 0, seek in progress, sip)
VM 306, WORD 06: OLDDISK ADDRESS, DISK 3, (-1, RECAL NECESSARY) (bit 0, seek in progress, sip)
VM 307, WORD 07: OLDDISK ADDRESS, DISK 4, (-1, RECAL NECESSARY) (bit 0, seek in progress, sip)
VM 310, WORD 10: FLAW CYLINDER, put in DISK(4MSB)/CYLINDER(8LSB) to be flawed
VM 311, WORD 11: FLAW CYLINDER, put in DISK(4MSB)/CYLINDER(8LSB) to be flawed
VM 312, WORD 12: FLAW CYLINDER, put in DISK(4MSB)/CYLINDER(8LSB) to be flawed
VM 313, WORD 13: FLAW CYLINDER, put in DISK(4MSB)/CYLINDER(8LSB) to be flawed
VM 317, WORD 17: OLD IOCB LINK
****************************************************************************************


****************************************************************************************
* INPUT OUTPUT CONTROLLER BLOCK (IOCB) DEFINITIONS:
*
*
NOTE: The first IOCB block begins at virtual memory address 3000 in EDRDCD.
*
Subsequent IOCB blocks follow every 40 locations. Thus the second IOCB
*
block starts at VM 3040. The last IOCB block executed is pointed by
*
CSB word 00 if it is nonzero. Otherwise, it is pointed to by CSB word 17,
*
if CSB word 00 is zero.

WORD 00: DISK/CYCL ADDRESS SENT TO CONTROLLER (disk: 4 MSB, cylinder: 8 LSB)
WORD 01: HEAD/SECTOR ADDRESS SENT TO CONTROLLER (head: 8 MSB, sector: 8 LSB)
WORD 02: DISK/CYCL ADDRESS RECEIVED FROM CONTROLLER (disk: 4 MSB, cylinder: 8 LSB)
WORD 03: HEAD/SECTOR ADDRESS RECEIVED FROM CONTROLLER (head: 8 MSB, sector: 8 LSB)
WORD 04: LABEL START
WORD 05: LABEL
WORD 06: LABEL
WORD 07: LABEL
WORD 10: LABEL
WORD 11: LABEL
WORD 12: LABEL
WORD 13: LABEL END
WORD 14: IOCBLINK
WORD 15: COMMAND
WORD 16: DATA POINTER
WORD 17: DATA POINTER
WORD 20: STATUS
WORD 21: SYNCH
WORD 22: SYNDROME
WORD 23: SYNDROME
****************************************************************************************

****************************************************************************************
* REGISTER DEFINITIONS (Alphabetical):

* ADDRESS:
ADDRESS OF DATA.
* BLOCK:
POINTER TO CURRENT DATA BLOCK.
* CHAIN:
A ONE MEANS CHAIN IOCB’S. A ZERO MEANS USE ONLY ONE IOCB.
* CMDPOINTER: A RING POINTER FOR PHASE3 WHICH POINTS TO A COMMAND LIST OF ALL THE DIFFERENT
TYPES OF COMMANDS FOR THE DISK. THIS POINTER GETS BUMPED AFTER EACH PASS.
* COMMAND:
SHOWS YOU THE CURRENT COMMAND THE FIRMWARE HAS.
* CYLE:
ENDING CYCL ADDRESS RANGE 0 TO 311.(HAS TO BE>=TO STARTING.)
* CYLINDERERROR: THE CYLINDER INVOLVED IN THE LAST IOCB THAT CAUSED AN ERROR BREAKPOINT.
* CYLS:
STARTING CYCL ADDRESS RANGE 0 TO 311.
* DISKE:
ENDING DISK ADDRESS RANGE 0 TO 3.(HAS TO BE>=TO STARTING.)
* DISKERROR:
THE DISK DRIVE INVOLVED IN THE LAST IOCB THAT CAUSED AN ERROR BREAKPOINT.
* DISKS:
STARTING DISK ADDRESS RANGE 0 TO 3.
* DISKSAVE:
IF NOT CHAINING, THIS HAS THE DISK/CYL ADDRESS OF THE CURRENT OPERATION.
IF CHAINING, HAS THE DISK/CYL ADDRESS OF THE LAST IOCB IN THE CHAIN.
* DISKSTATUS: SHOWS YOU CURRENT DISK STATUS.
* DTYPE:
USED FOR GENERATING AND CHECKING DATA BLOCKS.
* ERRORF:
CONTAINS THE DISK STATUS ON A DEVICE ERROR FOR THE FAILURE.
* EXPECTED:
DATA YOU EXPECTED.
* HEADE:
ENDING HEAD ADDRESS RANGE 0 TO 7.(HAS TO BE>=TO STARTING.)
* HEADERROR:
THE HEAD INVOLVED IN THE LAST IOCB THAT CAUSED AN ERROR BREAKPOINT.
* HEADS:
STARTING HEAD ADDRESS RANGE 0 TO 7.
* HEADSAVE:
IF NOT CHAINING, THIS HAS THE HEAD/SECTOR ADDRESS OF THE CURRENT OPERATION.
IF CHAINING, HAS THE HEAD/SECTOR ADDRESS OF THE LAST IOCB IN THE CHAIN.
* IOCBERROR:
THE IOCB THAT WAS BEING EXECUTED WHEN AN ERROR BREAKPOINT OCCURRED.
* MENDL:
LOWER 16 BITS OF ENDING ADDRESS (HOW MUCH MEMORY TO USE FOR DATA BLOCKS.)
* MSTARTL:
LOWER 16 BITS OF STARTING ADDRESS OF MAIN MEMORY TO USE FOR DATA BLOCKS.
THIS IS NORMALLY HEX ALIGNED BUT MAY BE QUAD ALIGNED.
IF NOT, PROGRAM WILL NOT RUN!!!!!
* MSTARTU:
UPPER 8 BIT OF STARTING ADDRESS OF MAIN MEMORY TO USE FOR DATA BLOCKS.
* NEWDISKADD: FOR DEBUGING PURPOSE.
* NEWSECTOR: FOR DEBUGING PURPOSE.
* NOCMDINC:
A ONE IN HERE STOPS THE COMMAND POINTER FROM BEING BUMPED.
* NODATAINC: A ONE IN HERE STOPS THE PROGRAM FROM CHANGING DATATYPE
AND DATASEED AFTER EACH PASS.
* NOHALT:
A ONE MEANS DON’T HALT ON ANY BREAKPOINT EXCEPT FOR DEVICETIMEOUT.
* NORATERR:
A ONE MEANS DON’T HALT ON ANY RATE ERROR.
* NORETRY:
A ONE MEANS NO RETRY FOR READ, BUT RETRY WRITES FOREVER.
A ZERO MEANS FOUR RETRIES FOR READS AND WRITES.
* OBSERVED:
DATA YOU OBSERVED.
* OLDDISKADD: FOR DEBUGING PURPOSE.
* OLDHEADSECTOR: FOR DEBUGING PURPOSE.
* PASSCOUNT: COUNT OF HOW MANY PASSES TO RUN BEFORE STOPING AT ’PASSDONE’.
* PHASE:
SHOWS YOU WHICH PHASE IS RUNNING.
* PHASE4COMD: USED IN PHASE4 TO RUN A SPECIAL COMMAND.(SUCH AS ’111’ WHICH IS
HEADER VERIFY,LABLE VERIFY,DATA VERIFY).
* PHASEDONE: FOR DEBUGING.TO FORCE PHASE TO TERMINATE, PUT A ONE IN HERE.
* RANDOM:
SHOWS YOU HOW MANY RANDOM OPERATIONS THAT ARE LEFT FOR THIS PHASE.
* RANDOMC:
SET THIS FOR HOW MANY RANDOM OPERATIONS TO RUN PER PHASE.
* RUNPHASES: WHERE YOU SELECT WHICH PHASES TO RUN.
* SECTORE:
ENDING SECTOR ADDRESS RANGE 0 TO 33.(HAS TO BE>=TO STARTING.)
* SECTORERROR:
THE SECTOR INVOLVED IN THE LAST IOCB THAT CAUSED AN ERROR BREAKPOINT.
* SECTORS:
STARTING SECTOR ADDRESS RANGE 0 TO 33.
* SEED:
USED FOR GENERATING AND CHECKING DATA BLOCKS.
* STP:
SHOWS YOU STATE POINTER FOR FIRMWARE.
* SUNKUP:
USED FOR DEBUGGING. IF #0 THEN DON’T ISSUE COMMAND TO CONTROLLER
UNLESS WE ARE ON SECTOR TO USE, SET A ONE IN REG THEN TYPE
START2 AND BUG ’GO’.
****************************************************************************************

****************************************************************************************
* Subroutine Description:
*
* CHKCMD:
CHKCMD finds out if all commands are done.
* CHKPHASE:
CHKPHASE checks for phase completed.
* DATAVFY:
DATAVFY verifies the data and label depending on the current phase.
* EXTRACT:
EXTRACT finds the last IOCB and extracts the disk, cylinder, head,
*
and sector information.
* HANDSHAKE:
HANDSHAKE reads R register EXPECTED written by the RDC task saves it in NWW,
*
reset bits 15 and 17, then writes it back to EXPECTED.
* INITIOCB:
INITIOCB initializes the memory dedicated to IOCB’s.
* INITNEWPHASE: INITNEWPHASE reinitializes the IOCB’s and the data buffer area in memory.
* ISSUEBLK:
ISSUEBLK issues RDC Data Blocks.
* FILDATA:
FILDATA fills the IOCB memory buffer area with the data pattern to be used.
* MEMPUT:
MEMPUT puts RDC Data into memory.
* NEWPHASE: NEWPHASE selects the next phase to run.
* RDCINIT:
RDCINIT saves return link in SAVE2 and notifies the RDC Task code to initialize.
* RDCINTR:
RDCINTR uses SAVE2 return address to return to the RDCD Task (Task 0).
* SETMAINT:
SETMAINT set the maintenance panel to display the phase.
* SRCADDR:
SRCADDR shifts out 16 task numbers to the controller boards.
* UPDTIOCB:
UPDTIOCB updates the IOCB block.
* UPDTCSB:
UPDTCSB updates the CSB block with the new IOCB pointer, clears status,
*
and sets process wakeup.
* WAKEUPWAIT:
WAKEUPWAIT waits until the RDC responds or until it is timed out.
****************************************************************************************
%

****************************************************************************************
* INITIALIZATION:

BUILTIN[INSRT,24];
INSRT[D0LANG];
NOMIDASINIT;
TITLE[EDRDC DIAG PROGRAM March 26, 1980];

********** Macros and Set Values: **********

SET[DIAGTASK,0];
SET[DISK,1];
SET[DISK1,2];
SET[DISK2,3];
SET[DISK3,4];
SET[DISK4,5];
SET[DISK5,10];
SET[DISK.1,LSHIFT[DISK,10]];
SET[DISK1.1,LSHIFT[DISK1,10]];
SET[DISK4.1,LSHIFT[DISK4,10]];

SET[RDCTASK,4];
SET[RPAGE,6];
SET[RPAGE1,7];
SET[RPAGE.1,LSHIFT[RPAGE,10]];
SET[RPAGE1.1,LSHIFT[RPAGE1,10]];
SET[DRUN0,LSHIFT[RDCTASK,4]];

SET TASK[DIAGTASK];

MC[MYIDU,1400];
*DISK ID IS 1407
MC[MYIDL,0];
*DISK ID IS 1407
MC[DIAGTASK.1,LSHIFT[DIAGTASK,14]];
MC[DISK.2,DISK.1];
MC[RPAGE1.2,RPAGE1.1];
MC[RDCSTASK,RDCTASK];
MC[RDCTASK.1,LSHIFT[RDCTASK,14]];
MC[RDCDTASK.1,LSHIFT[RDCTASK,14]];
MC[PMSTARTL,10000];

MC[PMSTARTU,0];

MC[PMENDL,70000];

MC[PDISKS,0];

MC[PDISKE,0];
MC[PHEADS,0];

MC[PHEADE,7];
MC[PCYLS,0];

MC[PCYLE,311];
MC[PSECTORS,0];

MC[PSECTORE,33];
MC[PDTYPE,1];

MC[PPHASE,0];

MC[PPHASEDONE,1];

MC[PDATAINC,0];

MC[PIODONE,0];
MC[PIOERROR,0];
MC[PSEED,400];

MC[DBSIZE,400];

MC[PCMDPOINTER,340];

MC[PRUNPHASES,17];

MC[PNORATERR,0];

MC[PCMDINC,0];

MC[PNOHALT,0];

MC[PERRORC,0];

MC[PERRORF,0];

MC[PIOCBA,3000];
*DISK CONTROL BLOCK
MC[IOCBAE,7000];
*DISK CONTROL BLOCK END
MC[CSBA,300];
*POINTER TO NEXT COMMAND BLOCK
MC[PRETRYC,3];
MC[HEADERW,200];
MC[HEAERR,100];
MC[DATAW,4];
MC[DATAC,1];
MC[DATAR,2];
MC[LABELW,40];
MC[LABELC,10];
MC[LABELR,20];

********** R-Registers: **********

RV[MSTARTL,0];
RV[MSTARTU,1];
RV[MENDL,2];
RV[RETRYC,3];
RV[DISKS,4];
RV[DISKE,5];
RV[HEADS,6];
RV[HEADE,7];
RV[EXPECTED,10];
RV[OBSERVED,11];
RV[ADDRESS,12];
RV[ERRORF,13];
RV[BLOCK,14];
RV[CMDPOINTER,15];
RV[DTYPE,16];
RV[PHASEDONE,17];

RV[SECTORE,20];
RV[SAVE1,21];
RV[SAVE2,22];
RV[NODATAINC,23];
RV[IODONE,24];
RV[IOERROR,25];
RV[IOCBA,26];
RV[IOCBA1,27];
RV[LDISKSAVE,30];
RV[LHEADSAVE,31];
RV[CHAIN,32];
RV[RANDOMC,33];
RV[PHASE4COMD,34];
RV[SUNKUP,35];
RV[NORETRY,36];
RV[RANDOMD,37];
RV[NWW,40];
RV[RUNPHASES,41];
RV[SEED,42];
RV[NORATERR,43];
RV[NOHALT,44];
RV[RANDOM,45];
RV[ERRORC,46];
RV[PASSCOUNT,47];
RV[DISKSAVE,50];
RV[HEADSAVE,51];
RV[SAVE,52];
RV[NOCMDINC,53];
RV[CYLS,54];
RV[CYLE,55];
RV[SECTORS,56];
RV[PHASE,57];

RV[RDC0,60];
RV[RDC1,61];
RV[RDC2,62];
RV[RDC3,63];
RV[RDC4,64];
RV[RDC5,65];
RV[RDC6,66];
RV[RDC7,67];
RV[RDC10,70];
RV[RDC11,71];
RV[RDC12,72];
RV[RDC13,73];
RV[RDC14,74];
RV[RDC15,75];
RV[RDC16,76];
RV[RDC17,77];

RV[PASSES-TO-RUN,47,1];

SetTask[7];
RV[CSBL,60];
RV[CSBH,61,0];
RV[IOCB0,62];
RV[IOCB1,63];
RV[IOCBERROR,64];
RV[IOCBH,65,0];
RV[DiskError,66];
RV[CylinderError,67];
RV[HeadError,70];
RV[SectorError,71];
RV[Temp7,72];
RV[REVISION,73,1];

** double define registers to enable Midas to address
** the registers with or without the RDC prefix

SetTask[0];
RV[RDCMSTARTL,0];
RV[RDCMSTARTU,1];
RV[RDCMENDL,2];
RV[RDCRETRYC,3];
RV[RDCDISKS,4];
RV[RDCDISKE,5];
RV[RDCHEADS,6];
RV[RDCHEADE,7];
RV[RDCEXPECTED,10];
RV[RDCOBSERVED,11];
RV[ADDRESS,12];
RV[ERRORF,13];
RV[RDCBLOCK,14];
RV[RDCCMDPOINTER,15];
RV[RDCDTYPE,16];
RV[RDCPHASEDONE,17];

RV[RDCSECTORE,20];
RV[RDCSAVE1,21];
RV[RDCSAVE2,22];
RV[RDCNODATAINC,23];
RV[RDCIODONE,24];
RV[RDCIOERROR,25];
RV[RDCIOCBA,26];
RV[RDCIOCBA1,27];
RV[RDCLDISKSAVE,30];
RV[RDCLHEADSAVE,31];
RV[RDCCHAIN,32];
RV[RDCRANDOMC,33];
RV[RDCPHASE4COMD,34];
RV[RDCSUNKUP,35];
RV[RDCNORETRY,36];
RV[RDCRANDOMD,37];
RV[RDCNWW,40];
RV[RUNPHASES,41];
RV[RDCSEED,42];
RV[RDCNORATERR,43];
RV[RDCNOHALT,44];
RV[RDCRANDOM,45];
RV[ERRORC,46];
RV[RDCPASSCOUNT,47];
RV[DISKSAVE,50];
RV[RDCHEADSAVE,51];
RV[RDCSAVE,52];
RV[RDCNOCMDINC,53];
RV[RDCCYLS,54];
RV[RDCCYLE,55];
RV[RDCSECTORS,56];
RV[RDCPHASE,57];


****************************************************************************************
*** MAIN routine:

ON PAGE[DISK];

GOTO[RDCINTR],AT[DISK.1,0];
GOTO[START],AT[DISK.1,377];

GO:
START:LOADPAGE[DISK5];
GOTOP[ADD0];
START1:RDC1←0C;
*START TO START2 PUTS DEFAULT PARAMARTERS
MSTARTU←PMSTARTU;
MSTARTU←(MSTARTU)OR(1C);
MSTARTL←PMSTARTL;
RETRYC←PRETRYC;
NORETRY←0C;
MENDL←PMENDL;
DISKS←PDISKS;
TASK,DISKE←PDISKE;
HEADS←PHEADS;
HEADE←PHEADE;
CYLS←PCYLS;
CYLE←PCYLE;
SECTORS←PSECTORS;
SECTORE←PSECTORE;
DTYPE←PDTYPE;
TASK,CHAIN←1C;
SEED←1C;
T←PSEED;
T←(SEED)+(T);
SEED←(SEED)-(T);
CMDPOINTER←PCMDPOINTER;
NOCMDINC←PCMDINC;
NODATAINC←PDATAINC;
RUNPHASES←PRUNPHASES;
TASK,NORATERR←PNORATERR;
NOHALT←PNOHALT;
RANDOMC←100C;
RANDOMD←0C;
RDC10←110C;
RDC11←120C;
RDC12←140C;
RDC13←111C;
RDC14←112C;
RDC15←114C;
RDC16←120C;
RDC17←121C;
RDC0←PCMDPOINTER;
TASK;
PSTORE4[RDC0,RDC10,0];
PSTORE4[RDC0,RDC14,4];
RDC10←112C;
RDC11←124C;
RDC12←140C;
RDC13←122C;
PHASE4COMD←111C;
SUNKUP←0C;
TASK,RANDOM←0C;
PSTORE4[RDC0,RDC10,10];
RDC0←CSBA;
RDC10←(ZERO)-1;
RDC11←(ZERO)-1;
RDC12←(ZERO)-1;
RDC13←(ZERO)-1;
TASK;
PSTORE4[RDC0,RDC10,10];
IOCBA1←0C;
IOCBA←PCMDPOINTER;
IOCBA←(IOCBA)+(17C);
PASSCOUNT←12C;
PSTORE1[IOCBA,SUNKUP,0];
PHASE←PPHASE;
IOCBA←PIOCBA;
ERRORC←PERRORC;
TASK,ERRORF←PERRORF;
BLOCK←(ZERO)-1;
PHASEDONE←PPHASEDONE,GOTO[SETPARAMETERS];
START2:IOCBA1←0C;
IOCBA←PCMDPOINTER;
IOCBA←(IOCBA)+(17C);
PASSCOUNT←1C;
TASK,PSTORE1[IOCBA,SUNKUP,0];
PHASE←PPHASE;
IOCBA←PIOCBA;
ERRORC←PERRORC;
ERRORF←PERRORF;
BLOCK←(ZERO)-1;
PHASEDONE←PPHASEDONE;
SETPARAMETERS:BREAKPOINT;
*HALT TO DISPLAY PARAMATERS
RDC0←CSBA;
RDC1←0C;
RDC10←0C;
RDC11←0C;
RDC12←0C;
RDC13←0C;
TASK;
PSTORE4[RDC0,RDC10,0];
PSTORE4[RDC0,RDC10,4];
PSTORE4[RDC0,RDC10,14];
*CLEAR RDCCSB WORDS
RDC10←0C;
TASK;
PSTORE1[RDC0,RDC10,1];
*RDCCSB WAKEUPMASK
RDC10←(ZERO)-1;
NOP;
PSTORE1[RDC0,RDC10,4];
*FORCE A RECAL FIRST OPERATION
TASK,PSTORE1[RDC0,RDC10,5];
*FORCE A RECAL FIRST OPERATION
PSTORE1[RDC0,RDC10,6];
*FORCE A RECAL FIRST OPERATION
PSTORE1[RDC0,RDC10,7];
*FORCE A RECAL FIRST OPERATION
T←MENDL;
TASK,RDC2←T;
T←MSTARTL;
T←RDC0←T;
RDC2←(RDC2)-T;
RDC2←(RDC2)+1;
RDC3←0C;
T←MSTARTU;
TASK,RDC1←T;
RDC3←0C;
RDC4←0C;
LOADPAGE[DISK5];
CALLP[MEMPUT],RDC5←0C;
*CLEAR MEMORY
NOP;
CALL[RDCINIT];
LOADPAGE[DISK4];
GOTOP[RUNLIST];

ON PAGE[DISK4];
RUNLIST:LOADPAGE[DISK];
CALLP[INITIOCB];
LOADPAGE[DISK];
CALLP[FILDATA];
RUNLIST1:LOADPAGE[DISK1];
CALLP[NEWPHASE];
T←DISKSAVE;
TASK,LDISKSAVE←T;
T←HEADSAVE;
LHEADSAVE←T;
RUNLIST2:LOADPAGE[DISK];
CALLP[ISSUEBLK];
NOP;
RUNLIST3:LOADPAGE[DISK1];
CALLP[UPDTIOCB];
T←CHAIN;
GOTO[RUN1,ALU=0];
IOCBA←(IOCBA)+(40C);
LU←(IOCBA)-(IOCBAE);
GOTO[RUN2,ALU<0];
IOCBA←PIOCBA;
RUNLIST4:LOADPAGE[DISK1];
CALLP[UPDTCSB];
RUNLIST5:NOP;
CALL[WAKEUPWAIT];
T←IOERROR;
GOTO[RUN0,ALU#0];
NOERROR:LU←(PHASE)AND(43C);
*DISK OPPERATION COMPLETE WITH NO ERROR
GOTO[RUN6,ALU#0],LU←(PHASE)AND(124C);
GOTO[RUNLIST7,ALU#0],LU←(PHASE)AND(10C);
GOTO[RUNLIST6,ALU#0];
BADPHASE:BREAKPOINT;
LOADPAGE[DISK];
GOTOP[START1];
RUNLIST6:NOP;
CALL[CHKCMD];
NOP;
RUNLIST7:LOADPAGE[DISK2];
CALLP[DATAVFY];
RETRYC←PRETRYC;
RUNLIST10:LOADPAGE[DISK1];
CALLP[CHKPHASE];
LU←RANDOMD;
GOTO[RUNLIST100,ALU=0],RANDOMD←0C;
DISKSAVE←(ZERO)-1;
HEADSAVE←(ZERO)-1;
RUNLIST100:GOTO[RUNLIST1];

RUN0: LOADPAGE[DISK3];
GOTOP[ERROR0];
RUN1: GOTO[RUNLIST4];
RUN2: GOTO[RUNLIST2];
RUN6: RETRYC←PRETRYC,GOTO[RUNLIST10];

ON PAGE[DISK3];
ERROR13:OBSERVED←T;
EXPECTED←0C;
TASK,T←IOCBA;
ADDRESS←T;
RDC7←13C,GOTO[ERROR];
ERROR12:T←RDC3;
EXPECTED←T;
T←RDC10;
TASK,OBSERVED←T;
T←RDC0;
ADDRESS←T;
ADDRESS←(ADDRESS)-(1C);
RDC7←12C,GOTO[ERROR];
ERROR11:T←RDC3;
EXPECTED←T;
T←RDC13;
TASK,OBSERVED←T;
T←RDC0;
ADDRESS←T;
ADDRESS←(ADDRESS)-(1C);
RDC7←11C,GOTO[ERROR];
ERROR10:T←RDC3;
EXPECTED←T;
T←RDC12;
TASK,OBSERVED←T;
T←RDC0;
ADDRESS←T;
ADDRESS←(ADDRESS)-(2C);
RDC7←10C,GOTO[ERROR];
ERROR7:T←RDC3;
EXPECTED←T;
T←RDC11;
TASK,OBSERVED←T;
T←RDC0;
ADDRESS←T;
ADDRESS←(ADDRESS)-(3C);
RDC7←7C,GOTO[ERROR];
ERROR6:T←RDC3;
EXPECTED←T;
TASK,T←RDC10;
OBSERVED←T;
T←RDC0;
ADDRESS←T;
ADDRESS←(ADDRESS)-(4C);
RDC7←6C,GOTO[ERROR];
ERROR5:T←RDC3;
EXPECTED←T;
T←RDC13;
TASK,OBSERVED←T;
T←RDC0;
ADDRESS←T;
ADDRESS←(ADDRESS)-(1C);
RDC7←5C,GOTO[ERROR];
ERROR4:T←RDC3;
EXPECTED←T;
T←RDC12;
TASK,OBSERVED←T;
T←RDC0;
ADDRESS←T;
ADDRESS←(ADDRESS)-(2C);
RDC7←4C,GOTO[ERROR];
ERROR3:T←RDC3;
EXPECTED←T;
T←RDC11;
TASK,OBSERVED←T;
T←RDC0;
ADDRESS←T;
ADDRESS←(ADDRESS)-(3C);
RDC7←3C,GOTO[ERROR];
ERROR2:T←RDC3;
EXPECTED←T;
T←RDC10;
TASK,OBSERVED←T;
T←RDC0;
ADDRESS←T;
ADDRESS←(ADDRESS)-(4C);
RDC7←2C,GOTO[ERROR];
ERROR0:RDC7←0C,GOTO[ERR];


ERROR: LU←NOHALT;
*THIS IS A DATA ERROR HALT
GOTO[ERR10,ALU#0];
*CHECK IF NOSTOP=1
LOADPAGE[DISK5];
CALLP[EXTRACT];
DATAERROR:BREAKPOINT;
ERR10: LOADPAGE[DISK];
CALLP[RDCINIT];
IOCBA←PIOCBA;
LU←NORETRY;
GOTO[NORETRYERROR,ALU#0];
RETRYC←(RETRYC)-1;
GOTO[NOTNEXT,ALU>=0];
NOP;
NORETRYERROR:T←DISKSAVE;
TASK,LDISKSAVE←T;
T←HEADSAVE;
LHEADSAVE←T;
NOTNEXT:NOP;
CALL[INITNEWPHASE];
T←LDISKSAVE;
DISKSAVE←T;
TASK,T←LHEADSAVE;
HEADSAVE←T;
LOADPAGE[DISK4];
GOTOP[RUNLIST10];



ERR:RDC1←0C;
*THIS IS A DISK STATUS ERROR HALT
RDC0←CSBA;
TASK;
PFETCH1[RDC0,RDC0,17];
RDC0←RDC0;
RDC1←0C;
TASK,T←20C;
PFETCH1[RDC0,RDC14];
*GET RDCIOCB STATUS
RDC14←RDC14;
LU←(RDC0)XOR(PIOCBA);
GOTO[ERR6,ALU=0];*,ALU=0
RDC0←(RDC0)-(40C);
TASK;
PFETCH2[RDC0,LDISKSAVE,0];
*GET LAST GOOD HEADER
LDISKSAVE←LDISKSAVE;
ERR6:RDC0←CSBA;
NOP;
TASK,PFETCH1[RDC0,RDC15,2];
*GET RDCCSB STATUS
T←RDC15;
RDC14←(RDC14)ORT;
*OR RDCIOCB AND RDCCSB
T←RDC14;
ERRORF←T;
LU←NORATERR;
GOTO[ERR5,ALU=0],T←(ERRORF)AND(400C);
GOTO[ERR7,ALU#0];
NOP;
ERR5:LU←NOHALT;
GOTO[DEVICEERROR1,ALU=0];
*CHECK IF NOSTOP=1
NOP;
ERR4: LOADPAGE[DISK];
CALLP[RDCINIT];
NOP;
ERR7:NOP;
CALL[INITNEWPHASE];
T←LDISKSAVE;
DISKSAVE←T;
TASK,T←LHEADSAVE;
HEADSAVE←T;
LOADPAGE[DISK4];
GOTOP[RUNLIST2],IOCBA←PIOCBA;
*SET RDCCSB SAME DISK ADD AND BLOCK

DEVICEERROR1:
LOADPAGE[DISK5];
CALLP[EXTRACT];
DEVICEERROR: BREAKPOINT;
GOTO[ERR4];

ON PAGE[DISK5];

ADD0: EXPECTED←MYIDU;
T←MYIDL;
EXPECTED←(EXPECTED)+T;
ADDRESS←20C;
ADD1: ADDRESS←(ADDRESS)-1;
*SHIFT OUT 17 TASK#’S
CALL[SRCADDR];
*CALL TO SHIFT OUT TASK#
LU←ADDRESS;
GOTO[ADD1,ALU#0];
*GO GET ANOTHER TASK# TO TRY
ADDRESS←20C;
ADD2: ADDRESS←(ADDRESS)-1;
*SHIFT OUT 17 TASK#’S
T←LSH[ADDRESS,4];
INPUT[OBSERVED];
OBSERVED←(OBSERVED)AND(177400C);
T←EXPECTED;
LU←(OBSERVED)XORT;
GOTO[ADD3,ALU=0],LU←ADDRESS;
GOTO[ADD2,ALU#0];
*GO GET ANOTHER TASK# TO TRY
NOIDHERE:BREAKPOINT;
*NO CONTROLER HAD MY ID
GOTO[ADD1],ADDRESS←20C;
ADD3: T←ADDRESS;
*FOUND MY ID IN POSITION SAVED IN RDC17
RDC17←T;
*RDC17←(RDC17)XOR(17C);
RDC15←20C;
ADD4: RDC15←(RDC15)-1;
*RDC15=MY SOFT ID # FROM 17 TO 0
ADD5: RDC16←20C;
ADD6: T←RDC16←(RDC16)-1;
*RDC16= CURRENT POSITION TO BE SHIFTED OUT
LU←(RDC17)XOR(T);
*DOES CURRENT POSITION= MY POSITION
GOTO[ADD7,ALU#0];
T←RDC15;
ADDRESS←T,GOTO[ADD10];
ADD7: T←RDC15;
ADDRESS←T;
ADDRESS←(ADDRESS)XOR(17C);
ADD10:CALL[SRCADDR];
LU←RDC16;
GOTO[ADD6,ALU#0];
*GO SHIFT ANOTHER TASK# OUT
T←LSH[RDC15,4];
*WE SHIFTED ALL 17 OUT NOW CHECK MY ID
INPUT[OBSERVED];
OBSERVED←(OBSERVED)AND(177400C);
T←EXPECTED;
LU←(OBSERVED)XORT;
GOTO[IDER1,ALU#0],LU←RDC15;
GOTO[ADD4,ALU#0];
ADD25: RDC16←20C;
ADD26: T←RDC16←(RDC16)-1;
*RDC16= CURRENT POSITION TO BE SHIFTED OUT
LU←(RDC17)XOR(T);
*DOES CURRENT POSITION= MY POSITION
GOTO[ADD27,ALU#0];
T←RDCSTASK;
ADDRESS←T,GOTO[ADD20];
ADD27: ADDRESS←0C;
ADD20:CALL[SRCADDR];
LU←RDC16;
GOTO[ADD26,ALU#0];
*GO SHIFT ANOTHER TASK# OUT
LOADPAGE[DISK];
GOTOP[START1];

IDER1: T←RDC15;
ADDRESS←T;
IDER: BREAKPOINT;
GOTO[ADD0];

********** SUBROUTINE: CHKCMD **********
*
*
CHKCMD finds out if all commands are done.
*
ON PAGE[DISK4];
CHKCMD: USECTASK;
T←GETRSPEC[143];
TASK,SAVE←T;
T←CMDPOINTER;
*THISE ROUTINE WILL RUN COMMD LIST FOR PHASE3
RDC0←T;
NOP;
TASK,PFETCH1[RDC0,RDC14,0];
*GET NEW CMMD
NOP;
PFETCH1[IOCBA,RDC16,15];
*GET LAST RDCCMD
T←RDC14;
LU←(RDC16)XOR(T);
GOTO[CHKCMD1,ALU=0];
RETRYC←PRETRYC;
RDC15←0C;
CHKCMDSPIN:PSTORE1[IOCBA,RDC14,15];
TASK,T←20C;
PSTORE1[IOCBA,RDC15];
LU←CHAIN;
GOTO[CHKCMD2,ALU=0];
IOCBA←(IOCBA)+(40C);
LU←(IOCBA)-(IOCBAE);
GOTO[CHKCMDSPIN,ALU<0];
NOP;
CHKCMD2: IOCBA←PIOCBA,GOTO[RUNLIST4];
*GOTO SET RDCCSB


CHKCMD1: APCTASK&APC←SAVE;
RETURN;
*GOTO CHECK BLOCK

********** SUBROUTINE: CHKPHASE **********
*
*
CHKPHASE checks for phase completed.
*
ON PAGE[DISK1];
CHKPHASE: USECTASK;
T←GETRSPEC[143];
TASK;
SAVE←T;
LU←RANDOM;
GOTO[CHKPHASE2,ALU=0];
GOTO[CHKPHASE1];
CHKPHASE2: T←LSH[DISKE,14];
T←(CYLE)OR(T);
T←(DISKSAVE)XOR(T);
GOTO[CHKPHASE1,ALU#0];T←LSH[HEADE,10];
T←(SECTORE)OR(T);
T←(HEADSAVE)XOR(T);
GOTO[CHKPHASE1$,ALU#0];
PHASEDONE←1C;
*SET PHASE DONE
TASK,DISKSAVE←(ZERO)-1;
HEADSAVE←(ZERO)-1;
T←NOCMDINC;
GOTO[CHKPHASE31,ALU#0];
LU←(PHASE)AND(10C);
GOTO[CHKPHASE30,ALU=0];
CMDPOINTER←(CMDPOINTER)+1;
CHKPHASE31: NOP;
CHKPHASE30: NOP;
CHKPHASE1$: NOP;
CHKPHASE1: APCTASK&APC←SAVE;
RETURN;

********** SUBROUTINE: DATAVFY **********
*
*
DATAVFY verifies the data and label
*
depending on the current phase.
*
ON PAGE[DISK2];
DATAVFY: USECTASK;
T←GETRSPEC[143];
SAVE←T;
IOCBA←PIOCBA;
*CHECK THE HEADER
DATAVFYSPIN:NOP;
TASK,PFETCH1[IOCBA,BLOCK,16];
PFETCH4[IOCBA,RDC10,0];
*GET 4 WORDS
T←RDC10;
T←(RDC12)XOR(T);
T←(RDC11)XOR(T);
T←(RDC13)XOR(T);
GOTO[ERROR13L,ALU#0];
RDC17←1C;
*ZERO=RDCDATA ,ONE = RDCLABLE
TASK,RDC2←10C;
*THIS ROUTINE CHECKS THE LABLE/DATA IN THE IOCB/BLOCK
T←IOCBA;
RDC0←T;
RDC1←0C;
RDC0←(RDC0)+(4C);
*RDC0=IOCBLABLEADD,RDC2=DBSIZE
NOP;
DATAVFY10:PFETCH1[RDC0,RDC3,0];
*RDC3=NEXT SEED WORD
T←(PHASE)XOR(100C);
*CHECK FOR PHASE6
GOTO[DATAVFY30,ALU=0];
DATAVFY0: T←RDC3;
TASK;
RDC4←T;
*RDC4=MODIFIER
DATAVFY1: PFETCH4[RDC0,RDC10,0];
*GET 4 WORDS
TASK,RDC2←(RDC2)-(4C);
*DECREASE WORD COUNT
RDC0←(RDC0)+(4C);
*INCREASE WORD ADDRESS
LU←DTYPE;
GOTO[DATAVFY2,ALU#0];
*CHECK RDCDATA DTYPE
T←RDC3;
LU←(RDC10)XORT;
GOTO[ERROR2L,ALU#0];
*CHECK FIRST WORD
NOP;
TASK,T←RDC4;
T←RDC3←(RDC3)+T;
*RDC3=NEXT WORD
LU←(RDC11)XORT;
GOTO[ERROR3L,ALU#0];
*CHECK SECOND WORD
T←RDC4;
T←RDC3←(RDC3)+T;
*RDC3=NEXT WORD
LU←(RDC12)XORT;
GOTO[ERROR4L,ALU#0];
*CHECK THIRD WORD
NOP;
TASK,T←RDC4;
T←RDC3←(RDC3)+T;
*RDC3=NEXT WORD
LU←(RDC13)XORT;
GOTO[ERROR5L,ALU#0];
*CHECK FOURTH WORD
DATAVFY3: T←RDC4;
TASK;
RDC3←(RDC3)+T;
*RDC3=NEXT WORD
GOTO[DATAVFY5];
DATAVFY2: T←RDC3;
TASK;
NOP;
LU←(RDC10)XORT;
GOTO[ERROR6L,ALU#0],T←RDC4;
*CHECK FIRST WORD
T←RDC3←(RDC3)XORT;
*RDC3=NEXT WORD
LU←(RDC11)XORT;
GOTO[ERROR7L,ALU#0],T←RDC4;
*CHECK SECOND WORD
T←RDC3←(RDC3)XORT;
*RDC3=NEXT WORD
LU←(RDC12)XORT;
GOTO[ERROR10L,ALU#0],T←RDC4;
*CHECK THIRD WORD
T←RDC3←(RDC3)XORT;
*RDC3=NEXT WORD
LU←(RDC13)XORT;
GOTO[ERROR11L,ALU#0];
*CHECK FOURTH WORD
DATAVFY4: T←RDC4;
TASK;
RDC3←(RDC3)XORT;
*RDC3=NEXT WORD
GOTO[DATAVFY5];


DATAVFY5: LU←RDC2;
GOTO[DATAVFY6,ALU=0];
GOTO[DATAVFY1];
DATAVFY6: RDC17←(RDC17)-1,GOTO[DATAVFY7,R<0];
NOP;
TASK,PFETCH2[IOCBA,RDC0,16];
RDC0←RDC0;
RDC2←DBSIZE,GOTO[DATAVFY10];
DATAVFY7: LU←CHAIN;
GOTO[DATAVFY11,ALU=0];
IOCBA←(IOCBA)+(40C);
LU←(IOCBA)-(IOCBAE);
GOTO[DATAVFYSPIN,ALU<0];
IOCBA←PIOCBA;
DATAVFY11:APCTASK&APC←SAVE;
RETURN;
DATAVFY30:GOTO[DATAVFY7];

ERROR13L:LOADPAGE[DISK3];
GOTOP[ERROR13];
ERROR12L:LOADPAGE[DISK3];
GOTOP[ERROR12];
ERROR11L:LOADPAGE[DISK3];
GOTOP[ERROR11];
ERROR10L:LOADPAGE[DISK3];
GOTOP[ERROR10];
ERROR7L:LOADPAGE[DISK3];
GOTOP[ERROR7];
ERROR6L:LOADPAGE[DISK3];
GOTOP[ERROR6];
ERROR5L:LOADPAGE[DISK3];
GOTOP[ERROR5];
ERROR4L:LOADPAGE[DISK3];
GOTOP[ERROR4];
ERROR3L:LOADPAGE[DISK3];
GOTOP[ERROR3];
ERROR2L:LOADPAGE[DISK3];
GOTOP[ERROR2];

********** SUBROUTINE: EXTRACT **********
*
*
Extract finds the last IOCB and extracts
*
the disk, cylinder, head, and sector information.
*
SetTask[0];
ON PAGE[DISK5];
EXTRACT:
PassCount ← 4000C;
PassCount ← (PassCount) OR (70000C);
APC&APCTASK ← (PassCount);
PassCount ← 1C, Return;*use task 7 R registers

SetTask[7];
FIOCB:
CSBL ← 300C, AT[4000];
CSBH ← 0C;
PFetch1[CSBL,IOCBERROR,0];*look at CSB word 0
lu ← IOCBERROR;*test for zero
goto[New, alu#0];*use CSB0 as IOCB pointer if none zero
Old:
PFetch1[CSBL,IOCBERROR,17];*get old IOCB pointer (word 17)
IOCBERROR ← IOCBERROR;*interlock
IOCBH ← 0C;
New:
PFetch2[IOCBERROR,IOCB0,0];*get IOCB word0 and word1
t ← LDF[IOCB0,0,4];
DiskError ← t;*extract disk drive number
t ← LDF[IOCB0,10,10];
CylinderError ← t;*extract cylinder number
t ← LDF[IOCB1,0,10];
HeadError ← t;*extract head number
t ← LDF[IOCB1,10,10];
SectorError ← t;*extract sector number

Temp7 ← 4000C;
Temp7 ← (Temp7) OR (40C);
APC&APCTASK ← (Temp7);
Return;*get back to task 0

SetTask[0];
ExtractDone:
Return, AT[4040];

********** SUBROUTINE: HANDSHAKE **********
*
*
HANDSHAKE reads R register EXPECTED written by the
*
RDC task, saves it in NWW, reset bits 15 and 17,
*
then writes it back to EXPECTED.
*
ON PAGE[DISK4];
HANDSHAKE: USECTASK;
TASK,T←GETRSPEC[143];
SAVE1←T;
RDC6 ← 10C;
*load address of NWW
T ← (GETRSPEC[103]) XOR (377C);
*save STKP, right side up
STKP ← RDC6, RDC6 ← T;
*set STKP to NWW, save old STKP in RDC6
T ← STACK;
NWW← T;
T←(NWW)AND NOT(5C);
STACK ← T; *set NWW TO ZERO
TASK,STKP ← RDC6;
NOP;
APCTASK&APC←SAVE1;
RETURN;

********** SUBROUTINE: INITIOCB **********
*
*
INITIOCB initializes the memory
*
dedicated to IOCB’s.
*
ON PAGE[DISK];
INITIOCB: USECTASK;
T←GETRSPEC[143];
SAVE2←T;
TASK,IOCBA←PIOCBA;
DISKSAVE←(ZERO)-1;
HEADSAVE←(ZERO)-1;
ASPIN:RDC10←0C;
RDC11←0C;
RDC12←0C;
RDC13←0C;
TASK;
PSTORE4[IOCBA,RDC10,0];
*INITIALIZE ALL RDCIOCB WORDS
PSTORE4[IOCBA,RDC10,4];
TASK,PSTORE4[IOCBA,RDC10,10];
PSTORE4[IOCBA,RDC10,14];
T←20C;
TASK,PSTORE4[IOCBA,RDC10];
RDC0←4C;
T←21C;
PSTORE1[IOCBA,RDC0];
LU←CHAIN;
GOTO[INITIOCB1,ALU=0];
T←(IOCBA)+(40C);
RDC0←T;
TASK;
PSTORE1[IOCBA,RDC0,14];
IOCBA←(IOCBA)+(40C);
LU←(IOCBA)-(IOCBAE);
GOTO[ASPIN,ALU<0];
IOCBA←(IOCBA)-(40C);
RDC0←0C;
TASK;
PSTORE1[IOCBA,RDC0,14];
NOP;
INITIOCB1: IOCBA←PIOCBA;
APCTASK&APC←SAVE2;
RETURN;

********** SUBROUTINE: INITNEWPHASE **********
*
*
INITNEWPHASE reinitializes the IOCB’s
*
and the data buffer area in memory.
*
ON PAGE[DISK3];
INITNEWPHASE:USECTASK;
T←GETRSPEC[143];
TASK,SAVE1←T;
BLOCK←(ZERO)-1;
LOADPAGE[DISK];
CALLP[INITIOCB];
LOADPAGE[DISK];
CALLP[FILDATA];
T←MENDL;
RDC2←T;
T←MSTARTL;
TASK,RDC0←T;
RDC2←(RDC2)-(T);
RDC2←(RDC2)+1;
*RDC2=COUNT
T←MSTARTU;
RDC1←T;
TASK,RDC3←0C;
RDC4←0C;
LU←(PHASE)AND(4C);
GOTO[NEWPHASE21,ALU=0];
LOADPAGE[DISK5];
CALLP[MEMPUT],RDC5←0C;
*CLEAR MEMORY
NOP;
NEWPHASE21:APCTASK&APC←SAVE1;
RETURN;

********** SUBROUTINE: ISSUEBLK **********
*
*
ISSUEBLK issues RDC Data Blocks.
*
ON PAGE[DISK];
ISSUEBLK: USECTASK;
T←GETRSPEC[143];
TASK,SAVE←T;
T←RDC7←DBSIZE;
*TRUE DBSIZE
T←BLOCK←(BLOCK)+T;
*OLD DB+DBSIZE=NEW DB
T←RDC7←(RDC7)+T;
*T=NEW DB+DBSIZE
T←(MENDL)-T;
*MENDL-(NEW DB+DBSIZE)
GOTO[ISSUEBLK1,ALU>=0];
GOTO[ISSUEBLK2];
ISSUEBLK1: T←MSTARTL;
T←(BLOCK)-T;
*NEW DB-RDCMSTART
GOTO[ISSUEBLK2,ALU<0];
APCTASK&APC←SAVE;
RETURN;
ISSUEBLK2: T←MSTARTL;
GOTO[ISSUEBLK1],BLOCK←T;
*NEW DB=RDCMSTART

********** SUBROUTINE: FILDATA **********
*
*
FILDATA fills the IOCB memory buffer area
*
with the data pattern to be used in the test.
*
ON PAGE[DISK];
FILDATA: USECTASK;
T←GETRSPEC[143];
SAVE2←T;
T←MSTARTL;
*THIS ROUTINE FILLS MEMORY BY BLOCKS WITH PATTERNS
TASK,RDC0←T;
*START ADDRESS
T←MSTARTU;
RDC1←T;
*START ADDRESSU
T←SEED;
RDC3←T;
*SEED WORD
RDC4←T;
*SEED WORD=MODIFIER
T←MENDL;
TASK,RDC7←T;
T←DTYPE;
RDC5←T;
*DTYPE
FILDATA1: LOADPAGE[DISK5];
CALLP[MEMPUT],RDC2←DBSIZE;
*START+BLSIZE
LU←(PHASE)AND(30C);
GOTO[FILDATA2,ALU#0];
RDC3←(RDC3)+1;
T←177400C;
RDC3←(RDC3)XOR(T);
T←377C;
T←RDC3←(RDC3)XOR(T);
RDC4←T;
FILDATA2:T←DBSIZE;
TASK;
T←(RDC0)+T;
*NEXT+DBSIZE
T←(MENDL)-T;
*DRDCMEND-NEXT+DBSIZE
GOTO[FILDATA1,ALU>=0];
APCTASK&APC←SAVE2;
RETURN;

********** SUBROUTINE: MEMPUT **********
*
*
MEMPUT puts RDC Data into memory.
*
RDC0: Low Address
*
RDC1: High Address
*
RDC2: Word Count
*
RDC3: RDCDATA to be stored
*
RDC4: Modifier to be applied to every word
*
RDC5: Function
*
ON PAGE[DISK5];
MEMPUT: USECTASK;
T←GETRSPEC[143];
TASK,RDC17←T;
T←RDC3;
RDC10←T;
*SET FIRST RDCDATA TO MEMORY
LU←RDC5;
GOTO[MEMPUTLOG,ALU#0];
T←RDC4;
RDC10←
(RDC10)-T;
TASK;
NOP;
MEMPUT0$: NOP;
*DUMMY ENTRY
MEMPUT0: RDC2←RDC2;
*WORD COUNT <=0 WE ARE DONE
GOTO[MEMPUTOUT,ALU=0],FREEZERESULT;
GOTO[MEMPUTOUT$,ALU<0];
LU←RDC5;
GOTO[MEMPUTLOG1,ALU#0];
T←RDC4;
TASK,T←RDC10←(RDC10)+T;
*FIRST RDCDATA WORD READY TO GO
T←(RDC4)+T;
RDC11←T;
T←(RDC4)+T;
RDC12←T;
TASK,T←(RDC4)+T;
RDC13←T;
MEMPUTCON: T←RSH[RDC2,2];
*SET OF FOUR RDCDATA, QUAD ALIGN AND ARITH MODIFIED
GOTO[MEMPUT1,ALU=0];
*IF WORD COUNT LESS THAN 4 DO ONE RDCPUT
T←LSH[RDC0,16];
*IS MEMORY ADD QUAD ALINE IF NOT DO ONE RDCPUT
GOTO[MEMPUT4,ALU=0];
T←T;
MEMPUT1: PSTORE1[RDC0,RDC10,0];
*RDCDATA TO MEMORY
TASK;
NOP;
RDC0←(RDC0)+1;
*UP COUNT MEMORY ADD
GOTO[MEMPUT10,NOCARRY];
RDC1←(RDC1)+(400C)+1;
*CARRY ONE INTO UPPER ADDRESS
MEMPUT10: RDC2←(RDC2)-1,GOTO[MEMPUT0];
*DOWN COUNT WORD COUNT
MEMPUT4: PSTORE4[RDC0,RDC10,0];
*COUNT>=TO 4 ADDRESS IS QUAD, RDCPUT 4 INTO MEMORY
TASK,T←(RDC13);
RDC10←T;
T←4C;
RDC2←(RDC2)-T;
*DOWN COUNT WORD COUNT BY 4
RDC0←(RDC0)+T;
*UP COUNT MEMORY ADDRESS BY 4
GOTO[MEMPUT40,NOCARRY];
RDC1←(RDC1)+(400C)+1;
*CARRY 1 INTO UPPER ADDRESS
MEMPUT40: GOTO[MEMPUT0];

MEMPUTOUT: T←T;
MEMPUTOUT$:APCTASK&APC←RDC17;
RETURN;
MEMPUTLOG: T←RDC4;
RDC10←(RDC10)XORT,GOTO[MEMPUT0$];
MEMPUTLOG1: T←RDC4;
TASK,T←RDC10←(RDC10)XORT;
*FIRST RDCDATA WORD READY TO GO
T←(RDC4)XORT;
RDC11←T;
T←(RDC4)XORT;
RDC12←T;
T←(RDC4)XORT;
GOTO[MEMPUTCON],RDC13←T;
*SET OF FOUR RDCDATA WORDS QUAD ALIGN & LOGICAL MODIFIED

********** SUBROUTINE: NEWPHASE **********
*
*
NEWPHASE selects the next phase to run.
*
ON PAGE[DISK1];
NEWPHASE:USECTASK;
T←GETRSPEC[143];
TASK;
SAVE←T;
LU ← RUNPHASES;
GOTO[.+2, ALU#0];
PHASE ← 0C, GOTO[NEWPHASE10];
T←PHASEDONE;
GOTO[NEWPHASE10,ALU=0];
NOP;
NEWPHASE1:PHASE←LSH[PHASE,1];
*//=NEXT PHASE
NEWPHASE2:T←PHASE;
GOTO[NEWPHASE4,ALU=0];
*CHECK FOR LAST PHASE
NEWPHASE3:T←PHASE;
TASK;
NOP;
T←(RUNPHASES)ANDT;
*SEE IF PHASE CONT HAS THIS BIT
GOTO[NEWPHASE1,ALU=0];
LOADPAGE[DISK5];
CALLP[SETMAINT];
NOP;
NEWPHASE7:LOADPAGE[DISK3];
CALLP[INITNEWPHASE];
RDC0←PCMDPOINTER;
TASK,T←12C;
T←RDC0←(RDC0)+(T);
LU←(CMDPOINTER)-(T);
GOTO[NEWPHASE24,ALU>=0];
NOP;
TASK,T←RANDOMC;
RANDOM←T;
NOP;
NEWPHASE10:PHASEDONE←0C;
APCTASK&APC←SAVE;
RETURN;
NEWPHASE4:LU←NODATAINC;
GOTO[NEWPHASE6,ALU=0];
NEWPHASE40:PHASE←1C;
TASK;
NOP;
PASSCOUNT←(PASSCOUNT)-1;
GOTO[NEWPHASE5,ALU<0];
GOTO[NEWPHASE2];
NEWPHASE5: PASSCOUNT←0C;
LU←NOHALT;
GOTO[NEWPHASE11,ALU#0];
*CHECK IF NOSTOP=1
PASSED-EDRDCD-TEST:BREAKPOINT;
NEWPHASE11:LOADPAGE[DISK];
CALLP[RDCINIT];
GOTO[NEWPHASE2];

NEWPHASE6:T←1C;
DTYPE←(DTYPE)XOR(T);
TASK,SEED←(SEED)+(T);
SEED←(SEED)+(400C);
GOTO[NEWPHASE40];

NEWPHASE24: CMDPOINTER←PCMDPOINTER;
GOTO[NEWPHASE10];

********** SUBROUTINE: RDCINIT **********
*
*
RDCINIT saves return link in SAVE2 and notifies
*
the RDC Task code to initialize.
*
ON PAGE[DISK];
RDCINIT: USECTASK;
T←GETRSPEC[143];
SAVE2←T;
TASK,RDC0←RDCDTASK.1;
T←RPAGE1.2;
RDC0←(RDC0)+T;
RDC0←(RDC0)OR(74C);
APCTASK&APC←RDC0;
*LINK TO TASK CODE TO INITIALIZE
RETURN;

********** SUBROUTINE: RDCINTR **********
*
*
RDCINTR uses SAVE2 return address
*
to return to the RDCD Task (Task 0).
*
ON PAGE[DISK];
RDCINTR: APCTASK&APC←SAVE2;
RETURN;

********** SUBROUTINE: SETMAINT **********
*
*
SETMAINT set the maintenance panel
*
to display the phase.
*
ON PAGE[DISK5];
SETMAINT: USECTASK;
T←GETRSPEC[143];
*THIS ROUTINE SETS UP THE MAINTANCE PANEL
TASK,SAVE1←T;
CLEARMPANEL;
RDC7←7C;
T←LSH[PHASE,10];
RDC6←T;
RDC6 ← RDC6, GOTO[SETMAINT2$, ALU = 0];
SETMAINT3:GOTO[SETMAINT1,ALU<0];
RDC7←(RDC7)-1;
GOTO[SETMAINT3],RDC6←LSH[RDC6,1];
SETMAINT1:RDC7←(RDC7)-1;
GOTO[SETMAINT2,ALU<0];
INCMPANEL;
TASK;
NOP;
GOTO[SETMAINT1];
SETMAINT2$:NOP;
SETMAINT2:APCTASK&APC←SAVE1;
RETURN;

********** SUBROUTINE: SRCADDR **********
*
*
SRCADDR shifts out 16 task numbers
*
to the controller boards.
*
ON PAGE[DISK5];
SRCADDR: USECTASK;
T←GETRSPEC[143];
SAVE1←T;
OBSERVED←4C;
*PUT TASK# INTO T AND SHIFT IT OUT
T←(ADDRESS)XOR(17C);
RDC14←T;
SRCADDR1: GENSRCLOCK;
TASK,T←RDC14←RSH[RDC14,1];
NOP;
OBSERVED←(OBSERVED)-1;
GOTO[SRCADDR1,ALU#0];
APCTASK&APC←SAVE1;
RETURN;
*QUIT WHEN YOU SHIFT FOUR TIMES

********** SUBROUTINE: UPDTIOCB **********
*
*
UPDTIOCB updates the IOCB block.
*
ON PAGE[DISK1];
UPDTIOCB: USECTASK;
T←GETRSPEC[143];
TASK,SAVE←T;
RDC16←2000C;
DISPATCH[PHASE,14,4];
DISP[UPDTIOCB0];
UPDTIOCB0: GOTO[RDCDISP],AT[DISK1.1,100];
*NO PHASE
GOTO[UPDTIOCB20],AT[DISK1.1,101];
*PHASE0
GOTO[UPDTIOCB11],AT[DISK1.1,102];
*PHASE1
GOTO[UPDTIOCB12],AT[DISK1.1,104];
*PHASE2
GOTO[UPDTIOCB11],AT[DISK1.1,110];
*PHASE3

RDCDISP:DISPATCH[PHASE,10,4];
DISP[UPDTIOCBD0];


UPDTIOCBD0: GOTO[NOPHASE],AT[DISK1.1,200];
*NO PHASE
GOTO[UPDTIOCB122],T←PHASE4COMD,AT[DISK1.1,201];
*PHASE4
GOTO[UPDTIOCB11],AT[DISK1.1,202];
*PHASE5
GOTO[UPDTIOCB12],AT[DISK1.1,204];
*PHASE6
GOTO[NOPHASE],AT[DISK1.1,210];
*PHASE7

NOPHASE:BREAKPOINT;
LOADPAGE[DISK];
GOTO[START2];

UPDTIOCB11: LU←(PHASE)AND(40C);
GOTO[UPDTIOCB111,ALU=0],RDC16←HEAERR;
*PHASE1 OR PHASE3 OR PHASE5
GOTO[UPDTIOCB20],RDC16←HEADERW;
UPDTIOCB111:T←LABELW;
*BUILD WRITE COMMD
TASK,RDC16←(RDC16)OR(T);
T←DATAW;
GOTO[UPDTIOCB20],RDC16←(RDC16)OR(T);
UPDTIOCB122:GOTO[UPDTIOCB20],RDC16←T;

UPDTIOCB12: LU←(PHASE)AND(100C);
*PHASE2 OR PHASE4 OR PHASE6
GOTO[UPDTIOCB121,ALU=0],RDC16←HEAERR;
GOTO[UPDTIOCB20],RDC16←HEAERR;
*PHASE6
UPDTIOCB121:T←LABELR;
*BUILD READ COMMD
TASK,RDC16←(RDC16)OR(T);
T←DATAR;
GOTO[UPDTIOCB20],RDC16←(RDC16)OR(T);

UPDTIOCB20: NOP;
TASK,PSTORE1[IOCBA,RDC16,15];
*COMMAND WORD RDCIOCB
PSTORE1[IOCBA,BLOCK,16];
*RDCDATA POINTER
PSTORE1[IOCBA,MSTARTU,17];
*RDCDATA POINTER UPPER
LU←RANDOM;
GOTO[UPDTIOCBNRDC1,ALU=0];
LOADPAGE[DISK4];
GOTOP[UPDTIOCBRANDOM];
UPDTIOCBNRDC1:T←LSH[DISKE,14];
TASK;
T←(CYLE)OR(T);
T←(DISKSAVE)XOR(T);
GOTO[UPDTIOCBNR$,ALU#0];T←LSH[HEADE,10];
T←(SECTORE)OR(T);
T←(HEADSAVE)XOR(T);
GOTO[UPDTIOCB30$,ALU=0];
*GET CURRENT RDCSECTOR
NOP;
UPDTIOCBNR$:NOP;
UPDTIOCBNR: T←LDF[HEADSAVE,10,10];
*GET CURRENT RDCSECTOR
TASK,RDC3←T;
T←RDC3←(RDC3)+1;
*RDC3=NEW RDCSECTOR+1
RDC4←35C;
LU←(RDC4)-T;
GOTO[UPDTIOCB23,ALU<0];
*IS RDC3>35
T←SECTORE;
TASK,RDC4←T;
T←RDC3;
T←(RDC4)-T;
GOTO[UPDTIOCB23$,ALU<0];
*IS RDC3>ENDING SEC
GOTO[UPDTIOCB30],HEADSAVE←(HEADSAVE)+1;
UPDTIOCB23$:NOP;
UPDTIOCB23: HEADSAVE←(HEADSAVE)AND(177400C);
TASK,T←SECTORS;
HEADSAVE←(HEADSAVE)OR(T);
RDC3←(RDC3)+1;
*RDC3=LAST RDCSECTOR +1
UPDTIOCB24: T←LDF[HEADSAVE,0,10];
*GET CURRENT RDCHEAD
RDC3←T;
TASK,T←RDC3←(RDC3)+1;
*RDC3=NEW RDCHEAD+1
RDC4←10C;
LU←(RDC4)-T;
GOTO[UPDTIOCB25,ALU<0];
*IS RDC3>7
T←HEADE;
TASK,RDC4←T;
T←RDC3;
T←(RDC4)-T;
GOTO[UPDTIOCB25$,ALU<0];
*IS RDC3>ENDING RDCHEAD
GOTO[UPDTIOCB30],HEADSAVE←(HEADSAVE)+(400C);
UPDTIOCB25$:NOP;
UPDTIOCB25: T←377C;
TASK,HEADSAVE←(HEADSAVE)AND(T);
T←HEADS;
*GET START RDCHEAD
RDC4←T;
T←LSH[RDC4,10];
HEADSAVE←(HEADSAVE)OR(T);
*RDC7=NEW RDCHEAD
UPDTIOCB26: T←LDF[DISKSAVE,0,4];
*GET CURRENT DISK
RDC3←T;
TASK,T←RDC3←(RDC3)+1;
*RDC3=NEW DISK+1
RDC4←3C;
LU←(RDC4)-T;
GOTO[UPDTIOCB27,ALU<0];
*IS RDC3>3
T←DISKE;
TASK,RDC4←T;
T←RDC3;
T←(RDC4)-T;
GOTO[UPDTIOCB27$,ALU<0];
*IS RDC3>ENDING DISK
GOTO[UPDTIOCB30],DISKSAVE←(DISKSAVE)+(10000C);
*DISKSAVE=NEW DISK
UPDTIOCB27$:NOP;
UPDTIOCB27: T←377C;
TASK,DISKSAVE←(DISKSAVE)AND(T);
T←DISKS;
*GET START DISK
RDC4←T;
T←LSH[RDC4,14];
DISKSAVE←(DISKSAVE)OR(T);
UPDTIOCB21: T←LDF[DISKSAVE,10,10];
RDC3←T;
TASK;T←RDC3←(RDC3)+1;
*RDC3=NEW TRACK+1
RDC4←311C;
LU←(RDC4)-T;
GOTO[UPDTIOCB22,ALU<0];
*IS RDC3>311
T←CYLE;
TASK,RDC4←T;
T←RDC3;
T←(RDC4)-T;
GOTO[UPDTIOCB22$,ALU<0];
*IS RDC3>ENDING TRACK
GOTO[UPDTIOCB30],DISKSAVE←(DISKSAVE)+(1C);
UPDTIOCB22$:NOP;
UPDTIOCB22: T←RDC3←177400C;
TASK,DISKSAVE←(DISKSAVE)AND(T);
T←CYLS;
DISKSAVE←(DISKSAVE)OR(T);
NOP;
UPDTIOCB30$:NOP;
UPDTIOCB30: RDC0←CSBA;
LOADPAGE[DISK3];
GOTOP[UPDTIOCB40];

ON PAGE[DISK3];
UPDTIOCB40:RDC1←0C;
TASK;
PFETCH4[RDC0,RDC10,10];
*GET NOT USED TRACKS
RDC10←RDC10;*INTERLOCK
T←DISKSAVE;
LU←(RDC10)XOR(T);
GOTO[UPDTIOCBBY0,ALU=0];
LU←(RDC11)XOR(T);
GOTO[UPDTIOCBBY1,ALU=0];
LU←(RDC12)XOR(T);
GOTO[UPDTIOCBBY2,ALU=0];
LU←(RDC13)XOR(T);
GOTO[UPDTIOCBBY3,ALU=0];
PSTORE2[IOCBA,DISKSAVE,0];
*NEW DISK ADDRESS
TASK,T←BLOCK;
RDC0←T;
T←MSTARTU;
RDC1←T;
NOP;
TASK,PFETCH4[RDC0,RDC10,0];
PFETCH4[RDC0,RDC14,4];
RDC14←RDC14;
TASK,PSTORE4[IOCBA,RDC10,4];
PSTORE4[IOCBA,RDC14,10];
APCTASK&APC←SAVE;
RETURN;
UPDTIOCBBY0:GOTO[UPDTIOCBBY3];
UPDTIOCBBY1:GOTO[UPDTIOCBBY3];
UPDTIOCBBY2:GOTO[UPDTIOCBBY3];
UPDTIOCBBY3:LOADPAGE[DISK1];
GOTOP[UPDTIOCBNRDC1];

ON PAGE[DISK4];
UPDTIOCBRANDOM:T←MSTARTL;
TASK,RDC0←T;
T←MSTARTU;
RDC1←T;
T←RANDOM←(RANDOM)-1;
GOTO[UPDTIOCBRANDOM1,ALU=0];
RANDOM4:PFETCH1[RDC0,RDC14];
*GET NEW WORD
T←LDF[DISKSAVE,10,10];
RDC14←(RDC14)+(T);
DISKSAVE←177400C;
HEADSAVE←(ZERO)-1;
TASK,T←(RDC14)AND(377C);
DISKSAVE←(DISKSAVE)OR(T);
LU←(CYLS)-T;
GOTO[UPDTIOCBRANDOM2,ALU>=0];
UPDTIOCBRANDOM3: DISKSAVE←(DISKSAVE)OR(T);
LOADPAGE[DISK1];
GOTOP[UPDTIOCBNR];

UPDTIOCBRANDOM1:RANDOMD←1C,GOTO[RANDOM4];

UPDTIOCBRANDOM2:T←(CYLE)-1,GOTO[UPDTIOCBRANDOM3];

********** SUBROUTINE: UPDTCSB **********
*
*
UPDTCSB updates the CSB block with the new
*
IOCB pointer, clears status, and sets process wakeup.
*
ON PAGE[DISK1];
UPDTCSB: USECTASK;
TASK,T←GETRSPEC[143];
SAVE←T;
LOADPAGE[DISK4];
CALLP[HANDSHAKE];
RDC0←CSBA;
*CLEAR STATUS AND SET RDCIOCB LINK INTO RDCCSB
RDC1←0C;
RDC14←PIOCBA;
RDC15←1C;*SET PROCESS W/U
RDC16←0C;
PSTORE2[RDC0,RDC14,0];
TASK;
PSTORE1[RDC0,RDC16,2];
RDC7←0C;*TIMERCOUNT
APCTASK&APC←SAVE;
RETURN;

********** SUBROUTINE: WAKEUPWAIT **********
*
*
WAKEUPWAIT waits until the RDC responds
*
or until it is timed out.
*
ON PAGE[DISK4];
WAKEUPWAIT: USECTASK;
TASK,T←GETRSPEC[143];
SAVE←T;
WAKEUPWAITSPIN:NOP;
CALL[HANDSHAKE];
IOERROR←0C;
*SPIN HERE UNTILL WE GET A PROCESS W/U#0
RDC0←CSBA;
RDC1←0C;
RDC7←(RDC7)-1;
GOTO[TIMERHALT1,ALU=0],T←(NWW)AND(4C);
GOTO[WAKEUPWAIT1,ALU=0],T←(NWW)AND(1C);*CHECK FOR IOCB DONE W/U
NWW←0C;
RDC7←0C;
TASK,PFETCH1[RDC0,RDC14,0];
*GET IOCB LINK
PFETCH1[RDC0,RDC0,17];
*GET OLDIOCBLINK
RDC14←RDC14; *INTERLOCK
GOTO[WAKEUPWAIT2,ALU#0];
*IF LINK #TO 0,NOT DONE YET
RDC0←RDC0;
*INTERLOCK
TASK,T←20C;
PFETCH1[RDC0,RDC14];
*GET IOCB STATUS WORD
RDC14←RDC14;
T←12C;
T←(LDF[RDC14,0,4])-(T);
GOTO[WAKEUPWAIT3,ALU<0];
WAKEUPWAIT4:IOERROR←1C;
WAKEUPWAIT3:APCTASK&APC←SAVE;
RETURN;
WAKEUPWAIT1:GOTO[WAKEUPWAIT5,ALU=0],NWW←0C;
RDC7←0C,GOTO[WAKEUPWAITSPIN];
WAKEUPWAIT2:GOTO[WAKEUPWAITSPIN];
WAKEUPWAIT5:GOTO[WAKEUPWAITSPIN];

TIMERHALT1:LOADPAGE[DISK5];
CALLP[EXTRACT];
TIMERHALT:BREAKPOINT;
GOTO[WAKEUPWAIT4];

END;