ER[KINT];

*I = 158

%ASSOCIATED WITH EACH DISK UNIT I IS RIGHT BANK REGISTER I, USED TO
KEEP A CHECKSUM WHILE READING OR WRITING, AND A 20-WORD BLOCK OF
SCRATCH MEMORY REGISTERS AT 400 + 20*I.  THE YKPTR← FUNCTION CAN
BE EXECUTED TO LOAD THE Y REGISTER FROM 400 + B[41-43]*20, AND THE
REGISTERS CAN THEN BE REFERENCED FROM SA IN THE INSTRUCTION.  THE
USAGE OF THE 20 REGISTERS IS AS FOLLOWS:%

SM[WCSA,0];	*B[0,16] NEGATIVE WORD COUNT
		*B[17,43] MAIN MEMORY ADDRESS FOR READING OR WRITING
SM[WIDISP,1];	*B[0,27] UNUSED
		*B[30,43] WORD INTERRUPT DISPATCH FOR "KDISP" OR
		*END-OF-COUNT DISPATCH FOR THE "RDATA" AND "WRDAT" ROUTINES
SM[SDISP,2];	*B[0,27] SIX FOUR-BIT DISPATCHES FOR CURRENT COMMAND
SM[USTATE,3];	*SOFTWARE STATE OF DISK UNIT
SM[CKA,4];	*B[0,11] KPREH (TO MATCH HEADER)
		*B[12,43] CURRENT COMMAND'S DISK ADDRESS
SM[CMMA,5];	*B[0,16] UNUSED
		*B[17,43] CURRENT COMMAND'S MAIN MEMORY ADDRESS
SM[KA,6];	*B[0,11] UNUSED
		*B[12,43] CURRENT DISK ADDRESS (CURRENT SECTOR + 1)
SM[NSDISP,7];	*B[0,27] SIX FOUR BIT DISPATCHES FOR NEXT COMMAND (IF ANY)
		*B[30-43] NEXT COMMAND'S SETUP ADDRESS (CSR, CSW, INTRET, KSERV)
SM[NKA,10];	*B[0-11] KPREH (TO MATCH HEADER)
		*B[12-43] NEXT COMMAND'S DISK ADDRESS
SM[NMMA,11];	*B[0-16] UNUSED
		*B[17-43] NEXT COMMAND'S MAIN MEMORY ADDRESS

%KBLK, AND KPARAM ARE SET BY THE SLOC JMC, MAXKA BY "KON".
OUR UNITS HAVE 3 SECTORS, 20 HEADS, AND 406 TRACKS.  APPROPRIATE KPARAM
VALUES ARE RHCYC=3, RCYC=3, WCYC=4, WHCYC=9, WTOCYC=3, AND WCCYC=7.
KPARAM= 00010 01000 00011 00011 00100 00111 00000 0
      = 64430 620700 OCTAL
MAXKA= 000 PPP 23 625 2 (SEE DISK ADDRESS FORMAT BELOW)
%
SM[MAXKA,12];	*B[0-11] UNUSED
		*B[12-43] LARGEST LEGAL DISK ADDRESS ON THIS UNIT
SM[KBLK,13];	*B[0-16] UNUSED
		*B[17-43] BLOCK ADDRESS FOR THIS UNIT
SM[KPARAM,14];	*WORD CONTAINING SIX 5-BIT FIELDS WHICH ARE THE WORD
		*COUNTS ON THIS UNIT FOR DIFFERENT PARTS OF THE SECTOR.
*SET[RHCYC,37];	*WORDS TO SPACE OVER IN HEADER BEFORE RSYNC
*SET[WHCYC,32];	*NO. ZERO WORDS WRITTEN BEFORE SYNC WORD IN HEADER
*SET[WTOCYC,25];	*WRITE TURN-OFF WAIT TIME WHILE ERASING
*SET[RCYC,20];	*WORDS SKIPPED BEFORE READ-SYNCING NON-HEADER RECORD
*SET[WCYC,13];	*WORDS OF ZEROES BEFORE WRITING NON-HEADER SYNC WORD
*SET[WCCYC,6];	*NO. WORDS OF ZEROES TO WRITE WHEN CONTINUING FROM
		*ONE RECORD TO THE NEXT
*15 BLISP STATE DISPATCH, 16 EVENT COUNTERS, 17 INSTRUCTION COUNTERS

%DISK ADDRESSES HAVE FORMAT:
   12-21   PACK NUMBER
   22-27   HEAD NUMBER (IN POSITION FOR SET-HEAD)
   30-40   ARM
   41-43   SECTOR
THE UNIT NO. IS NORMALLY NOT GIVEN.  THE 8 UNIT ARRAYS MUST BE SEARCHED
UNTIL A MATCH WITH THE SPECIFIED PACK NO. IS FOUND.
%

M[PREIRET,Z[0]?]; *UNDEFINE BECAUSE OF SUSPECTED HARDWARE BUG

%"KBLK" POINTS TO A THREE-WORD BLOCK USED AS FOLLOWS:
   0   UNIT STATE = (KSTAT) U (SOFTWARE FLAGS AND ERRORS)
       THIS WORD IS STORED INTO BY "KSECTR".
   1   COMMAND ADDRESS (AFTER COMPLETION) OR 0 (NO COMMAND WAS DONE)
       STORED INTO BY "KSERV" OR "CSTRT"
   2   DISK ADDRESS BUT NEXT SECTOR (FOR COMMAND SETUP)
       STORED INTO BY THE PDP-10 INTERRUPT ROUTINE "KPISV"

"NMMA" AND "CMMA" POINT TO A 9-WORD BLOCK USED AS FOLLOWS:
   0   4-10    COMMAND NUMBER (SEE BELOW)
       12-43   DISK ADDRESS
   1           HEADER (IGNORED WHEN WRITTEN, LEFT HERE WHEN READ)
   2-5         UNIQUE NAME WORDS UN0, UN1, UN2, UN3
   6-7         PREDATA WORDS PD0, PD1
   10  0-16    - WORD COUNT
       17-43   STARTING MAIN MEMORY ADDRESS OF DATA BLOCK

DISK OPERATION IS DRIVEN BY A FINITE STATE MACHINE WHICH BEGINS ANEW AT
EACH SECTOR INTERRUPT.  THE COMMON SECTOR INTERRUPT CODE DISPATCHES TO
NSDISP[30,43] WHICH WILL CONTINUE AT ONE OF THE FOLLOWING:
	CSR	SAVE PREVIOUS RESULTS AND INTERRUPT, BEGIN READ-HEADER
	CSW	SAVE PREVIOUS RESULTS AND INTERRUPT, BEGIN WRITE-HEADER
	KSERV	SAVE PREVIOUS RESULTS AND INTERRUPT, DO NOTHING
	INTRET	SAVE PREVIOUS RESULTS, DO NOTHING
WHEN A UNIT IS PUT ONLINE WITH "KON", SECTOR INTERRUPTS START OCCURRING
AT "INTRET".  WHEN A SEEK IS STARTED BY "KSEEK", INTERRUPTS ARE SWITCHED
TO "KSERV".  DURING THE SEEK IT IS PROBABLY WISE TO SETUP A COMMAND AT
EACH SECTOR (IF ANY) BY "KGO", SO THAT IF THE SEEK COMPLETES BEFORE
THE SECTOR FINISHES, THE COMMAND CAN BE DONE WITHOUT WAITING ONE REVOLUTION.
THE COMMAND WILL NOT BE STARTED UNLESS THE SEEK HAS FINISHED.  "KGO" SETS
UP A COMMAND IN "NKA", "NMMA", AND "NSDISP".  WHEN THE COMMAND IS STARTED,
"NKA", "NMMA", AND "NSDISP" ARE MOVED INTO "CKA", "CMMA", AND "SDISP",
RESPECTIVELY; THEN "NMMA" IS ZEROED AND "NSDISP" IS POINTED AT "KSERV",
SO THAT THE INTERRUPT ROUTINE NEED NOT TAKE ANY EXPLICIT ACTION TO BE
IDLE.  WHEN ALL THE COMMANDS QUEUED FOR THE UNIT ARE EXHAUSTED, "KIOFF"
DISABLES SECTOR INTERRUPTS UNTIL ANOTHER "KSEEK" IS DONE.


THE FOUR-BIT BYTES IN NSDISP[0,27] DETERMINE SUBSEQUENT MACHINE STATES
FOR COMMANDS BEGINNING WITH "CSR" OR "CSW".  THESE ARE DISPATCHED TO BY
"XDISP".  CURRENTLY DEFINED OPERATIONS PERMITTED BY "KGO" ARE:

NO.  HEADER   U.N.     DATA
 0    WRITE    --       --
 1    READ     --       --
 2    READ    READ      --
 3    READ    WRITE     --
 4    READ    READ     READ
 5    READ    COMPARE  READ
 6    READ    READ     WRITE
 7    READ    COMPARE  WRITE
10    READ    WRITE    WRITE
11    READ    COMPARE  CHECK

OTHER OPERATIONS CAN BE ADDED EASILY LATER PROVIDED:
   1.  TRANSITION FROM WRITING AT ONE RECORD TO READING THE NEXT IS
       NOT PERMITTED, ALTHOUGH IT SHOULD BE POSSIBLE TO WRITE THE U.N.
       RECORD IN ONE OPERATION WITHOUT CLOBBERING THE DATA RECORD WHICH
       COMES AFTER IT AND THEN ON ANOTHER OPERATION TO READ BOTH RECORDS.
   2.  THE PRELIMINARIES FOR UN AND DATA RECORDS ARE THE SAME.
   3.  THE POSTLIMINARIES FOR HEADER, U.N., AND DATA RECORDS ARE THE SAME.
ANY WORD COUNT LESS THAN 1001 MAY BE SUPPLIED FOR THE DATA RECORD.
HOWEVER, IF THE WORD COUNT USED FOR A READ IS DIFFERENT FROM THE WORD
COUNT USED FOR ITS PRECEDING WRITE, THEN THE CHECKSUM WILL BE WRONG.
ALL HARDWARE ERRORS STOP READING, WRITING, ERASING, AND WORD INTERRUPTS
UNTIL THEY ARE CLEARED BY THE (NEXT) EXECUTION OF THE SECTOR INTERRUPT
ROUTINE.  SOFTWARE DETECTED READ ERRORS (HDNE, HCHKE, UNNE, AND UNCHKE)
DO NOT STOP TRANSFERS UNLESS A WRITE OF A LATER RECORD IS SETUP.

THE TIMING FOR DISK COMMANDS CAN BE COMPUTED USING THE FOLLOWING COMPONENTS:
   SECTOR INTERRUPTS:
	30 2/3 FOR "KSECTR"
	53 + UNIT NO. IN "PI"
	5 IN "KPISV"
	6 + M IN "PICYC"
   FOR FINITE STATE MACHINE:
	CSR		13 + 6 + 6*RHCYC = 31
	CSW		13 + 6 + 8*WHCYC = 83
	0 RSETUP	13 + 6*RCYC = 31
	1 WSETUP	17 + 8*WCYC = 49
	2 DONE		13
	3 WDONE		12 + 3*6 + 5 = 35
	4 WCON		13 + 6*WCCYC = 55
	5 RUN		13 + 4*(6 + W WAIT) + 3 + 10 + 1 ON ERROR
			= 50 + 4*W WAIT + 1 ON ERROR
	6 CUN		12 + 2*(11 + R) + 2*(6 + W WAIT) + 3 + 10 + 1 ON ERROR
			= 59 + 2*(R + W WAIT) + 1 ON ERROR
	7 RDT		13 + 514*(6 + W WAIT) + 3 + R + 3 + 10 + 1 ON ERROR
			= 3113 + 514*W WAIT + R + 1 ON ERROR
	10 RHDR		11 + 12 + 10 + 1 ON ERROR = 33 + 1 ON ERROR
	11 WHDR		11 + 7 + 4 = 22
	12 WUN		13 + 4*(6 + R) + 3 + 4 = 44 + 4*R
	13 WDT		13 + 514*(6 + R) + 3 + R + 3 + 4
			= 3107 + 515*R
	14 CHKDT	12 + 514*8 + 1 + 10 + 1 ON ERROR = 4135 + 1 ON ERROR

THESE COMPONENTS SUM TO GIVE THE FOLLOWING TIMES/COMMAND:
	W	= CSW + WHDR + WDONE = 83 + 22 + 35 = 140
	R	= CSR + RHDR + DONE = 31 + 33 + 13 = 77
	RR	= R + RSETUP + RUN
		= 77 + 31 + 50 + 4*W WAIT = 158 + 4*W WAIT
	RW	= CSR + RHDR + WSETUP + WUN + WDONE
		= 31 + 33 + 49 + 44 + 4*R + 35 = 192 + 4*R
	RRR	= RR + RSETUP + RDT
		= 158 + 4*W WAIT + 31 + 3113 + 514*(W WAIT) + R 
		= 3302 + 518*W WAIT + R
	RCR	= R + 2*RSETUP + CUN + RDT
		= 77 + 2*31 + 59 + 2*(R + W WAIT) + 3113 + 514*W WAIT + R
		= 3311 + 3*R + 516*W WAIT
	RRW	= RR - DONE + WSETUP + WDT + WDONE
		= 158 + 4*W WAIT - 13  + 49 + 3107 + 515*R + 35
		= 3336 + 4*W WAIT + 515*R
	RWW	= RW + WCON + WDT
		= 192 + 4*R + 55 + 3107 + 515*R = 3354 + 519*R
	RCW	= CSR + RHDR + RSETUP + CUN + WSETUP + WDT + WDONE
		= 31 + 33 + 31 + 59 + 2*(R + W WAIT) + 49 + 3107 + 515*R + 35
		= 3345 + 517*R + 2*W WAIT
	RCC	= R + 2*RSETUP + CUN + CHKDT
		= 77 + 2*31 + 59 + 2(R + W WAIT) + 4135 = 4333 + 2(R + W WAIT)
%

*KSTAT AND USTATE BITS
*MP[IX,0];	*INDEX CONDITION
*MP[UNS,1];	*UNIT UNSAFE
*MP[OFFL,2];	*UNIT OFFLINE (ILLEGAL UNIT OR OPERATOR MUST TAKE ACTION)

MP[UNRDY,3];	*=SEEKING IF OTHER STUFF OK
*MP[SKF,4];	*SEEK FAILURE (VERY RARE--RESTORE AND TRY AGAIN BUT PROBABLY
		*HARDWARE FIX IS REQUIRED)
*MP[RO,5];	*UNIT READ ONLY

*MP[CNRDY,6];	*CONTROLLER NOT READY (CAN'T DO KSET).  SET UNTIL
		*PREVIOUS COMMAND HAS BEEN RECEIVED (ABOUT TWO USEC)
MP[KSEC,7];	*SECTOR CONDITION (TRUE CONCURRENT WITH THE SECTOR
		*INTERRUPT REQUEST AND FALSE FROM THE SECOND WORD TIME AFTER IT)
*MP[PDTL,10];	*PROCESSOR DATA LATE (MICROINTERRUPT SERVICED TOO LATE)

*MP[CDTL,11];	*CONTROLLER DATA LATE (HARDWARE PROBLEMS)
*MP[SOVF,12];	*SECTOR OVERFLOW
MP[DESEL,13];	*UNIT DESELECTED
PM[KRERRS,1600 000000]; *CONTROLLER-DETECTED ERRORS = CDTL, SOVF, PDTL
PM[HWERRS,320100 000000]; *HARDWARE-DETECTED ERRORS = UNS, OFFL, SKF, DESEL

*SOFTWARE CONTROLLER STATE SUPPLEMENTING STATE OF HARDWARE
*COMMAND RECEPTION ERRORS
SM[ILLOP,IP[10000S]];	*27 ILLEGAL COMMAND NUMBER

SM[ILLPK,IP[4000S]];	*30 PACK NO. # ANY ONLINE PACK NUMBER
SM[ILLARM,IP[1000S]];	*32 ILLEGAL ARM SELECTED FOR SEEK

SM[ILLHD,IP[400S]];	*33 ILLEGAL HEAD (OR ILL. ARM OR SECTOR IF HEAD=MAXIMUM HEAD)
*SM[SECNE,IP[200S]];	*34 SECTOR # NEXT SECTOR OR ARM # CURRENT ARM

*DATA TRANSFER SOFTWARE DETECTED ERRORS
*MP[KSTRT,36];	*COMMAND NOT FINISHED (CLEARED WHEN DONE)
*MP[DCHKE,37];	*DATA CHECKSUM ERROR
*MP[UNCHKE,40];	*UN CHECKSUM ERROR

*MP[UNNE,41];	*UN ON DISK # UN IN COMMAND
*MP[HCHKE,42];	*HEADER CHECKSUM ERROR
*MP[HDNE,43];	*HEADER DOESN'T = DISK ADDRESS OF COMMAND

PM[SWERRS,10000 000037]; *RO, DCHKE, UNCHKE, UNNE, HCHKE, HDNE
SM[HCHKE,IP[2S]];  ***DEPARAMETERIZED TO MERGE CONSTANTS
SM[UNNE,IP[4S]];  ***
SM[UNCHKE,IP[10S]];  ***
SM[DCHKE,IP[20S]];  ***

*KSET← AND KCSET← BUS INTERPRETATION
MP[ENS,0];	*ENABLE/DISABLE SECTOR INTERRUPTS ON UI CHNL 12
MP[LDCYL,1];	*LOAD CYLINDER REG. FROM B[17,27]
MP[LDHD,2];	*LOAD HEAD REG. FROM B[19,23]
MP[DOCOM,3];	*DO COMMAND ON DRIVE BUS
MP[ENRI,4];	*ENABLE/DISABLE READ INTERRUPTS ON UI CHNL 4
MP[ENWI,5];	*ENABLE/DISABLE WRITE INTERRUPTS ON UI CHNL 5
MP[ENDI,6];	*ENABLE/DISABLE DISPATCH INTERRUPTS ON UI CHNL 6
*BITS 7, 10, 11, 12, AND 13 ARE THE SAME AS KSEC, PDTL, CDTL, SOVF,
*AND DESEL IN KSTAT AND SERVE TO RESET THESE ERRORS (EXCEPT THAT A 1 IN
*DESEL DESELECTS THE UNIT)
%BITS 17-27 ARE THE DISK DRIVE BUS INTERPRETED AS FOLLOWS BY KSET←:
    23-27 ARE THE HEAD ADDRESS ON SET HEAD
    17-27 ARE THE CYLINDER NO. ON SET CYLINDER REG.
CONTROL TAG:
%
MP[WRG,20];	*WRITE GATE
MP[RDG,21];	*READ GATE
MP[SEEK,22];	*SEEK START
MP[RHD,23];	*RESET HEAD REG.
MP[ERS,24];	*ERASE GATE
MP[SEHD,25];	*SELECT HEAD
MP[RECAL,26];	*RECALIBRATE ARMS TO CYLINDER 0
*MP[HDAD,27];	*HEAD ADVANCE (NOT USED)

*AT THE BEGINNING OF A SECTOR, IF THERE IS A COMMAND READY TO DO, IT
*WILL BE DONE UNLESS (USTATE U KSTAT) AND (NOSKER)#0.
MC[NOSKER,HWERRS,UNRDY];	*CONDITIONS PREVENTING A SEEK
SM[KSTRT,IP[40S]];  ***
SV[NOTCNRDY,773777 777777];
MC[HWERRS,HWERRS]; *HARDWARE ERRORS
MC[DERRS,SWERRS,KRERRS,HWERRS];

*ARGUMENTS FOR KSET← AND KCSET←
MC[SECERRS,ENS,DOCOM,RHD,KSEC,KRERRS]; *RESET ERRORS OF LAST TRANSFER (KNEWCOMM)
MC[SETHWI,ENS,LDHD,ENDI]; *LOAD HEAD REG. AND START DISPATCH INTS (KNEWCOMM)
MC[SLHEAD,ENS,DOCOM,ENDI,SEHD]; *SELECT HEAD AND DISPATCH INTS (KNEWCOMM)

MC[ENS&ENDI,ENS,ENDI];  *CHANGE TO DISPATCH INTS (KCSET←, CHANNEL 11)
MC[ENS&ENRI,ENS,ENRI];  *CHANGE TO READ INTS (KCSET←, CHANNEL 13)
MC[ENS&ENWI,ENS,ENWI];  *CHANGE TO WRITE INTS (KCSET←, CHANNEL 12)
MC[KSTOP,DOCOM,ENS,ENDI,SEHD];          *STOP READING
MC[KWSTOP,DOCOM,ERS,ENS,ENDI,SEHD];     *STOP WRITING (CONTINUE ERASING)
MC[KEOS,DOCOM,ENS];                     *STOP EVERYTING AND DONE
MC[KRDGO,RDG,ENDI,DOCOM,ENS,SEHD];      *KSET←START READING AND DISPATCH INTS
MC[KWGO,WRG,ERS,DOCOM,ENS,ENDI,SEHD];   *KSET←START WRITING AND ERASING

MC[KOFFL,DOCOM,RECAL,RHD,KSEC,KRERRS];	*RECALIBRATE
MC[LOADC,LDCYL,KRERRS,ENS];
MC[SEEK,DOCOM,ENS,SEEK];
MC[KOFFX,DOCOM,RHD,KSEC,KRERRS];	*SAME AS KOFFL WITHOUT RECALIBRATE
SM[DESEL,IP[100 000000S]];	*DESELECT

%THE DISK MICROCODE IS DIVIDED INTO TWO PARTS:
   1) MICROINTERRUPT COROUTINES WHICH DRIVE A DISK THROUGH A DATA OPERATION
USING THE DATA IN THE 20-WORD BLOCK OF S REGISTERS AS STATE
INFORMATION.
   2) JMC MICROCODE TO SETUP COMMANDS GENERATED BY A PDP-10 PROGRAM.
***CAVEATS FOR INTERRUPT ROUTINES:
   1) FRZBALUBC, BUS B.C.'S, PQ RCY [44-Y] DON'T WORK
   2) DON'T USE STORAGE USED BY NON-INTERRUPT LEVEL ROUTINES (E.G., F REGISTER)
EXCEPT FOR STORAGE WHICH IS MANIPULATED WITH THE INTERRUPT SYSTEM OFF.
   3) THE VALUE IN P IS PRESERVED ACROSS MICROINSTRUCTIONS ONLY SO LONG AS
RCYQQ, RCY0Q, OR RCYNOTLUQ ISN'T USED.  WHEN ONE OF THESE FUNCTIONS OCCURS,
THE ASSEMBLER SUBSTITUTES P←P1 FOR PQ RCY [0] AS THE DEFAULT LOADING RULE FOR P.
   4) NEITHER THE INSTRUCTION CONTAINING KWDATA (OR KRDATA) NOR THE ONE AFTER
IT SHOULD INVOKE THE PROCESSOR'S STOP LOGIC.
   5) KUNIT CANNOT BE READ IN THE INSTRUCTION AFTER IT IS WRITTEN, NOR
RELIED ON TO ADDRESS THE CORRECT DISK UNIT.  HENCE, NON-INTERRUPT
ROUTINE SHOULD INHINT BEFORE READING KSTAT.
   6) KSET←, KCSET←, KWDATA, KRDATA VERBOTEN WITH IRETURN AT INTERRUPT LEVEL
AND MUST BE INHINTED AT NON-INTERRUPT LEVEL (SO THAT KUNIT WILL BE THE SAME ON
THE NEXT MICROINSTRUCTION)
   7) STOP LOGIC MUST NOT BE INVOKED WITH IRETURN.
%
M[IRETURN,(RETURN, P←P1, Q←LINT, IRET)];

RVN[RINT]; LVN[LINT]; LVN[LINT1];

IM[XILC,5]; TARGET[XILC];
	X←YKPTR←KUNIT, LINT←Q, CALL[KSECTR]; *SECTOR INTERRUPT
IM[XILC,11];
	X←YKPTR←KUNIT, LINT←Q, Q←10 000001R, CALL[KDISP]; *DISPATCH
	X←YKPTR←KUNIT, LINT←Q, P←10 000001R, CALL[WRDAT]; *WRITE
	X←YKPTR←KUNIT, LINT←Q, P←10 000001R, CALL[RDATA]; *READ

TARGET[ILC];


*DISK INTERRUPT ROUTINES

%"RDATA" DOES A BLOCK TRANSFER FROM THE DISK TO MAIN MEMORY SPECIFIED BY
THE NEGATIVE WORD COUNT AND STARTING ADDRESS [WCSA].  A DISPATCH TO
[WIDISP] IS MADE AFTER COMPLETION OF THE TRANSFER WITH [CMMA] IN P.
(T = 6+W WAIT (+3 ON LAST))
%
RDATA:	Q←KWRITE←WCSA;
	Q←P+Q, P←KRDATA;
	WCSA←Q, Q←(RX) RCY 1, P←P, DGOTO[ENDC,ALU>=0];  *NOTE P←P REQUIRED
SCHKS:	Q←P+Q, P←KMDRL;
WRDTX:	RX←P+Q, IRETURN;

%"WRDAT" DOES A BLOCK TRANSFER FROM MAIN MEMORY TO THE DISK IN THE SAME
FASHION AS "RDATA" GOING THE OTHER DIRECTION. (T = 6+R+(3 ON LAST))
%
WRDAT:	Q←KREAD←WCSA, CALL[QPQ];
	WCSA←Q, AQ;
	P←KMDRL, Q←(RX) RCY 1, AQ;
	Q←P+Q, P←KWDATA, GOTO[WRDTX,ALU<0];

ENDC:	RX←P+Q, NPC←WIDISP;
	P←CMMA;


*"KDISP" DISPATCHES TO [WIDISP] WITH [WCSA] IN P, 10 000001 IN Q
KDISP:	NPC←WIDISP;             *GENERAL WORD DISPATCH
	P←WCSA;

*RANDOM FINISHING ROUTINES
WD1:	WCSA←KMDR, GOTO[INTRET]; *CANNOT INVOKE STOP LOGIC WITH IRETURN
URET:	USTATE←Q, IRETURN;
INTR1:	WCSA←Q, IRETURN;

*"SETWC" PUTS A WORD COUNT IN P[37,43] INTO WCSA AND IRETURNS
SETWC:	Q←P, PREIRET, GOTO[INTR1];

*WAIT UNTIL CONTR'R READY TO DO KSET← (UNIT MUST HAVE BEEN STABLE 1 CYCLE)
*! MAXC1 ONLY
KRDYW:	P←(KSTAT) U (NOTCNRDY), INHINT;
*!
*~ MAXC2 ONLY
KRDYW:	P←KSTAT, INHINT;
KRDYW1:	P←(P) U (NOTCNRDY), INHINT;
*~
	NOT P, DGOTO[KRDYW];
	INHINT, RETURN[ALU#0];

*ROUTINE WHICH ACCEPTS UNIT NO. IN X AND SETS THE INTERRUPT REQUEST FOR THE
*CURRENT UNIT IN "MICINTS".  "CMMA" IS PUT IN KMDR, "RINT" LEFT IN P
*NOTE HOW, SINCE [X] = UNIT NO., 2↑[X] = XMASK[-1] = THE INT.REQ. BIT
KMIMASK: KMDR←CMMA, P←A1, XMASK;
	Q←(P+1) U (MICINTS), GOTO[KPIS1]; *IN "IOCOM"

PFKP:	P←KPARAM, RETURN;

KAP:	P←KA, AQ, RETURN;

KWRR:	KWDATA, RETURN;


%SECTOR INTERRUPTS ARE SERVICED HERE WITHIN TWO WORD TIMES OF THE REQUEST.
					1 FOR "INTRET"
TIMING = 13 + (1 IF INDEX SECTOR) +	6 FOR "KSERV" (W+1)
					16 FOR "CSR" OR "CSW"
%
KSECTR:	KWRITE←P←KBLK; *WRITE STATUS FOR CLEANUP AT [KBLK]
*! MAXC1 ONLY
	KMDR←Q←(KSTAT) U (USTATE), LINT1←P+1, CALL[KRDYW];
*!
*~ MAXC2 ONLY
	P←KSTAT, LINT1←P+1;
*MUST CALL KRDYW SINCE SEEK OR RECALIBRATE MAY BE INTERRUPTED
	KMDR←Q←(P) U (USTATE), CALL[KRDYW1];
*~
*CLEAR HW ERRORS, HEAD REG., SEC. INTREQ.
	KSET←SECERRS, KNEWCOMM, RINT←Q, CALL[KAP];
*CANNOT BRANCH IN PRECEDING INSTRUCTION BECAUSE BUS B.C.'S DON'T WORK
	Q←KSTRT, GOTO[.+3,ALU>=0];
*HERE ON INDEX SECTOR.  SECTOR←0 IN KA
	P←(NOT P) U (7S);
	USTATE←Q, Q←NOT P, GOTO[.+2];
*HERE ON NON-INDEX SECTOR.  INCREMENT SECTOR NO.
	USTATE←Q, Q←P+1;  *KNOW SECTOR FIELD IS [41,43]
%NOW DISPATCH TO ONE OF THE SETUP ROUTINES WITH OLD STATUS IN KMDR, Q,
AND RINT, AND WITH KBLK+1 IN P.  DISPATCH ROUTINES ARE "KSERV", "INTRET",
"CSR", AND "CSW"
%
	P←NPC←NSDISP;
KSEC2:	KA←Q, P←LINT1, Q←P;


*"KSERV" GENERATES CLEANUP/SETUP INT. REQ. BUT DOESN'T START NEW COMMAND.
*HAVE KBLK+1 IN P
KSERV:	KWRITE←P, SETF[MICRO], CALL[KMIMASK];
	CMMA←NULL, PREIRET;
KSUFIN:	NMMA←NULL, IRETURN;

*"CSTRT" SETS UP FOR READ OR WRITE HEADER AND IS JUMPED TO BY "CSR" OR "CSW".
*P HAS KBLK+1, Q HAS 6 FOUR-BIT DISPATCHES FOR "SDISP"
CSTRT:	SDISP←Q;
*! MAXC1 ONLY
	P←(KSTAT) U (USTATE), Q←P;
*!
*~ MAXC2 ONLY
	Q←KSTAT;
	P←(Q) U (USTATE), Q←P;
*~
	KWRITE←Q, RINT←P, SETF[MICRO], CALL[KMIMASK];
*KMIMASK RETURNS WITH "RINT" IN P (= OLD STATUS)
	Q←NOSKER, DGOTO[KSERV];
	NSDISP←NPC, P AND Q, GOTO[.+1];
*DON'T START IF STILL SEEKING OR HARDWARE ERRORS
	Q←NMMA, DGOTO[KSUFIN,ALU#0];
	CMMA←Q, CALL[KWRR];
	Q←NKA, P←777777R;
**THE INSTRUCTION BELOW IS SUPPOSED TO HAVE KNEWCOMM BUT SINCE SETHWI IS PUT
**ON THE BUS BY F2=READS=KNEWCOMM, THIS DOESN'T HAVE TO BE DONE EXPLICITLY.
*KRDYW ISN'T NECESSARY BEFORE HERE EITHER SINCE 18 MICROINSTRUCTIONS
*HAVE ELAPSED AND THAT IS LONG ENOUGH
	KSET←(P AND Q) U (SETHWI);
	CKA←Q, PREIRET, GOTO[KSUFIN];

%"SELHD" IS ENTERED FROM "CSR" AND "CSW" AT THE FIRST WORD INTERRUPT
OF THE SECTOR.  THE HEAD HAS PREVIOUSLY BEEN "SET" DURING THE SECTOR
INTERRUPT ROUTINE AND IS "SELECTED" BY "SELHD".
%
SELHD:	KMDR←P;
	WCSA←KWDATA, CALL[KRDYW];
	KSET←SLHEAD, KNEWCOMM, PREIRET, GOTO[INTRET];

*DISPATCH HERE FROM "KSECTR1" TO READ HEADER
CSR:	WIDISP←NPC, GOTO[CSTRT];

*FIRST WORD INT. HERE TO SELECT THE HEAD (T=12)
	P←KPARAM;
	PQ RCY [37], AMASK[5], WIDISP←NPC, GOTO[SELHD];

*SECOND WORD INT. HERE (T=6)
	KMDRL←KMDR←NULL, DGOTO[RR1];
	KWDATA, DGOTO[RR];


*DISPATCH HERE FROM "KSECTR1" TO WRITE HEADER
CSW:	WIDISP←NPC, GOTO[CSTRT];

*FIRST WORD INT. HERE TO SELECT THE HEAD (T=12)
	P←KPARAM;
	PQ RCY [32], AMASK[5], WIDISP←NPC, GOTO[SELHD];

*2ND WORD INT. HERE (WASTE TIME FOR HEAD SELECTION TO SETTLE) (T=6)
	KMDRL←KMDR←NULL, DGOTO[RR1];
	KWDATA, DGOTO[WW];

KRX:	KSET←KRDGO, PREIRET, GOTO[RR1];

RSETUP:	PQ RCY [20], AMASK[5], WIDISP←NPC, GOTO[SETWC];

*NO-OP UNTIL WORD COUNT IN "WCSA" EXPIRES, THEN READ-SYNC, THEN TAKE
*ACTION DISPATCH IN SDISP[30,43].  -WC WAS PREVIOUSLY PUT IN "WCSA" BY
*RECORD SETUP ROUTINE. (T = 6)
RR:	Q←P-1, KMDRL←KMDR←NULL, DGOTO[KRX];
KWX:	KWDATA, GOTO[INTR1,ALU>0];
RR1:	WIDISP←NPC, IRETURN;

*HERE FOR GARBAGE WORD ON READS, FOR SYNC CHAR ON WRITES (T=9 + ACTION)
	Q←P-1, KMDRL←KMDR←17S, GOTO[XDISP];


WSETUP:
*~ MAXC2 ONLY
	Q←(Q) U (USTATE);
*~
	P←DERRS, A0, DGOTO[.+1];
	P AND Q, P←KPARAM, GOTO[DONE,ALU#0];
	PQ RCY [13], AMASK[5], WIDISP←NPC, GOTO[SETWC];

*WRITE ZEROES UNTIL THE WORD COUNT IN WCSA EXPIRES, THEN WRITE THE SYNC
*CHARACTER, AND FINALLY TAKE THE ACTION DISPATCH IN SDISP
**DON'T BOTHER WITH "KRDYW1" (T=8)
WW:	KMDRL←KMDR←NULL, Q←P-1, CALL[KWRR];
	KSET←KWGO, DGOTO[WW1];    *START WRITING AND ERASING
	WIDISP←NPC, PREIRET, GOTO[INTR1];


%"RCSUM" COMPARES CHECKSUMS FOR ANY RECORD.  IT ACCEPTS AN
ERROR FLAG IN Q WHICH IS LEFT IN USTATE ON A CHECKSUM ERROR.
*** MUST NOT INVOKE STOP LOGIC WITH KRDATA (T = 10 + 1 ON ERROR)
%
RCSUM1:	P←RX, Q←KRDATA, LINT1←Q;
	P#Q, Q←KMDRL, P←1R;  *TAG BITS = 1 IN CHECKSUM
	P#Q, KSET←KSTOP, P←LINT1, DGOTO[URET,ALU#0];
CURET:	Q←(USTATE) U (P), PREIRET, GOTO[URET,ALU#0];
INTRET:	IRETURN;

RCSUM:	WIDISP←NPC, GOTO[RCSUM1];

*NOW DO ONE WORD OF NO-OP AND TAKE POSTLIM DISPATCH (T=9 + ACTION)
	KMDRL←KMDR←NULL, GOTO[XDISP];


*FINISHED! (T=10)
DONE:	P←402000 000040S; *CLEAR INDEX AND SECTOR CONDITIONS AND KSTRT
	Q←NOT P AND Q, KSET←KEOS, PREIRET, GOTO[URET];

*TERMINATE WRITING (T = 11)
WDONE:	WIDISP←NPC, PREIRET, GOTO[INTR1];

*MUST WRITE THREE WORDS OF ZEROES HERE TO ENSURE THAT ONE FULL WORD OF
*ZEROES IS WRITTEN AFTER THE CHECKSUM BEFORE TURNING OFF WRITE GATE
*(T=6+5 ON LAST)
	Q←P-1, KMDR←KMDRL←NULL;
	KWDATA, GOTO[INTR1,ALU>0];
	KSET←KWSTOP, CALL[PFKP];    *STOP WRITING BUT CONTINUE ERASING
*GET THE PARAMETER FOR THIS UNIT WHICH IS THE NO. WORDS TO ERASE
	PQ RCY [25], AMASK[5], WIDISP←NPC, GOTO[SETWC];

*HERE DURING ERASE TURN-OFF WORDS (T=6+3 ON LAST)
	Q←P-1, KMDR←KMDRL←NULL, DGOTO[INTR1];
	KWDATA, GOTO[WDONE1,ALU<=0];

%"WCON" SETS UP TO WRITE THE NEXT RECORD.  IT IS ASSUMED THE PRELIMINARIES
FOR ALL RECORDS OTHER THAN THE HEADER RECORD ARE THE SAME AND THAT
TRANSITION FROM WRITING ONE RECORD TO READING THE NEXT IS VERBOTEN.
%
WCON:	PQ RCY [6], AMASK[5], WIDISP←NPC, GOTO[SETWC];

*PREAMBLE WRITING USES THE LOOP BELOW (T = 6)
WW1:	Q←P-1, KMDRL←KMDR←NULL, GOTO[KWX];

*(T=12)
RHDR:	KWRITE←P+1;
	P←KRDATA;
	Q←KMDRL;
	RX←P+Q, Q←CKA;
	P#Q, P←1R, WIDISP←NPC, GOTO[CURET]; *HDNE=1

*NOW READ THE CHECKSUM FOR THE HEADER RECORD (T=10+1 ON ERROR)
	KMDR←Q←HCHKE, GOTO[RCSUM];


*"CUN" COMPARES UN WORDS 0-1 WITH WORDS 2-3 OF COMMAND AND READS UN
*WORDS 2-3 INTO COMMAND 4-5.
CUN:	Q←P+Q, WIDISP←NPC, PREIRET, GOTO[INTR1];

*HERE TWICE TO COMPARE FIRST TWO WORDS OF UN.  (T = 11+R)
	Q←P+Q, KREAD←WCSA, P←7777 777777R, BAMASK[26];
	WCSA←Q, Q←NOT P OR Q, GOTO[CUN1,ALU<0];
	WCSA←Q;
	KCSET←ENS&ENRI;
	WIDISP←NPC, GOTO[CUN1];

*HERE FOR UN CHECKSUM (T = 10+1 ON ERROR)
UNCSUM:	KMDR←Q←UNCHKE, GOTO[RCSUM];

CUN1:	P←KMDRL, Q←(RX) RCY 1;
	Q←P+Q, P←KMDR;
	RX←P+Q, Q←KRDATA;
	P#Q, P←UNNE, GOTO[CURET];

RDSTRT:	KCSET←ENS&ENRI, PREIRET, GOTO[INTR1];

*"RUN" READS THE 4 WORDS OF UN INTO WORDS 3 TO 6 OF THE COMMAND
RUN:	Q←P+Q, WIDISP←NPC, GOTO[RDSTRT];

*HERE AFTER READING THE UN (T = 3)
	KCSET←ENS&ENDI, PREIRET, DGOTO[UNCSUM];
	WIDISP←NPC, IRETURN;

%"RDT" READS THE FIRST TWO WORDS OF THE DATA RECORD INTO COMMAND
WORDS 6 AND 7, THEN PICKS UP THE -WC AND MAIN MEMORY ADDRESS IN WORD
10 OF THE COMMAND AND READS THE SPECIFIED WORD COUNT FROM THE DISK
INTO THE CORE AREA.
%
RDT:	Q←P+Q, WIDISP←NPC, GOTO[RDSTRT];

*HERE AFTER READING PREDATA WORDS WITH CMMA+10 IN WCSA (T = 3+R)
	KREAD←WCSA;
	WIDISP←NPC, PREIRET, GOTO[WD1];

*HERE AFTER LAST WORD OF DATA RECORD (T=9)
	KCSET←ENS&ENDI, PREIRET;
	WIDISP←NPC, IRETURN;

	KMDR←Q←DCHKE, GOTO[RCSUM]; *(T = 10 + 1 ON ERROR)

*SCAN DATA TO SEE IF CHECKSUM AGREES
CHKDT:	Q←P+Q, WIDISP←NPC, PREIRET, GOTO[INTR1];

*(T = 8 + 1 ON LAST)
	KMDR←NULL, Q←P+Q;	*INVOKE STOP LOGIC BEFORE KRDATA
	WCSA←Q, GOTO[CHKDT1,ALU<0];
	WIDISP←NPC, GOTO[CHKDT1];

	KMDR←Q←DCHKE, GOTO[RCSUM];

CHKDT1:	Q←(RX) RCY 1, P←KRDATA, GOTO[SCHKS];

%ROUTINES BELOW ARE THE WRITE "ACTION" ROUTINES WHICH ARE ENTERED
BY THE ACTION DISPATCH IN "WW"
%

WUN:	Q←P+Q, WIDISP←NPC, GOTO[WD2];

%"WCSUM" SWITCHES TO DISPATCH INTERRUPTS, WRITES THE CHECKSUM IN "RX"
WITH THE VALUE 1 IN THE TAG FIELD, AND TAKES THE POSTLIM DISPATCH (T=5)
%
WCSUM:	KCSET←ENS&ENDI, PREIRET;
WCSUM0:	WIDISP←NPC, IRETURN;

*WRITE CHECKSUM (T = 4)
	Q←RX, KMDRL←1S;
	KMDR←Q, GOTO[XDISP];

WD2:	KCSET←ENS&ENWI, PREIRET, GOTO[INTR1];

*WRITE DATA
WDT:	Q←P+Q, WIDISP←NPC, GOTO[WD2];

*COME HERE AFTER WRITING THE PREDATA WORDS WITH CMMA+10 IN WCSA (T=9+2R)
	KREAD←WCSA, DGOTO[WCSUM];
	WIDISP←NPC, GOTO[WD1];

*DISPATCH TABLE TO NEXT TASK.  TIMING BEGINS AT THE INSTR. WITH GOTO[XDISP].
E[ADD[LASTOK,20]];	*MUST START AT BOUNDARY OF 20
DISPT:	P←KPARAM, GOTO[RSETUP];		*0  READ SETUP (T = 13)
*! MAXC1 ONLY
	Q←(KSTAT) U (USTATE), GOTO[WSETUP];
*!
*~ MAXC2 ONLY
	Q←KSTAT, GOTO[WSETUP];		*1  WRITE SETUP (T = 17)
*~
WDONE1:	Q←USTATE, GOTO[DONE];		*2  DONE (T = 13)
	Q←3S, GOTO[WDONE];		*3  WRITE DONE (T = 12)
	P←KPARAM, GOTO[WCON];		*4  CONTINUE WRITING (T = 13)
	Q←777740 000002S, GOTO[RUN];	*5  READ UN (T = 13)
	Q←777760 000002S, GOTO[CUN];	*6  COMPARE UN (T = 12)
	Q←777760 000006S, GOTO[RDT];	*7  READ DATA (T = 13)
	WIDISP←NPC, IRETURN;		*10  READ HEADER (T = 10)
	P←CMMA, GOTO[RHDR];
	Q←777740 000002S, GOTO[WUN];	*12  WRITE UN (T = 13)
	Q←777760 000006S, GOTO[WDT];	*13  WRITE DATA (T = 13)
	Q←767760 000000S, GOTO[CHKDT];	*14  CHECK DATA (T = 12)
	WIDISP←NPC, IRETURN;		*15  WRITE HEADER (T = 10)
*CKA[0,11] CONTAIN "KPREH" (T = 7)
	P←KMDR←CKA, DGOTO[WCSUM0];
	RX←P, KMDRL←NULL, CALL[KWRR];

TARGET[ILC];

*PICK OFF THE LEFT 4 BITS OF "SDISP" AS A DISPATCH INTO THE "DISPT"
*TABLE AND CYCLE "SDISP" LEFT 4, ZERO CHECKSUM, P←CMMA.
XDISP:	P←Q←SDISP, RX←A0;
	PQ RCY [40], Q←17L, KWDATA, DGOTO[DISPT];
	B←(P AND Q) U (NPC), NPC←B, GOTO[.+1];
	Q←P, P←CMMA, CALL[.+1];
	SDISP←Q, RETURN;