.MCALL .MODULE .MODULE RK,VERSION=13,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 ; MMG$T std conditional ; TIM$IT std conditional (no code effects) ; ERL$G std conditional ;- ; Edit History: ; ; 001 25-Apr-82 08:03 PM Martin Gentry [40,121] ; V5 development: set options ; (001) ; ; 002 ?? JFW? add .module? ; ; 003 4-Aug-85 Jim Williams ; Add .DRPTR, .DREST ; ; 004 23-Sep-85 Martin Gentry ; Adding .DRINS, changing references to 176 to INSCSR ; ; 005 01-Nov-85 Martin Gentry ; Adding check for QBUS to limit data transfers to 16-bit ; addresses, RKV11 does not support extended bus addresses. ; ; 006 17-Nov-85 Martin Gentry ; Replacement of low limit check with upper limit check. This ; provides a check of the entire transfer. Must be within ; 16-bit address space for RKV11, may be within 18-bit address ; space for RK11. ; ; 007 27-JUL-88 Linda Banche ; Add code for UB support ;- .SBTTL MACROS AND DEFINITIONS .MCALL .DRDEF .ASSUME .IF EQ MMG$T .DRDEF RK,0,FILST$,4800.,177400,220,DMA=NO .IFF ;EQ MMG$T .DRDEF RK,0,FILST$,4800.,177400,220,DMA=YES .ENDC ;EQ MMG$T .DRPTR .DREST CLASS=DVC.DK ; RK CONTROL/STATUS REGISTER DEFINITIONS RKDS = RK$CSR ;DRIVE STATUS REGISTER RKER = RKDS+2 ;ERROR REGISTER RKCS = RKDS+4 ;CONTROL & STATUS REGISTER RKWC = RKDS+6 ;WORD COUNT RKBA = RKDS+10 ;BUS ADDRESS RKDA = RKDS+12 ;DISK ADDRESS RKCNT = 8. ;NUMBER OF ERROR RETRYS RKNREG = 7 ;NUMBER OF CSR'S TO LOG ON ERRORS ; BITS IN DRIVE STATUS REGISTER (RKDS) DSID = 160000 ;ID OF INTERRUPTING DRIVE (MASK) DSDPL = 10000 ;DRIVE POWER LOW DSRK05 = 4000 ;SET => DRIVE IS RK05 DSDRU = 2000 ;DRIVE UNSAFE DSSIN = 1000 ;SEEK INCOMPLETE DSSOK = 400 ;SECTOR COUNTER OK DSDRY = 200 ;DRIVE READY DSREDY = 100 ;READ/WRITE/SEEK READY DSWPS = 40 ;WRITE PROTECT STATUS DSSCOK = 20 ;SECTOR COUNTER = SECTOR ADDRESS DSSC = 17 ;SECTOR COUNTER MASK (LOOK AHEAD) ; BITS IN ERROR REGISTER (RKER) ERDRE = 100000 ;DRIVE ERROR EROVR = 40000 ;OVERRUN ERWLO = 20000 ;WRITE LOCK OUT VIOLATION ERSKE = 10000 ;SEEK ERROR ERPGE = 4000 ;PROGRAMMING ERROR ERNXM = 2000 ;NON-EXISTENT MEMORY ERDLT = 1000 ;DATA LATE ERTE = 400 ;TIMING ERROR ERNXD = 200 ;NON-EXISTENT DISK ERNXC = 100 ;NON-EXISTENT CYLINDER ERNXS = 40 ;NON-EXISTENT SECTOR ERCSE = 2 ;CHECKSUM ERROR ERWCK = 1 ;WRITE CHECK ERROR ; BITS IN CONTROL AND STATUS REGISTER (RKCS) CSERR = 100000 ;ERROR CSHE = 40000 ;HARD ERROR CSSCP = 20000 ;SEARCH COMPLETE CSINHB = 4000 ;INHIBIT BUS ADDRESS INCREMENT CSFMT = 2000 ;FORMAT CSSSE = 400 ;STOP ON SOFT ERROR CSRDY = 200 ;CONTROL READY CSIE = 100 ;INTERRUPT ENABLE CSBA67 = 60 ;BUS ADDRESS BITS 16-17 CSBA16 = 20 ;BUS ADDRESS BIT 16 CSFUN = 16 ;FUNCTION CODE CSGO = 1 ;GO BIT ; FUNCTION CODES IN CSFUN FNRST = 0*2 ;CONTROL RESET FNWRITE = 1*2 ;WRITE FNREAD = 2*2 ;READ FNWCHK = 3*2 ;WRITE CHECK FNSEEK = 4*2 ;SEEK FNRCHK = 5*2 ;READ CHECK FNDRST = 6*2 ;DRIVE RESET FNWLK = 7*2 ;WRITE LOCK ; BITS IN DISK ADDRESS REGISTER DAUNIT = 160000 ;DRIVE SELECT BITS DACYL = 17740 ;CYLINDER BITS DASUR = 20 ;SURFACE DASC = 17 ;SECTOR BITS ; System communications area definitions SYSPTR =: 54 ;Pointer to base of RMON ; RMON fixed offsets CONFG2 =: 370 ; second configuration word BUS$ =: 000100 ; PROS$ =: 020000 ; BUS$M =: BUS$!PROS$ ;Mask for type bits BUS$X =: BUS$!PROS$ ;Strange (busless) KXJ BUS$C =: PROS$ ;CTI bus BUS$Q =: BUS$ ;QBUS BUS$U =: 0 ;UNIBUS .SBTTL Installation Code .DRINS RK NOP ;Check both data NOP ; and system device MOV @#SYSPTR,R0 ;Get address of RMON MOV CONFG2(R0),R0 ;Get configuration word for BUS check BIC #^C,R0 ;Isolate bus bits CMP #,R0 ;Running on KXJ? BEQ 10$ ;Yes, don't install CMP #,R0 ;CTI? BEQ 10$ ;Yes, don't install 5$: TST (PC)+ ;Clear carry, skip setting carry 10$: SEC ;Set carry RETURN .SBTTL SET OPTIONS .DRSET CSR, 160000, O.CSR, OCT .DRSET VECTOR, 500, O.VEC, OCT .DRSET RETRY, 127., O.RTRY, NUM .IF NE ERL$G .DRSET SUCCES, -1, O.SUCC, NO .ENDC 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 ; Now we ensure that the bootstrap reflects any change in the CSR MOV PC,R1 ;R1->READ/WRITE EMT AREA ADD #BAREA-.+4,R1 ; (BUFFER ADDRESS WORD) MOV PC,R2 ;R2->BUFFER FOR READ/WRITE ADD #1000-.,R2 ; (OVERWRITES CORE COPY OF BLOCK 1) MOV R2,(R1) ;SET BUFFER ADDRESS, MOV #BTCSR/1000,-(R1) ; BOOT BLOCK TO READ/WRITE TST -(R1) ;R1->EMT AREA MOV R0,R3 ;SAVE CSR ELSEWHERE, EMT NEEDS R0 ADD #RKDA-RKDS,R3 ; (MUST POINT TO RKDA) MOV R1,R0 ;R0->EMT AREA FOR READ EMT 375 ; *** (.READW) *** BCS O.BAD MOV R3,(R2) ;SET THE BOOTSTRAP CSR (RKDA) MOV R1,R0 ;R0->EMT AREA FOR WRITE INCB 1(R0) ; CHANGE FROM 'READ' TO 'WRITE' EMT 375 ; *** (.WRITW) *** BCS O.BAD MOV R1,R0 ;R0->EMT AREA FOR READ (LAST TIME) DECB 1(R0) ; CHANGE BACK TO 'READ' MOV #1,2(R0) ; OF HANDLER BLOCK 1 EMT 375 ; *** (.READW) *** BCS O.BAD ; Now we update the handler CSR. We do it now because the area that ; contains block 1 is used as a buffer for reading, updating and ; rewriting the boot block. MOV R3,RKCSR ;SET THE HANDLER CSR (RKDA) O.GOOD: TST (PC)+ ;GOOD RETURN (CARRY CLEAR) O.BAD: SEC ;ERROR RETURN (CARRY SET) RTS PC O.VEC: CMP R0,R3 ;IS VECTOR IN RANGE? (<500) BHIS O.BAD ;NOPE... BIT #3,R0 ;IS IT ON A VECTOR BOUNDRY? BNE O.BAD ;NOPE... MOV R0,RKSTRT ;YES, PLACE IN ENTRY AREA BR O.GOOD O.RTRY: CMP R0,R3 ;ASKING FOR TOO MANY? BHI O.BAD ;YES... MOV R0,DRETRY ;LOOKS REASONABLE, TRY IT BNE O.GOOD ;ITS OKAY... 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) MOV R3,SCSFLG ;'NOSUCCESS' ENTRY POINT BR O.GOOD .ENDC BAREA: .BYTE 17,10 ;CHANNEL 17, READ .BLKW ;BLOCK NUMBER .BLKW ;BUFFER ADDRESS .WORD 256. ;WORD COUNT .WORD 0 ;COMPLETION (WAIT) .ASSUME . LE 1000,<;SET area overflow> .SBTTL DRIVER ENTRY .DRBEG RK MOV (PC)+,(PC)+ ;SET RETRY COUNT DRETRY: .WORD RKCNT ; :MAXIMUM RETRY COUNT .ASSUME . LE RKSTRT+1000,<;SET object not in block 1> RETRY: .WORD 0 ;SIGN BIT SET IF DRIVE RESET IN PROGRESS MOV RKCQE,R5 ;GET CURRENT QUEUE ELEMENT POINTER MOV @R5,R2 ;PICK UP BLOCK NUMBER MOV Q$UNIT-1(R5),R4 ;GET REQUESTED UNIT NUMBER IN HIGH BYTE ASR R4 ;SHIFT UNIT NUMBER ASR R4 ; TO HIGH 3 BITS ASR R4 ; OF LOW BYTE SWAB R4 ;PUT UNIT NUMBER IN HIGH 3 BITS OF WORD BIC #^C,R4 ;ISOLATE UNIT IN DRIVE SELECT BITS BR 2$ ;ENTER COMPUTATION LOOP 1$: ADD R2,R4 ;ADD 16R TO ADDRESS ASR R2 ;R2 = 8R ASR R2 ;R2 = 4R ADD R3,R2 ;R2 = 4R 2$: MOV R2,R3 ;R3 = N = 16R+S BIC #^C<17>,R3 ;R3 = S BIC R3,R2 ;R2 = 16R BNE 1$ ;LOOP IF R <> 0 CMP #12.,R3 ;IF S < 12. BGT 3$ ; THEN F(S) = S ADD #4,R3 ; ELSE F(S)=F(12+S')=16+S'=4+S 3$: ADD R3,R4 ;MERGE SECTOR INTO CYL TO GET DISK ADDRESS MOV R4,DISKAD ;SAVE IT AGAIN: MOV RKCQE,R5 ;POINT TO QUEUE ELEMENT MOV #CSIE!FNWRITE!CSGO,R3 ;ASSUME A WRITE FUNCTION MOV (PC)+,R4 ;POINT TO DISK ADDRESS REGISTER RKCSR: .WORD RKDA .ASSUME . LE RKSTRT+1000,<;SET object not in block 1> MOV (PC)+,@R4 ;LOAD DISK ADDRESS & UNIT SELECT INTO RKDA DISKAD: .WORD 0 ;SAVED COMPUTED DISK ADDRESS CMP (R5)+,(R5)+ ;ADVANCE TO BUFFER ADDRESS IN QUEUE ELT .IF EQ MMG$T MOV (R5)+,R1 ;R1 = Lo order buffer address CLR R2 ;R2 = Hi order buffer address .IFF ;EQ MMG$T CALL @$MPPTR ;Convert to physical address MOV (SP)+,R1 ;R1 = Lo order buffer address MOV (SP)+,R2 ;R2 = Hi order buffer address MOV R2,R0 ;Need unshifted high order for later ASH #-4,R2 ;Shift to bottom of register .ENDC ;EQ MMG$T MOV R1,-(R4) ;Set the lo order buffer address MOV (R5),-(SP) ;Get the transfer word count BPL 46$ ;(SP) = |(SP)| NEG (SP) ; 46$: ADD (SP),R1 ;Add transfer size to double- ADC R2 ; precision buffer start address ADD (SP)+,R1 ; (done twice, argument is in words) ADC R2 ;R2 now contains hi order component ; of buffer end address ; (If end of transfer is within ; limits, start must be also!) MOV #<^B11>,-(SP) ;U-bus controller can handle 18-bit ; transfers MOV @#SYSPTR,R1 ;R1 -> $RMON BIT #,CONFG2(R1) ;Running on qbus? BEQ 47$ ;Nope... CLR (SP) ;Q-bus controller can handle 16-bit ; transfers 47$: BIC (SP)+,R2 ;Strip off allowed hi-order component BNE HERROR ;Anything else is wrong MOV (R5)+,-(R4) ;PUT WORD COUNT INTO RKWC BEQ 7$ ;0 COUNT => SEEK BMI 5$ ;NEGATIVE => WRITE, SO ALL SET UP NEG @R4 ;POSITIVE => READ, FIX COUNT FOR CONTROLLER MOV #CSIE!FNREAD!CSGO,R3 ;FUNCTION IS READ 5$: .IF NE MMG$T BIS R0,R3 ;MERGE HIGH ORDER ADDRESS BITS INTO FUNCTION .ENDC ;NE MMG$T MOV R3,-(R4) ;START THE OPERATION 6$: RTS PC ;AWAIT INTERRUPT 7$: MOV #CSIE!FNSEEK!CSGO,-(R4) ;START UP A SEEK BR 6$ ;AWAIT INTERRUPT .IF NE ERL$G SCSFLG: .WORD 0 ;SUCCESSFUL LOGGING FLAG (DEFAULT=TRUE) .ASSUME . LE RKSTRT+1000,<;SET object not in block 1> ; = 0, SUCCESSFUL LOGGING ON ; <> 0, SUCCESSFUL LOGGING OFF .ENDC .SBTTL INTERRUPT ENTRY POINT .DRAST RK,5 MOV RKCSR,R5 ADD #RKER-RKDA,R5 ;R5->ERROR STATUS REGISTER MOV (R5)+,R4 ;GET ERROR REGISTER, POINT TO RKCS TST RETRY ;WERE WE DOING A DRIVE RESET? BPL NORMAL ;NO, NORMAL OPERATION TST @R5 ;ANY ERROR ON DRIVE RESET? BMI NORMAL ;YES, HANDLE NORMALLY BIT #CSSCP,@R5 ;RESET DONE YET (SEARCH COMPLETE)? BEQ RTSPC ;NO, INTERRUPT AGAIN WHEN RESET COMPLETE .FORK RKFBLK ;CONTINUE RETRY AFTER RESET AT FORK LEVEL RKRETR: CLRB RETRY+1 ;CLEAR RESET-IN-PROGRESS FLAG BR AGAIN ;RETRY THE OPERATION (AT FORK LEVEL) NORMAL: CMP @R5,#CSRDY!CSIE!FNSEEK ;FIRST OF 2 INTERRUPTS CAUSED BY SEEK? BEQ RTSPC ;YES, IGNORE IT. INTERRUPT AGAIN WHEN COMPLETE TST @R5 ;ANY ERRORS? BPL DONE ;NO, WE'RE ALL DONE .FORK RKFBLK ;PROCESS ERRORS AT FORK LEVEL .IF NE ERL$G BIT #EROVR!ERWLO!ERNXM!ERNXD!ERNXC!ERNXS,R4 ;USER ERROR? BNE RKERR ;YES, DON'T LOG IT MOV PC,R5 ;GET REGISTER SAVE AREA ADDRESS ADD #RKRBUF-.,R5 ; IN A PIC WAY MOV R5,R2 ;SAVE ADDRESS IN FOR ERROR LOGGER MOV RKCSR,R3 ADD #RKDS-RKDA,R3 ;R3->CONTROLLER REGISTERS MOV #RKNREG,R4 ;GET COUNT OF REGISTERS TO COPY RKRREG: MOV (R3)+,(R5)+ ;MOVE REGISTERS TO BUFFER DEC R4 ;DONE? BNE RKRREG ;NO, MORE MOV DRETRY,R3 SWAB R3 ADD #RKNREG,R3 ;R3= MAX RETRY COUNT/NUMBER OF REGISTERS MOV RKCQE,R5 ;POINT TO THIRD WORD OF QUEUE ELEMENT MOVB RETRY,R4 ;GET RK$COD(=0)/RETRY COUNT DEC R4 ;RETRY COUNT VALUE AFTER IT IS DECREMENTED JSR PC,@$ELPTR ;CALL ERROR LOGGER MOV RKCSR,R5 ADD #RKER-RKDA,R5 ;RESET REGISTERS ON RETURN MOV (R5)+,R4 ; ON RETURN .ENDC ;NE ERL$G RKERR: MOV #FNRST!CSGO,@R5 ;RESET CONTROLLER 3$: TSTB @R5 ;WAIT BPL 3$ ; FOR RESET TO TAKE DECB RETRY ;ANY RETRIES LEFT? BEQ HERROR ;NO, CALL IT A HARD ERROR BIT #ERDRE!ERSKE,R4 ;SEEK INCOMPLETE OR DRIVE ERROR? BEQ RKRETR ;NO, JUST RETRY OPERATION MOV DISKAD,@RKCSR ;YES, RESELECT DRIVE BIS #100000,RETRY ;SET RESET-IN-PROGRESS FLAG MOV #CSIE!FNDRST!CSGO,@R5 ;START A DRIVE RESET RTSPC: RTS PC ;AWAIT INTERRUPT HERROR: MOV RKCQE,R5 ;HARD ERROR, POINT TO QUEUE ELEMENT BIS #HDERR$,@-(R5) ;SET HARD ERROR STATUS IN CHANNEL .IF NE ERL$G BR RKEXIT ;EXIT AFTER ERROR DONE: .FORK RKFBLK ;CALL ERROR LOG AT FORK LEVEL FOR SUCCESS TST SCSFLG ;LOGGING SUCCESSES? BNE RKEXIT ;NOPE... MOV (PC)+,R4 ;SUCCESS, SET RK ID CODE IN HIGH BYTE, .BYTE 377,RK$COD ; -1 IN LOW BYTE FOR SUCESS MOV RKCQE,R5 ;POINT TO THIRD WORD OF QUEUE ELEMENT JSR PC,@$ELPTR ;CALL ERROR LOGGER .IFF DONE: .ENDC RKEXIT: CLR RETRY ;CLEAR RETRY AND RESET FLAGS .DRFIN RK ;EXIT TO COMPLETION RKFBLK: .WORD 0,0,0,0 ;FORK QUEUE BLOCK .IF NE ERL$G RKRBUF: .BLKW RKNREG ;ERROR LOG STORAGE FOR REGISTERS .ENDC .SBTTL BOOTSTRAP DRIVER .DRBOT RK,BOOT1,READ . = RKBOOT+40 ;PUT THE JUMP BOOT INTO SYSCOM AREA BOOT1: JMP @#BOOT-RKBOOT ;START THE BOOTSTRAP . = RKBOOT+210 READ: MOV #12.,R3 ;PHYSICAL BLOCK TO RK DISK ADDRESS BR 2$ ;ENTER BLOCK NUMBER COMPUTATION 1$: ADD #20,R3 ;CONVERT DISK ADDRESS 2$: SUB #12.,R0 BPL 1$ ADD R3,R0 ;R0 HAS DISK ADDRESS MOV BOTCSR,R3 ;R3->DISK ADDRESS REGISTER BIC #^C,@R3 ;LEAVE THE UNIT NUMBER BIS R0,@R3 ;PUT DISK ADDRESS INTO CONTROLLER MOV R2,-(R3) ;BUFFER ADDRESS MOV R1,-(R3) ;WORD COUNT NEG @R3 ;(NEGATIVE) MOV #FNREAD!CSGO,-(R3) ;START DISK READ 3$: TSTB @R3 ;WAIT UNTIL COMPLETE BPL 3$ TST @R3 ;ANY ERRORS BMI BIOERR ;HARD HALT ON ERROR ;CLC ;CARRY IS CLEAR FROM 'TST' ABOVE RTS PC . = RKBOOT+574 BOOT: MOV #10000,SP ;SET STACK POINTER MOV @(PC)+,-(SP) ;GET THE RK UNIT NUMBER BOTCSR: .WORD RKDA ROL @SP ;SHIFT IT ROL @SP ; AROUND THE TOP ROL @SP ; TO THE LOW 3 BITS ROL @SP ; OF THE WORD BIC #^C<7>,@SP ;EXTRACT THE UNIT NUMBER MOV #2,R0 ;READ IN SECOND PART OF BOOT FROM BLOCK 2 MOV #<4*400>,R1 ;EVERY BLOCK BUT THE ONE WE ARE IN (4 BLOCKS) MOV #1000,R2 ;INTO LOCATION 1000 JSR PC,READ ;GO READ IT IN MOV #READ-RKBOOT,@#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 RK .END