.MCALL .MODULE .MODULE DM,VERSION=31,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 ; RK6$B = 1 BBR support ; ; RK6$S = 1 SPFUN support ; ; EIS$I (MMG$T) SOB instruction (no code effects!) ; 0 simulate SOB ; 1 use SOB ; ; DM$CSR (177440) CSR ; DM$VEC (210) Vector ; ; MMG$T std conditional ; TIM$IT std conditional (no code effects) ; ERL$G std conditional ;- .SBTTL MACROS AND DEFINITIONS .MCALL .DRDEF .ASSUME .ADDR .BR .LIBRARY "SRC:SYSTEM.MLB" .MCALL .UBVDF .UBVDF 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 .WRITE =: 375 ; EMT CODE for .WRITE ..READ =: 010 ; subcode for .READ ..WRIT =: 011 ; subcode for .WRITE SYSCHN =: 17 ; system channel .IIF NDF RK6$S, RK6$S=0 ;SPECIAL FUNCTION RK6$B =: 1 ;ALWAYS DEFINE BAD BLOCK SUPPORT RK6$S =: 1 ;NOTE: turning off these conditionals may require .DREST and .DRSPF ; calls to be altered??? Also changes for UMR support. .IF NE MMG$T .ASSUME RK6$B EQ 1 MESSAGE=<; UMR support requires bad block support > .ENDC ;NE MMG$T DMDSI6 =: 410.*3.*22. ;SIZE OF RK06 DMDSI7 =: 814.*3.*22. ;SIZE OF RK07 ; 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 ; DM INTERNAL DMA BUFFER EQUATES .IF NE RK6$B BUFSIZ = /2 ; WORD SIZE OF DM INTERNAL DMA BUFFER NOUMRS = ; NUMBER OF PERMANENT UMRS REQUIRED .ENDC ;NE RK6$B .IF EQ MMG$T .DRDEF DM,23,FILST$++VARSZ$,DMDSI6,177440,210,DMA=NO .DRPTR FETCH=FETCH,LOAD=FETCH .IFF ;EQ MMG$T .IF NE RK6$B .DRDEF DM,23,FILST$++VARSZ$,DMDSI6,177440,210,DMA=YES,PERMUMR=NOUMRS .DRPTR FETCH=FETCH,LOAD=FETCH,RELEASE=RELEAS,UNLOAD=RELEAS .IFF ;NE RK6$B .DRPTR FETCH=FETCH,LOAD=FETCH .ENDC ;NE RK6$B .ENDC ;EQ MMG$T .DREST CLASS=DVC.DK,MOD=DVM.DM,REPLACE=RTABLE .IF NE RK6$B .IF NE MMG$T .DRSPF +UBTAB ;UB spfuns go into UBTAB .ENDC ;NE MMG$T .DRSPF <377> ;Read with error word returned .DRSPF <376> ;Write with error word returned .DRSPF <374> ;Re-read replacement table (perm UMR) .DRSPF <373> ;Return device size (not DMA) .ENDC; NE RK6$B .IIF NDF EIS$I EIS$I = MMG$T .IIF EQ EIS$I .MCALL SOB RETRY =: 8. ;NUMBER OF RETRIES ; SPECIAL FUNCTION BITS SPFUNB =: 100000 SPERR =: 077400 SPHARD =: 000200 SPRCAL =: 000010 SPOFF =: 000004 SPRETY =: 000002 SPECC =: 000001 ; SPECIAL FUNCTION CODES SPREAD =: 377 SPWRIT =: 376 SPREP =: 374 SPDSIZ =: 373 ;RETURNS DEVICE SIZE ;NOTE: if you add a special function code also add it to .DRSPF ; ERROR LOG DEFINITIONS DMNREG =: 13. ;NUMBER OF REGISTERS =13. DMNRG1 =: 7. ;READ 9 REGISTERS FIRST,SKIP TWO, DMNRG2 =: 4. ;THEN READ THE LAST FOUR ; RK06 CONTROLLER REGISTERS ; NOTE: DON'T DO BYTE OPERATIONS TO RK611 REGISTERS RKCS1 =: DM$CSR ;CONTROL AND STATUS REGISTER RKWC =: DM$CSR+2 ;WORD COUNT REGISTER RKBA =: DM$CSR+4 ;BUS ADDRESS REGISTER RKDA =: DM$CSR+6 ;DISK ADDRESS REGISTER RKCS2 =: DM$CSR+10 ;CONTROL AND STATUS REGISTER 2 RKDS =: DM$CSR+12 ;DRIVE STATUS REGISTER RKER =: DM$CSR+14 ;DRIVE ERROR REGISTER RKASOF =: DM$CSR+16 ;ATTENTION SUMMARY/OFFSET REGISTER RKDC =: DM$CSR+20 ;DESIRED CYLINDER REGISTER RKECPS =: DM$CSR+30 ;ECC POSITION REGISTER RKECPT =: DM$CSR+32 ;ECC PATTERN REGISTER ; BITS IN RKCS1 CERR =: 100000 ;COMBINED ERROR/CONTROLLER CLEAR DI =: 040000 ;DRIVE INTERRUPT SPAR =: 020000 ;DRIVE-TO-CONTROLLER PARITY ERROR CDT =: 002000 ;CONTROLLER DRIVE TYPE CTO =: 004000 ;CONTROLLER TIME-OUT RDY =: 000200 ;CONTROLLER READY IE =: 000100 ;INTERRUPT ENABLE GO =: 000001 ;GO ; BITS IN RKCS2 DLT =: 100000 ;DATA LATE ERROR WCE =: 040000 ;WRITE CHECK ERROR UPE =: 020000 ;UNIBUS PARITY ERROR NED =: 010000 ;NONEXISTENT DRIVE NEM =: 004000 ;NONEXISTENT MEMORY PGE =: 002000 ;PROGRAMMING ERROR MDS =: 001000 ;MULTIPLE DRIVE SELECT UFE =: 000400 ;UNIT FIELD ERROR SCLR =: 000040 ;SUBSYSTEM CLEAR ; BITS IN RKDS DDT =: 000400 ;DISK DRIVE TYPE VV =: 000100 ;VOLUME VALID DROT =: 000040 ;DRIVE OFF TRACK DCLO =: 000020 ;SPEED LOSS ACLO =: 000010 ;DRIVE AC LOW OFST =: 000004 ;OFFSET MODE ; BITS IN RKER DCK =: 100000 ;DATA CHECK UNS =: 040000 ;DRIVE UNSAFE OPI =: 020000 ;OPERATION INCOMPLETE DTE =: 010000 ;DRIVE TIMING ERROR WLE =: 004000 ;WRITE LOCK ERROR IDAE =: 002000 ;INVALID DISK ADDRESS ERROR COE =: 001000 ;CYLINDER OVERFLOW ERROR HVRC =: 000400 ;HEADER VERTICAL REDUNDANCY CHECK ERR BSE =: 000200 ;BAD SECTOR ERROR ECH =: 000100 ;ERROR CORRECTION HARD DTYE =: 000040 ;DRIVE-TYPE ERROR FMTE =: 000020 ;FORMAT ERROR DRPAR =: 000010 ;CONTROL-TO-DRIVE PARITY ERROR NXF =: 000004 ;NONEXECUTABLE FUNCTION SKI =: 000002 ;SEEK INCOMPLETE ILF =: 000001 ;ILLEGAL FUNCTION ; FUNCTIONS (BITS 1-5) IN RKCS1 PCKACK =: 2 ;PACK ACKNOWLEDGE DRVCLR =: 4 ;DRIVE CLEAR RECAL =: 12 ;RECALIBRATE SETOFF =: 14 ;OFFSET POSITION READAT =: 20 ;READ DATA WRITE =: 22 ;WRITE DATA .SBTTL INSTALLATION CODE .DRINS DM 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 3,44.,5.,3.,22.,0 ; Replacement table ; Software bad block replacement ; Some blocks replacable ; 44. blocks to skip to bad sector ; 5. sectors in bad sector table ; 3. tracks per sector ; 22. sectors per track ; 2**0 sectors per block .Assume . LE 400,MESSAGE=<;Install code too big> .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 ;CSR IN RANGE? (>160000) BLO O.BAD ;NOPE... MOV R0,INSCSR ;YES, INSTALLATION CODE NEEDS IT MOV R0,DISCSR ;DISPLAY CODE NEEDS IT TOO ; Now we ensure that the bootstrap reflects any change in the 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 AND MOV #,-(R1) ; THE BOOT BLOCK THAT NEEDS ALTERING TST -(R1) ;R1->EMT AREA MOV R0,R3 ;SAVE CSR ELSEWHERE, EMT NEEDS R0 ADD #,R3 ; (NEEDS TO POINT AT RKCS2) MOV R1,R0 ;R0->EMT AREA EMT .READ ; *** (.READW) *** BCS O.BAD MOV R3,(R2) ;SET THE CSR IN THE BOOTSTRAP ; (RKCS2) MOV R1,R0 ;R0->EMT AREA AGAIN .ASSUME ..READ+1 EQ ..WRIT INCB 1(R0) ;CHANGE FROM 'READ' TO 'WRITE' EMT .WRITE ; *** (.WRITW) *** BCS O.SYWL ; system write locked MOV R1,R0 ;R0->EMT AREA (ONE MORE TIME) .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,DMCSR ;LET THE HANDLER KNOW THE NEW CSR ADD #,R3 ;R3 -> RKCS1 MOV R3,DMCSR1 ;LET THE HANDLER KNOW THE NEW CSR O.GOOD: TST (PC)+ ;GOOD RETURN (CARRY CLEAR) O.BAD: SEC ;ERROR RETURN (CARRY SET) RETURN O.VEC: CMP R0,R3 ;VECTOR IN RANGE? (<500) BHIS O.BAD ;NOPE... BIT #3,R0 ;ON A VECTOR BOUNDRY? BNE O.BAD ;NOPE... MOV R0,DMSTRT ;TELL HANDLER ABOUT NEW VECTOR BR O.GOOD O.RTRY: CMP R0,R3 ;ASKING FOR TOO MANY? BHI O.BAD ;YEP... MOV R0,DRETRY ;USER SEEMS REASONABLE... BNE O.GOOD ;OKAY IF NON-ZERO BR O.BAD ;CAN'T ASK FOR NO RETRIES BAREA: .BYTE SYSCHN,..READ ;CHANNEL 17, READ .BLKW ;BLOCK NUMBER .BLKW ;BUFFER ADDRESS .WORD 256. ;WORD COUNT .WORD 0 ;COMPLETION (WAIT) .IF NE ERL$G O.SUCC: MOV #0,R3 ;'SUCCESS' ENTRY POINT ; (MUST BE TWO WORDS) N.SUCC: MOV R3,SCSFLG ;'NOSUCCESS' ENTRY POINT .ASSUME O.SUCC+4 EQ N.SUCC BR O.GOOD .ENDC .Assume . LE 1000,MESSAGE=<;Set code too big> .SBTTL DRIVER ENTRY .IF EQ MMG$T .DRBEG DM .IFF ;EQ MMG$T .IF NE RK6$B .DRBEG DM,SPFUN=UBTAB .ENDC ;NE RK6$B .ENDC ;EQ MMG$T DMBASE=DMSTRT+6 .ENABL LSB MOV DMCQE,R5 ; GET QUEUE ELEMENT POINTER ; CHECK FOR INVALID SPFUN FUNCTION CODE CMPB Q$FUNC(R5),#SPDSIZ ; IS FUNCTION CODE LESS AND 373 ? BLT DMEXIJ ; YES, EXIT CMPB Q$FUNC(R5),#SPREP+1 ; IS FUNCTION CODE EQUAL TO 375 ? BEQ DMEXIJ ; YES, EXIT ; CHECK FOR INVALID UNIT NUMBER MOV (PC)+,R3 ; R3 -> RKCS2 DMCSR: .WORD RKCS2 .Assume . LE DMSTRT+1000,MESSAGE=<;Set code object not in block 1> MOV (PC)+,R4 ; R4 -> RKCS1 DMCSR1: .WORD RKCS1 .Assume . LE DMSTRT+1000,MESSAGE=<;Set code object not in block 1> MOVB Q$UNIT(R5),R0 ; GET UNIT NUMBER BIC #^C<7>,R0 ; ISOLATE IT MOV R0,@R3 ; SET UNIT SELECT MOV #GO,@R4 ; SELECT THE DRIVE 1$: BIT #,@R4 ; WAIT FOR MESSAGE BEQ 1$ MOV (R3),R1 ; GET DRIVE STATUS BIC #^C,R1 ; MASK OFF DRIVE TYPE .ASSUME CDT EQ DDT*4 ASL R1 ; SHIFT OVER TO ASL R1 ; CDT POSITION MOV #DMDSIZ,R2 ; ASSUME SIZE FOR RK06 MOV R1,(PC)+ ; SAVE IT FOR OTHER FUNCTIONS, ALSO DMTYPE: .WORD 0 ; CONTROLLER DRIVE TYPE BEQ 2$ ; DEVICE IS AN RK06 MOV #DMDSI7,R2 ; GET SIZE FOR RK07 2$: MOV #CERR,@R4 ; CLEAR DRIVE TYPE ERROR MOV R0,@R3 ; SET UNIT SELECT MOV R1,@R4 ; SET DRIVE TYPE BIS #,@R4 ; SELECT THE DRIVE 3$: BIT #,@R4 ; WAIT FOR MESSAGE BEQ 3$ TST @R4 ; WAS THERE AN ERROR? .ASSUME CERR EQ 100000 BPL 4$ ; NO, CONTINUE JMP DMHERR ; NO, LOG ERROR 4$: CMPB Q$FUNC(R5),#SPDSIZ ; IS IT A GET SIZE FUNCTION ? BNE 5$ ; NO MOV R2,SPFUN ; SET DEVICE SIZE TO RETURN .IF NE RK6$B .IF NE MMG$T MOV Q$MEM(R5),SPMEM ; SAVE PAR BIAS (WHICH IS Q$MEM ; AS OF V5.5) .ENDC;NE MMG$T .ENDC;NE RK6$B MOV Q$BUFF(R5),SPBUFA ; SET RETURN BUFFER ADDRESS MOV #SCLR,@R3 ; CLEAR DRIVE AND CONTROLLER JMP DMSPEX ; EXIT 5$: .IF NE RK6$B CLR (PC)+ ; CLEAR BAD BLOCK FLAG BADBLK: .BYTE 0 ; : BAD BLOCK FLAG ; LOW BYTE => READ BLOCK 1 .BYTE 0 ; HIGH BYTE, I/O TO BLOCK REPLACEMENT CMPB Q$FUNC(R5),#SPREP ; FORCE REPLACEMENT TABLE READ ? BEQ 6$ ; YES BR 7$ ; NO, DO I/O BLK1RD: INCB BADBLK ;BLOCK 1 READ FLAG: 2=NORMAL, 1=FORCED 6$: INCB BADBLK ; SET TO READ REPLACEMENT FILE .IF EQ MMG$T ; .ADDR #BBUF,R3 ; STORE BUFFER ADDRESS ; MOV R3,BADD ; SET BUFFER ADDRESS FOR BLOCK 1 READ MOV BBUFPT,BADD ; SET BUFFER ADDRESS FOR BLOCK 1 READ .IFF ;EQ MMG$T MOV #.-.,BPAR ;GET DMA PAR ADDRESS OF BBUF BUFPAR =: .-4 ;DBB+ MOV #.-.,BMEM ;GET MEMORY PAR ADDRESS OF BBUF BUFMEM =: .-4 ;DBB- MOV #.-.,BADD ;GET PAR 1 VIRTUAL ADDRESS OF BBUF BUFADD =: .-4 .ENDC ;EQ MMG$T JSR R3,STBQUE ; SET REST OF QUEUE FOR BLOCK 1 READ .WORD 64. ; NUMBER OF WORDS TO READ .WORD 1 ; BLOCK TO READ .ENDC ;NE RK6$B 7$: MOV #READAT+GO+IE,DMFUNC ; ASSUME A READ OPERATION BIS DMTYPE,DMFUNC ; SET DRIVE TYPE INTO FUNCTION ; SPFUN DOES ABSOLUTE BLOCK READ OR WRITE WITHOUT BLOCK REPLACEMENT ; AND RETURNS AN EXTRA WORD OF ERROR INFORMATION IN FIRST BUF ADDRESS .IF NE RK6$B .IF NE MMG$T MOV Q$MEM(R5),(PC)+ ; SAVE PAR BIAS FOR ERROR REPORTING SPMEM: .WORD 0 ; STORAGE FOR PAR BIAS (WHICH IS ; STORED IN Q$MEM AS OF V5.5) .ENDC;NE MMG$T MOV #SPFUNB,SPFUN ; ASSUME A SPECIAL FUNCTION REQUEST CMPB Q$FUNC(R5),#SPWRIT ; TEST FOR SPFUN READ OR WRITE BHI DMSPFA ; SPFUN READ BEQ DMWRIT ; SPFUN WRITE CLR (PC)+ ; NOT A SPFUN READ OR WRITE ,ZERO FLAG SPFUN: .WORD 0 ; =0 FOR NON SPFUN ; SET BIT 15 FOR SPFUN ; ON EXIT ; = 100000, I/O SUCCESS - NO ERRORS ; = 100200, MARKED BAD BLOCK ON DISK ; = 100001, ECC CORRECTED ; = 100002, GOOD ON RETRY ; = 100004, GOOD AFTER OFFSET RETRY ; = 100010, GOOD AFTER RECALIBRATION ; = 1774XX, UNRECOVERABLE ERROR .ENDC;NE RK6$B TST Q$WCNT(R5) ; READ, WRITE OR SEEK? BNE 8$ ; READ/WRITE... DMEXIJ: JMP DMEXIT ; SEEK... 8$: BPL 9$ ; BRANCH IF READ NEG Q$WCNT(R5) ; KEEP WORD COUNTS POSITIVE BIS #WRITE,DMFUNC ; SET A WRITE OPERATION 9$: MOV Q$WCNT(R5),R1 ; DETERMINE LENGTH OF TRANSFER ADD #255.,R1 ; IN BLOCKS CLRB R1 SWAB R1 ADD @R5,R1 ; COMPUTE FIRST BLOCK AFTER TRANSFER CMP R2,R1 ; DOES XFER REACH REPLACEMENT BLOCK ? BHIS DMRETY ; NO, XFER OK JMP DMHENL ; YES, ERROR DMWRIT: BIS #WRITE,DMFUNC ; SET A WRITE OPERATION DMSPFA: MOV Q$BUFF(R5),(PC)+ ; SAVE ADDRESS OF BUFFER SPBUFA: .WORD 0 ; ADDRESS OF WORD TO RETURN SPFUN INFO ADD #2,Q$BUFF(R5) ; BUMP FOR FIRST LOCATION OF BUFFER .IF NE MMG$T CMP Q$BUFF(R5),#20100 ; OVERFLOWED THIS 32 WORD CHUNK? BLO DMRETY ; NOPE... SUB #100,Q$BUFF(R5) ; YES, REDUCE TO RANGE 20000-20076 INC Q$PAR(R5) ; AND BUMP 32 WORD CHUNK ADDRESS INC Q$MEM(R5) ; AND BUMP 32 WORD CHUNK ADDRESS .ENDC DMRETY: MOV (PC)+,(PC)+ ; SET CONTROLLER RETRY COUNT DRETRY: .WORD RETRY ; : MAX RETRY COUNT .Assume . LE DMSTRT+1000,MESSAGE=<;Set code object not in block 1> RETCNT: .WORD 0 ; : CURRENT RETRY COUNT DMRSET: CALL DMROFF ;RESET OFFSET POSITIONING DATA .DSABL LSB ; START TRANSFER ROUTINE DMSET: MOV DMCSR,R4 ;R4->CONTROLLER 2ND STATUS REGISTER MOV (R5)+,R3 ;GET BLOCK NUMBER .ASSUME Q$BLKN+2 EQ Q$FUNC TSTB (R5)+ ;BUMP PAST UNUSED SPFUNS BYTE .ASSUME Q$FUNC+1 EQ Q$UNIT MOVB (R5)+,R0 ;GET UNIT NUMBER BIC #^C<7>,R0 ;ISOLATE IT ; R0 = UNIT NUMBER ; R1 = N/A ; R2 = N/A ; R3 = BLOCK NUMBER ; R4 = DMCSR ; R5 = Q$BUFF 4$: BIT #VV,(R4) ;TEST FOR NEW DISK BNE 1$ ;NOPE, WE'VE ACCESSED THIS DISK BEFORE MOV #-1,BADRB1 ;FORCE READ OF BAD BLOCK TABLE 1$: MOV #SCLR,@R4 ;CLEAR DRIVE AND CONTROLLER MOV R0,@R4 ;SET THE UNIT NUMBER MOV DMTYPE,(R4) ;SET DRIVE TYPE BIS #PCKACK+GO,(R4) ;PACK ACKNOWLEDGE MOV R0,(PC)+ ;SAVE THE UNIT NUMBER FOR OTHER SCLR'S DMUNIT: .WORD 0 ;DRIVE UNIT NUMBER OF CURRENT REQUEST CMP R0,BADRB1 ;TEST IF SAME UNIT ACTIVE BEQ 5$ ;YES MOV #-1,BADRB1 ;FORCE REPLACEMENT TABLE READ IF ; BSE ERROR 5$: JSR R0,DIV ;DIVIDE R3/@R0, REM IN R3, QUO IN R2 .WORD 3.*22. ;NUMBER OF BLOCKS IN CYLINDER MOV R2,R1 ;SAVE CYLINDER NUMBER JSR R0,DIV ;FIND TRACK AND SECTOR .WORD 22. ;NUMBER OF SECTORS/TRACK SWAB R2 ;GET TRACK INTO HIGH BYTE BISB R3,R2 ;PUT IN SECTOR NUMBER 3$: BIT #,(R4) ;TEST IF READY BEQ 3$ ;NO, SPIN ON READY 4$: MOV R1,(R4) ;SET DESIRED CYLINDER MOV R2,-(R4) ;SET TRACK AND SECTOR REGISTER (RKDA) BUSADD: .IF EQ MMG$T MOV (R5)+,-(R4) ;SET BUS ADDRESS REGISTER (RKBA) .IFF CALL @$MPPTR ;CONVERT TO PHYSICAL ADDRESS MOV (SP)+,-(R4) ;MOVE LOW 16 BITS INTO RKBA ASL (SP) ;Now shift bits <05:04> to ASL (SP) ; <09:08> where they are needed ASL (SP) ; for RKCS1 ASL (SP) BIC #1400,DMFUNC ;Ensure old extended address bits ; have been reset before BIS (SP),DMFUNC ;Merging the new extended address bits BIT #36000,(SP)+ ;22-BIT ADDRESS SPECIFIED? BEQ 2$ ;NOPE, OK AS IS MOV DMCQE,R5 ;YES, INVALID FOR THIS CONTROLLER, ; R5->CURRENT QUEUE ELEMENT JMP DMHENL ;TAKE ERROR EXIT .ENDC ;EQ MMG$T .ASSUME Q$BUFF+2 EQ Q$WCNT 2$: MOV (R5)+,-(R4) ;SET WORD COUNT REGISTER (RKWC) NEG @R4 ;MAKE IT NEGATIVE, IE IS OFF, ; DONE 0'S WC BEQ DMDONJ ;BRANCH IF WC IS 0, TRANSFER IS DONE MOV (PC)+,-(R4) ;START TRANSFER DMFUNC: .WORD 0 ;FUNCTION CODE FOR OPERATION DMWAIT: RETURN ;RETURN DMDONJ: JMP DMDONE .IF NE ERL$G SCSFLG: .WORD 0 ; :SUCCESS LOGGING FLAG (DEFAULT=YES) ; = 0 SUCCESSFUL LOGGING=TRUE ; <> 0 SUCCESSFUL LOGGING=FALSE .Assume . LE DMSTRT+1000,MESSAGE=<;Set code object not in block 1> .ENDC .SBTTL INTERRUPT SERVICE ENTRY .ENABL LSB .DRAST DM,5 MOV DMCQE,R5 ;GET POINTER TO QUEUE ELEMENT TST BADBLK ;FAKE QUEUE ELEMENT IN USE ? BEQ 3$ ;NO, USE DMCQE MOV SAVCQE,R5 ;YES, USE THE FAKE QUEUE POINTER 3$: MOV DMCSR1,R4 ;R4->CONTROLLER FIRST STATUS REGISTER BIT #,@R4 ;WAS THIS A READ OR WRITE? BNE DMRDWR ;BRANCH IF YES .FORK DMFBLK BIT #,@R4 ;WE WANT DRIVE READY INTERRUPT BEQ DMWAIT ;BRANCH TO IGNORE CONTROLLER READY BPL DMST1 ;BRANCH TO TRY TRANSFER AGAIN DMCERR: CLR R1 ;DEFAULT TO NO RECALIBRATE RECHK: BIC #^C,R1 ;ISOLATE RECALIBRATE NEEDED BITS NEG R1 ;C=1 IF WE SHOULD RECALIBRATE, ; ELSE C=0 DECB RETCNT ;SHOULD WE TRY AGAIN? BLE DMHERJ ;NO .IF NE RK6$S BIS #SPRETY,SPFUN ;SET IF CONTROLLER RETRY .ENDC ;NE RK6$S BCS 2$ ;IF C=1 TRY RECALIBRATE DMST1: JMP DMSET ;ELSE, JUST TRY AGAIN 2$: MOV #SCLR,@DMCSR ;CLEAR OUT THE ERROR MOV DMUNIT,@DMCSR ;RESET THE UNIT NUMBER .IF NE RK6$S BIS #SPRCAL,SPFUN ;SET RECALIBRATE BIT IN SPFUN .ENDC ;NE RK6$S MOV DMTYPE,@R4 ;SET DRIVE TYPE BIS #,@R4 ;START A RECALIBRATE ; CALL DMROFF ;RESET THE OFFSET POSITIONING DATA ; BR DMWAIT ;WAIT FOR INTERRUPT .BR DMROFF ;RESET THE OFFSET POSITIONING DATA ; DMROFF WILL RETURN TO CALLER ; AND WAIT FOR INTERRUPT .DSABL LSB ; INITIALIZE OFFSET PARAMETERS DMROFF: CLR (PC)+ ;INIT THE OFFSET COUNTER OFFCNT: .WORD 0 ;OFFSET RETRY COUNT ; .ADDR #,OFFPTR ;RESET OFFSETS POINTER MOV (PC)+,(PC)+ ;RESET OFFSETS POINTER OFFTBP: .WORD OFFTAB-2-DMBASE ;-> TO BEG. OF OFFSET POSITIONS TABLE OFFPTR: .WORD 0 ;POINTER INTO OFFSET POSITIONS TABLE RETURN ;RETURN DMRDWR: TST @R4 ;WAS THERE AN ERROR? .IF NE ERL$G BMI 1$ ;ERROR .FORK DMFBLK ;CALL ERROR LOG SUCCESS AT FORK LEVEL BR DMDONJ .IFF BPL DMDONJ ;BRANCH IF NO ERRORS .ENDC ;NE ERL$G 1$: .FORK DMFBLK ;ERROR PROCESS AT FORK LEVEL MOV DMCSR,R3 ;R3->CONTROLLER 2ND STATUS REGISTER MOV (R4),R1 ;GET ERROR REGISTER .IF NE RK6$B TST SPFUN ;TEST IF SPECIAL FUNCTION BEQ USERR ;DON'T EXIT ON BSE ERROR BIT #BSE,R1 ;TEST FOR BAD SECTOR BEQ USERR BIS #SPHARD,SPFUN ;YES, SET SPFUN BIT BR DMHENJ ;BR TO HARD ERROR EXIT .ENDC ;NE RK6$B USERR: BIT #,R1 ;IS IT A ONCE-ONLY KIND OF USER ERROR? BNE DMHERJ ;YES... BIT #,@R3 ;MAYBE, CHECK OTHER REGISTER BEQ HARDCK ;NOPE...CHECK FOR HARD ERRORS DMHERJ: JMP DMHERR ;LOG BUT DON'T RETRY TRANSFER HARDCK: BIT #,R1 ;TEST FOR HARD ERROR BEQ USERR1 ;NO ERROR DMHENJ: JMP DMHENL ;HARD ERROR,EXIT USERR1: BIT #PGE,@R3 ;MORE TEST FOR HARD ERROR BNE DMHENJ .IF NE ERL$G BIT #BSE,R1 ;IS THIS A BSE ERROR? BNE LOGERE ;YES, DON'T LOG BSE ERRORS CALL LOGERR ;LOG IT LOGERE: .ENDC ;NE ERL$G BIT #UNS+DTYE+FMTE,R1 ;TEST FOR OTHER HARD ERRORS BNE DMHERJ ;BR IF YES. TST @R3 ;DATA LATE ERROR?, CLEAR CARRY! BMI SUBDIV ;BRANCH IF YES TO SUBDIVIDE TRANSFER BIT #,R1 ;TEST FOR PARTIAL TRANSFER BEQ DMCERR ;BRANCH IF CONTROLLER TYPE ERROR, C=0! .ENABL LSB ; TAKE WHAT WE CAN GET FROM PARTIAL TRANSFER SUBDIV: MOV (R4),R0 ;GET WORD COUNT REGISTER ADD Q$WCNT(R5),R0 ;CALCULATE NUMBER OF WORDS TRANSFERED MOV R0,R2 ;IT'LL BE RIGHT FOR SOFT ECC, AND HVRC BEQ BSECON ;SKIP ROUND DOWN IF NOTHING TRANSFERED BIT #,R1 ;NEED TO ROUND DOWN? BNE 2$ ;BRANCH IF AT NEW BLOCK TYPE ERROR DEC R0 ;ROUND DOWN TO START OF BAD BLOCK 2$: CLRB R0 ;CLEAN UP WORD COUNT (ESP. WRITES) TST R1 ;ECC ERROR? BPL BSECON ;BRANCH IF NOT BIT #ECH,R1 ;CORRECTABLE ECC ERROR? BNE BSECON ;HARD ERROR. MOV R2,-(SP) ;SAVE FOR LATER CALL ECC ;APPLY ECC TO DATA .IF NE RK6$S BIS #SPECC,SPFUN ;SET IF ECC APPLIED .ENDC ;NE RK6$S MOV (SP)+,R0 ;GET WORD COUNT OF WHATS GOOD CLR R1 ;CLEAR OUT ERROR WORD BSECON: SUB R0,Q$WCNT(R5) ;UPDATE WORD COUNT BEQ DMDONE ;BRANCH IF TRANSFER COMPLETED .IF EQ MMG$T ADD R0,Q$BUFF(R5) ;UPDATE BUFFER ADDRESS ADD R0,Q$BUFF(R5) ;TWICE FOR BYTE COUNT .ENDC ;EQ MMG$T SWAB R0 ;CONVERT WORD COUNT TO BLOCK COUNT .ASSUME Q$BLKN EQ 0 ADD R0,@R5 ;UPDATE BLOCK NUMBER .IF NE MMG$T ASL R0 ;MULTIPLY NUMBER OF BLOCKS BY 8. ASL R0 ASL R0 ADD R0,Q$PAR(R5) ;UPDATE ADDRESS BY ADDING TO THE ; PAR BASE. ADD 8 FOR EACH BLOCK ADD R0,Q$MEM(R5) ;UPDATE ADDRESS BY ADDING TO THE ; PAR BASE. ADD 8 FOR EACH BLOCK .ENDC ;NE MMG$T .IF NE RK6$B BIT #,R1 ;TEST FOR A BSE/BAD HEADER ERROR BEQ NOBSE ;NO ;BSE ERROR, WILL TRY TO FIND A ; REPLACEMENT BLOCK AND USE IT TST (PC)+ ;NEED TO READ REPLACEMENT TABLE? BADRB1: .WORD -1 ;IF= -1 READ IT BPL 3$ ;NOPE, USE CURRENT TABLE MOV DMFUNC,(PC)+ ;READ BAD BLOCK TABLE, SAVFUN: .WORD 0 ; SAVE CURRENT I/O FUNCTION HERE JMP BLK1RD ;GO READ TABLE BADCON: MOV SAVFUN,DMFUNC ;RESTORE FUNCTION OF THIS I/O REQUEST ; CONTINUE HERE TO DO BSE REPLACEMENT 3$: ; .ADDR #BBUF,R2 ;GET ADDRESS OF REPLACEMENT TABLE MOV (PC)+,R2 ;GET ADDRESS OF REPLACEMENT TABLE BBUFPT: .WORD BBUF-DMBASE 5$: TST @R2 ;TEST FOR END OF TABLE BEQ NOBSE ;YES, RETRY THE FUNCTION .ASSUME Q$BLKN EQ 0 CMP @R5,(R2)+ ;LOOK FOR BAD BLOCK IN TABLE BEQ 6$ ;MATCH TST (R2)+ ;SKIP TO NEXT ENTRY BR 5$ ;AND DO THE COMPARE 6$: MOV @R2,NEWBLK ;STORE THE REPLACEMENT BLOCK MOV Q$BUFF(R5),BADD ;SET BUFFER ADDR IN REPLACEMENT QUEUE .IF NE MMG$T MOV Q$PAR(R5),BPAR ;STORE ADDRESS PAR VALUE MOV Q$MEM(R5),BMEM ;STORE ADDRESS MEM VALUE .ENDC ;NE MMG$T MOV Q$WCNT(R5),NEWWC ;SET WORD COUNT CMP Q$WCNT(R5),#256. ;IS IT GREATER THAN A BLOCK? BLOS 10$ ;IF LOS NO MOV #256.,NEWWC ;ELSE - SET TO ONLY TRANSFER 1 BLOCK 10$: JSR R3,STBQUE ;STORE VALUES INTO THE REPLACEMENT Q NEWWC: .WORD 256. ;NUMBER OF WORDS TO DO NEWBLK: .WORD 0 ;NEW BLOCK NUMBER TO USE INCB BADBLK+1 ;SET FLAG FOR REPLACEMENT BLOCK I/O DMRSEJ: JMP DMRSET ;RESET AND CONTINUE .ENDC ;NE RK6$B .DSABL LSB NOBSE: TST R0 ;ANY GOOD DATA TRANSFERED? BNE DMRSEJ ;YES, DO REINIT OFFSET SEQUENCE ; *SOFT ECC ERRORS WILL ALWAYS BRANCH* BIT #,R1 ;CAN OFFSET RECOVERY HELP? BEQ RECHKJ ;BRANCH IF NOT, MAYBE RECALIBRATE WILL DECB OFFCNT ;ARE WE DONE IN CURRENT POSITION BGT DMSETJ ;BRANCH IF NOT ADD #2,OFFPTR ;BUMP TO NEXT POSITION MOV @OFFPTR,R0 ;GET RETRY COUNT AND OFFSET MOVB R0,OFFCNT ;SET NEW RETRY COUNT BMI DMHERR ;BRANCH IF HIT END OF TABLE .IF NE RK6$S BIS #SPOFF,SPFUN ;SET IF OFFSET RETRY TRIED .ENDC ;NE RK6$S CLRB R0 ;LEAVE ONLY OFFSET SWAB R0 ;IN RIGHT PLACE MOV #SCLR,@DMCSR ;CLEAR EVERYTHING MOV DMUNIT,@DMCSR ;RESET THE UNIT NUMBER MOV R0,(R4) ;SET THE OFFSET REGISTER MOV DMTYPE,@R4 ;SET DRIVE TYPE BIS #,@R4 ;START OFFSET FUNCTION RETURN ;WAIT FOR THE INTERRUPTS RECHKJ: JMP RECHK DMSETJ: JMP DMSET ;NO DMHERR: .IF NE ERL$G CALL LOGERR ;LOG THE ERROR .ENDC ;NE ERL$G .ASSUME Q$CSW EQ -2 DMHENL: BIS #HDERR$,@-(R5) ;SET HARD ERROR IN CSW MOV DMCSR1,R4 ;R4 -> RKCS1 BIS #CERR,@R4 ;REINIT CONTROLLER .IF NE RK6$S BIS #SPERR,SPFUN ;SET ERROR IN SPFUN WORD .ENDC ;NE RK6$S BR DMRRST DMDONE: .IF NE RK6$B TST BADBLK ;BAD BLOCK REPLACEMENT OR READING ; BLOCK 1? BEQ DMCOMP ;NO .IF EQ ERL$G .FORK DMFBLK ;MUST GO TO FORK LEVEL ; TO RECALL REQUEST .ENDC ;EQ ERL$G MOV DMCQE,R5 ;AND R5 CMP BADBLK,#2 ;TEST FOR TYPE OF BADBLK BLO DMCOMP ;FORCED READ OF BLOCK 1, SO EXIT BHI 1$ ;BAD BLOCK REPLACEMENT ; READ OF BAD BLOCK REPLACEMENT TABLE CLR BADBLK ;CLEAR BAD BLOCK FLAG MOV DMUNIT,BADRB1 ;SAVE UNIT IN FLAG TO READ ; REPLACEMENT TABLE JMP BADCON ;CONTINUE TO DO BSE REPLACEMENT 1$: CLR BADBLK ;BAD BLOCK REPLACEMENT,CLEAR FLAG MOV NEWWC,R0 ;SET R0=NUMBER OF WORDS READ/WRITE CLR R1 ;SET R1 AS IF NO ERRORS JMP BSECON ;CONTINUE WITH I/O .ENDC ;NE RK6$B DMCOMP: .IF NE ERL$G BIT #,DMFUNC ;TEST FOR WRITE BEQ DMEL3 ;READ NEG Q$WCNT(R5) ;SET WORD COUNT NEGATIVE FOR ERROR LOG DMEL3: TST SCSFLG ;LOGGING SUCCESSES? BNE DMRRST ;NOPE... MOV #DM$COD*400+377,R4 ;R4=DEV ID/-1 MOV DMCQE,R5 ;R5 -> 3RD WORD OF QUEUE ELEMENT CALL @$ELPTR ;CALL ERROR LOG MOV DMCSR1,R4 ;R4->CONTROLLER 1ST STATUS REGISTER .ENDC ;NE ERL$G DMRRST: CLR @R4 ;DISABLE INTERRUPTS .IF NE RK6$B TST SPFUN ;TEST FOR A SPFUN READ/WRITE REQUEST BPL DMEXIT ;NO DMSPEX: MOV SPBUFA,R5 ;R5 = ADDRESS OF BUFFER .IF NE MMG$T MOV DMCQE,R4 ;R4 -> 3RD WORD OF Q ELEMENT ;Q.BLKN MOV R5,Q$BUFF(R4) ;RESTORE ORIGINAL BUFFER ADDRESS MOV SPMEM,Q$MEM(R4) ;FIX PAR MOV SPFUN,-(SP) ;PUT ERROR INFO ON STACK CALL @$PTWRD ;STORE INFO IN USER BUFFER (XM) .IFF MOV SPFUN,@R5 ;STORE INFO IN USER BUFFER (SJ,FB) .ENDC ;NE MMG$T .ENDC ;NE RK6$B DMEXIT: .DRFIN DM ;EXIT TO COMPLETION ; DIVIDE SUBROUTINE DIV: MOV R3,R2 ;COPY THE DIVIDEND CLR R3 ;CLEAR THE SHIFTER MOV #16.,-(SP) ;STACK A LOOP COUNT 1$: ASL R2 ;SHIFT THE DIVIDEND ROL R3 ;BRING A BIT INTO THE HIGH ORDER CMP @R0,R3 ;DOES IT GO? BHI 2$ ;NO SUB @R0,R3 ;YES, TAKE OUT ONE INC R2 ;PUT IN A BIT OF QUOTIENT 2$: DEC @SP ;DONE? BNE 1$ ;NOT YET CMP (SP)+,(R0)+ ;YES, POP STACK AND RETURN RTS R0 ; ECC SUBROUTINE .ENABLE LSB ECC: MOV (R4),R2 ;GET BIT NUMBER OF START OF ERROR DEC R2 ;ADJUST FOR 0 ORIGIN MOV R2,-(SP) ;MAKE COPY BIC #17,@SP ;REMOVE BIT NUMBER IN WORD BIC @SP,R2 ;CLEAR WORD INFO FROM BIT NUMBER ASR @SP ;MAKE WORD OFFSET USEABLE ASR @SP ASR @SP ASR @SP ;TOP OF STACK NOW CONTAINS WORD OFFSET ADD (SP)+,R0 ;NOW R0 CONTAINS RELATIVE WORD TO FIX MOV (R4),R3 ;GET FIXEM BIT PATTERN CLR R1 ;DISPLACE BIT PATTERN REASONABLY BR 2$ ;JUMP INTO LOOP 1$: ASL R3 ;DOUBLE WORD SHIFT BIT PATTERN ROL R1 2$: DEC R2 ;SHIFT TO CORRECT BIT POSITION BGE 1$ ;LOOP CALL @PC ;LOOP THROUGH THE FOLLOWING CODE TWICE CMP R0,Q$WCNT(R5) ;ENSURE WORD TO CORRECT IS IN TRANSFER BHIS ECCDON ;BRANCH IF NOT MOV R0,R2 ;MAKE COPY OF RELATIVE WORD OFFSET .IF NE MMG$T ASH #-6+1,R2 ;R2 = # OF 32-WORD BLOCKS TO ; ERROR LOC (NO SIGN EXTEND) ADD Q$MEM(R5),R2 ;R2=NEW PAR1 ADDRESS MOV R2,3$ ;SET PAR BIAS FOR EXTERNAL ROUTINE MOV R0,R2 ;RESTORE WDCNT BIC #^C<37>,R2 ;CLEAR HIGH BITS NOW REPRESENTED ; IN PAR .ENDC ;NE MMG$T ASL R2 ;MAKE BYTE OFFSET ADD Q$BUFF(R5),R2 ;FORM ADDRESS OF ERROR WORD .IF NE MMG$T JSR R0,@(PC)+ ;CALL THE EXTERNALIZER $P1EXT: .WORD 0 .WORD 3$-. ;THIS MANY INSTRUCTIONS .ENDC ;NE MMG$T MOV @R2,-(SP) ;MAKE COPY OF EVIL WORD BIC R3,@R2 ;PERFORM AN XOR BIC (SP)+,R3 BIS R3,@R2 ;WORD IS NOW GOOD .IF NE MMG$T 3$: .WORD 0 ;PAR BIAS FOR USE BY P1EXT .ENDC MOV R1,R3 ;SET UP REST OF BIT PATTERN INC R0 ;BUMP TO NEXT WORD ECCDON: RETURN ;RETURN .DSABL LSB .IF NE ERL$G .SBTTL LOGERR - REPORTS TO ERROR LOGGER LOGERR: ; .ADDR #DMRBUF,R1 ;R1 -> BUFFER TO STORE DM REGISTERS MOV (PC)+,R1 DMRBFP: .WORD DMRBUF-DMBASE MOV R1,R2 ;SAVE IN R2 FOR ERROR LOG MOV DMCSR1,R3 ;R3->CONTROLLER REGISTERS MOV #DMNRG1,R4 ;R4=COUNT OF REGISTERS TO SAVE DMRREG: MOV (R3)+,(R1)+ ;STORE A REGISTER'S CONTENTS SOB R4,DMRREG ; do all of them MOV (R3)+,-(SP) ;PUSH VALUE OF RKASOF BIT #OFST,(R3) ;ARE WE IN OFFSET MODE? BEQ 1$ ;IF EQ NO MOV @OFFPTR,@SP ;@SP=OFFSET TBL ENTRY CLRB @SP ;GET RID OF RETRY COUNT SWAB @SP ;PUT OFFSET IN LOW BYTE 1$: MOV (SP)+,(R1)+ ;RKASOF VALUE MOV (R3)+,(R1)+ ;RKDC MOV #DMNRG2,R4 ;READ LAST FOUR REGISTERS ADD #6,R3 ;SKIP OVER RKDB AND RKMR1 SINCE ; THERE IS NO INFORMATION IN THEM ; AND READING THEM CAUSES BITS 15 ; OF RKCS1,RKCS2 TO BE SET DMRRG1: MOV (R3)+,(R1)+ ;READ REST OF REGISTERS DEC R4 BNE DMRRG1 MOV DRETRY,R3 SWAB R3 ADD #DMNREG,R3 ;R3 = MAX RETRY COUNT/REGISTER COUNT MOVB RETCNT,R4 ADD #DM$COD*400,R4 ;R4 = DEVICE ID/CURRENT RETRY COUNT BIT #,DMFUNC ;TEST FOR A WRITE FUNCTION BEQ DMEL1 ;READ NEG Q$WCNT(R5) ;NEGATE WORD COUNT FOR LOG (WRITE) DMEL1: CALL @$ELPTR ;CALL ERROR LOG, R5 -> 3RD WORD OF Q BIT #,DMFUNC BEQ DMEL2 NEG Q$WCNT(R5) ;RESTORE WORD COUNT POSITIVE DMEL2: MOV DMCSR,R3 ;R3->CONTROLLER 2ND STATUS REGISTER MOV DMCSR1,R4 ;R4->CONTROLLER 1ST STATUS REGISTER MOV (R4),R1 RETURN .ENDC ;NE ERL$G .IF NE RK6$B ; BAD BLOCK REPLACEMENT QUEUE BQUE: .WORD -1 ;STORE ADDRESS OF CSW HERE BBLK: .WORD -1 ;BLOCK 1 OF DISK .BYTE 0 ;SFC = 0 BUNT: .BYTE -1 ;STORE UNIT # HERE BADD: .WORD -1 ;BUFFER ADDRESS BWCT: .WORD -1 ;WORD COUNT .IF NE MMG$T .WORD 0 ;COMPLETION ADDRESS PLACE BPAR: .WORD -1 ;ADDRESS PAR VALUE BMEM: .WORD -1 ;ADDRESS MEM VALUE .WORD 0 ;PAD OUT Q ELEMENT FOR XM .ENDC ;NE MMG$T ;+ ; THIS IS THE DMA BUFFER FOR UMR SUPPORT ;- BBUF: .WORD 0 ;INDICATES NO REPLACEMENT .BLKW 63. ;BAD BLOCK REPLACEMENT STORAGE ; 2 WORDS FOR EACH BAD BLOCK ; WORD 1 = BAD BLOCK ; WORD 2 = REPLACEMENT BLOCK ; LIST TERMINATED BY 0 .WORD 0 ;UP TO 32. BAD BLOCKS ALLOWABLE BBEND: ; ROUTINE TO SET UP REPLACEMENT QUEUE STBQUE: ;GET ADDRESS OF REPLACEMENT Q, ; .ADDR #BWCT,R2 ;AT WORD COUNT MOV (PC)+,R2 ;AT WORD COUNT BWCTPT: .WORD BWCT-DMBASE MOV (R3)+,@R2 ;STORE WORD COUNT TST -(R2) ;SKIP BUFFER ADDRESS MOVB Q$UNIT(R5),-(R2) ;STORE UNIT NUMBER TSTB -(R2) ;SKIP SPFUN STUFF MOV (R3)+,-(R2) ;STORE BLOCK NUMBER .ASSUME Q$BLKN-2 EQ Q$CSW MOV -(R5),-2(R2) ;STORE POINTER TO CSW MOV R2,(PC)+ ;SAVE VALUE OF DMCQE SAVCQE: .WORD 0 MOV R2,R5 ;POINT R5 AT REPLACEMENT Q RTS R3 ;RETURN .IF NE MMG$T ;+ ; TABLE OF STANDARD DMA SPFUNS THAT DO NOT HAVE A PERMANENT UMR ; ALLOCATED TO THEM ;- UBTAB: .DRSPF -, ;READ WITH ERROR WORD RETURNED .DRSPF -, ;WRITE WITH ERROR WORD RETURNED .WORD 0 ;TABLE TERMINATOR .ENDC ;NE MMG$T .ENDC ;NE RK6$B ; OFFSET TABLE RETRY OFFSET ; COUNT .WORD -1 OFFTAB: .BYTE 16, 0 ;CENTERLINE .BYTE 2, 20 ; +400 .BYTE 2, 220 ; -400 .BYTE 2, 40 ; +800 .BYTE 2, 240 ; -800 .BYTE 2, 60 ; +1200 .BYTE 2, 260 ; -1200 .BYTE 0, 0 ;CENTERLINE .WORD -1 ;END OF TABLE DMFBLK: .WORD 0,0,0,0 ;FORK QUEUE BLOCK ECCBAD: .WORD 0 ;ADDRESS OF ECC CORRECTABLE WORD .IF NE ERL$G DMRBUF: .BLKW DMNREG ;ERROR LOG STORAGE FOR REGISTERS .ENDC ;NE ERL$G .SBTTL BOOTSTRAP DRIVER .DRBOT DM,BOOT1,READ . = DMBOOT+40 ;PUT THE JUMP BOOT INTO SYSCOM AREA BOOT1: JMP @#BOOT-DMBOOT ;START THE BOOTSTRAP . = DMBOOT+210 READ: MOV #<3.*22.>,R3 ;NUMBER OF BLOCKS IN CYLINDER MOV #-1,R4 ;INIT QUOTIENT MOV R4,R5 ;INIT SECOND QUOTIENT 1$: INC R4 ;BUMP QUOTIENT SUB R3,R0 ;(DIVIDE) BCC 1$ ;LOOP UNTIL DONE ADD R3,R0 ;FIX NUMERATOR MOV #22.,R3 ;GET NUMBER OF BLOCKS PER TRACK 2$: INC R5 ;BUMP QUOTIENT SUB R3,R0 ;(DIVIDE) BCC 2$ ;LOOP UNTIL DONE ADD R3,R0 ;FIX NUMERATOR SWAB R5 ;GET TRACK INTO HIGH BYTE BIS R5,R0 ;PUT IN SECTOR NUMBER MOV BOTCSR,R5 ;R5->CONTROLLER 2ND STATUS REGISTER BIT #400,(R5) ; IS IT AN RK07? BEQ 3$ ;NO - OK. BIS #2000,RDFCN ;YES- SET DRIVE TYPE BIT FOR RKCS1 3$: MOV R4,(R5) ;SET DESIRED CYLINDER MOV R0,-(R5) ;SET TRACK AND SECTOR REGISTER (RKDA) MOV R2,-(R5) ;SET BUS ADDRESS REGISTER (RKBA) MOV R1,-(R5) ;SET WORD COUNT REGISTER (RKWC) NEG @R5 ;MAKE IT NEGATIVE MOV (PC)+,-(R5) ;START READ TRANSFER RDFCN: .WORD 21 ; 21=RK06 READ/2021=RK07 READ 4$: BIT #100200,@R5 ;WAIT FOR READY BEQ 4$ ;BRANCH IF NOT READY BMI BIOERR ;BRANCH IF ANY ERROR, EVEN MINOR ONES! CLC ;ENSURE CARRY CLEAR BEFORE RETURN RETURN . = DMBOOT+604 BOOT: MOV #10000,SP ;SET STACK POINTER MOV @(PC)+,-(SP) ;GET THE UNIT NUMBER BOTCSR: .WORD RKCS2 BIC #^C7,@SP ;STRIP TO 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 CALL READ ;GO READ IT IN MOV #READ-DMBOOT,@#B$READ ;STORE START LOCATION FOR READ ROUTINE MOV #B$DNAM,@#B$DEVN ;STORE THE RAD50 DEVICE NAME MOV (SP)+,@#B$DEVU ;STORE THE UNIT NUMBER TO BOOT FROM JMP @#B$BOOT ;START SECONDARY BOOT .DREND DM .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,R0 ; GET ADDRESS OF DMLQE MOV @#SYSPTR,R3 ; GET START OF RMON ADD R0,(R0) .IF NE ERL$G ADD R0,(R0) .ENDC ;NE ERL$G .IF NE MMG$T MOV P1$EXT(R3),<$P1EXT-DMBASE>(R0) ;SAVE POINTER TO P1EXT ROUTINE .ENDC ;NE MMG$T .IF NE RK6$B ADD R0,(R0) ADD R0,(R0) .IF NE MMG$T ;+ ; ALLOCATE PERMANENT UMRS TO POINT INTO DM'S INTERNAL DMA BUFFER, ; BBUF, AND GET THE UNIBUS VIRTUAL ADDRESS. ;- MOV R5,R4 ; R4 -> DM'S $ENTRY TABLE ENTRY SUB R2,R4 ; R4 -> DM'S $PNAME TABLE ENTRY MOV #,R1 ; R1 = LOW 16 BITS OF DMABUF ADDRESS ADD R0,R1 ; CLR R2 ; R2 = HIGH 6 BITS OF DMABUF ADDRESS ;DBB+ MOV R1,R5 ; GET LOW 16 BITS OF ADDRESS BIC #77,R5 ; CLEAR OFFSET WITHIN CHUNK ASL R5 ; SHIFT ROL R5 ; HIGH 10 BITS ROLB R5 ; OF ADDRESS SWAB R5 ; 6 BITS TO RIGHT MOV R5,(R0) ; STORE MEMORY PAR1 VALUE ;DBB- MOV $H2UB(R3),R5 ; GET UB ENTRY ADDRESS MOV R0,-(SP) ; SAVE DM STARTING ADDRESS MOV #NOUMRS,R0 ; R0 = NUMBER OF UMRS REQUIRED CALL UB.ALL(R5) ; CALL ALLUMR MOV (SP)+,R0 ; RESTORE DM STARTING ADDRESS BCS 30$ ; COULDN'T GET UMR, FAIL THE LOAD MOV R1,R3 ; GET LOW 16 BITS OF ADDRESS BIC #177700,R3 ; STRIP ALL BUT OFFSET WITHIN CHUNK BIS #20000,R3 ; FORM PAR1 VIRTUAL ADDRESS MOV R3,(R0) ; STORE PAR1 VIRTUAL ADDRESS ASL R1 ; SHIFT HIGH 8-BITS OF ADDRESS ROL R2 ; INTO LOW BYTE OF R2 LEAVING ASL R1 ; NEXT 8-BITS OF ADDRESS IN ROL R2 ; HIGH BYTE OF R1 CLRB R1 ; COMBINE LOW BYTE OF R2 WITH BISB R2,R1 ; HIGH BYTE OF R1 INTO R1 SWAB R1 ; PUT HI BITS INTO CORRECT PLACE MOV R1,(R0) ; STORE PAR1 VALUE .ENDC ;NE MMG$T .ENDC ;NE RK6$B CLC ; LOAD SUCCEEDED 30$: RETURN .IF NE MMG$T .IF NE RK6$B ;+ ; RELEAS ; ; ROUTINE TO UNLOAD DM ; ; 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 CALLR UB.RLS(R5) ; RELEASE UMRS AND EXIT .ENDC ;NE RK6$B .ENDC ;NE MMG$T .END