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;