ER[JMC]; *I = 191 TARGET[ILC]; *! MAXC1 ONLY SV[XPARITY,2160]; *DISK INTERRUPT CHANNELS *! *~ MAXC2 ONLY SV[XPARITY,200 002160]; *DISK INTERRUPTS & PARITY (700 002160 DOESN'T WORK) *~ %FOR THE IN-OUT RESET ROUTINE, "KRESET" TURNS OFF ALL THE DISK UNITS BY "KOFF" (BUT DOES NOT RECALIBRATE). I = 4 % DECX, RETURN[X<0]; KRESET: KUNIT_X, DGOTO[.-1], LTEMP_A1; CALL[.+1,X>=0], YKPTR_X, INHINT; KSET_KOFFX, KNEWCOMM, INHINT, GOTO[.+3]; **NO KRDYW %"KOFF" IS A JMC WHICH: 1. TURNS OFF SECTOR MICROINTERRUPTS, DISMISSES WORD INT., CLEARS ERRORS, AND RECALIBRATES UNIT 2. CLEARS THE INTERRUPT REQUEST BIT IN MICINTS FOR THIS UNIT 3. MAXKA_NULL (SO THAT "KGO" AND "KSEEK" WILL BE REJECTED) 4. WIDISP_CRASH (SO THAT FALSE DISPATCH INTS WILL CRASH) 5. WCSA_NULL (SO THAT FALSE READ AND WRITE INTS WILL WRITE A HARMLESS LOCATION AND CRASH) 6. NSDISP_NULL (SO THAT FALSE SECTOR INTS WILL CRASH) 7. DESELECT THE UNIT AT CALL: KUNIT_UNIT NO. HAS BEEN DONE I = 10 % KOFF: X_KUNIT; KSET_KOFFL, KNEWCOMM, INHINT; ***NO KRDYW P_LTEMP, AMASK[30], MAXKA_KMDR_NULL, DGOTO[SCRASH]; WIDISP_NPC, P_P+1, INHINT, GOTO[.+1]; Q_KSTAT, A1, DGOTO[.+1]; *CHECK "DESEL" TO SEE IF A UNIT IS REALLY THERE, ELSE "KRDYW" WILL HANG P AND Q, WCSA_NULL, INHINT, CALL[KRDYW,ALU=0]; KSET_DESEL, KNEWCOMM, INHINT; P_A1, XMASK, INHINT, Q_MICINTS; P_P+1, KA_KWDATA, DGOTO[SCRASH]; Q_NOT P AND Q, INHINT, NSDISP_NPC, GOTO[KPIS1]; %"PKSER" IS A SUBROUTINE TO LOOK AT EACH OF THE DISK UNITS AND DECIDE ON WHICH UNIT A PARTICULAR DISK PACK IS MOUNTED. AT CALL: PACK NO. IN RTEMP[12,21], 7 IN X. AT RETURN: Y POINTS TO THE 16-WORD UNIT ARRAY FOR THE PACK AND KUNIT POINTS TO THE UNIT, MAXKA IN Q, P PRESERVED. IF THE PACK IS OFF-LINE, THE ILLEGAL PACK BIT IS RETURNED IN AC, AND AN IMMEDIATE EXIT IS MADE. I = 5 % PKSER: LPGRT_P, YKPTR_KUNIT_X, P_777777R; Q_MAXKA, P_NOT P, BAMASK[32]; Q_P AND Q, P_RTEMP, DECX, DGOTO[QTOAC,X<0]; P#Q, Q_ILLPK, DGOTO[PKSER]; RETURN[ALU=0], P_LPGRT, Q_MAXKA; %"KON" IS ENTERED WITH THE MAXIMUM LEGAL DISK ADDRESS IN AC FOR UNIT E. IT RESETS THAT UNIT AND PUTS IT ON-LINE. IF THE UNIT IS ALREADY ON LINE IT SERVES TO RESET THE UNIT AS FOLLOWS: 1. NSDISP_INTRET; 2. ENABLE SECTOR INTERRUPTS AND CLEAR ERRORS 3. MAXKA_Q 4. CMMA_NMMA_USTATE_0 5. ENABLE THE DISK MICROINTERRUPT CHANNELS 6. KA_PACK,,7770 KBLK AND KPARAM SHOULD BE SET IN ADVANCE BY THE SLOC JMC THERE ARE NO ERRORS. KON ALWAYS SKIPS. I = 7 % *YKPTR_KUNIT_E WAS DONE BY JMC DISPATCH INSTRUCTION KON: MAXKA_Q, P_LTEMP, AMASK[14], DGOTO[INTRET]; Q_P OR Q, NSDISP_NPC, INHINT, GOTO[.+1]; KSET_SECERRS, KNEWCOMM, INHINT; ARM_XPARITY, INHINT; CMMA_KMDR_NULL, P_LTEMP, AMASK[3], DGOTO[KSEC2]; USTATE_KWDATA, Q_NOT P AND Q, DGOTO[.+1]; NMMA_NULL, GOTO[ASKIP]; %"KNOPDP" TURNS OFF THE PDP-10 PORTION OF DISK INTERRUPTS ON THE PACK SELECTED BY AC. ERROR RETURN IF THE PACK NUMBER ISN'T FOUND OR UNIT BUSY. OTHERWISE, NSDISP_@INTRET AND SKIP RETURN. AT CALL: PACK NUMBER IN Q, 377 000000 IN P I = 5 % KNOPDP: RTEMP_P AND Q, X_7S, CALL[PKSER]; MDR_NMMA, DGOTO[KNOP1]; P_(MDR) U (CMMA), DGOTO[INTRET]; CRJ: Q_ILLOP; *COMMAND REJECT *! MAXC 1 ONLY ILLRET: Q_(KSTAT) U (Q) U (USTATE), GOTO[QTOAC]; *! *~ MAXC 2 ONLY ILLRET: P_KSTAT; Q_(P OR Q) U (USTATE), GOTO[QTOAC]; *~ %"KSEEK" IS USED TO INITIATE A SEEK AND ENABLE PDP-10 INTERRUPTS. ERROR RETURNS WITH STATUS IN AC ARE GIVEN FOR: 1. PACK NO. NOT ON-LINE 2. ILLEGAL ARM POSITION 3. SEEKING TO A DIFFERENT ARM POSITION ALREADY 4. HARDWARE FAILURE OTHERWISE, A SKIP RETURN IS GIVEN. AT ENTRY: DISK ADDRESS (PACK AND ARM) IN Q AND IN AC, 377 000000 IN P I = 21 % KSEEK1: P_(MDR) U (CMMA), DGOTO[KSERV]; KNOP1: P, Q_NPC, GOTO[.+1]; P_PC, GOTO[ASKIP1,ALU#0]; *BUSY? NSDASK: NSDISP_Q, GOTO[ASKIP]; KSEEK: RTEMP_P AND Q, P_7770S; LTEMP_P AND Q, X_7S, CALL[PKSER]; *LTEMP_NEW ARM POSITION RTEMP_P AND Q, Q_KA; *RTEMP_MAX. ARM POS. P_P AND Q, Q_LTEMP, MDR_NMMA; *P_CURRENT ARM POS. P#Q, P_RTEMP,INHINT; *SEEK TO CURRENT POS. ENABLES PDP-10 INTERRUPTS IFF THEY ARE OFF P-Q, PQ RCY [33], Q_KSTAT, GOTO[KSEEK1,ALU=0]; *CHECK FOR LEGAL ARM POSITION GOTO[.+2,ALU>=0], RPGRT2_P, P_NOSKER; Q_ILLARM, GOTO[ILLRET]; *CHECK FOR HARDWARE ERRORS OR SEEKING P AND Q, P_(MDR) U (CMMA); P, P_KA, INHINT, GOTO[ILLRET,ALU#0]; *SECTOR INTERRUPTS TABOO WHILE UPDATING KA USTATE_NULL, INHINT, GOTO[CRJ,ALU#0]; Q_(NOT P) U (7770S), P_LTEMP, DGOTO[KSERV]; Q_P OR NOT Q, P_RPGRT2, NSDISP_NPC, GOTO[.+1], INHINT; KA_Q, Q_P, CALL[KRDYW], INHINT; *LOAD CYLINDER REGISTER (MUST CALL KRDYW BECAUSE OF SECTOR INTS) *(KNOW (LOADC) WILL BE F1 = READS WHICH = KNEWCOMM) *USE "FSET" PURELY AS A GARBAGE ROUTINE TO ALLOW INTERRUPTS WHILE WAITING KSET_(Q) U (LOADC), INHINT, CALL[FSET]; INHINT, CALL[KRDYW]; KSET_SEEK, KNEWCOMM, INHINT, GOTO[ASKIP]; %"KGO" IS USED TO INITIATE ALL DATA TRANSFERS. IT CAN BE ISSUED AT ANY TIME AND NOTHING BAD WILL HAPPEN IF A SECTOR MICROINTERRUPT OCCURS IN MEDIAS RES. THE ADDRESS OF THE 9-WORD COMMAND BLOCK IS IN P. ERROR RETURNS WITH STATUS IN AC ARE GIVEN FOR: 1. MAIN MEMORY ADDRESS < 20 2. PACK NOT ON-LINE 3. ARM # CURRENT ARM POSITION OR SECTOR # NEXT SECTOR 4. ILLEGAL HEAD SELECT 5. ILLEGAL OPERATION # AT CALL: Q CONTAINS VIRTUAL ADDRESS OF A DISK DATA TRANSFER COMMAND FOR WHICH MAPVA_P_AQ, SAMASK[22] HAS JUST BEEN DONE. A SKIP RETURN IS GIVEN IF THE COMMAND IS ACCEPTED. EACH COMMAND DISPATCH WORD CONTAINS AN INITIAL COMMAND DISPATCH IN B[30,43] AND 6 4-BIT BYTES IN B[0,27] CONTROLLING THE PATH OF THE DISK FINITE STATE MACHINE (SEE "DISPT" TABLE IN KINT) I = 13 % F[FL,0,3]; F[FM,4,7]; F[FN,10,13]; F[FO,14,17]; F[FP,20,23]; F[FQ,24,27]; M[KOP,XSLC[E1[#1]FL[#2]FM[#3]FN[#4]FO[#5]FP[#6]FQ[#7]]]; SM[XSLC,IP[KCOMS]]; *BEGINNING OF COMMAND DISPATCH TABLE (10 WORDS) KOP[CSW,15,3]; *WRITE HEADER KOP[CSW,15,4,12,4,13,3]; *WRITE, WRITE, WRITE KOP[CSR,10,0,5,2]; *READ, READ KOP[CSR,10,1,12,3]; *READ, WRITE KOP[CSR,10,0,5,0,7,2]; *READ, READ, READ KOP[CSR,10,0,6,0,7,2]; *READ, COMPARE, READ KOP[CSR,10,0,5,1,13,3]; *READ, READ, WRITE KOP[CSR,10,0,6,1,13,3]; *READ, COMPARE, WRITE KOP[CSR,10,1,12,4,13,3];*READ, WRITE, WRITE KOP[CSR,10,0,6,0,14,2]; *READ, COMPARE, CHECK SV[KPREH,777400 000000]; *LEADING BITS OF DISK HEADER ***ERROR IF NOT RESIDENT PAGE, BUT NOT NECESSARILY IN MAP KGO: CALL[RQARG]; *Q_COMMAND AND DISK ADDRESS Q_(Q) U (KPREH), QQ RCY [33], DGOTO[KCOMS]; RPGRT2_Q, Q_NPC, PQ RCY [0], SAMASK[4], GOTO[.+1]; *RPGRT2_DISK HEADER *COMMAND REJECT ERROR IF G=1 (COMMAND BLOCK IN AC) Y_P+Q, P_RPGRT2, SAMASK[22], GOTO[CRJ,G=1]; *Y_OPER. CODE + KCOMS LPGRT_P, Q_SY, GOTO[CRJ,Y>=0]; *Y-REG. OVF IF COMMAND NO. > 11 LPGRT2_Q, Q_RPGRT2, P_377 000000S; *LPGRT2_NSDISP VALUE RTEMP_P AND Q, P_LPGRT, X_7S, CALL[PKSER]; Q_P, P_Q, BAMASK[22], MDR_ILLHD; P-Q, P_RPGRT2, Q_KA, INHINT; *MUST TURN-OFF INTS. DURING VOLATILE PART GOTO[ILLRET,ALU<0], P_P#Q, SAMASK[14], Q_MDR, INHINT; *KNOW SECTOR AND ARM ARE RIGHT-MOST FIELDS OF ADDRESS P, NMMA_MAR, Q_RPGRT2, DGOTO[NSDASK]; NKA_Q, Q_LPGRT2, P_777777R, AMASK[7], INHINT, GOTO[.+1,ALU#0]; NMMA_NULL, Q_P+1, GOTO[ILLRET]; *Q_200 = SECNE *ASSIGN DEVICE X[36,43] TO PRIORITY LEVEL P[41,43], -1 IN RTEMP ASNLEV: LTEMP_P, Q_FINTS, P_RTEMP, XMASK; RPGRT3_P_P+1, FRZBALUBC, DGOTO[.+3,ALU=0]; P_P AND Q, Q_NOTFCOND, CALL[UPQ,ALU=0]; Q_NOT P AND Q; *ENABLE FCOND NOTFCOND_Q, Q_RPGRT3, P_LTEMP, GOTO[SPILEV]; *ASSIGN AC[14,43] TO BE VALUE OF INTERRUPT PARAMETER FOR DEVICE [P] ASNLOC: P-Q, Q_INTTAB, DGOTO[SETPARAM]; GOTO[ILLIO,ALU>=0], Y_P+Q; *ASSIGN BOTH LEVEL AND LOCATION FOR DEVICE ALEVLOC: LTEMP_P_P, SAMASK[6], CALL[ASNLOC]; P_LTEMP, RTEMP_A1, GOTO[ALEVX]; %*READ LEVEL INTO AC[0,13] AND PARAMETER INTO AC[14,43] FOR DEVICE [P] *DEIMPLEMENTED FOR BYTE LISP. JMC DISPATCH WAS Q_INTTAB, GOTO[RLEVLOC] RLEVLOC: X_P; Y_P+Q, P_RTEMP, XMASK; *Y_INTTAB+DEV NO. Q_SY, P_LTEMP, BAMASK[30], RTEMP_P+1; LAC_P AND Q, Y_IONTABX, DGOTO[6]; X_NPC, Q_A0, P_LAC, INCY, GOTO[.+1]; Q_SY, LAC_P+Q, INCY, P_RTEMP, RETURN[ALU#0]; P AND Q, DECX, P_LAC, Q_100 000000S, GOTO[.-1,X>=0]; P_LAC, SAMASK[30], GOTO[PTOAC]; % *SUBROUTINE FOR "SETIR" AND "CLRIR" IOCK: P_A1, XMASK, Q_FINTS; Q_P+1, P_Q, SETFC[MICRO,G=1]; MDR_P AND Q; STEMP_MDR; SETFB[STEMP,G=1], GOTO[QMIC,G=1]; *SETF AND GO FOR "SETIR", CLEARF FOR "CLRIR" %ROUTINE ENTERED WITH BITS IN MICINTS TO CLEAR IN Q, VALUES TO BE RESTORED TO P AND TO Q IN RTEMP AND LTEMP, RESPECTIVELY. BALUBC DOESN'T CHANGE. % CLRMINT: P_MICINTS, FRZBALUBC, CALL[CLRPQ], INHINT; MICINTS_Q, Q_LTEMP, P_RTEMP, FRZBALUBC, RETURN; *HERE WITH FINTS IN P *! MAXC1 ONLY READIR: Q_NOT F; LTEMP_P AND NOT Q, Q_MICINTS; *! *~ MAXC2 ONLY READIR: Q_FLAGS; LTEMP_P AND Q, Q_MICINTS; *~ P_NOT P AND Q, Q_LTEMP, GOTO[POQA]; *0 THE BIT FOR DEVICE [X] IN MAXNV AND SIGNAL THE NOVA SIGNAL: P_A1, XMASK, RMW_MAXNV, INHINT, CALL[RETN]; Q_P+1, P_MDR, SIGNOVA, GOTO[PANQM]; *ENABLE/DISABLE INTERRUPTS ON PI LEVELS SELECTED BY E[35,43] LEVX: PQ RCY [35], AMASK[16], Q_PISTAT, CALL[UPQ,J=1]; Q_NOT P AND Q, PISTAT_Q, GOTO[CONINTCOND,J=1]; PISTQ: PISTAT_Q, GOTO[CONINTCOND]; MC[TTYBSY&K,TTYBSY,K]; *DLS VARIABLES SVN[DLSOD]; SVN[DLSO]; SVN[DLSIN]; SVN[DLSB]; *RESET APR, PI, MAP, AND DISKS. DON'T CLOBBER Q, LPGRT3 PRES: X_RESCNT, RTEMP_Q, DGOTO[SLMIC]; Y_NPC, CLEARF[-1S], INHINT, GOTO[.+1]; ARM_NULL, INHINT, CALL[IREAD]; Y_INTTAB, DGOTO[52]; X_NPC, GOTO[.+1]; P_IMINTT, CALL[IREAD]; PRES1: X_7S, CALL[KRESET]; ***WAIT FOR DISK ACTIVITY TO CEASE??? SETF[IENABLE], GOTO[MAPRESET]; *RETURN "RTEMP" IN Q %IORESET CLEARS THE CONTROL LOGIC IN ALL PERIPHERAL EQUIPMENT BUT DOES NOT AFFECT THE PRIORITY INTERRUPT SYSTEM OR PROCESSOR FLAGS. IT ALSO MUST RELOAD ALL INTER-PROCESSOR COMMUNICATION VARIABLES WHICH ARE POINTERS. ***MUST NOT CLOBBER "RTEMP" OR "STEMP1" % RESIO: P_DLSOD_MDR; IORESET: P_Q_P+1, CLEARF[TTYBSY&K], DGOTO[.+1]; DLSO_Q, P_Q_P+1; DLSIN_Q, Q_P+1, P_LPGRT2, BAMASK[24]; *P_IORESET BIT -1 DLSB_Q, LPGRT2_P+1; *CLEAR ALL INTS EXCEPT OVF, NXM, PARITY, FOVF, POWFL, PDLOVF Q_17757 777777S, CALL[CLRMINT]; WRITE_MAXNV, SIGNOVA, Q_LPGRT2, DGOTO[PRES1]; MDR_P_NOT Q, CALL[SPUNT]; *READ "LOGF" INTO AC[23], "INCMP" INTO AC[24], NOT "PIACTIVE" *INTO AC[25], PI LEVELS OFF INTO AC[26,34], AND PI-IN-PROG INTO AC[35,43] PIREAD: P_PISTAT, Q_P+1, CALL[PQORP,K=1]; SETSF[PIACTIVE&G], DGOTO[PIRDX]; Q RSH 1, SETSF[LOGF&K], CALL[PQORP,G=0]; %SET VALUE OF SYSTEM PARAMETER: 0 TO SLOCLOW-1 ARE IN SM TABLE, 413 + 20*UNIT AND 414 + 20*UNIT ARE "KBLK" AND "KPARAM" FOR THE DISK UNITS RESPECTIVELY. OTHER VALUES BETWEEN 400 AND 577 ARE RESERVED FOR MORE DISK PARAMETERS. % SETSYSP: P-Q, Q_400S; P-Q, Q_600S, GOTO[SETSYS1,ALU<0]; *0 TO SLOCLOW-1? P-Q, Q_13S, GOTO[ILLIO,ALU<0]; *400-577? Y_P, SAMASK[4], GOTO[ILLIO,ALU>=0]; P#Q, Q_14S; P#Q, Q_LAC, GOTO[QTOSY,ALU=0]; *KBLK? GOTO[ILLIO,ALU#0]; *KPARAM? QTOSY: SY_Q, RETURN; SETSYS1: DGOTO[SLMIC]; Q_NPC, GOTO[.+1]; Y_P+Q, Q_LAC, GOTO[QTOSY]; *WRITE ABSOLUTE ADDRESS WABS: MDR_Q, RETURN; *READ FROM ABSOLUTE ADDRESS RABS: Q_MDR, GOTO[QTOAC]; *MAP VIRTUAL ADDRESS [P] BY USING THE "LOADMAP" ROUTINE. IF IT TRAPS, *THE TRAP CAUSE MAY BE ILL. READ, WRITE, OR EXECUTE, BUT THE KIND OF *ACCESS ATTEMPTED WILL SHOW THAT NOTHING WAS ATTEMPTED. IT IS NOT *NECESSARY TO CLEAR THE FORMER MAP ENTRY BEFORE DOING THIS JMC. MVA: P_(REFADR_P) U (1 000000S); *PGRMM LEFADR_P, P_RTEMP, BAMASK[26]; Q_NOT P AND Q, CALL[LOADMAP]; Q_MAP, PQ RCY [0], BAMASK[11]; PQ RCY [33], SAMASK[26], Q_P, GOTO[POQA]; *AC_INSTRUCTION COUNTER. P HAS 10, Q HAS E. E=0 SELECTS LEVEL 1 COUNTER, *E=1 LEVEL 2, ... , E=6 LEVEL 7, AND E=7 NON-INTERRUPT LEVEL COUNTER. *E>7 SELECTS THE "CURRENT" INSTRUCTION COUNTER. RICTR: P-Q, P_@ICTR, GOTO[WICTR,G=1]; P#Q, Q_ICTR, GOTO[QTOAC,ALU<=0]; P_YICTR, GOTO[PTOAC,ALU#0]; LAC_Q, ENDM; *INSTRUCTION COUNTER_AC WICTR: P#Q, Q_LAC, GOTO[.+2,ALU<=0]; GOTO[.+2,ALU#0]; ICTR_Q, RETURN; YICTR_Q, RETURN; *INCREMENT EVENT COUNTER POINTED TO BY Y AND RETURN EVINC: LINT1_P, P_EVCTR, INHINT; Q_P+1, P_Q, INHINT; *WRITE EVENT COUNTER 0-7 IN 16TH WORD OF DISK BLOCKS 0-7 WECTR: Q_P, EVCTR_Q, P_LINT1, INHINT, RETURN; *READ EVENT COUNTER E INTO AC RECTR: P_EVCTR, GOTO[PTOAC]; %UJMC 2 = CSUM16: AC -NWords,,Pointer to block AC+1 Initial checksum Loop performs CSum _ (CSum + Item) LCy 1 over 16-bit items, where the first item is bits 0:15 in the first word and the last item is bits 16:31 in the last word, and sums are ones-complement (wraparound carry) over 16 bits. Carries out of bits 20:35 in the checksum word are folded back after each pair of 16-bit bytes has been processed, so that at the end of each step, the number in AC+1 is .le. 200010b (provided that the original checksum is .le. this value). After the last PDP-10 word has been processed, the carry word is folded one more time to produce a 16-bit final checksum in AC+1. Note that if a zero count is in AC initially, so that the inner loop is not executed, then the checksum in AC+1 will be folded precisely once; this will produce a 16-bit result if the original value is less than 2^17-1, a 17-bit result if the original value is less than 2^32-1, and a 22-bit result for arbitrary values. If the inner loop is executed at least once, then the original checksum can be as great as 2^32-1 and still produce a final result that is .le. 16 bits. This means that after checksumming an odd 16-bit byte at the beginning, one execution of the opcode will produce a 16-bit result, even if the word count is 0, and after checksumming an additional odd byte at the end, one execution of the opcode will produce a 16-bit result. % * P _ LAC, AQ, SAMASK[22], GOTO[CSUM16]; *P/ 16-bits, Q/ previous csum; P _ (P+Q) LCY 1 CS16X: P _ P + Q; PQ LCY [1], Q _ MDR, RETURN; CS16LP: LAC _ P _ P + Q, SAMASK[22], GOTO[PI,H=1]; *P/ 777777, Q/ Pointer to block, AC/ pointer to initial csum. CSUM16: INCAC, GOTO[C16DON,ALU>=0]; MAPVA _ P, CALL[RTOMDR]; P _ MDR, Q _ A0; *P_bits 0:15 of current word, Q_previous csum (.le. 200010b) PQ RCY [24], Q _ LAC, CALL[CS16X]; *Q_previous csum (.le. 1000020b), P_bits 16:31 of current word Q _ P, QQ RCY [4], SAMASK[20], CALL[CS16X]; *P has new checksum (.le. 2400036b); fold it to 17d bits here so that *carries won't propagate outside bits 4:15 of the word. Q _ P, PQ RCY[20], SAMASK[24]; Q _ P, P _ Q, SAMASK[20]; *Largest result from this operation (for Q = 2377777b) is 200010b. LAC _ P + Q, DECAC; P _ LAC, Q _ (2 000002R) RSH 1, SETSF[INTCONDH], GOTO[CS16LP]; *Fold 36-bit result once into the sum of the right-most 16d bits and the *left-most 20d bits (This will result in a 16d-bit result for LAC .le. *377776b, which is the case when the loop has run one or more times.). C16DON: P _ Q _ LAC, SAMASK[20]; QQ RCY [20], Q _ P, SAMASK[24]; LAC _ P + Q, ENDM; %UJMC 3 = BYTBLT: A AC -NWords,,pointer to source block D AC+1 source to destination offset - 1 B AC+2 No. unused bits at right of source C AC+3 Number of bits to right-shift the source word pair so that the right-most word has the destination data right-justified. Approximate equivalent code: SKIPA T1,(A) LP: MOVE T1,T3 ; Collect source word pair in T1..T2 JUMPGE A,EXIT MOVE T2,1(A) MOVE T3,T2 LSH T1,-B ; Squeeze out "crack" between T1 and T2 LSHC T1,-C ; Right-shift T1..T2 so that T2 contains ; the destination data right-justified LSH T2,B MOVEM T2,D+1(A) AOBJN A,LP EXIT: ... % * RTEMP1 _ Q, INCAC, GOTO[BYTB0]; BYTB0: MAPVA _ P _ AQ, SAMASK[22], CALL[RQARG]; *Have P/ AC, Q/ memory data RTEMP _ Q, INCAC; *RTEMP _ 0(AC) P _ RTEMP1, Q _ LAC, INCAC; Q _ LAC, STEMP _ Q, DECAC; *STEMP_B STEMP1 _ Q, P _ P, DECAC, GOTO[BYTBA]; *STEMP1_C *RTEMP/ 0(AC) = first memory word *STEMP1/ right-shift distance for word pair BYTBLP: LAC _ P _ P + Q, INCAC, GOTO[PI,H=1]; *Here the AC register contains its original value + 1 (points at D) *P contains A, which has been put through the ALU. BYTBA: INCAC, GOTO[REMAPPC,ALU>=0]; MAPVA _ P _ P + 1, SAMASK[22], CALL[RTOMDR]; P _ RTEMP, Y _ P; Q _ A0; PQ RCY [Y], Y _ STEMP1; *P_T1 data right-justified P _ MDR, Q _ P; *RTEMP_T2 now to be T1 next time RTEMP _ P, PQ RCY [Y], Q _ LAC, DECAC; Y _ Q, Q _ P _ P, SAMASK[0], CALL[RETN]; *NOTE: delay 1 instruction after Y_ before PQ RCY[44-Y] PQ RCY[44-Y]; *LSHIFT by B to zero unused bits MDR _ P, P _ REFADR, Q _ LAC, DECAC; MAPVA _ P _ P + Q, SAMASK[22], CALL[WMDR]; P _ LAC, Q _ (2 000002R) RSH 1, SETSF[INTCONDH], GOTO[BYTBLP]; *Write data in MDR to address in P for which MAPVA has been done *and return to caller. On page fault, PC is not advanced. WMDR: WREF, REFADR _ P, Q _ MDR, GOTO[WMDR2,G=1]; WMDR1: P _ (P) U (BLTWLE), RETURN[G=0]; Q _ WMQ, LEFADR _ P, CALL[LOADMAP]; WREF, Q _ MDR _ WDATA, GOTO[WMDR1,G=0]; WMDR2: P _ (X) U (ACBASE), GOTO[WMDR3,H=0]; MAPVA _ P _ (P) U (BLTWLE); WREFDXK, MDR _ Q, GOTO[WMDR1]; WMDR3: LX _ Q, RETURN; %UJMC 4 = WDUMP0: AC -NWords,,pointer to first src word AC+1 points at destination block Loop moves two 40-bit words from the source to the destination translating into Maxc dump format, where data bytes begin with 0:7 in the first source word and with 0:7 in the first destination word. Translation of nibbles is as follows: Source Destination xx xx xx xx s t xx xx xx xx yy yy yy yy u v -- st yy yy yy yy -- uv where s and u are bits 32:35 in the two source words and t and v are the tag bits in the source words and where -- denotes a garbage byte. In other words, 40-bit words from the source (including 4 tag bits/word) is copied to the destination as 5 8-bit bytes with an extra garbage byte thrown in between the 32nd and 33rd source bits, and the destination is packed 4 8-bit bytes/word. % * P _ LAC, INCAC, GOTO[WDMP0]; WD0LP: GOTO[REMAPPC,ALU>=0]; WDMP0: MAPVA _ P _ P, SAMASK[22], CALL[RTOMDR]; P _ A0, Q _ MDRL, SETSF[INTCONDH]; PQ RCY [4], Q _ MDR, GOTO[PI,H=1]; *P/ t0 00 00 00 0 PQ RCY [14], Q _ LAC, DECAC; *P/ -- st 00 00 0 RTEMP _ P, P _ Q, SAMASK[22]; *RTEMP/ -- st 00 00 0 MAPVA _ P, CALL[WMDR]; *Write xx xx xx xx - P _ LAC, INCAC; MAPVA _ P _ P+1, SAMASK[22], CALL[RTOMDR]; Q _ A0, P _ STEMP _ MDR; PQ RCY [20], Q _ RTEMP, STEMP1 _ MDRL; MDR _ P OR Q, P _ LAC; MAPVA _ P _ P+1, SAMASK[22], CALL[WMDR]; P _ A0, Q _ STEMP; PQ RCY [24], Q _ STEMP1; *P/ yy yy u0 00 0 RTEMP _ P, 0Q RCY [4], Q _ STEMP; *P/ v0 00 00 00 0 PQ RCY [34], SAMASK[14], Q _ RTEMP; *P/ 00 00 00 uv 0 MDR _ P OR Q, Q _ LAC, P _ 2 000002R; MAPVA _ P _ P+Q, SAMASK[22], CALL[WMDR]; Q _ LAC, P _ 2 000002R; P _ P+Q, Q _ (2 000002R) RSH 1; LAC _ P+Q, DECAC; P _ LAC, Q _ 2 000002R; LAC _ P _ P+Q, INCAC, GOTO[WD0LP]; %UJMC 5 = WDUMP1: AC -NWords,,pointer to first src word AC+1 Right-justified 8-bit byte from the previous iteration. AC+2 address of destination block Like WDUMP0 but with a different destination alignment. Translation of nibbles is as follows: Source Destination xx xx xx xx s t ll xx xx xx yy yy yy yy u v xx -- st yy yy yy yy -- where ll is the byte from the previous iteration and where uv is left right-justified in AC+1 for the next iteration. % * P _ LAC, INCAC, GOTO[WDMP1]; WD1LP: GOTO[REMAPPC,ALU>=0]; WDMP1: MAPVA _ P _ P, SAMASK[22], CALL[RTOMDR]; P _ STEMP _ MDR, Q _ LAC, INCAC; RTEMP _ P, PQ RCY [10], Q _ MDRL, SETSF[INTCONDH]; MDR _ P, 0Q RCY [4], Q _ RTEMP, GOTO[PI,H=1]; PQ RCY [10]; *P/ -s t0 00 00 0 PQ RCY [14], Q _ LAC, DECAC; *P/ xx -- st 00 0 RTEMP _ P, P _ Q, DECAC; MAPVA _ P _ P, SAMASK[22], CALL[WMDR]; P _ LAC, INCAC; MAPVA _ P _ P+1, SAMASK[22], CALL[RTOMDR]; P _ STEMP _ MDR, Q _ A0, INCAC; PQ RCY [30], Q _ RTEMP, STEMP1 _ MDRL; MDR _ P OR Q, P _ LAC; MAPVA _ P _ P+1, SAMASK[22], CALL[WMDR]; P _ A0, Q _ STEMP; PQ RCY [34]; MDR _ P, P _ LAC, Q _ 2 000002R; MAPVA _ P _ P+Q, SAMASK[22], CALL[WMDR]; *Now update AC's for the iteration P _ LAC, Q _ 2 000002R; P _ P+Q, Q _ (2 000002R) RSH 1; LAC _ P+Q, DECAC; *DEST AC _ DEST AC+3 P _ A0, Q _ STEMP1; PQ RCY [4], Q _ STEMP; PQ RCY [40], SAMASK[10]; LAC _ P, DECAC; *Byte carried to next iteration P _ LAC, Q _ 2 000002R; LAC _ P _ P+Q, INCAC, GOTO[WD1LP]; *Source AC %JMC, A CATCH-ALL INSTRUCTION ADDED TO THE PDP-10, IS PRIVILEGED. E[22,30] SELECTS ONE OF 128 MICROCODED ROUTINES FOR EXECUTION. THE TABLE OF MICROINSTRUCTIONS BEGINNING AT "ALEVX" IS USED TO DISPATCH TO THE SELECTED ROUTINE WITH E[31,43] IN P AND AC IN Q. I = 6 + NUJMCS + NJMCS + 72 = 116 (+8 COMMENTED OUT) % *MUST USE REFADR JMC: REFADR_P, PQ RCY [13], Q_NPC, RETURN, SETSF[UM&J], BAMASK[7]; *JMC DISPATCH. HERE WITH -1 IN RTEMP AND LTEMP, E[30,43] IN P, AC IN Q ALEVX: X_P, PQ RCY [6], SAMASK[3], GOTO[ASNLEV]; *0 PILEV P[33,35] TO DEVICE P[36,43] Q_44S, RTEMP_Q, GOTO[ASNLOC]; *1 ASSIGN 24-BIT PARAM. TO DEV IN P Q_44S, RTEMP_Q, GOTO[ALEVLOC]; *2 ASSIGN BOTH LEV AND PARAM YKPTR_P, GOTO[WECTR]; *3 WRITE EVENT COUNTER E X_P, SETSF[G], GOTO[IOCK]; *4 CLEAR INTERRUPT REQUEST FOR DEV P X_P, SETF[G], GOTO[IOCK]; *5 INITIATE INTERRUPT REQUEST FOR DEV P RPGRT3_Q, PQ RCY [0], SAMASK[3], GOTO[SPILEV]; *6 SET PI LEVEL *FOR DEVICES SELECTED BY AC P_FINTS, GOTO[READIR]; *7 AC_INTERRUPTING DEVICE MASK P_FINTS, BRKP[1], GOTO[ILLIO]; *10 INITIATE INTS FOR DEVICES IN AC MASK CLEARF[PIACTIVE&G], GOTO[CONINTCOND]; *11 TURN OFF PI SYSTEM SETF[PIACTIVE&MICRO], GOTO[CONINTCOND]; *12 TURN ON PI SYSTEM SETF[INCMP&K], RETURN; *13 ENTER INCOMPATIBLE MODE CLEARF[INCMP&K], RETURN; *14 LEAVE INCOMPATIBLE MODE X_P, SETSF[G], GOTO[SIGNAL]; *15 SIGNAL NOVA DEVICE E (BIT 43-E) PRESC: P_GOTAB, IRET, INHINT, GOTO[PRES]; *16 PROCESSOR RESET P_777777R, AMASK[17], SETSF[INCMP&K], GOTO[PIREAD]; *17 READ PI STATE Q_SLOCLOW, GOTO[SETSYSP]; *20 SET SYSTEM PARAMETER TO AC MAPRESET: CLEARF[CUM&G], Y_NULL, GOTO[MAPRES]; *21 TURNOFF MAPPING P_Y_NULL, GOTO[SETPLO], Q_P; *22 SET PLO EQUAL TO E READ_PSWITCH, GOTO[ASWIT]; *23 RELOAD BASE REGS. WITHOUT MAP CLEAR Q_1000S, GOTO[VPGCLR]; *24 CLEAR VIRTUAL PAGE E CLEARF[CUM&G], Y_A1, GOTO[MAPCLR]; *25 CLEAR ABSOLUTE PAGE E GOTO[USWIT], P_Y_PLO; *26 SWITCH MAP TO NEW PROCESS YKPTR_KUNIT_P, GOTO[KOFF]; *27 DESELECT DISK UNIT E YKPTR_KUNIT_P, GOTO[KON]; *30 SELECT DISK UNIT E WITH THE *MAXIMUM DISK ADDRESS IN AC P_377 000000S, GOTO[KNOPDP]; *31 DISABLE PDP-10 SECTOR INTERRUPTS *FOR THE PACK IN AC P_377 000000S, GOTO[KSEEK]; *32 ENABLE PDP-10 SECTOR INTERRUPTS *AND SEEK IF ARM # CURRENT POSITION READ_DLSBS, GOTO[RESIO]; *33 I/O RESET MAPVA_P_AQ, SAMASK[22], GOTO[KGO]; *34 DO DATA TRANSFER SPECIFIED *BY COMMAND POINTED TO BY V.A. IN AC WRITE_P, INHINT, GOTO[WABS]; *35 MOVEM AC,E[31,43] ABSOLUTE READ_P, GOTO[RABS]; *36 MOVE AC,E[31,43] ABSOLUTE MAPVA_P_AQ, SAMASK[22], GOTO[MVA]; *37 MAP VIRTUAL TO ABSOLUTE *ADDRESS (1240,,E + 100000,,0 FOR READ *40400,,0 FOR WRITE AND 20000 FOR XCT) SETF[G], GOTO[RICT1]; *40 WRITE INST. COUNTER E Q_LAC, GOTO[CHECK]; *41 CHECK MICROMEMORY (MUST HAVE 0 *IN AC AT CALL. CLOBBERS AC TO AC+4) Q_P, P_NULL, SETF[J], GOTO[LEVX]; *42 TURN OFF PI LEVELS Q_P, P_NULL, SETF[MICRO], GOTO[LEVX]; *43 TURN ON PI LEVELS SETF[LOGF&K], RETURN; *44 ENABLE OPTIONAL MAIN LOOP PATH CLEARF[LOGF&K], RETURN; *45 DISABLE OPTIONAL MAIN LOOP PATH DM[DLC,777]; DLC[E1[JMC] E2[JMC1] E3[ADD[4000,IP[ILC],NOT[IP[JMC]]]]]; JMC1: MDR_P+Q, SETSF[G], GOTO[ILLIO,J=1]; Q_STACK, LTEMP_RTEMP_A1; P-Q, NPC_MDR; GOTO[ILLIO,ALU>=0], P_REFADR, Q_LAC, AMASK[13], POP; UJMC: REFADR_P, PQ RCY [13], Q_NPC, BAMASK[7], SETSF[J], RETURN; RICT1: P_10L, Q_YKPTR_P, GOTO[RICTR]; *0 READ INST. COUNTER E YKPTR_P, GOTO[RECTR]; *1 AC_EVENT COUNTER E P _ LAC, AQ, SAMASK[22], GOTO[CSUM16]; *2 CSUM16 RTEMP1 _ Q, INCAC, GOTO[BYTB0]; *3 BYTBLT P _ LAC, INCAC, GOTO[WDMP0]; *4 WDUMP0 P _ LAC, INCAC, GOTO[WDMP1]; *5 WDUMP1 DM[DLC,776]; DLC[E1[UJMC] E2[JMC1] E3[ADD[4000,IP[ILC],NOT[IP[UJMC]]]]];