.MCALL .MODULE .MODULE DX,VERSION=17,COMMENT=,AUDIT=YES ; Copyright (c) 1998 by Mentec, Inc., Nashua, NH. ; All rights reserved ; ; This software is furnished under a license for use only on a ; single computer system and may be copied only with the ; inclusion of the above copyright notice. This software, or ; any other copies thereof, may not be provided or otherwise ; made available to any other person except for use on such ; system and to one who agrees to these license terms. Title ; to and ownership of the software shall at all times remain ; in Mentec, Inc. ; ; The information in this document is subject to change without ; notice and should not be construed as a commitment by Digital ; Equipment Corporation, or Mentec, Inc. ; ; Digital and Mentec assume no responsibility for the use or ; reliability of its software on equipment which is not supplied ; by Digital or Mentec, and listed in the Software Product ; Description. .SBTTL CONDITIONAL ASSEMBLY SUMMARY ;+ ;COND ; DXT$O (0) Two controller support ; 0 support 1 controller ; 1 support 2 controllers ; ; DX$CSR (177170) primary CSR ; DX$CS2 (177174) second CSR ; ; DX$VEC (264) primary Vector ; DX$VC2 (270) second Vector ; ; MMG$T std conditional ; TIM$IT std conditional (no code effects) ; ERL$G std conditional ;- .SBTTL DEFINITIONS .ENABL LC ; SOME RT-11 MACROS WE WILL USE .MCALL .DRDEF .ASSUME .BR .ADDR .DSTATUS=:342 ;EMT code for .DSTATUS .READ =:375 ;EMT code for .READ ..READ =:010 ; subcode for .READ .WRITE =:375 ;EMT code for .WRITE ..WRIT =:011 ; subcode for .WRITE SYSCHN =:17 ; system channel ; RT-11 SYSCOM LOCATIONS JSW =:44 ;JOB STATUS WORD SYSPTR =:54 ;POINTER TO BASE OF RMON P1EXT =: 432 ;OFFSET FROM $RMON TO EXTERNAL ROUTINE ; RX01 CONTROLLER DEFAULTS .IIF NDF DXT$O, DXT$O=0 ;DEFAULT TO ONLY ONE CONTROLLER .IIF NDF DX$CS2, DX$CS2 == 177174 ;2ND CONTROLLER CSR .IIF NDF DX$VC2, DX$VC2 == 270 ;2ND CONTROLLER VECTOR .DRDEF DX,22,FILST$!SPFUN$!DX$COD,494.,177170,264,DMA=NO .DRPTR .DREST CLASS=DVC.DK,MOD=DVM.DX .DRSPF <377> ;Read Absolute .DRSPF <376> ;Write Absolute .DRSPF <375> ;Write Deleted ; CONTROL AND STATUS REGISTER BIT DEFINITIONS CSGO =: 1 ;INITIATE FUNCTION CSUNIT =: 20 ;UNIT BIT CSDONE =: 40 ;DONE BIT CSINT =: 100 ;INTERUPT ENABLE CSTR =: 200 ;TRANSFER REQUEST CSRX02 =: 4000 ;CONTROLLER IS RX02 (ALWAYS 0) CSINIT =: 40000 ;RX11 INITIALIZE CSERR =:100000 ;ERROR ; CSR FUNCTION CODES IN BITS 1-3 CSFBUF =:0*2 ;0 - FILL SILO (PRE-WRITE) CSEBUF =:1*2 ;1 - EMPTY SILO (POST-READ) CSWRT =:2*2 ;2 - WRITE SECTOR CSRD =:3*2 ;3 - READ SECTOR ;4 - UNUSED CSRDST =:5*2 ;5 - READ STATUS CSWRTD =:6*2 ;6 - WRITE SECTOR WITH DELETED DATA CSMAIN =:7*2 ;7 - MAINTENANCE CSREAD =:CSEBUF&CSRD&CSRDST&CSMAIN .ASSUME CSRD&2 NE 0 ;2 BIT MUST BE ON IN READ .ASSUME CSWRT&2 EQ 0 ;2 BIT MUST BE OFF IN WRITE .ASSUME CSWRTD&2 EQ 0 ;2 BIT MUST BE OFF IN WRITE ; ERROR AND STATUS REGISTER BIT DEFINITIONS ESCRC =: 1 ;CRC ERROR ESPAR =: 2 ;PARITY ERROR ESID =: 4 ;INITIALIZE DONE ESDD =: 100 ;DELETED DATA MARK ESDRY == 200 ;DRIVE READY ; ERROR LOG VALUES DXNREG =:3 ;# OF REGISTERS TO READ FOR ERROR LOG. RETRY =:8. ;RETRY COUNT SPFUNC =:100000 ;SPECIAL FUNCTIONS FLAG ; (IN COMMAND WORD) ; GENERAL COMMENTS: ; ; THIS HANDLER SERVES AS THE STANDARD RT-11 RX01 DEVICE HANDLER AS ; BOTH THE SYSTEM DEVICE HANDLER AND NON-SYSTEM HANDLER. IT ALSO PRO- ; VIDES THREE SPECIAL FUNCTION CAPABILITIES TO SUPPORT PHYSICAL I/O ; ON THE FLOPPY AS A FOREIGN VOLUME. THE SPECIAL FUNCTIONS ARE: ; CODE ACTION ; 377 ABSOLUTE SECTOR READ. WCNT=TRACK, BLK=SECTOR, BUFFER=65 ; WORD BUFFER OF WHICH WORD 1 IS DELETED DATA FLAG. ; 376 ABSOLUTE SECTOR WRITE. ARGUMENTS SAME AS READ. ; 375 ABSOLUTE SECTOR WRITE WITH DELETED DATA. 1ST WORD ; OF 65 WORD BUFFER ALWAYS SET TO 0. ; ; IN STANDARD RT-11 MODE A 2:1 INTERLEAVE IS USED ON A SINGLE TRACK AND ; A 6 SECTOR SKEW IS USED ACROSS TRACKS. TRACK 0 IS LEFT ALONE FOR ; PROPOSED ANSI COMPATABILITY. .SBTTL INSTALLATION CHECKS .IF EQ DXT$O .DRINS DX .IFF .DRINS DX, .ENDC ;EQ DXT$O NOP ;SAME CHECK FOR SYSTEM AND NON-SYSTEM HANDLER BIT #CSRX02,@INSCSR ;IS THE RX02 BIT ON? BEQ O.GOOD ;NOPE, IS AN RX01, INSTALL IT BR O.BAD ;YES, AN RX02, DON'T INSTALL IT ; Routine to find the entry for DX in the monitor device tables FINDRV: .ADDR #DEVNAM,R0 ;R0->DEVICE NAME .ADDR #DAREA+1,-(SP) ;(SP)->.DSTATUS INFO AREA(+physical) EMT .DSTATUS ;*** (.DSTAT #DAREA+1,#DEVNAM) *** BCS O.BAD ;IN CASE IT'S NOT KNOWN MOV DAREA+4,R1 ;RETURN THE ENTRY POINT BNE O.GOOD BR O.BAD ;UNLESS HANDLER'S NOT LOADED DAREA: .BLKW 4 ;.DSTAT INFORMATION BLOCK DEVNAM: .RAD50 /DX / ;DEVICE NAME ; The emt area for reads/writes of the handler is placed here ; to leave room for code for the set options BAREA: .BYTE SYSCHN,..READ ;CHANNEL 17, READ .BLKW ;BLOCK NUMBER .BLKW ;BUFFER .WORD 256. ;WORD COUNT .WORD 0 ;COMPLETION (WAIT) ; NOW ALTER THE CODE WHICH WILL BE WRITTEN BACK TO DISK X.WP: .ADDR #DXWPRO,R0 ;R0-> THE WRITE PROTECT TABLE ADD R3,R0 ; POINT TO ENTRY MOVB (PC)+,(R0) ; AND SET IT THE WAY THE USER WANTS IT O.WPF: .BLKW 1 ; NOW TO ALTER THE IN-CORE COPY OF THE PROTECTION TABLE CALL FINDRV ;IS THE HANDLER LOADED? BCS O.GOOD ;NOPE... CMP @#SYSPTR,R1 ;is this the system handler? BHI 10$ ; no, then leave 1-shot as is MOV #100000,DXW1-DXLQE(R1) ; yes, set it 10$: ADD R3,R1 ;ADD IN UNIT OFFSET MOVB O.WPF,DXWPRO-DXLQE(R1) ;SET THE WRITE-PROTECT STATUS BR O.GOOD .IIF GT,<.-376> .ERROR ;INSTALLATION CODE IS TOO LARGE; .SBTTL SET OPTIONS ; The write-protect/enable SET option makes use of the new ; calling convention, i.e. the unit number (DXn, n=0 if a space) ; passed in R1. .DRSET CSR, 160000, O.CSR, OCT .DRSET VECTOR, 500, O.VEC, OCT .IF NE DXT$O .DRSET CSR2, 160000, O.CSR2, OCT .DRSET VEC2, 500, O.VEC2, OCT .ENDC;NE DXT$O .DRSET RETRY, 127., O.RTRY, NUM .IF NE ERL$G .DRSET SUCCES, -1, O.SUCC, NO .ENDC ;NE ERL$G .DRSET WRITE, 1, O.WP, NO BTCSR = ++1000 O.CSR: CMP R0,R3 ;IS CSR IN RANGE? (>160000) BLO O.BAD ;NOPE... MOV R0,INSCSR ;YES, INSTALLATION CODE NEEDS IT MOV R0,DISCSR ;FILL IN DISPLAY CSR ; When the csr for units 0 and 1 is changed, the bootstrap must ; be altered such that it will use the correct controller. ;R1->READ/WRITE EMT AREA .ADDR #BAREA+4,R1 ; (BUFFER ADDRESS WORD) ;BUILD ADDRESS OF BUFFER .ADDR #1000,R2 ; (WHICH WILL OVERWRITE CORE ; COPY OF BLOCK 1) MOV R2,(R1) ;SET THE BUFFER ADDRESS MOV #BTCSR/1000,-(R1) ;SET TO BLOCK NUMBER TO READ/WRITE ; (BOOT BLOCK THAT NEEDS MODIFICATION) TST -(R1) ;R1->EMT AREA MOV R0,R3 ;SAVE CSR ELSEWHERE, EMT NEEDS R0 MOV R1,R0 ;R0->EMT AREA FOR READ EMT .READ ; *** (.READW) *** BCS O.BAD MOV R3,(R2) ;SET THE NEW CSR MOV R1,R0 ;R0->EMT AREA FOR WRITE .ASSUME ..READ+1 EQ ..WRIT INCB 1(R0) ;BUMP FROM 'READ' TO 'WRITE' EMT .WRITE ; *** (.WRITW) *** BCS O.SYWL ; SY: write-locked MOV R1,R0 ;R0->EMT AREA .ASSUME ..WRIT-1 EQ ..READ DECB 1(R0) ;CHANGE FROM 'WRITE' TO 'READ' MOV #1,2(R0) ; OF BLOCK 1 OF HANDLER EMT .READ ; *** (.READW) *** BCS O.BAD .IF EQ DXT$O MOV R3,RXCSA .IFF MOV R3,DXCSR .ENDC ;EQ DXT$O O.GOOD: TST (PC)+ ;GOOD RETURN (CARRY CLEAR) O.BAD: SEC ;ERROR RETURN (CARRY SET) RETURN O.SYWL: MOV @SP,R0 ; copy return address INC R0 ; point to opcode at return CMPB #BR/400,(R0)+ ; is it a BR xxx? BNE O.BAD ; NO, old style SET MOV R0,@SP ; use alternate return (RET+2) BR O.BAD ; with carry set O.VEC: CMP R0,R3 ;VECTOR IN RANGE? BHIS O.BAD ;NOPE... BIT #3,R0 ;YES, BUT ON A VECTOR BOUNDRY? BNE O.BAD ;NOPE... .IF EQ DXT$O MOV R0,DXSTRT ;YES, SET IT IN ENTRY AREA .IFF MOV R0,DX$VTB ;PLACE IT IN MULTI-VECTOR TABLE .ENDC ;NE DXT$O BR O.GOOD .IF NE DXT$O O.CSR2: CMP R0,R3 ;CSR IN RANGE? BLO O.BAD ;NOPE... MOV R0,DXCSR2 ;YES, PLACE IT IN CODE MOV R0,DISCS2 ;SET DISPLAY CSR BR O.GOOD O.VEC2: CMP R0,R3 ;VECTOR IN RANGE? BHIS O.BAD ;NOPE... BIT #3,R0 ;YES, BUT IS IT ON A VECTOR BOUNDARY? BNE O.BAD ;NOPE... MOV R0,DX$VTB+6 ;YES, PLACE IN MULTI-VECTOR TABLE BR O.GOOD .ENDC ;NE DXT$O O.RTRY: CMP R0,R3 ;ASKING FOR TOO MANY? BHI O.BAD ;YES, USER IS BEING UNREASONABLE MOV R0,DRETRY ;NOPE, SO TELL THE HANDLER BNE O.GOOD ;OKAY IF NON-ZERO BR O.BAD ;CAN'T ASK FOR NO RETRIES .IF NE ERL$G O.SUCC: MOV #0,R3 ;'SUCCESS' ENTRY POINT ; (MUST BE TWO WORDS) N.SUCC: MOV R3,SCSFLG ;'NOSUCCES' ENTRY POINT .ASSUME O.SUCC+4 EQ N.SUCC BR O.GOOD .ENDC ;NE ERL$G O.WP: NOP ;'WRITE' ENTRY POINT CLR R3 ;CLEAR FLAG N.WP: ;'NOWRITE' ENTRY POINT .ASSUME O.WP+4 EQ N.WP MOV R3,O.WPF ;SAVE THE USER'S SELECTION MOV R1,R3 ; save unit number CMP R3,#DXT$O*2+1 ;IS IT A VALID UNIT BHI O.BAD ;NOPE... JMP X.WP ; go to rest of the code .IIF GT,<.-1000> .ERROR ;SET CODE IS TOO LARGE; .SBTTL DRIVER REQUEST ENTRY POINT .ENABL LSB .DRBEG DX BR DXENT ;BRANCH AROUND PROTECTION TABLE DXWPRO: .REPT DXT$O+1 .BYTE 0,0 .ENDR .ASSUME . LE DXSTRT+1000 .IF NE ERL$G SCSFLG: .WORD 0 ; :SUCCESSFUL LOGGING FLAG (DEFAULT=YES) ; =0 - LOG SUCCESSES, ; <>0 - DON'T LOG SUCCESSES .ASSUME . LE DXSTRT+1000 .ENDC ;NE ERL$G .IF NE DXT$O .DRVTB DX,DX$VEC,DXINT .DRVTB ,DX$VC2,DXINT .ENDC ;NE DXT$O DXENT: .IF NE MMG$T MOV @#SYSPTR,R4 ; R4 -> MONITOR BASE MOV P1EXT(R4),(PC)+ ; GET ADDRESS OF EXTERNALIZATION ROUTINE $P1EXT: .WORD P1EXT ; POINTER TO EXTERNALIZATION ROUTINE .ENDC ;NE MMG$T MOV (PC)+,(PC)+ ;INITIALIZE RETRY COUNT DRETRY: .WORD RETRY ; :RETRY MAXIMU .ASSUME . LE DXSTRT+1000 RXTRY: .WORD 0 ; :CURRENT RETRY COUNT MOV DXCQE,R3 ;GET POINTER TO QUEUE ELEMENT MOV (R3)+,R5 ;GET BLOCK NUMBER MOV #CSRD!CSGO,R4 ;GUESS THAT CONTROLLER FUNCTION IS READ .ASSUME Q$BLKN+2 EQ Q$FUNC MOVB (R3)+,R1 ;PICK UP SPECIAL FUNCTION CODE (SIGN EXTENDED) .ASSUME Q$FUNC+1 EQ Q$UNIT MOVB (R3)+,R0 ;PICK UP THE UNIT NUMBER ASRB R0 ;SHIFT IT TO CHECK FOR ODD UNIT BCC 1$ ;BRANCH IF EVEN UNIT BIS #CSUNIT,R4 ;SELECT ODD UNIT FOR TRANSFER 1$: .IF EQ DXT$O ;ONE CONTROLLER BITB #6/2,R0 ;ANY UNITS BUT 0 OR 1? BNE RXERR ;BRANCH IF YES, ERROR .IFF MOV (PC)+,-(SP) ;ASSUME FIRST DX CONTROLLER DXCSR = . .WORD DX$CSR .ASSUME . LE DXSTRT+1000 ASRB R0 ;SHIFT UNIT TO CHECK FOR SECOND CONTROLLER BCC 2$ ;NOPE, FIRST CONTROLLER MOV (PC)+,(SP) ;CHANGE CSR TO USE SECOND CONTROLLER DXCSR2 = . .WORD DX$CS2 .ASSUME . LE DXSTRT+1000 2$: MOV (SP)+,RXCSA ASRB R0 ;BUT WAS IT UNIT 4 TO 7? BCS RXERR ;ERROR IF SO .ENDC ;EQ DXT$O .ASSUME Q$UNIT+1 EQ Q$BUFF MOV (R3)+,R0 ;GET THE USER'S BUFFER ADDRESS .ASSUME Q$BUFF+2 EQ Q$WCNT MOV (R3)+,R2 ;GET WORD COUNT BPL 3$ ;POSITIVE MEANS READ, SO ALL SET UP ; HERE TO CHECK IF UNIT IS WRITE-PROTECTED ASL (PC)+ ; CHECK WRITE ANYWAY ONE-SHOT DXW1: .WORD .-. ; 100000 MEANS WRITE ANYWAY .ASSUME . LE DXSTRT+1000 BCS 33$ ; SKIP TEST IF WRITE ANYWAY CLR -(SP) ;SET TO GET UNIT .ASSUME Q$WCNT+2 EQ Q$COMP MOVB Q$UNIT-Q$COMP(R3),(SP) ;GET IT (PLUS OTHER CRUFT BIC #<^C3>,(SP) ; WHICH WE DISCARD NOW) ;ADD ADDRESS OF WRITE-PROTECT TABLE .ADDR #DXWPRO,(SP),ADD; TO UNIT OFFSET TSTB @(SP)+ ;CHECK UNIT WRITE STATUS BNE RXERR ;IT'S WRITE-PROTECTED, USER CAN'T DO THIS .ASSUME CSRD-2 EQ CSWRT 33$: CMPB -(R4),-(R4) ;CHANGE CSRD (3*2) TO CSWRT (2*2) FOR WRITE .ASSUME CSWRT EQ CSRD-2 NEG R2 ; AND MAKE WORD COUNT POSITIVE 3$: ASL R1 ;DOUBLE THE SPECIAL FUNCTION CODE ADD PC,R1 ;FORM PIC REFERENCE TO CHGTBL ADD CHGTBL-.(R1),R4 ;MODIFY THE CODE, SET SIGN BIT IF SPFUN MOV R4,RXFUN2 ;SAVE THE FUNCTION CODE AND SPFUN FLAG BMI 7$ ;IF SPFUN, GO DO SPECIAL SETUP ; NORMAL I/O, CONVERT TO TRACK AND SECTOR NUMBER AND INTERLEAVE MOVB R2,FILLCT ;SAVE WORD COUNT IN CASE WE HAVE TO FILL DECB FILLCT ; EXTRA SECTORS ON WRITE ASL R2 ;MAKE WORD COUNT UNSIGNED BYTE COUNT ASL R5 ;NORMAL READ/WRITE. COMPUTE REAL SECTOR NUMBER ASL R5 ; AS BLOCK*4 MOV (PC)+,R4 ;LOOP COUNT FOR 8 BIT DIVISION .BYTE -7,-26. ;COUNT BECOMES 1, -26 IN HIGH BYTE FOR LATER 4$: CMP #26.*200,R5 ;DOES 26 GO INTO DIVIDEND? BHI 5$ ;BRANCH IF NOT, C CLEAR ADD #-26.*200,R5 ;SUBTRACT 26 FROM DIVIDEND, SET C 5$: ROL R5 ;SHIFT DIVIDEND AND QUOTIENT INCB R4 ;DECREMENT LOOP COUNT BLE 4$ ;BRANCH UNTIL DIVIDE DONE MOVB R5,R1 ;COPY TRACK NUMBER 0:75, ZERO EXTEND ADD R4,R5 ;BUMP TRACK TO 1-76, MAKE SECTOR<0 MOV R1,R4 ;COPY TRACK NUMBER ASL R1 ;MULTIPLY ADD R4,R1 ; BY ASL R1 ; 6 6$: SUB #26.,R1 ;REDUCE TRACK NUMBER * 6 MOD 26 BGT 6$ ; TO FIND OFFSET FOR THIS TRACK, -26:0 MOV R1,TRKOFF ;SAVE IT BR 8$ ;GO SAVE PARAMETERS AND START ; SPECIAL FUNCTION REQUEST, SET TRACK AND SECTOR AND BYTE COUNT 7$: SWAB R5 ;PUT PHYSICAL SECTOR IN HIGH BYTE BISB R2,R5 ; AND PHYSICAL TRACK IN LOW BYTE MOV #128.,R2 ;SET THE BYTE COUNT TO 128 .IF EQ MMG$T CLR (R0)+ ;CLEAR DELETED DATA FLAG WORD, BUMP USER ADDR .IFF MOV DXCQE,R4 ;POINT TO QUEUE ELEMENT AT Q.BLKN CLR -(SP) ;STACK A ZERO AND STORE IT IN FIRST WORD OF CALL @$PTWRD ; BUFFER. NOTE THAT Q.BUFF GETS BUMPED BY 2 TST (R0)+ ;ADD 2 TO OUR COPY OF USER BUFFER ADDRESS .ENDC ;EQ MMG$T ; MERGE HERE TO START OPERATION 8$: MOV R0,(PC)+ ;SAVE BUFFER ADDRESS BUFRAD: .WORD 0 ; : USER VIRTUAL BUFFER ADDRESS MOV R5,TRACK ;SAVE IT FOR STARTING I/O MOV R2,(PC)+ ; AND BYTE COUNT. BYTCNT: .WORD 0 ; : BYTE COUNT FOR TRANSFER .IF NE MMG$T TST (R3)+ ;SKIP THE COMPLETION ROUTINE ADDRESS MOV @R3,PARVAL ;SAVE THE PAR1 VALUE FOR MAPPING USER BUFFER .ENDC ;NE MMG$T .BR RXINIT ;GO TO FORK LEVEL AND START IT UP .DSABL LSB .SBTTL START TRANSFER OR RETRY .ENABL LSB RXINIT: MOV #100000,RXIRTN ;SET RETURN AFTER INITIAL INTERRUPT MOV RXCSA,R4 ;ENSURE THAT WE POINT TO THE CSR BR RXIENB ;GO INTERRUPT, RETURN TO 1$ LATER 1$: BIT #CSREAD,R0 ;READ OR WRITE FUNCTION? BNE 3$ ;IF READ, GO FILL THE SILO FROM DISK 2$: JSR R0,SILOFE ;WRITE, LOAD THE SILO FROM THE USER BUFFER .WORD CSFBUF!CSGO ; FILL BUFFER COMMAND MOVB (R2)+,@R5 ; MOVB TO BE PLACED IN-LINE IN SILOFE MOV R1,@R5 ; ZERO-FILL INSTRUCTION FOR SHORT WRITES 3$: MOVB SECTOR,R2 ;GET THE SECTOR NUMBER BGT 5$ ;POSITIVE MEANS SPFUN, DON'T INTERLEAVE SUB #-14.,R2 ;ADD 14 TO DO INTERLEAVING BGT 4$ ;IF > 0, MAP -13:-1 TO 2:26, NOTE C=0 ADD #12.,R2 ; ELSE MAP -26:-14 TO 1:25 SEC ;ADD 1 WHEN DOUBLING 4$: ROL R2 ;DOUBLE AND INTERLEAVE, SECTOR 1:26 ADD (PC)+,R2 ;ADD IN THE TRACK OFFSET, SECTOR -25:26 TRKOFF: .WORD 0 ; : TRACK OFFSET = TRACK*6 MOD 26, RANGE -26:0 BGT 5$ ;NO MODULUS PROBLEMS ADD #26.,R2 ;FIX TO PUT SECTOR IN 1:26 RANGE 5$: MOV R0,@R4 ;SET THE FUNCTION IN THE FLOPPY CONTROLLER 6$: TSTB @R4 ;WAIT FOR BEQ 6$ ; TRANSFER READY BPL RXRTRY ;TRANSFER DONE WITHOUT TRANSFER READY, ERROR MOVB R2,@R5 ;SET SECTOR NUMBER 7$: TSTB @R4 ;WAIT AGAIN FOR BEQ 7$ ; TRANSFER READY BPL RXRTRY ;TRANSFER DONE WITHOUT TRANSFER READY, ERROR MOVB (PC)+,@R5 ;SET THE TRACK NUMBER TRACK: .BYTE 0 ;TRACK NUMBER SECTOR: .BYTE 0 ;SECTOR NUMBER, KEPT < 0 UNLESS SPFUN RXIENB: BIS #CSINT,@R4 ;SET IE TO CAUSE AN INTERRUPT WHEN DONE IS UP RETURN ;RETURN, WE'LL BE BACK WITH AN INTERRUPT RXERR: MOV DXCQE,R4 ;R4 -> CURRENT QUEUE ELEMENT BIS #HDERR$,@-(R4) ;SET HARD ERROR IN CSW BR 13$ ;EXIT ON HARD ERROR .DRAST DX,5,RXABRT ;AST ENTRY POINT TABLE .FORK DXFBLK ;REQUEST FORK LEVEL IMMEDIATELY MOV (PC)+,R0 ;GET A VERY USEFUL FLAG WORD RXFUN2: .WORD 0 ; : READ OR WRITE COMMAND ON CORRECT UNIT MOV #128.,R3 ;LOAD A HANDY CONSTANT MOV (PC)+,R4 ;GET ADDRESS OF RX CONTROLLER RXCSA: .WORD DX$CSR ; : ADDRESS OF CONTROLLER .ASSUME . LE DXSTRT+1000 MOV R4,R5 ;POINT R5 TO RX DATA BUFFER TST (R5)+ ;CHECK FOR ERROR, R5 -> DX REGISTER WITH ERROR BMI RXRTRY ;ERROR, PROCESS IT ASL (PC)+ ;NO ERROR, DISPATCH AFTER INTERRUPT RXIRTN: .WORD 0 ;OFFSET TO INTERRUPT CONTINUATION BCS 1$ ;FIRST INTERRUPT, START I/O BIT #CSREAD,R0 ;READ OR WRITE? BEQ 10$ ;WRITE, DON'T EMPTY SILO TST R0 ;READ, IS THIS A SPECIAL FUNCTION? BPL 9$ ;NO, SIMPLY EMPTY THE SILO THAT WAS JUST READ BIT #ESDD,@R5 ;IF SPFUN READ, IS DELETED DATA FLAG PRESENT? BEQ 9$ ;NOPE, JUST EMPTY THE SILO .IF EQ MMG$T MOV BUFRAD,R2 ;GET ADDRESS OF USER BUFFER AREA INC -(R2) ;SET FLAG WORD TO 1 TO INDICATE DELETED DATA .IFF MOV R4,R1 ;SAVE R4 MOV DXCQE,R4 ;POINT TO QUEUE ELEMENT MOV #1,-(SP) ;STACK A 1 TO PUT INTO FLAG WORD SUB #2,Q$BUFF(R4) ;MOVE BUFFER POINTER BACK TO FIRST WORD. CMP Q$BUFF(R4),#20000 ;POINTER OUT OF THIS PAR'S RANGE? BHIS 85$ ;NOPE... ADD #20000,Q$BUFF(R4) ;YES, GET IT BACK IN RANGE SUB #200,Q$PAR(R4) ; IN THE PREVIOUS PAR SUB #200,Q$MEM(R4) ; IN THE PREVIOUS PAR 85$: CALL @$PTWRD ;STORE IN 1ST WORD. Q.BUFF IS AGAIN ORIGINAL+2 MOV R1,R4 ;RESTORE R4. .ENDC ;EQ MMG$T 9$: JSR R0,SILOFE ;FOR READ, MOVE THE DATA FROM SILO TO BUFFER .WORD CSEBUF!CSGO ; EMPTY BUFFER COMMAND MOVB @R5,(R2)+ ; MOVB TO BE PLACED IN LINE IN SILOFE MOV @R5,R2 ; DATA SLUFFER TO BE USED FOR SHORT READ 10$: INCB SECTOR ;RETURN HERE AFTER WRITES. BUMP SECTOR NUMBER BNE 11$ ;NOT OFF END OF TRACK YET ADD #-26.*400+1,TRACK ;RESET SECTOR, BUMP TO NEXT TRACK ADD #6,TRKOFF ;BUMP TRACK OFFSET VALUE BLE 11$ ;OK IF STILL IN RANGE -25:0 SUB #26.,TRKOFF ;RESET TO PROPER RANGE MOD 26 11$: .IF EQ MMG$T ADD R3,BUFRAD ;UPDATE BUFFER ADDRESS .IFF ADD #2,PARVAL ;CHANGE MAP TO BUMP ADDRESS FOR NEXT TIME .ENDC ;EQ MMG$T SUB R3,BYTCNT ;REDUCE THE AMOUNT LEFT TO TRANSFER BHI 1$ ;LOOP IF WE ARE NOT DONE CLR BYTCNT ;FIX BYTE COUNT SO THAT WRITES ARE ALL 0-FILLS BIT #CSREAD!SPFUNC,R0 ;READ OR SPECIAL FUNCTION OPERATION? BNE 12$ ;IF SO, NO ZERO-FILLING, SO WE'RE DONE ADD #040000,(PC)+ ;CHECK ORIGINAL WORD COUNT FOR # OF SECTORS .BYTE 0 ; FILLER FILLCT: .BYTE 0 ; : ORIGINAL WORD COUNT LOW BYTE IN HIGH BYTE BCC 2$ ;YES, LOOP FOR ZERO-FILLING ON WRITE 12$: ;AHH, A SUCCESSFUL TRANSFER IS DONE .IF NE ERL$G TST SCSFLG ;LOGGING SUCCESSFUL TRANSFERS? BNE 13$ ;NOPE... MOV #DX$COD*400+377,R4 ;SET UP R4 = ID/-1 MOV DXCQE,R5 ; AND R5 -> CURRENT QUEUE ELEMENT CALL @$ELPTR ;CALL ERROR LOGGER TO REPORT SUCCESS .ENDC ;EQ ERL$G 13$: CLR @RXCSA ;DISABLE FLOPPY INTERRUPTS 14$: .DRFIN DX ;GO TO I/O COMPLETION ; ABORT TRANSFER RXABRT: MOV #CSINIT,@RXCSA ;PERFORM AN RX11 INITIALIZE CLR DXFBLK+2 ;CLEAR FORK BLOCK TO AVOID A DISPATCH BR 14$ ; AND FINISH UP THIS I/O .DSABL LSB ; TRANSFER ERROR HANDLING RXRTRY: .IF NE ERL$G .ADDR #DXRBUF,R3 ;R3 -> LOCATION TO STORE REGISTER INFO. MOV R3,R2 ;SAVE IN R2 FOR LATER MOV @R4,(R3)+ ;STORE RXCS MOV @R5,(R3)+ ;STORE STATUS RXES MOV #CSMAIN!CSGO,@R4 ;READ ERROR REGISTER (NO INTERRUPTS) 1$: BIT #CSDONE,@R4 ;WAIT FOR READ COMPLETION BEQ 1$ MOV @R5,@R3 ;STORE IN BUFFER MOV DRETRY,R3 SWAB R3 ADD #DXNREG,R3 ;R3 = MAX RETRIES/# OF REGS MOV #DX$COD*400,R4 ;R4 = DEVICE ID IN HIGH BYTE BISB RXTRY,R4 ; AND CURRENT RETRY COUNT IN LOW BYTE DECB R4 ; -1 FOR THIS ERROR MOV DXCQE,R5 ;R5 -> QUEUE ELEMENT CALL @$ELPTR ;CALL ERROR LOGGER MOV RXCSA,R4 ;RESTORE R4 = RXCS ADDRESS .ENDC ;NE ERL$G DEC RXTRY ;SHOULD WE TRY AGAIN? BGT 2$ ;YES JMP RXERR ;NOPE, REPORT AN ERROR 2$: MOV #CSINIT,@R4 ;START A RECALIBRATE JMP RXINIT ;EXIT THROUGH START OPERATION CODE .SBTTL SILOFE - FILL OR EMPTY THE SILO ;+ ; SILOFE - FILL OR EMPTY THE SILO, DUMPING OR ZERO-FILLING IF NEEDED ; ; R3 = 128. ; R4 -> FLOPPY CSR ; JSR R0,SILOFE ; COMMAND: CSFBUF!CSGO FOR FILL (WRITE) ; CSEBUF!CSGO FOR EMPTY (READ) ; FILL/EMPTY INSTRUCTION: (R2 -> USER BUFFER, R5 -> RXDB) ; MOVB (R2)+,@R5 FOR FILL (WRITE) ; MOVB @R5,(R2)+ FOR EMPTY (READ) ; SLUFF INSTRUCTION: (R1 = 0, R5 -> RXDB) ; CLRB @R5 FOR FILL (WRITE) ; MOVB @R5,R2 FOR EMPTY (READ) ; R1 = RANDOM ; R2 = RANDOM ; ; NOTE: 1. THIS ROUTINE ASSUMES ERROR CAN NOT COME UP DURING A FILL OR EMPTY!! ; 2. SEEK DOES A SILO EMPTY, A TIME WASTER ;- .ENABL LSB SILOFE: MOV (R0)+,@R4 ;INITIATE FILL OR EMPTY BUFFER COMMAND MOV (R0)+,3$ ;PUT CORRECT MOV INSTRUCTION IN FOR FILL/EMPTY MOV (R0)+,5$ ;PUT IN INSTRUCTION TO SLUFF DATA MOV BYTCNT,R1 ;GET BYTE COUNT BEQ 4$ ;IF ZERO, WE ARE SEEKING OR ZERO FILLING CMP R1,R3 ;IS THE BYTE COUNT <= 128? BLOS 1$ ;OK IF SO MOV R3,R1 ;DO ONLY 128 BYTES AT A TIME 1$: MOV BUFRAD,R2 ;GET USER VIRTUAL BUFFER ADDRESS IN R2 .IF NE MMG$T JSR R0,@$P1EXT ;Let the monitor execute the following code. .WORD PARVAL-. ;Number of instructions in bytes plus 2. .ENDC ;NE MMG$T 2$: TSTB @R4 ;**EXT** TRY FOR THE TRDY BPL 2$ ;**EXT** TRANSFER READY 3$: HALT ;**EXT** INSTRUCTION TO MOV OR SLUFF DATA FROM TSTB @R4 ;**EXT** TOUCH THE CSR TO GET IT READY DECB R1 ;**EXT** CHECK FOR COUNT DONE BNE 2$ ;**EXT** STILL MORE TO TRANSFER .IF NE MMG$T PARVAL: .WORD 0 ;using this value for the PAR 1 bias. .ENDC ;NE MMG$T 4$: TSTB @R4 ;WAIT FOR TRANSFER READY OR TRANSFER DONE BGT 6$ ;TDNE UP WITH NO TRDY, SO ALL DONE BEQ 4$ ;LOOP 5$: HALT ;TRANSFER READY, SO SLUFF DATA BR 4$ ;LOOP TO SLUFF MORE 6$: RTS R0 ;RETURN .DSABL LSB .SBTTL TABLES, FORK BLOCK, END OF DRIVER ; CHANGES TO CSR CODE FOR SPECIAL FUNCTIONS .WORD CSWRTD-CSRD+SPFUNC ;375: READ+GO -> WRITE DELETED+GO .WORD CSWRT-CSRD+SPFUNC ;376: READ+GO -> WRITE+GO .WORD CSRD-CSRD+SPFUNC ;377: READ+GO -> READ+GO CHGTBL: .WORD 0 ; READ/WRITE STAY THE SAME DXFBLK: .WORD 0,0,0,0 ;DX FORK QUEUE ELEMENT .IF NE ERL$G DXRBUF: .BLKW DXNREG ;ERROR LOG STORAGE .ENDC ;NE ERL$G .SBTTL BOOTSTRAP DRIVER .DRBOT DX,BOOT1,READ . = DXBOOT+14 .WORD READS-DXBOOT .WORD 340 .WORD WAIT-DXBOOT .WORD 340 . = DXBOOT+34 ;34-52 USEABLE BOOT1: MOVB UNITRD-DXBOOT(R0),RDCMD ;SET READ FUNCTION FOR CORRECT UNIT REETRY: MOV @PC,SP ;INIT SP WITH NEXT INSTRUCTION MOV #200,R2 ;AREA TO READ IN NEXT PART OF BOOT CLR R0 ;SET TRACK NUMBER BR B2$ ;OUT OF ROOM HERE, GO TO CONTINUATION . = DXBOOT+56 UNITRD: .BYTE CSGO+CSRD ;READ FROM UNIT 0, SETS WEIRD BUT OK PS .BYTE CSGO+CSRD+CSUNIT;READ FROM UNIT 1 . = DXBOOT+70 ;PAPER TAPE VECTORS WAIT: TST @R4 ;IS TR, ERR, DONE UP? INT ENB CAN'T BE BEQ WAIT ;LOOP TILL SOMETHING BMI REETRY ;START AGAIN IF ERROR RTIRET: RTI ;RETURN . = DXBOOT+120 READS: MOV (PC)+,R4 ;R4 -> RX STATUS REGISTER BOTCSR: .WORD DX$CSR MOV R4,R5 ;R5 WILL POINT TO RX DATA BUFFER MOV (PC)+,(R5)+ ;INITIATE READ FUNCTION RDCMD: .WORD 0 ;GETS FILLED WITH READ COMMAND IOT ;CALL WAIT SUBROUTINE MOV R3,@R5 ;LOAD SECTOR NUMBER INTO RXDB IOT ;CALL WAIT SUBROUTINE MOV R0,@R5 ;LOAD TRACK NUMBER INTO RXDB IOT ;CALL WAIT SUBROUTINE MOV #CSGO+CSEBUF,@R4;LOAD EMPTY BUFFER FUNCTION INTO RXCS BROFFS = READF-. ;USE FOR COMPUTING BR OFFSET RDX: IOT ;CALL WAIT SUBROUTINE TSTB @R4 ;IS TRANSFER READY UP? BPL RTIRET ;BRANCH IF NOT, SECTOR MUST BE LOADED MOVB @R5,(R2)+ ;MOVE DATA BYTE TO MEMORY DEC R1 ;CHECK BYTE COUNT BGT RDX ;LOOP AS LONG AS WORD COUNT NOT UP CLR R2 ;KLUDGE TO SLUFF BUFFER IF SHORT WD CNT BR RDX ;LOOP B2$: MOV SP,R1 ;SET TO BIG WORD COUNT INC R0 ;SET TO ABSOLUTE TRACK 1 MOV @PC,R3 ;ABSOLUTE SECTOR 3 FOR NEXT PART .ASSUME BPT EQ 3 BPT ;CALL READS SUBROUTINE ;SECTOR 2 OF RX BOOT BOOT2: CMPB (R3)+,(R3)+ ;BUMP TO SECTOR 5 BPT ;CALL READS SUBROUTINE CMPB (R3)+,(R3)+ ;BUMP TO SECTOR 7 BPT ;CALL READS SUBROUTINE BIT #CSUNIT,RDCMD ;CHECK UNIT ID BNE BOOT ;BRANCH IF BOOTING UNIT 1, R0=1 CLR R0 ;SET TO UNIT 0 BR BOOT ;NOW WE ARE READY TO DO THE REAL BOOT READ: MOV (PC)+,@(PC)+ ;MODIFY READ ROUTINE .WORD 167 .WORD RDX-DXBOOT MOV (PC)+,@(PC)+ .WORD READF-RDX-4 .WORD RDX-DXBOOT+2 MOV #READ1-DXBOOT,@#B$READ ;CALLS TO B$READ WILL GO TO READ1 MOV #TRWAIT-DXBOOT,@#20 ;LETS HANDLE ERRORS DIFFERENTLY CLR @#JSW ;CLEAR JSW SINCE THE DX BOOT IN SYSCOM AREA TST HRDBOT ;DID WE REACH HERE VIA A HARDWARE BOOT? BEQ READ1 ;YES, DON'T SET UP UNIT NUMBER MOV @#B$DEVU,R3 ;NO, SET UP UNIT NUMBER MOVB UNITRD-DXBOOT(R3),RDCMD ;STORE UNIT NUMBER READ1: ASL R0 ;CONVERT BLOCK TO LOGICAL SECTOR ASL R0 ;LSN=BLOCK*4 ASL R1 ;MAKE WORD COUNT BYTE COUNT 1$: MOV R0,-(SP) ;SAVE LSN FOR LATER MOV R0,R3 ;WE NEED 2 COPIES OF LSN FOR MAPPER MOV R0,R4 CLR R0 ;INIT FOR TRACK QUOTIENT BR 3$ ;JUMP INTO DIVIDE LOOP 2$: SUB #23.,R3 ;PERFORM MAGIC TRACK DISPLACEMENT 3$: INC R0 ;BUMP QUOTIENT, STARTS AT TRACK 1 SUB #26.,R4 ;TRACK=INTEGER(LSN/26) BPL 2$ ;LOOP - R4=REM(LSN/26)-26 CMP #-14.,R4 ;SET C IF SECTOR MAPS TO 1-13 ROL R3 ;PERFORM 2:1 INTERLEAVE 4$: SUB #26.,R3 ;ADJUST SECTOR INTO RANGE -1,-26 BPL 4$ ;(DIVIDE FOR REMAINDER ONLY) ADD #27.,R3 ;NOW PUT SECTOR INTO RANGE 1-26 BPT ;CALL READS SUBROUTINE MOV (SP)+,R0 ;GET THE LSN AGAIN INC R0 ;SET UP FOR NEXT LSN TST R1 ;WHATS LEFT IN THE WORD COUNT BGT 1$ ;BRANCH TO TRANSFER ANOTHER SECTOR RETURN READF: TST @R4 ;ERROR, DONE, OR TR UP? BEQ READF ;BR IF NOT BMI BIOERR ;BR IF ERROR TSTB @R4 ;TR OR DONE? BPL READFX ;BR IF DONE MOVB @R5,(R2)+ ;MOVE DATA BYTE TO MEMORY DEC R1 ;CHECK BYTE COUNT BGT READF ;LOOP IF MORE MOV #1,R2 ;SLUFF BUFFER IF SHORT WD CNT ;DON'T DESTROY LOC 0 BR READF ;LOOP TRWAIT: TST @R4 ;ERROR, DONE, OR TR UP? BMI BIOERR ;HARD HALT ON ERROR BEQ TRWAIT ;BR IF NOT READFX: RTI . = DXBOOT+606 BOOT: MOV #10000,SP ;SET STACK POINTER MOV R0,-(SP) ;SAVE THE UNIT NUMBER MOV #2,R0 ;READ IN SECOND PART OF BOOT MOV #<4*400>,R1 ;EVERY BLOCK BUT THE ONE WE ARE IN MOV #1000,R2 ;INTO LOCATION 1000 CLR (PC)+ ;CLEAR TO SHOW HARDWARE BOOT HRDBOT: .WORD 1 ;INITIALLY SET TO 1 CALL READ ;GO READ IT IN MOV #READ1-DXBOOT,@#B$READ ;STORE START LOCATION FOR READ ROUTINE MOV #B$DNAM,@#B$DEVN ;STORE RAD50 DEVICE NAME MOV (SP)+,@#B$DEVU ;STORE THE UNIT NUMBER JMP @#B$BOOT ;START SECONDARY BOOT .DREND DX .END