.MCALL .MODULE .MODULE DL,VERSION=42,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 ; VENU$C (0) VAX8600 console version ; 0 PDP11 version ; 1 VAX8600 console version ; VENU$C=1 only with MMG$T & ERL$G = 0 ; ; DL$UN (2) unit to support (additive only) ; 1-4 valid range ; ; EIS$I (MMG$T) use SOB instruction (no code effects!) ; 0 simulate SOB ; 2 use SOB ; ; DL$CSR (174400) CSR ; DL$VEC (160) Vector ; (130) if VENU$C=1 ; ; MMG$T std conditional ; TIM$IT std conditional (no code effects) ; ERL$G std conditional ;- .SBTTL MACROS AND DEFINITIONS .ENABL LC .MCALL .DRDEF, .MFPS, .MTPS, .ASSUME, .ADDR, .BR .LIBRARY "SRC:SYSTEM.MLB" .MCALL .UBVDF .UBVDF ; VECTOR DEFINITIONS NXM.V =: 4 ;NON-EXISTENT MEMORY TRAP VECTOR IOT.V =: 20 ;IOT TRAP VECTOR ; VENUS CONDITIONAL .IIF NDF VENU$C, VENU$C == 0 ;TURN OFF - IF NOT DEFINED. ; VENUS RESTRICTIONS .IF NE MMG$T ; No support under XM. .ASSUME VENU$C EQ 0 MESSAGE=<; no VENUS support under extended memory > .ENDC .IF NE ERL$G ; No support under error logger .ASSUME VENU$C EQ 0 MESSAGE=<; no VENUS support under error logger> .ENDC ; SYSTEM GENERATION OPTION .IIF NDF DL$UN, DL$UN == 2 ;NUMBER OF UNITS SUPPORTED .IIF GT DL$UN-4, DL$UN == 4 ;CAN'T HAVE MORE THAN 4 UNITS .IIF LE DL$UN, DL$UN == 1 ;CAN'T HAVE NO UNITS .IRP X,<\DL$UN> .SBTTL *** THIS HANDLER SUPPORTS X UNITS *** .ENDR ; SPECIAL FUNCTION DEFINITIONS ; ALL SPECIAL FUNCTIONS ARE DMA EXCEPT FOR FN$SIZ AND FN$GET ; FN$WRT AND FN$RED GO IN UBTAB. FN$REP USES A PERMANENT UMR .IIF NE VENU$C, FN$GET =: 370 ;GET DEVICE STATUS FN$SIZ =: 373 ;GET DEVICE SIZE FN$REP =: 374 ;FORCE RE-READ OF REPLACEMENT TABLE FN$WRT =: 376 ;ABSOLUTE WRITE (NO BAD BLOCK) FN$RED =: 377 ;ABSOLUTE READ (REPLACEMENT) ;NOTE: if you add a SPFUN code also add it to .DRSPF ; ERROR LOGGING DEFINITIONS DLRCNT =: 8. ;ERROR RETRY COUNT DLREG =: 6 ;REGISTERS TO LOG ON ERROR ; RL11/RL01 PARAMETERS ; GEOMETRY: 256 CYLINDERS (512 ON RL02) ; 2 TRACKS PER CYLINDER ; 20 BLOCKS PER TRACK ; 2 128-WORD SECTORS PER BLOCK DLBPT =: 20. ;NUMBER OF BLOCKS PER TRACK DLWPT =: 256.*DLBPT ;WORDS PER TRACK DLNBAD =: 10. ;NUMBER ALLOWABLE BAD BLOCKS PER DISK DLSIZE =: <256.*2-1>*DLBPT-DLNBAD ;BLOCKS PER RL01 (LESS BSF) DLSIZ2 =: <512.*2-1>*DLBPT-DLNBAD ;BLOCKS PER RL02 (LESS BSF) DLTSIZ =: DLNBAD*4.+2 ;SIZE OF BAD BLOCK TABLE ; (PLUS END OF TABLE FENCE) ; UB DEFINITIONS ; FIXED OFFSETS EQUATES (.FIXDF) $PNPTR =: 000404 ;RMON OFFSET OF PNAME TABLE P1$EXT =: 000432 ;RMON OFFSET OF $P1EXT ADDRESS $H2UB =: 000460 ;RMON OFSET OF UB ENTRY VECTOR PTR ; EXTENDED MEMORY SUBROUTINE OFFSETS FROM $P1EXT (.PIXDF) $MPMEM =: -22. ;OFFSET TO MAP KT-11 VIRTUAL TO PHYSICAL ; UB ENTRY VECTOR EQUATES (.UBVDF) ; UB.IDV =: 0 ; IDENTIFICATION WORD ; UB.VDV =: <^rUBV> ; IDENTIFICATION WORD VALUE ; UB.GET =: 2 ; JUMP TO GETUMR ; UB.ALL =: 6 ; JUMP TO ALLUMR ; UB.RLS =: 12 ; JUMP TO RLSUMR ; DL INTERNAL DMA BUFFER EQUATES BUFSIZ =: 54/2*DL$UN ; SIZE OF DL INTERNAL DMA BUFFER ; WORD SIZE OF DLBBUF*DL$UN NOUMRS =: ; NUMBER OF PERMANENT UMRS REQUIRED .SBTTL HANDLER MACROS .IF EQ VENU$C ;If not VENUS console .IF EQ MMG$T .DRDEF DL,5,FILST$!SPFUN$!VARSZ$,DLSIZE,174400,160,DMA=NO .DRPTR .IFF ;EQ MMG$T .DRDEF DL,5,FILST$!SPFUN$!VARSZ$,DLSIZE,174400,160,DMA=YES,PERMUMR=NOUMRS .DRPTR FETCH=FETCH,LOAD=FETCH,RELEASE=RELEAS,UNLOAD=RELEAS .ENDC ;EQ MMG$T .DREST CLASS=DVC.DK,REPLACE=RTABLE .IFF ;EQ VENU$C ;If VENUS console .DRDEF DL,5,FILST$!SPFUN$!VARSZ$,DLSIZ2,174400,130 .DRPTR .DREST CLASS=DVC.DK .ENDC ;EQ VENU$C .IF NE MMG$T .DRSPF +UBTAB ;SPFUN FOR UB GOES IN TABLE UBTAB .ENDC ;NE MMG$T .DRSPF .IIF NE VENU$C, .DRSPF ;GET DEVICE STATUS .DRSPF ;GET DEVICE SIZE .DRSPF ;FORCE RE-READ OF REPLACEMENT TABLE .DRSPF ;ABSOLUTE WRITE (NO BAD BLOCK) .DRSPF ;ABSOLUTE READ (REPLACEMENT) .IIF NDF EIS$I EIS$I = MMG$T .IIF EQ EIS$I .MCALL SOB .SBTTL HARDWARE DEFINITIONS ; RL11 DEVICE REGISTER OFFSETS .IF EQ VENU$C ;DEFINE THE OFFSETS RLCS =: 0 ;CONTROL STATUS REGISTER RLBA =: 2 ;BUS ADDRESS REGISTER RLDA =: 4 ;DISK ADDRESS REGISTER RLMP =: 6 ;MULTI-PURPOSE REGISTER RLBAE =: 10 ;BUS ADDRESS REGISTER (EXTENDED) .IFF RLCS =: 174400 ;CONTROL STATUS REGISTER RLBA =: 174402 ;BUS ADDRESS REGISTER RLDA =: 174404 ;DISK ADDRESS REGISTER RLMP =: 174406 ;MULTI-PURPOSET REGISTER RLBAE =: 174410 ;BUS ADDRESS REGISTER (EXTENDED) .ENDC ; RLCS BIT ASSIGNMENTS CSERR =: 100000 ;ERROR SUMMARY CSDE =: 040000 ;DRIVE ERROR CSERRC =: 036000 ;ERROR CODE MASK CSNXM =: 020000 ;NON-EXISTENT MEMORY CSDLT =: 010000 ;DATA LATE CSHNF =: 010000 ;HEADER NOT FOUND CSDCRC =: 004000 ;DATA CRC ERROR CSHCRC =: 004000 ;HEADER CRC ERROR CSOPI =: 002000 ;OPERATION INCOMPLETE CSDS01 =: 001400 ;DRIVE SELECT BITS 0 AND 1 CSDS0 =: 000400 ;DRIVE SELECT BIT 0 CSCRDY =: 000200 ;CONTROLLER READY CSIE =: 000100 ;INTERRUPT ENABLE CSBA17 =: 000040 ;BUS ADDRESS BIT 17 CSBA16 =: 000020 ;BUS ADDRESS BIT 16 CSFUN =: 000016 ;FUNCTION CODE CSDRDY =: 000001 ;DRIVE READY ; RLCS FUNCTION CODE VALUES FNNOP =: 0*2 ;NO OPERATION FNWCHK =: 1*2 ;WRITE CHECK FNGSTS =: 2*2 ;GET DRIVE STATUS FNSEEK =: 3*2 ;SEEK FNRDH =: 4*2 ;READ HEADERS FNWRITE =: 5*2 ;WRITE DATA FNREAD =: 6*2 ;READ DATA FNRDNH =: 7*2 ;READ DATA WITH NO HEADER CHECK ; RLMP GET STATUS RETURNED BIT ASSIGNMENTS STWDE =: 100000 ;WRITE DATA ERROR STCHE =: 040000 ;CURRENT HEAD ERROR STWL =: 020000 ;WRITE LOCK STATUS STSKTO =: 010000 ;SEEK TIMEOUT ERROR STSP =: 004000 ;SPEED ERROR STWGE =: 002000 ;WRITE GATE ERROR STVC =: 001000 ;VOLUME CHECK STDSE =: 000400 ;DRIVE SELECT ERROR STDT =: 000200 ;DRIVE TYPE STHS =: 000100 ;HEAD SELECT STATUS STCO =: 000040 ;COVER OPEN STHO =: 000020 ;HEADS HOME STBH =: 000010 ;BRUSHES HOME STST =: 000007 ;STATE BIT MASK STSLM =: 000005 ;DRIVE IN SEEK-LINEAR MODE STATE ; RLDA BIT VALUES FOR SEEK COMMANDS SKCADF =: 077600 ;CYLINDER ADDRESS DIFFERENCE SKCA0 =: 000200 ;CYLINDER ADDRESS DIFFERENCE BIT 0 SKHS =: 000020 ;HEAD SELECT (SURFACE 0 OR 1) SKDIR =: 000004 ;DIRECTION (0 => OUTWARD, 1 => INWARD) SKMARK =: 000001 ;MARK BIT MUST BE 1 TO INDICATE A SEEK ; RLDA BIT VALUES FOR I/O COMMANDS IOCA =: 077600 ;CYLINDER ADDRESS IOCA0 =: 000200 ;CYLINDER ADDRESS BIT 0 IOHS =: 000100 ;HEAD SELECT IOSA =: 000077 ;SECTOR ADDRESS MASK ; RLDA BIT VALUES FOR GET STATUS COMMAND GSRST =: 000010 ;RESET DRIVE GSGS =: 000002 ;GET STATUS INDICATOR MUST BE 1 GSMARK =: 000001 ;THIS MUST BE 1 TO INDICATE GET STATUS ; RMON REFERENCES SYSPTR =: 54 ; SYSCOM pointer to RMON 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 .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 .IF NE VENU$C .SBTTL QBUS/RL GENERIC ACCESS MACROS ;+ ; The following macros are used to communicate with the RL02 thru the ; Q-bus adapter. Two sets of macros have been defined, one for the ; run-time code and the other for the primary driver. In each set there ; is a macro to send data to the RL and to receive data from it. ;- ; Primary Driver macros .MACRO MOVTORL SRC,DST .IIF DIF , MOV SRC,R5 JSR R4,TORL .WORD DST .ENDM MOVTORL .MACRO MOVFMRL SRC,DST JSR R4,FMRL .WORD SRC .IF NB,DST .IIF DIF , MOV R5,DST .ENDC .ENDM MOVFMRL ; Run-time code macros .MACRO HANTORL SRC,DST .IIF DIF , MOV SRC,R4 CALL HTORL .WORD DST .ENDM HANTORL .MACRO HANFMRL SRC,DST CALL HFMRL .WORD SRC .IIF DIF , MOV R4,DST .ENDM HANFMRL .ENDC .IF NE VENU$C .SBTTL QBUS Interface registers and bit definitions ;+ ; This is the interface which the handler will use to talk to the ; RL02 controller. ;- ; Bit definitions BIT0 =: 000001 BIT1 =: 000002 BIT2 =: 000004 BIT3 =: 000010 BIT4 =: 000020 BIT5 =: 000040 BIT6 =: 000100 BIT7 =: 000200 BIT8 =: 000400 BIT9 =: 001000 BIT10 =: 002000 BIT11 =: 004000 BIT12 =: 010000 BIT13 =: 020000 BIT14 =: 040000 BIT15 =: 100000 ; Qbus interface registers defined $QCSR0 =: 176400 ; QBUS CONTROL STATUS REG 0 $QCSR1 =: 176401 ; " " " " " " " " " " " " 1 $QCSR2 =: 176402 ; " " " " " " " " " " " " 2 $QCSR3 =: 176403 ; " " " " " " " " " " " " 3 $QDAT0 =: 176404 ; QBUS DATA REGISTER BYTE 0 $QDAT1 =: 176405 ; " " " " " " " " " " " " 1 $QADR0 =: 176406 ; QBUS ADDRESS REGISTER BYTE 0 $QADR1 =: 176407 ; " " " " " " " " " " " " " 1 ; $QCSR0 bit definition REQMASTER =: BIT0 ; REQ MASTER H MSTRPEND =: BIT1 ; MASTER PEND H QBAWRT =: BIT2 ; QBA WRITE H QBAREAD =: BIT3 ; QBA READ H QBAIE =: BIT4 ; QBA IE H DMAENA =: BIT5 ; ENA QBUS DMA H QBAINIT =: BIT6 ; QBA INIT H DIAGMODE =: BIT7 ; MAINT MODE H .ENDC ; NE VENU$C .IF EQ VENU$C ;Installation code not needed in ;Venus! .SBTTL INSTALLATION CODE .DRINS DL BR 10$ ;Data device installation check .ASSUME . EQ INSSYS BR 20$ ;System device installation check (none) 10$: 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 30$ ;Yes, don't install CMP #,R0 ;CTI? BEQ 30$ ;Yes, don't install 20$: TST (PC)+ ; clear carry, skip setting carry 30$: SEC ; set carry 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 RTABLE: .BYTE 2,10.,5.,2.,40.,1. ; Replacement factors table ; all replacable ; 10. blocks to skip ; 5. sectors of bad sector file ; 2. tracks per cylinder ; 40. sectors per track ; 2**1 sectors per block .Assume . LE 400,MESSAGE=<;Install code overflow> .ENDC .IF EQ VENU$C ; Set options not needed in Venus! .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 ;NE ERL$G BTCSR = ++1000 ; SET DL CSR=address O.CSR: CMP R0,R3 ;CSR IN RANGE? BLO O.BAD ;NOPE... MOV R0,INSCSR ;YES, INSTALLATION CODE NEEDS IT MOV R0,DISCSR ;AND RESORC DOES TOO ; When the CSR is changed, we must also alter the bootstrap so ; that it will use the correct CSR. ;R1->READ/WRITE EMT AREA .ADDR #BAREA+4,R1 ; (BUFFER ADDRESS WORD) ;R2->BUFFER .ADDR #1000,R2 ; (OVERWRITES CORE COPY OF BLOCK 1) MOV R2,(R1) ;SET THE BUFFER ADDRESS MOV #BTCSR/1000,-(R1) ; THE BLOCK TO READ/WRITE ; (BOOT BLOCK THAT NEEDS ALTERING) 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) ;CHANGE FROM 'READ' TO 'WRITE' EMT .WRITE ; *** (.WRITW) *** BCS O.SYWL MOV R1,R0 ;R0->EMT AREA (LAST TIME, HONEST) .ASSUME ..WRIT-1 EQ ..READ DECB 1(R0) ;CHANGE FROM 'WRITE' TO 'READ' MOV #1,2(R0) ; OF HANDLER BLOCK 1 EMT .READ ; *** (.READW) *** BCS O.BAD MOV R3,DLCSR ;TELL HANDLER ABOUT NEW CSR O.GOOD: TST (PC)+ ;GOOD RETURN (CARRY CLEAR) O.BAD: SEC ;ERROR RETURN (CARRY SET) RETURN ; SET DL VECTOR=address O.VEC: CMP R0,R3 ;VECTOR IN RANGE? (<500) BHIS O.BAD ;NOPE... BIT #3,R0 ;YES, BUT ON A VECTOR BOUNDRY? BNE O.BAD ;NOPE... MOV R0,DLSTRT ;TELL HANDLER ABOUT NEW VECTOR BR O.GOOD ; SET DL RETRY=count O.RTRY: CMP R0,R3 ;Test retry limits BHI O.BAD ;Branch if out of bounds MOV R0,DRETRY ;Store the user selected retry count BEQ O.BAD ;Zero retries not allowed BR O.GOOD ;Otherwise, good .IF NE ERL$G ; SET DL [NO]SUCCES O.SUCC: MOV #0,R3 ;'SUCCESS' ENTRY POINT ; (MUST BE TWO WORDS) MOV R3,SCSFLG ;'NOSUCCESS' ENTRY POINT BR O.GOOD .ENDC ;NE ERL$G BAREA: .BYTE SYSCHN,..READ ;CHANNEL 17, READ .BLKW ;BLOCK NUMBER .BLKW ;BUFFER ADDRESS .WORD 256. ;WORD COUNT .WORD 0 ;COMPLETION (WAIT) .Assume . LE 1000,MESSAGE=<;Set area overflow> .ENDC .SBTTL REQUEST ENTRY POINT .ENABL LSB .IF EQ MMG$T .DRBEG DL .IFF ;EQ MMG$T .DRBEG DL,SPFUN=UBTAB .ENDC ;EQ MMG$T DLBASE=DLSTRT+6 MOV DLCQE,R5 ;POINT TO CURRENT QUEUE ELEMENT MOV (PC)+,R4 ;POINT TO CONTROLLER CSR .ASSUME .-DLSTRT LT 1000 DLCSR: .WORD DL$CSR ;ADDRESS OF CONTROLLER MOV Q$FUNC(R5),R0 ;GET FUNCTION CODE / UNIT NUMBER MOVB R0,R2 ;GET SPECIAL FUNCTION CODE ;[+GTS] *** START OF ADDED CODE *** .IF NE VENU$C CMPB R2,#FN$GET ;.SPFUN TO GET SPECIAL STATUS BEQ 10$ ;YES, VALID .SPFUN REQUEST .ENDC ;NE VENU$C CMPB R2,#FN$SIZ ;.SPFUN LESS THAN 373 (SIGNED BYTE) BLT 5$ ;YES, .SPFUN 200 THRU 372 INVALID CMPB R2,#FN$REP+1 ;IS THIS .SPFUN 375 BNE 10$ ;NO, HAVE VALID SPFUN REQUEST 5$: JMP DLQCOM ;DISMISS QUEUE REQUEST 10$: ;[+GTS] *** END OF ADDED CODE *** BIC #^C<7*400>,R0 ;ISOLATE UNIT NUMBER BITS CMP R0,#DL$UN*400 ;DO WE SUPPORT THIS UNIT? BHIS DLELNK ;NO, ERROR NOW MOV R0,DLUNIT ;SAVE UNIT NUMBER .ASSUME CSDS01 EQ 3*400 MOV #FNREAD!CSIE,DLCODE ;ASSUME READ (FOR TABLE) .IF NE MMG$T CMPB R2,#FN$SIZ ;SEE IF .SPFUN GET SIZE BEQ 15$ ;YES -- DON'T CHANGE Q.BUFF AND Q.PAR .ASSUME Q$BLKN+4 EQ Q$BUFF CMP (R5)+,(R5)+ ;POINT TO Q.BUFF IN QUEUE ELEMENT .ASSUME Q$BUFF+2 EQ Q$WCNT ; done by MPPTR CALL @$MPPTR ;CONVERT ADDRESS TO 18 BIT PHYSICAL .ASSUME Q$WCNT-2 EQ Q$BUFF MOV (SP)+,-(R5) ;REPLACE Q.BUFF WITH BITS <15:00> .ASSUME Q$BUFF-4 EQ Q$BLKN CMP -(R5),-(R5) ;FIX QUEUE ELEMENT POINTER MOV (SP)+,Q$PAR(R5) ;SAVE BITS <21:16> IN Q.PAR WORD .ENDC ;NE MMG$T 15$: .ADDR #DLBBUF-,R3 ; GET BIASED ADDRESS OF TABLE BUFFER SWAB R0 ;GET UNIT NUMBER 20$: ADD #DLTSIZ+2,R3 ;POINT TO NEXT UNIT'S TABLE DEC R0 ; REDUCE UNIT NUMBER BPL 20$ ; ALL GONE? MOV R3,(PC)+ ;SAVE POINTER TO UNIT'S DLCC: .WORD 0 ; CURRENT CYLINDER TABLE (LOW ADDR) TST (R3)+ ;POINT TO REPLACEMENT TABLE .ASSUME .+4 EQ DLUSIZ .IF EQ VENU$C ;If not VENUS console MOV #DLSIZE,(PC)+ ;ASSUME RL01 .IFF ;EQ VENU$C ;If VENUS console ;***NOTE*** Assume Venus will always use RL02s MOV #DLSIZ2,(PC)+ ;ASSUME RL02 .ENDC ;EQ VENU$C DLUSIZ: .WORD 0 .IF EQ VENU$C CALL DLGST ;GET DISK STATUS TSTB R1 ;SINGLE DENSITY? BPL 25$ ;IF ZERO, RL01 SINGLE DENSITY MOV #DLSIZ2,DLUSIZ ;IF SET, RL02 DOUBLE DENSITY 25$: TST R0 ;Now, error in get status? BMI 30$ ;Yes, invalidate everything BIT #STVC,R1 ;IS THERE A NEW DISK IN THIS DRIVE? BEQ 35$ ;NO, SAME AS LAST TIME 30$: MOV #-1,-(R3) ;INVALIDATE CURRENT CYLINDER MOV (R3)+,@R3 ; AND INVALIDATE REPLACEMENT TABLE .IFF CMPB R2,#FN$GET ;SEE IF .SPFUN GET SPECIAL STATUS BEQ DLGSTA ;YES, GO DO IT! CALL DLGST ;GET DISK STATUS (NORMAL) TST R0 ;Now, error in get status? BMI 30$ ;Yes, invalidate everything CALL INVVC ;INVALIDATE IF VOLUME CHECK ON BR 35$ ;SKIP NEXT 30$: CALL INVAL ;UNCONDITIONAL INVALIDATION .ENDC 35$: CMPB R2,#FN$REP ;CHECK OUT THE SPECIAL FUNCTION BGE 40$ ;BRANCH IF NOT 'GET SIZE' ; (NOTE SIGNED COMPARE) JMP DLGSIZ ;GO DO 'GET SIZE' 40$: BEQ 50$ ;GO READ BAD-BLOCK REPLACEMENT TABLE BHI 55$ ;GO DO ABSOLUTE BLOCK READ/WRITE TST Q$WCNT(R5) ;NORMAL REQUEST, SEEK? BNE 45$ ;BRANCH IF NOT DLFLNK: JMP DLQCOM ;.DRFIN TIME 45$: TST @R3 ;IS TABLE IN MEMORY YET? BPL DLTRAN ;YES, WE CAN GO DO THE TRANSFER ; ; WE ALWAYS COME HERE TO REREAD THE REPLACEMENT TABLE ; 50$: .IF NE MMG$T MOV R3,-(SP) ;SAVE R3 .ADDR #DLBBUF,R3 ;R3=PIC ADDRESS OF START OF DLBBUF MOV DLCC,R1 ;R1=START ADDRESS FOR THIS UNIT SUB R3,R1 ;R1=OFFSET INTO DLBBUF FOR THIS UNIT ADD #2,R1 ;POINT TO REPLACEMENT TABLE MOV BUFADH,R2 ;GET HI ORDER DLBBUF ADDRESS MOV BUFADL,R3 ;GET LOW ORDER DLBBUF ADDRESS ADD R1,R3 ;R3=THIS UNIT'S START ADDR IN UMR BCC 52$ ;BRANCH IF NO CARRY ADD #CSBA16,R2 ;ADD CARRY TO HI ORDER ADDR 52$: MOV R2,DLBPAR ;PUT HI ORDER ADDR INTO PSEUDO QEL ; MOV Q$MEM(R5),DLBMEM ;PUT Q$MEM INTO PSEUDO QEL (NOT NEEDED) .ENDC ;NE MMG$T MOV #1,R1 ;TABLE IS IN BLOCK 1 MOV #DLTSIZ/2,R2 ;WORDS TO READ (TABLE SIZE) CALL DLSQUE ;SET UP REST OF PSEUDO QUEUE ELEMENT .IF NE MMG$T MOV (SP)+,R3 ;RESTORE R3 (ADDR FOR MOV'S) .ENDC ;NE MMG$T MOV #-1,@R3 ;FLAG THAT THERE IS NO TABLE IN MEMORY MOV @R3,-(R3) ;VOID CURRENT CYLINDER, TOO BR DLADDR ;COMPUTE DISK ADDRESS AND START THE ; TABLE READ 55$: INCB R2 ;ABSOLUTE BLOCK READ? .ASSUME FN$RED EQ 377 BEQ DLADDR ;YES, WE ARE ALL SET UP MOV #FNWRITE!CSIE,DLCODE ;SET WRITE FUNCTION CODE BR DLADDR ;GO DO IT .IF NE ERL$G .ASSUME .-DLSTRT LT 1000 SCSFLG: .WORD 0 ; :SUCCESS LOGGING FLAG (DEFAULT=YES) ; =0 - LOG SUCCESSES ;<>0 - DON'T LOG SUCCESSES .ENDC ;NE ERL$G .DSABL LSB .IF NE VENU$C .SBTTL GET SPECIAL DEVICE STATUS ;+ ; Special function to get volume status: ; o Block 0 - request return new status ; o block 1 - request return old status ; o block 2 - request return new status (do reset function too) ; o block 3 - request enable volume valid enforcement ; ; CSR and MPR contents returned in first 2 word of user's buffer ; DLGSTA: MOV @R5,R4 ; LOAD REQUEST SUBCODE CMP #4,R4 ; IS IT WITHIN RANGE ? BLO DLELNK ; NO, ERROR ASL R4 ; MAKE INTO WORD INDEX ADD R4,PC ; STRANGE INDEXED JUMP PIC .370.X: .ASSUME . EQ .370.X+<0*2> BR .370.0 ; SUBCODE 0 .ASSUME . EQ .370.X+<1*2> BR .370.1 ; SUBCODE 1 .ASSUME . EQ .370.X+<2*2> BR .370.2 .ASSUME . EQ .370.X+<3*2> BR .370.3 .ASSUME . EQ .370.X+<4*2> .370.4: CLRB VOLCHK ; DISABLE VOLUME CHECKING BR DLFLNK ; DONE .370.3: MOV R4,#0 ; CLEAR NEWVOL, SET VOLCHK .=.-2 ; THIS DEPENDS ON THE CODE FOR 370 SUB 3 VOLCHK: .BLKB 1 ; BEING NON-ZERO IN LOW BYTE NEWVOL: .BLKB 1 ; AND ZERO IN THE HIGH BYTE BR DLFLNK .370.2: CALL DLGST ; GET STATUS CALL INVVC ; INVALIDATE STUFF IF STVC ON CALL DLRST ; GET NEW STATUS WITH RESET CLRB NEWVOL ; CLEAR POSSIBLE VOL VALID FLG BR .370.1 ; JOIN COMMON CODE .370.0: CALL DLGST ; GET NEW STATUS .370.1: .IF EQ MMG$T MOV Q$BUFF(R5),R4 ; POINT TO BUFFER MOV STATCS,(R4)+ ; RETURN VALUES MOV STATMP,(R4)+ ; ... DITTO BR DLFLNK ; DONE .IFF MOV R5,R4 ; Q-ELEMENT PTR IN R4 MOV STATCS,-(SP) ; PASS TO PUTWORD CALL @$PTWRD ; TO USER MOV STATMP,-(SP) ; PASS TO PUTWORD CALL @$PTWRD ; TO USER BR DLFLNK ; DONE .ENDC ;EQ MMG$T ; Common invalidation routines. INVVC: BIT #STVC,R1 ; IS THERE A NEW DISK ? BEQ INVRET ; NO, EXIT INVAL: MOV #-1,-(R3) ; INVALIDATE CURRENT CYLINDER MOV (R3)+,@R3 ; INVALIDATE REPLACEMENT TABLE MOVB @PC,NEWVOL ; INDICATE VOLUME INVALID ;*NOTE* This depends on NEWVOL being on an odd address. TSTB VOLCHK ; ARE WE CHECKING FOR INVALID BNE DLELNK ; YES, THEN HARD ERROR INVRET: RETURN .ENDC ;NE VENU$C DLELNK: JMP DLEROR ;LINK TO FATAL ERROR .SBTTL INITIALIZE FOR TRANSFER, SET FUNCTION CODE, FIX WORD COUNT ;+ ; SET READ OR WRITE FUNCTION CODE ; IF TRANSFER HAS REPLACED BLOCKS IN IT, BREAK IT INTO PIECES AND ; SEND EACH PIECE TO DLADDR SEPARATELY FOR I/O ; NOTE: ALL PIECES EXCEPT THE FIRST ARE BLOCK MULTIPLES ; ; R4 -> CSR ; R5 -> USER QUEUE ELEMENT ;- .ENABL LSB DLTRAN: TST Q$WCNT(R5) ;READ OR WRITE OPERATION? BPL 1$ ;READ... ; (NOTE: THIS FAILS 2ND TIME THROUGH) NEG Q$WCNT(R5) ;WRITE, MAKE WORD COUNT POSITIVE MOV #FNWRITE!CSIE,DLCODE ;SET WRITE FUNCTION CODE 1$: MOV Q$WCNT(R5),R2 ;MAYBE, DETERMINE LENGTH OF [+GTS] MOV R2,R3 ;TRANSFER IN BLOCKS [+GTS] ADD #255.,R3 ; [+GTS] CLRB R3 ; [+GTS] SWAB R3 ; [+GTS] .ASSUME Q$BLKN EQ 0 ; [+GTS] ADD @R5,R3 ;COMPUTE FIRST BLOCK AFTER TRANSFER [+GTS] CMP DLUSIZ,R3 ;DOES OPEATION EXTEND INTO REPLACEMENT [+GTS] ;BLOCKS ? [+GTS] BLO DLELNK ;YES, NOT ALLOWED W READ/WRITE [+GTS] MOV DLCC,R0 ;POINT TO REPLACEMENT TABLE - 2 [+GTS] TST 4(R0) ;IS THE FIRST REPLACEMENT BLOCK = 0? BEQ DLADDR ;YES, THEN INVALID TABLE (FILES-11) 2$: TST (R0)+ ;SKIP OVER REPLACEMENT BLOCK NUMBER MOV (R0)+,R1 ;GET NEXT BLOCK NUMBER TO REPLACE BEQ DLADDR ;END OF TABLE, NO REPLACEMENT, DO IO .ASSUME Q$BLKN EQ 0 CMP R1,@R5 ;THIS BAD BLOCK PART OF TRANSFER? BLO 2$ ;NOPE, BELOW, IGNORE IT CMP R1,R3 ;BAD BLOCK WITHIN TRANSFER? BHIS DLADDR ;NOPE, BEYOND, WHOLE TRANSFER GOOD MOV @R0,R1 ;YES, PICK UP REPLACEMENT BLOCK NUMBER MOV -(R0),R0 ;GET BAD BLOCK NUMBER .ASSUME Q$BLKN EQ 0 SUB @R5,R0 ;COMPUTE DISTANCE OF BAD BLOCK ; INTO TRANSFER BNE 3$ ;NOT THE FIRST BLOCK, ; GO DO GOOD FIRST PART ; FIRST BLOCK OF TRANSFER IS BAD ; FILL IN PSEUDO QUEUE TO TRANSFER THE REPLACEMENT INC R0 ;SET BLOCK COUNT TO BE 1 BLOCK SWAB R2 ;IS THE REAL COUNT > 1 BLOCK ; HI BYTE>0? BEQ 5$ ;COUNT < 256. WORDS, FIX AND USE IT BR 4$ ;COUNT >= 256. WORDS, GO USE 1 BLOCK ; BAD BLOCK IS IN MIDDLE OF TRANSFER ; FILL IN PSEUDO QUEUE FOR A TRANSFER UP TO BUT NOT INCLUDING THE BAD ; BLOCK. .ASSUME Q$BLKN EQ 0 3$: MOV @R5,R1 ;START BLOCK OF PARTIAL=ORIGINAL BLOCK 4$: MOV R0,R2 ;COPY BLOCK COUNT OF TRANSFER 5$: SWAB R2 ; MULTIPLY BY 256. TO GET WORD COUNT MOV Q$BUFF(R5),R3 ;GET ORIGINAL BUFFER ADDRESS ; FOR PSEUDO QUEUE .ASSUME Q$BLKN EQ 0 ADD R0,@R5 ;UPDATE BLOCK NUMBER BY PARTIAL ; BLOCK COUNT SUB R2,Q$WCNT(R5) ;FIX WORD COUNT IN USER QUEUE ELEMENT MOV R2,R0 ;COPY THE WORD COUNT ASL R0 ;CHANGE WORD COUNT TO BYTE COUNT ADD R0,Q$BUFF(R5) ;UPDATE USER BUFFER ADDRESS .IF NE MMG$T MOV Q$PAR(R5),DLBPAR ;*C*SET HI ADDR BITS IN PSEUDO QUEUE MOV Q$MEM(R5),DLBMEM ;*C*SET HI ADDR BITS IN PSEUDO QUEUE BCC 6$ ;NO OVERFLOW ADD #CSBA16,Q$PAR(R5) ;OVERFLOW ORIGINAL ADDRESS INTO ; HIGH BITS ADD #CSBA16,Q$MEM(R5) ;OVERFLOW ORIGINAL ADDRESS INTO ; HIGH BITS 6$: .ENDC ;NE MMG$T CALL DLSQUE ;FILL IN REST OF PSEUDO QUEUE .BR DLADDR ;COMPUTE ADDRESS AND DO I/O .DSABL LSB .SBTTL COMPUTE DISK ADDRESS AND START TRANSFER ;+ ; R4 -> CSR ; R5 -> QUEUE ELEMENT (USER OR PSEUDO) ;- .ENABL LSB DLADDR: MOV R5,(PC)+ ;SAVE POINTER TO QUEUE ELEMENT ; WE ARE USING DLQPTR: .WORD 0 .ASSUME Q$BLKN EQ 0 MOV @R5,R2 ;GET BLOCK NUMBER BMI DLELNK ;NO NEGATIVE BLOCK NUMBERS! MOV #DLBPT,R1 ;GET NUMBER OF BLOCKS ON ONE TRACK .ASSUME DLBPT EQ 20. CLR R0 ;INITIALIZE I/O DISK ADDRESS TO 0 BR 2$ ;ENTER DIVIDE LOOP 1$: MOV R2,R3 ;COPY DIVIDEND BIC #^C<17>,R2 ;COMPUTE DIV = 16Q + R BIC R2,R3 ; AND GET 16Q TO WORK WITH ADD R3,R0 ;RESULT <- RESULT + IOHS/4 .ASSUME IOHS/2/2 EQ 16. ASR R3 ;COMPUTE 8Q ASR R3 ; THEN 4Q SUB R3,R2 ;NEW DIVIDEND = R - 4Q 2$: CMP R2,R1 ;DONE? (NUMBER NOW < DLBPT) BHIS 1$ ;NOPE... ASL R0 ;YES, QUOTIENT*IOHS/4 => QUO*IOHS/2 BIS R2,R0 ;MERGE BLOCK NUMBER WITH TRACK ASL R0 ;*2 FOR TWO 128. WORD SECTORS/BLOCK BCS DLELNK ;OVERFLOW MEANS BEYOND END OF DEVICE BPL 3$ ;POSITIVE IS OK FOR EITHER RL01/02 CMP DLUSIZ,#DLSIZ2 ;NEGATIVE IS OK FOR RL02 ONLY BNE DLELNK ; BUT NOT OK FOR RLO1 3$: MOV R0,DLDA ;SAVE STARTING DISK ADDRESS SUB R2,R1 ;CALCULATE BLOCKS LEFT ON TRACK SWAB R1 ;CONVERT TO WORDS LEFT ON TRACK MOV R1,DLWTRK ;SAVE THAT NUMBER .IF NE ERL$G MOV Q$WCNT(R5),DLWC ;SET WORD COUNT FOR EL .ENDC ;NE ERL$G MOV #1,(PC)+ ;CLEAR RETRY COUNT ; (THESE ARE FATAL ERRORS) DLRTY: .WORD 0 CALL DLRST ;RESET DRIVE CALL DLGST ;AND GET STATUS BMI DLERJM ;ERROR HERE IS FATAL ASR R0 ;IS THE DRIVE READY? .ASSUME CSDRDY EQ 1 BCC DLERJM ;NO, FATAL UNRETRYABLE ERROR BIC #STWL!STHS!STDT,R1 ;IGNORE WRITE LOCK, HEAD SELECT, ; DRIVE TYPE CMP #STHO!STBH!STSLM,R1 ;HEADS, BRUSHES AND STATE OK? BNE DLERJM ;NO, FATAL ERROR DRETRY = .+2 .ASSUME DRETRY-DLSTRT LT 1000 MOV #DLRCNT,DLRTY ;SET REAL RETRY COUNT .BR DLTRAK ;GET ON TRACK .DSABL LSB .SBTTL ENSURE THAT DISK IS ON TRACK BEFORE TRANSFER ;+ ; CALCULATE THE DIFFERENCE WORD FOR THE SEEK. ; TRY 16 TIMES TO READ A HEADER. ; IF ALL FAIL, LOG AN ERROR AND ISSUE A REVERSE SEEK (SEEK -1 TRACK) ; AND A READ HEADER TO CAUSE AN INTERRUPT. ; ; R4 -> CSR ; R5 -> QUEUE ELEMENT ;- .ENABL LSB DLTRAK: CLR (PC)+ ;RESET REVERSE SEEK FLAG DLREV: .WORD 0 MOV @DLCC,R1 ;GET CURRENT CYLINDER CMP #-1,R1 ;IS IT VALID? BNE 2$ ;YES, USE IT TO START WITH ;***ACTION*** OLD CODE HAS ANOTHER RETRY VALUE MOV DRETRY,R2 ;SET READ HEADER RETRY COUNT ASL R2 ; (DLRCNT*2) 1$: MOV #FNRDH,R1 ;SET CODE FOR READ HEADERS FUNCTION CALL DLXCT ;EXECUTE THE FUNCTION BPL 2$ ;FUNCTION EXECUTED OK SOB R2,1$ ; any retries left? INCB DLREV ;SET REVERSE SEEK FLAG DLERJM: JMP DLERRH ;RETRY OPERATION 2$: MOV DLDA,R0 ;RETRIEVE STARTING DISK ADDRESS MOV #IOSA,R2 ;MASK OUT BIC R2,R0 ;SECTOR BITS FROM DESIRED ADDRESS BIC R2,R1 ; AND FROM CURRENT ADDRESS CMP R0,R1 ;DO WE NEED TO DO A SEEK? BEQ DLXFER ;NOPE, ALREADY ON CYLINDER AND HEAD MOV R0,R3 ;YES, SAVE DESIRED CYLINDER AND HEAD INC R2 ;GET MASK FOR HEAD SELECT .ASSUME IOHS EQ IOSA+1 BIC R2,R0 ;STRIP HEAD SELECT BIT FROM ; DESIRED ADDRESS BIC R2,R1 ; AND FROM CURRENT ADDRESS SUB R0,R1 ;COMPUTE DISTANCE FROM DESIRED ; TO ACTUAL CYLINDER .ASSUME SKCADF EQ IOCA BHIS 3$ ;DESIRED <= ACTUAL, MOVE TOWARD EDGE NEG R1 ;DESIRED > ACTUAL, MOVE TOWARD SPINDLE BIS #SKDIR,R1 ; (SET DIRECTION BIT) 3$: INC R1 ;SET MARKER BIT .ASSUME SKMARK EQ 1 BIT R2,R3 ;DO WE WANT TO USE SURFACE 1? BEQ 4$ ;NO BIS #SKHS,R1 ;YES, SET SURFACE 1 BIT 4$: MOV #-1,@DLCC ;VOID KNOWLEDGE OF CURRENT CYLINDER CALL DLSEEK ;EXECUTE THE SEEK BMI DLERRH ;OOPS, ERROR EXECUTING SEEK MOV DLDA,@DLCC ;SET CURRENT CYLINDER .BR DLXFER ;NOW DO THE TRANSFER .DSABL LSB .SBTTL DLXFER - START AN I/O TRANSFER ;+ ; R4 -> CSR ; R5 -> QUEUE ELEMENT ;- .ENABL LSB DLXFER: .IF EQ VENU$C ADD #RLMP,R4 ;POINT TO RLMP IN CONTROLLER .ENDC ;EQ VENU$C ADD #Q$WCNT,R5 ;POINT TO WORD COUNT IN QUEUE ELEMENT MOV (PC)+,R3 ;GET NUMBER OF WORDS LEFT ON TRACK DLWTRK: .WORD 0 CMP R3,@R5 ;COMPARE AGAINST TOTAL TRANSFER BLOS 1$ ;<=, USE REMAINDER OF TRACK MOV @R5,R3 ;>, USE TOTAL TRANSFER COUNT 1$: MOV R3,(PC)+ ;SAVE TRANSFER COUNT FOR LATER DLWC: .WORD 0 ; : TRANSFER COUNT NEG R3 ;MUST BE 2'S COMPLEMENT .IF EQ VENU$C MOV R3,@R4 ;LOAD WORD COUNT INTO CONTROLLER MOV (PC)+,-(R4) ;LOAD STARTING DISK ADDRESS DLDA: .WORD 0 MOV -(R5),-(R4) ;SET BUS ADDRESS .IFF HANTORL R3,RLMP ;LOAD WORD COUNT INTO CONTROLLER MOV (PC)+,R4 ;LOAD STARTING DISK ADDRESS DLDA: .WORD 0 CALL HTORL ;MOVE IT TO RL .WORD RLDA ;QBUS ADDRESS HANTORL -(R5),RLBA ;SET BUS ADDRESS .ENDC ;EQ VENU$C MOV (PC)+,R0 ;GET FUNCTION CODE DLCODE: .WORD 0 ;READ OR WRITE CODE BIS (PC)+,R0 ;ADD IN UNIT SELECT BITS DLUNIT: .WORD 0 ;UNIT NUMBER IN BITS 8-9 .IF NE MMG$T $RLV1A: BR 10$ ;IF NO RLV12... ; (CHANGED TO 'NOP' IF USING RLV12) MOV Q$PAR-Q$BUFF(R5),-(SP) ;SAVE Q22 HIGH-ORDER BITS ASR (SP) ;SHIFT THEM TO THEIR CORRECT POSITIONS ASR (SP) ASR (SP) ASR (SP) MOV (SP)+,RLBAE-RLBA(R4) ;SET THE HIGH-ORDER BITS MOV Q$PAR-Q$BUFF(R5),-(SP) ;SAVE HIGH-ORDER BUS ADDRESS BIC #<^C60>,(SP) ;STRIP TO HIGH-ORDER BITS <17:16> BIS (SP)+,R0 ; AND MERGE WITH COMMAND WORD BR 30$ 10$: BIT #1700,Q$PAR-Q$BUFF(R5) ;22-BIT ADDRESS SPECIFIED? BEQ 20$ ;NOPE, THEN ADDRESS IS OKAY TO USE JMP DLEROR ;YES, CAN'T BE USED ON NON RLV12 20$: BIS Q$PAR-Q$BUFF(R5),R0 ;MERGE EXTENDED ADDRESS BITS INTO ; COMMAND WORD 30$: .ENDC ;NE MMG$T .IF EQ VENU$C MOV R0,-(R4) ;LOAD FUNCTION AND GO .IFF HANTORL R0,RLCS ;LOAD FUNCTION AND GO .ENDC RETURN ;WAIT FOR AN INTERRUPT .DSABL LSB .SBTTL DLINT - INTERRUPT ENTRY POINT ; INTERRUPTS ENTER THE HANDLER HERE .ENABL LSB .DRAST DL,5 .IF NE VENU$C ;If VENUS console BISB #QBAIE,@#$QCSR0 ;Turn on the Qbus interrupt NOP ;Let the Qbus settle down NOP ; BICB #QBAIE,@#$QCSR0 ;Turn off Qbus interrupt .ENDC ;NE VENU$C .FORK DLFBLK ;GO TO FORK LEVEL MOV DLCSR,R4 ;POINT TO CSR ADDRESS MOV DLQPTR,R5 ;POINT TO QUEUE ELEMENT TSTB DLREV ;REVERSE SEEK IN PROGRESS? BNE DLTRAK ;YES, GO RETRY THE REAL TRANSFER .IF EQ VENU$C TST @R4 ;CHECK RLCS .IFF HANFMRL RLCS,R4 ;CHECK RLCS USING TST R4 ; VALUE IN R4 .ENDC ;EQ VENU$C BMI DLERRH ;IF ERROR, GO DIAGNOSE IT .ASSUME CSERR EQ 100000 MOV DLWC,R3 ;GET WORD COUNT OF THIS TRANSFER SUB R3,Q$WCNT(R5) ;CALCULATE WORDS REMAINING TO TRANSFER BNE 2$ ;MORE TO DO, USE NEXT TRACK CMP DLCODE,#FNWRITE!CSIE ;WAS THE LAST FUNCTION A WRITE? BNE 11$ ;NO, DONE WITH THIS (PARTIAL) ELEMENT .IF EQ VENU$C BIT #1,RLDA(R4) ;GOT A SECTOR TO WRITE YET? .IFF HANFMRL RLDA,R4 ;GET RLDA VALUE BIT #1,R4 ;GOT A SECTOR TO WRITE YET? .ENDC ;EQ VENU$C BEQ 11$ ;NO, DON'T ZERO FILL INC Q$WCNT(R5) ;SET WORD COUNT TO 1 ; (CONTROLLER FILLS 127.) .IF EQ MMG$T .ADDR #DLFILL,-(SP) ;GET THE BUFFER ADDRESS .IFF ;EQ MMG$T MOV BUFADH,Q$PAR(R5) ;GET HI ADDR OF UMR MOV BUFADL,-(SP) ;GET LO ADDR OF UMR ADD #,@SP ;POINT TO DLFILL BCC 100$ ;IF NO OVERFLOW, BRANCH ADD #CSBA16,Q$PAR(R5) ;UPDATE HI ORDER ADDRESS BITS 100$: .ENDC ;EQ MMG$T MOV (SP)+,Q$BUFF(R5) ;SET THE BUFFER ADDRESS .IF EQ VENU$C MOV RLDA(R4),DLDA ; AND THE DISK ADDRESS .IFF HANFMRL RLDA,DLDA ; AND THE DISK ADDRESS .ENDC ;EQ VENU$C 1$: JMP DLTRAK ;GO DO IT (DLWTRK > 1 = Q$WCNT) 11$: JMP DLEXFR ;GO FINISH TRANSFER 2$: ASL R3 ;CHANGE WORD COUNT TO BYTE COUNT ADD R3,Q$BUFF(R5) ;UPDATE USER BUFFER ADDRESS .IF NE MMG$T BCC 3$ ;NO OVERFLOW ADD #CSBA16,Q$PAR(R5) ;UPDATE HIGH ORDER ADDRESS BITS 3$: .ENDC ;EQ MMG$T BIS #77,DLDA ;UPDATE SURFACE/CYLINDER ADDRESS INC DLDA ; TO FIRST SECTOR, NEXT HEAD/CYLINDER BEQ DLEROR ;OVERFLOWED DEVICE !!! BPL 301$ ;OK FOR EITHER RL01/02 CMP DLUSIZ,#DLSIZ2 ;MINUS OK ONLY FOR RL02 BNE DLEROR ; VERY BAD IF RL01 !!! 301$: MOV #DLWPT,DLWTRK ;SAVE NUMBER OF WORDS ON A WHOLE TRACK 4$: BR 1$ ;GO CONTINUE TRANSFER ON NEXT TRACK .SBTTL HANDLE THE ERRORS DLERRH: .IF EQ ERL$G .IF EQ VENU$C MOV @R4,R3 ;GET RLCS CONTENTS WITH ERROR BITS .IFF HANFMRL RLCS,R3 ;GET RLCS CONTENTS WITH ERROR BITS .ENDC .IFF MOV R4,R1 ;GET CSR ADDRESS .ADDR #DLRBLK,R2 ; CALCULATE ADDRESS OF REGISTER BUFFER MOV R2,R3 ;SAVE BUFFER ADDRESS MOV (R1)+,(R3)+ ;TRANSFER RLCS MOV (R1)+,(R3)+ ;TRANSFER RLBA MOV (R1)+,(R3)+ ;TRANSFER RLDA MOV (R1)+,(R3)+ ;TRANSFER RLMP CALL DLGST ;GET THE DRIVE STATUS INFO MOV R1,(R3)+ ; AND SAVE IT FOR ERROR LOGGER COM R1 ;COMPLEMENT BIT #STWL,R1 ;Write lock error? BEQ 5$ ;Yes, don't log it ; (reversed logic due to COM above) MOV DLDA,(R3)+ ;SAVE THE DISK ADDRESS THAT WE USED $RLV1B: BR 10$ ;IF NO RLV12... ; (CHANGED TO 'NOP' IF USING RLV12) MOV RLBAE(R4),(R3)+ ;TRANSFER RLBAE 10$: MOV DRETRY,R3 SWAB R3 ADD #DLREG,R3 ;R3= MAX RETRIES/ NUMBER OF REGISTERS $RLV1C: BR 20$ ;IF NO RLV12... ; (CHANGED TO 'NOP' IF USING RLV12) INC R3 ;BUMP FOR EXTRA REGISTER ON RLV12 20$: JSR R4,FIXWC ;GET Q$WCNT SET RIGHT, PUSH OLD VALUE MOV DLRTY,R4 ;GET NUMBER OF RETRIES LEFT ADD #DL$COD*400-1,R4 ;SET DEVICE ID FLAG, COUNT=COUNT-1 ; (report retries remaining, not ; current retry number) CALL @$ELPTR ;LOG THE ERROR MOV (SP)+,Q$WCNT(R5) ;RESET WORD COUNT 5$: MOV DLCSR,R4 ;POINT TO CSR AGAIN MOV DLRBLK,R3 ;GET RLCS AT TIME OF FAILURE .ENDC ;EQ ERL$G MOV #-1,@DLCC ;INVALIDATE CURRENT CYLINDER ; (FORCE READ HEADER) CALL DLRST ;RESET DRIVE TSTB DLREV ;REVERSE SEEK REQUIRED? BEQ 6$ ;NO, GO SEE IF WE CAN RETRY 51$: INCB DLREV ;SET REVERSE SEEK FLAG IF RETRY ; FROM DRIVE N;002 MOV #177600!SKMARK,R1 ;Reverse seek to cylinder zero CALL DLSEEK ;EXECUTE THE SEEK BMI DLEROR ;SEEK FAILED, CALL IT FATAL MOV DLUNIT,R0 ;GET UNIT NUMBER TO USE BIS #CSIE!FNRDH,R0 ;ADD CODE FOR READ HEADER .IF EQ VENU$C MOV R0,@R4 ;LOAD FUNCTION AND GO .IFF HANTORL R0,RLCS .ENDC ;EQ VENU$C RETURN ;WAIT FOR THE INTERRUPT 6$: ASRB R3 ;AT TIME OF FAILURE, WAS DRIVE READY? BCC 51$ ;NO, REVERSE SEEK UNTIL IT IS .ASSUME CSDRDY EQ 1 ASL R3 ;SHIFT TO GET DRIVE ERROR BIT IN CARRY ASL R3 ; AND NXM BIT IN SIGN BMI DLEROR ;FATAL IF NON-EXISTENT MEMORY .ASSUME CSNXM EQ 020000 BCC 7$ ;GO RETRY IF NOT DRIVE ERROR .ASSUME CSDE EQ 040000 CALL DLGST ;DRIVE ERROR, GO GET DRIVE STATUS BIT #STWGE,R1 ;WRITE GATE ERROR? BEQ DLEROR ;FATAL IF NOT BIT #STWL,R1 ;YES, WRITE GATE WITH WRITE LOCK? BNE DLEROR ;YES, FATAL 7$: DEC DLRTY ;ANY RETRIES LEFT? BGT 4$ ;YES, GO DO ONE DLEROR: MOV DLCQE,R5 ;GET QUEUE ELEMENT POINTER .ASSUME Q$BLKN-2 EQ Q$CSW BIS #HDERR$,@-(R5) ;FLAG CHANNEL ERROR BR DLQCOM ;FINISH-UP .DSABL LSB .SBTTL FINISH SUCCESSFUL OPERATION .ENABL LSB DLEXFR: MOV DLCQE,R5 ;GET ORIGINAL QUEUE ELEMENT POINTER CMP R5,DLQPTR ;PSEUDO QUEUE IN USE? BEQ 1$ ;NO, THIS IS THE END OF THE REQUEST CMPB Q$FUNC(R5),#FN$REP ;WAS FUNCTION A FORCE TABLE RE-READ? BEQ 1$ ;YES, WE ARE NOW DONE TST Q$WCNT(R5) ;IS THERE ANYTHING LEFT TO TRANSFER? BEQ 1$ ;NOPE, ALL DONE JMP DLTRAN ;GO DO NEXT PART OF BROKEN TRANSFER 1$: .IF NE ERL$G JSR R4,FIXWC ;FIX WORD COUNT FOR READ/WRITE TST (SP)+ ;DUMP STACKED OLD VALUE TST SCSFLG ;LOGGING SUCCESSES? BNE DLQCOM ;NOPE... MOV #DL$COD*400+377,R4 ;FLAG SUCCESS FOR EL CALL @$ELPTR ;CALL THE ERROR LOG HANDLER .ENDC ;NE ERL$G DLQCOM: .DRFIN DL ;COMPLETE I/O OPERATION .DSABL LSB .SBTTL GET DEVICE SIZE ; SPECIAL FUNCTION TO GET VOLUME SIZE: ; READ THE DRIVE TYPE BIT FOR THE SELECTED DRIVE. THEN RETURN THE ; DRIVE'S SIZE, IN BLOCKS, IN THE FIRST WORD OF THE USER'S BUFFER. DLGSIZ: .IF EQ MMG$T MOV DLUSIZ,@Q$BUFF(R5) ;PUT SIZE IN BUFFER .IFF MOV DLUSIZ,-(SP) ;SET SIZE ON STACK MOV R5,R4 ;COPY QUEUE POINTER FOR PUTWORD CALL @$PTWRD ;PUT SIZE IN BUFFER .ENDC ;EQ MMG$T TST R0 ;Was there an error (no drive?) ;R0 should be CSR from DLGST .Assume CSERR EQ 100000 BPL DLQCOM ;Branch if not BIT #CSERRC,R0 ;Is there an error code? BNE DLEROR ;Branch if yes BIT #STVC,R1 ;Is it a volume check error? BEQ DLEROR ;If not, report hard error BR DLQCOM .SBTTL DLXCT - FUNCTION EXECUTION ROUTINES ;+ ; EXECUTE A GET DRIVE STATUS OR ANY NON-INTERRUPT FUNCTION ; AND WAIT FOR COMPLETION ; ; INPUTS: ; R1 = FUNCTION CODE IF DLXCT ; SEEK DIFFERENCE WORD IF DLSEEK ; R4 -> CSR ; ; OUTPUTS: ; FUNCTION EXECUTED ; ; R0 = CSR CONTENTS ; R1 = MP CONTENTS ; N = 1 IF ERROR ;- .ENABL LSB DLSEEK: .IF EQ VENU$C MOV R1,RLDA(R4) ;LOAD DIFFERENCE WORD IN CONTROLLER .IFF HANTORL R1,RLDA ;LOAD DIFF WORD IN CONTROLLER .ENDC ;EQ VENU$C MOV #FNSEEK,R1 ;ISSUE SEEK COMMAND BR DLXCT DLGST: .IF EQ VENU$C MOV #GSGS!GSMARK,RLDA(R4) ;TELL DRIVE TO GET STATUS .IFF HANTORL #GSGS!GSMARK,RLDA ;TELL DRIVE TO GET STATUS .ENDC ;EQ VENU$C CALL 1$ ;EXECUTE THE GET STATUS BPL 4$ ;NO ERROR SO EXIT .IF EQ VENU$C TST RLBA(R4) ;ERROR -- IS IT AFTER BUS INIT? .IFF HANFMRL RLBA,R4 ;GET RLBA VALUE TST R4 ;ERROR -- IS IT AFTER BUS INIT? .ENDC ;EQ VENU$C BNE 4$ ;NO -- LOG THE ERROR CALL DLRST ;YES -- DO A RESET .IF EQ VENU$C MOV #GSGS!GSMARK,RLDA(R4) ;AND TRY THE GET STATUS AGAIN .IFF HANTORL #GSGS!GSMARK,RLDA ;AND TRY TO GET STATUS AGAIN .ENDC BR 1$ ;BUT ONLY TRY IT ONCE! DLRST: .IF EQ VENU$C MOV #GSRST!GSGS!GSMARK,RLDA(R4) ;GET DRIVE RESET COMMAND .IFF HANTORL #GSRST!GSGS!GSMARK,RLDA ;GET DRIVE RESET COMMAND .ENDC 1$: MOV #FNGSTS,R1 ;GET 'GET STATUS' FUNCTION CODE DLXCT: BIS DLUNIT,R1 ;ADD IN UNIT SELECT BITS .IF EQ VENU$C MOV R1,@R4 ;GIVE IT TO DRIVER 2$: TSTB @R4 ;WAIT FOR FUNCTION TO BE ACCEPTED .IFF HANTORL R1,RLCS ;GIVE IT TO DRIVER 2$: HANFMRL RLCS,R4 ;WAIT FOR FUNCTION TO BE ACCEPTED TSTB R4 ; VALUE IN R4. .ENDC ;EQ VENU$C BPL 2$ 3$: .IF EQ VENU$C MOV RLMP(R4),R1 ;GET RETURNED STATUS WORD MOV @R4,R0 ; AND CSR VALUE (SET N-BIT IF ERROR) .IFF HANFMRL RLMP,R1 ;GET RETURNED STATUS WORD MOV R1,(PC)+ STATMP: .WORD -1 HANFMRL RLCS,R0 ; AND CSR VALUE (SET N-BIT IF ERROR) MOV R0,(PC)+ STATCS: .WORD -1 .ENDC ;EQ VENU$C 4$: RETURN .DSABL LSB .IF NE VENU$C .SBTTL Macro routines to access q-bus adapter (IN_LINE) ; ; Send to RL ; HTORL: BICB #QBAWRT!QBAREAD,@#$QCSR0 BISB #REQMASTER!QBAWRT!DMAENA,@#$QCSR0 ; REQUEST BUS CALL HGETQB ; GO POLL MOV R4,@#$QDAT0 ; DATA TO XFER BR HBCYCLE ; CYCLE AND WAITF ; ; From RL ; HFMRL: BICB #QBAWRT!QBAREAD,@#$QCSR0 BISB #REQMASTER!QBAREAD!DMAENA,@#$QCSR0 ; REQUEST BUS CALL HGETQB ; GO POLL HBCYCL: MOV (SP)+,R4 ; GET RETURN ADDRESS MOV (R4)+,@#$QADR0 ; SET ADDRESS AND ... ; START. HWAITF: BITB #MSTRPEND,@#$QCSR0 ; IS CYCLE COMPLETE? BNE HWAITF ; NO, BRANCH ;*NOTE* When MSTRPEND clears cycle is done. Returned data is in ; $QDAT0 reg. MOV R4,-(SP) ; RESET RETURN ADDR MOV @#$QDAT0,R4 ; PASS RESULTS TO DST BICB #REQMASTER,@#$QCSR0 ; CLEAR REQST MASTER RETURN ; RETURN HGETQB: ;*NOTE* To access the bus you must become master. BITB #MSTRPEND,@#$QCSR0 ; DO WE HAVE IT ? BEQ HGETQB ; NO, REPEAT RTS PC ; RETURN .ENDC .DSABL LSB .SBTTL DLSQUE - SETUP PSEUDO QUEUE ELEMENT ;+ ; SET UP THE PSEUDO QUEUE FOR BAD BLOCK TABLE READS OR PARTIAL TRANSFERS ; ; INPUTS: ; R1 = STARTING BLOCK NUMBER OF PARTIAL TRANSFER ; R2 = WORD COUNT ; R3 -> BUFFER ; R5 -> USER QUEUE ELEMENT ; ; OUTPUTS: ; R0 = RANDOM ; R5 -> PSEUDO QUEUE ELEMENT ;- DLSQUE: .ADDR #DLBWCT,R0 ; POINT TO PSEUDO QUEUE ELEMENT MOV R2,@R0 ;STORE WORD COUNT MOV R3,-(R0) ;STORE BUFFER ADDRESS MOV Q$FUNC(R5),-(R0) ;COPY UNIT NUMBER AND ; SPECIAL FUNCTION BYTE MOV R1,-(R0) ;STORE BLOCK NUMBER .ASSUME Q$BLKN-2 EQ Q$CSW MOV -(R5),-2(R0) ;STORE POINTER TO CSW MOV R0,R5 ;POINT R5 AT PSEUDO QUEUE RETURN .IF NE ERL$G .SBTTL FIXWC - FIX WORD COUNT FOR LOGGER ;+ ; FIX WORD COUNT IN QUEUE ELEMENT FOR ERROR LOGGER ; ; INPUTS: ; R5 -> QUEUE ELEMENT ; DLWC = WORD COUNT USED FOR I/O ; ; OUTPUTS: ; R4 = RANDOM ; @SP = OLD VALUE OF Q$WCNT TO RESTORE ; Q$WCNT(R5) = DLWC (NEGATED IF WRITE) ;- FIXWC: MOV Q$WCNT(R5),@SP ;SAVE OLD COUNT ON STACK MOV DLWC,Q$WCNT(R5) ;SET THE CORRECT VALUE CMP DLCODE,#FNWRITE!CSIE ;WAS IT A WRITE? BNE 1$ ;NO NEG Q$WCNT(R5) ;YES, FIX ELEMENT VALUE 1$: JMP @R4 ;RETURN .ENDC ;NE ERL$G .SBTTL DATA AREAS ; PSEUDO QUEUE ELEMENT .WORD -1 ;ADDRESS OF CSW .WORD -1 ;BLOCK NUMBER .BYTE 0 ;SPECIAL FUNCTION BYTE .BYTE -1 ;UNIT NUMBER DLBADD: .WORD -1 ;BUFFER ADDRESS DLBWCT: .WORD -1 ;WORD COUNT .IF NE MMG$T .WORD 0 ;COMPLETION ADDRESS DLBPAR: .WORD -1 ;PAR VALUE DLBMEM: .WORD -1 ;MEM VALUE .WORD 0 ;(RESERVED) .ENDC ;NE MMG$T ; BAD BLOCK REPLACEMENT TABLE BUFFER AND CURRENT CYLINDER WORD ; ; CONSISTS OF ONE WORD AND ONE TABLE FOR EACH UNIT. ; EACH TABLE CONSISTS OF TWO WORD ENTRIES. WORD 1 ; IS BAD BLOCK AND WORD 2 IS IT'S REPLACEMENT. A ; TABLE IS ENDED BY A ZERO ENTRY. ; ; THIS TABLE WILL BE MAPPED INTO HIGH MEMORY WITH UB SUPPORT ; DLBBUF: .REPT DL$UN ;ONE TABLE PER UNIT .WORD -1 ;CURRENT CYLINDER NUMBER (-1=UNKNOWN) .WORD -1 ;INDICATES TABLE NOT READ YET .BLKB DLTSIZ-2 ;THE TABLE .ENDR BUFEND: ; DLFILL ALSO USES THE PERMANENT UMR DLFILL: .WORD 0 ;MUST BE 0 TO ZERO-FILL BUFFER DLFBLK: .WORD 0,0,0,0 ;FORK QUEUE BLOCK .IF NE ERL$G DLRBLK: .BLKW DLREG+1 ;DL STATUS REGISTERS FOR CALL ; TO ERROR LOGGER (+1 FOR RLBAE) .ENDC ;NE ERL$G .IF NE MMG$T ;+ ; DL INTERNAL VARIABLE DEFINITIONS. ;- $ENTPT: .WORD 0 ; POINTER TO $ENTRY TABLE $PNMPT: .WORD 0 ; POINTER TO $PNAME TABLE H2UB: .WORD 0 ; POINTER TO UBVECT DLSLOT: .WORD 0 ; DL'S OFFSET IN DEVICE TABLES DLENT: .WORD 0 ; DL'S $ENTRY TABLE ENTRY POINTER DLPNA: .WORD 0 ; DL'S $PNAME TABLE ENTRY POINTER DLILQE: .WORD 0 ; DL INTERNAL QUEUE LAST QEL POINTER DLICQE: .WORD 0 ; DL INTERNAL QUEUE FIRST QEL POINTER ;+ ; DEFINITION OF THE HANDLER INTERNAL BUFFER AND THE WORDS THAT ARE ; USED TO PROGRAM DMA DEVICES THAT TRANSFER DATA TO AND FROM IT. ;- BUFADH: .WORD 0 ; BITS 0-15 OF UNIBUS VIRTUAL POINTER TO DLBBUF BUFADL: .WORD 0 ; BITS 16-21 OF UNIBUS VIRTUAL POINTER TO DLBBUF ; TABLE OF STANDARD DMA SPFUNS THAT DO NOT HAVE A PERMANENT UMR ; ALLOCATED TO THEM UBTAB: .DRSPF -, ;ABSOLUTE WRITE, NO BAD BLOCK .DRSPF -, ;ABSOLUTE READ (REPLACEMENT) .WORD 0 ;TABLE TERMINATOR .ENDC ;NE MMG$T .SBTTL BOOTSTRAP DRIVER .DRBOT DL,BOOT1,B.READ . = DLBOOT+40 ;PUT THE JUMP BOOT INTO SYSCOM AREA BOOT1: JMP @#BOOT-DLBOOT ;START THE BOOTSTRAP .SBTTL BOOTSTRAP READ ROUTINE .ENABL LSB . = DLBOOT+210 B.READ: CLR R4 ;CLEAR TRACK COUNTER 1$: SUB #DLBPT,R0 ;COUNT DOWN ANOTHER WHOLE TRACK BLO 2$ ;IF OVERFLOW, DONE ADD #IOHS,R4 ;ADD IN ANOTHER TRACK BR 1$ ;LOOP FOR MORE 2$: ADD #DLBPT,R0 ;CORRECT TRACK COUNTER ASL R0 ;CONVERT REMAINDER TO SECTOR IN TRACK BIS R4,R0 ;MERGE SECTOR WITH TRACK/CYL .IF EQ VENU$C MOV BOTCSR,R5 ;GET ADDRESS OF CONTROLLER ADD #RLDA,R5 ;POINT TO DISK ADDRESS REGISTER MOV RLCS-RLDA(R5),B.DLCS ;GET CURRENT CSR VALUE BIC #^C,B.DLCS ;ISOLATE CURRENT UNIT NUMBER .ENDC CALL B.SEEK ;SEEK TO PROPER TRACK NEG R1 ;NEGATE WORD COUNT .IF EQ VENU$C MOV R2,RLBA-RLDA(R5) ;SET BUS ADDRESS .IFF MOVTORL R2,RLBA .ENDC DLREAD: .IF EQ VENU$C MOV R1,RLMP-RLDA(R5) ;SET WORD COUNT MOV R0,@R5 ;SET DISK ADDRESS .IFF MOVTORL R1,RLMP MOVTORL R0,RLDA .ENDC JSR R0,B.XCT ;EXECUTE THE READ .WORD FNREAD ;READ FUNCTION CODE CLC ;ENSURE CARRY=0 BEFORE RETURN BPL 5$ ;SUCCESS, EXIT .IF EQ VENU$C MOV @R5,R3 ;GET LAST DISK ADDRESS .IFF MOVFMRL RLDA,R3 ;GET LAST DISK ADDRESS MOV R3,R4 ;SAVE A COPY OF IT .ENDC BIC #^C,R3 ;CLEAR ALL BUT SECTOR ADDRESS CMP #DLBPT*2,R3 ;TRACK OVERRUN? BNE BIOERR ;IF NOT, REAL ERROR, EXIT .IF EQ VENU$C MOV @R5,R3 ;GET DISK ADDRESS .IFF MOV R4,R3 ;GET DISK ADDRESS .ENDC SUB R0,R3 ;COMPUTE SECTORS TRANSFERRED SWAB R3 ;CONVERT SECTORS TO WORD COUNT ASR R3 ADD R3,R1 ;REMOVE WORDS TRANSFERRED .IF EQ VENU$C MOV @R5,R0 ;GET DISK ADDRESS .IFF MOV R4,R0 ;GET DISK ADDRESS AND CLEAR THE STACK .ENDC ADD #IOHS-,R0 ;INCREMENT SURFACE/TRACK MOV #DLREAD-DLBOOT,-(SP) ;CALL TO SEEK NEXT TRACK, THEN READ IT .BR B.SEEK ;SEEK NOW B.SEEK: JSR R0,B.XCT ;EXECUTE READ HEADERS .WORD FNRDH ;READ HEADER FUNCTION CODE .IF EQ VENU$C MOV RLMP-RLDA(R5),R3 ;GET CURRENT DISK TRACK AND SURFACE .IFF MOVFMRL RLMP,R3 .ENDC BIC #IOHS!IOSA,R3 ;CLEAR SURFACE/SECTOR TO GET ; CURRENT TRACK MOV R0,R4 ;COPY DESIRED DISK ADDRESS BIC #IOHS!IOSA,R4 ;CLEAR SURFACE/SECTOR TO GET ; DESIRED TRACK SUB R4,R3 ;SUBTRACT DESIRED FROM CURRENT TRACK BCC 3$ ;IF CURRENT >= DESIRED, ; SEEK OUTWARD BY DIFF NEG R3 ;MAKE POSITIVE DIFFERENCE OF ; DELTA POSITION BIS #SKDIR,R3 ;INDICATE MOVE TOWARD SPINDLE 3$: BIT #IOHS,R0 ;DO WE DESIRE SURFACE 1? BEQ 4$ ;NO, LEAVE SURFACE SELECT 0 BIS #SKHS,R3 ;SET BIT TO SELECT SURFACE 1 4$: INC R3 ;SET MARKER BIT .IF EQ VENU$C MOV R3,@R5 ;LOAD DIFFERENCE WORD .IFF MOVTORL R3,RLDA .ENDC JSR R0,B.XCT ;EXECUTE A SEEK .WORD FNSEEK ;SEEK FUNCTION CODE BMI BIOERR ;IF PL, OK .IF EQ VENU$C MOV R0,@R5 ;SET ACTUAL DISK ADDRESS .IFF MOVTORL R0,RLDA .ENDC 5$: RETURN ;RETURN ; EXECUTE THE FUNCTION IN R3 AND RETURN ERROR STATUS B.XCT: MOV (R0)+,R3 ;GET FUNCTION CODE .IF EQ VENU$C BIS (PC)+,R3 ;ADD UNIT BITS TO FUNCTION CODE B.DLCS: .WORD 0 ;BOOTED UNIT NUMBER MOV R3,RLCS-RLDA(R5) ;EXECUTE FUNCTION 6$: BIT #CSERR!CSCRDY,RLCS-RLDA(R5) ;WAIT FOR COMPLETION OR ERROR .IFF MOVTORL R3,RLCS ; EXECUTE FUNCTION 6$: MOVFMRL RLCS ; GET STATUS INTO R5 BIT #CSERR!CSCRDY,R5 ; WAIT FOR COMPLETION ON ERROR .ENDC BEQ 6$ ;NEITHER, LOOP RTS R0 ;RETURN WITH N=1 IF ERROR .IF NE VENU$C .SBTTL Macro routines to access q-bus adapter (BOOT) ; ; Send to RL ; TORL: MOVB #REQMASTER!QBAWRT!DMAENA,@#$QCSR0 ; REQUEST BUS CALL GETQB ; GO POLL MOV R5,@#$QDAT0 ; DATA TO XFER BR BCYCLE ; CYCLE AND WAITF ; ; From RL ; FMRL: MOVB #REQMASTER!QBAREAD!DMAENA,@#$QCSR0 ; REQUEST BUS CALL GETQB ; GO POLL BCYCLE: MOV (R4)+,@#$QADR0 ; SET TARGET ADDRESS ; AND START BUS CYCLE WAITF: BITB #MSTRPEND,@#$QCSR0 ; IS CYCLE COMPLETE? BNE WAITF ; NO, BRANCH ;*NOTE* When MSTRPEND clears cycle is done. Returned data is in ; $QDAT0 reg. MOV @#$QDAT0,R5 ; PASS RESULTS TO DST BICB #REQMASTER,@#$QCSR0 ; CLEAR REQST MASTER RTS R4 ; RETURN GETQB: ;*NOTE* To access the bus you must become master. BITB #MSTRPEND,@#$QCSR0 ; DO WE HAVE IT ? BEQ GETQB ; NO, REPEAT RTS PC ; RETURN .ENDC .DSABL LSB .SBTTL BOOTSTRAP CONTINUED .IF NE VENU$C ;REORG FOR VENUS .ASSUME .-DLBOOT-612 LE 0 . = DLBOOT+612 .IFF ;NE VENU$C . = DLBOOT+600 .ENDC BOOT: MOV #10000,SP ;SET STACK POINT .IF EQ VENU$C ; ALWAYS UNIT 0 IN VENUS! MOV @(PC)+,-(SP) BOTCSR: .WORD DL$CSR BIC #^C1400,@SP ;STRIP TO UNIT NUMBER SWAB @SP ;MOVE TO BITS 0-1 .ENDC MOV #2,R0 ;READ IN SECOND PART OF BOOT MOV #4*256.,R1 ;FOUR BLOCKS TO READ MOV #1000,R2 ;INTO LOCATION 1000 CALL B.READ ;READ THE REST OF THE BOOT MOV #B.READ-DLBOOT,@#B$READ ;STORE START LOCATION OF READ ROUTINE MOV #B$DNAM,@#B$DEVN ;STORE RAD50 DEVICE NAME .IF EQ VENU$C MOV (SP)+,@#B$DEVU ;SET THE UNIT NUMBER IN THE BOOT .IFF CLR @#B$DEVU ; UNIT = 0 IN VENUS ! .ENDC JMP @#B$BOOT ;GO DO THE BOOT WORK .DREND DL .IF EQ VENU$C .IF NE MMG$T .SBTTL FETCH/LOAD CODE ;+ ; FETCH ; ; ENTRY: R0 = STARTING ADDRESS OF THIS HANDLER SERVICE ROUTINE. ; R1 = ADRESS OF GETVEC ROUTINE. ; R2 = VALUE $SLOT*2. (LENGTH OF THE $PNAME TABLE IN BYTES.) ; R3 = TYPE OF ENTRY. ; R4 = ADDRESS OF SY READ ROUTINE. ; R5 -> $ENTRY SLOT FOR THIS HANDLER. ; ;- FETCH: MOV R5,R1 ; SAVE PTR TO DL'S $ENTRY SLOT MOV @R5,R5 ; GET ADDRESS OF DLLQE MOV DLCSR-DLLQE(R5),R4 ; GET CSR FOR DL CLR -(SP) ; SPACE FOR RETURN VALUE .MFPS ; GET PROCESSOR STATUS .MTPS #340 ; RAISE PROCESSOR PRIORITY LEVEL TO 7 MOV @#NXM.V+2,-(SP) ;;;SAVE CURRENT NXM TRAP PSW [+GTS] MOV @#NXM.V,-(SP) ;;;SAVE CURRENT NXM TRAP VECTOR .ADDR #$DLNXM,-(SP) ;;;BUILD ADDRESS TO OUR TRAP ROUTINE MOV (SP)+,@#NXM.V ;;;SET UP THE NXM VECTOR MOV #340,@#NXM.V+2 ;;;SET UP THE NXM PSW [+GTS] TST RLBAE(R4) ;;;BAE REGISTER EXIST? MOV (SP)+,@#NXM.V ;;;MAYBE, FIRST RESTORE NXM VECTOR MOV (SP)+,@#NXM.V+2 ;;; AND NXM PSW [+GTS] ROL 2(SP) ;;;SAVE THE CARRY BIT .MTPS ; RESTORE PREVIOUS PRIORITY LEVEL ROR (SP)+ ; RESTORE CARRY BCS 20$ ; NOT AN RLV12... BR IS NOT AN ERROR .IF EQ ERL$G MOV #NOP,$RLV1A-DLLQE(R5) ; Change BR to NOP for RLV12 .IFF MOV #NOP,R0 ; R0="NOP" MOV R0,$RLV1A-DLLQE(R5) ; PATCH 'BR' TO 'NOP' FOR RLV12 MOV R0,$RLV1B-DLLQE(R5) ; PATCH ERROR LOGGING CODE SO IT KNOWS MOV R0,$RLV1C-DLLQE(R5) ; ABOUT EXTRA REGISTER (RLBAE) .ENDC ;EQ ERL$G 20$: CLC ;+ ; LOAD UP LOCAL VARIABLES WITHIN DL ;- MOV R1,R5 ; RESTORE PTR TO DLLQUE TO R5 MOV @R1,R0 ; GET ADDRESS OF DLLQE MOV @#SYSPTR,R4 ; GET START OF RMON MOV $H2UB(R4),R3 ; R3 = UBVECT POINTER MOV R3,(R0) ; H2UB = ADDRESS OF UBVECT MOV $PNPTR(R4),R3 ; R3 = RMON OFFSET TO PNAME TABLE ADD R4,R3 ; R3 -> PNAME TABLE ADDRESS MOV R3,<$PNMPT-DLBASE>(R0) ; $PNMPT -> PNAME TABLE ADDRESS ADD R2,R3 ; R3 -> $ENTRY TABLE MOV R3,<$ENTPT-DLBASE>(R0) ; $ENTPT -> $ENTRY TABLE MOV R5,(R0) ; DLENT -> DL'S $ENTRY TABLE ENTRY SUB R2,R5 ; R5 -> DL'S $PNAME TABLE ENTRY MOV R5,(R0) ; DLPNA -> DL'S $PNAME TABLE ENTRY ;+ ; ALLOCATE PERMANENT UMRS TO POINT INTO DL'S INTERNAL DMA BUFFERS, ; DLBBUF AND DLFILL, AND GET THE UNIBUS VIRTUAL ADDRESS. ;- MOV #,R1 ; R1 = LOW 16 BITS OF DMABUF ADDRESS ADD R0,R1 ; CLR R2 ; R2 = HIGH 6 BITS OF DMABUF ADDRESS MOV (R0),R4 ; R4 -> PNAME ENTRY FOR DL MOV (R0),R5 ; GET UB ENTRY ADDRESS MOV R0,-(SP) ; SAVE DL STARTING ADDRESS MOV #NOUMRS,R0 ; R0 = NUMBER OF UMRS REQUIRED CALL UB.ALL(R5) ; CALL ALLUMR MOV (SP)+,R0 ; RESTORE DL STARTING ADDRESS BCS 30$ ; COULDN'T GET UMR, FAIL THE LOAD MOV R1,(R0) ; STORE UNIBUS VIRTUAL ADDRESS LOW ASL R2 ; SHIFT ASL R2 ; HI BITS LEFT 4 ASL R2 ; TO GET THEM INTO THE ASL R2 ; CORRECT PLACE MOV R2,(R0) ; STORE UNIBUS VIRTUAL ADDRESS HIGH CLC ; LOAD SUCCEEDED 30$: RETURN ; $DLNXM: BIS #1,2(SP) ;SET THE CARRY BIT RTI ;+ ; RELEAS ; ; ROUTINE TO UNLOAD DL ; ; ENTRY: SAME AS FOR LOAD. ; ;- .ENABL LSB RELEAS:: MOV R5,R1 ; R1 = $ENTRY SLOT FOR DM SUB R2,R1 ; R2 -> $PNAME SLOT FOR DM MOV @#SYSPTR,R4 ; GET START OF RMON MOV $H2UB(R4),R5 ; R5 = UB ENTRY VECTOR CALL UB.RLS(R5) ; RELEASE UMRS RETURN ; AND EXIT .ENDC ;NE MMG$T .ENDC ;EQ VENU$C .END