$DRIVER DESCRIPTION=, VERSION=<2> .SBTTL Macros and definitions .MCALL .ADDR,.ASSUME,.DRDEF .IF NDF RT$OLD .LIBRARY "SY:SYSTEM.MLB" ;Indicates SYSTEM.MLB .MCALL .CF3DF ; CF3.64 definition .MCALL .FIXDF ; $CNFG3 and $PNPTR definitions .MCALL .SYCDF ; $SYPTR definition .CF3DF .FIXDF .SYCDF .ENDC $DRDEF .IF NDF RT$OLD .IF NE CF$N64 .DRPTR FETCH=FETCH, LOAD=LOAD, UNLOAD=UNLOAD, RELEASE=RELEASE .ENDC .DREST DVC.DK .ENDC .SBTTL Driver $DRBEG PROCEDURE DRIVER BEGIN CALL DRVINI LET R4 := (PC)+ CSR2: .WORD CFBASE+P$CSR2 .IF NE CF$INT LET (R4) := #DC.STA .IFF LET (R4) := #DC.STA!DC.NIE .ENDC LET R5 := CFCQE ; Get current queue element ; CS.RDM =: ^O<304> ; Read Multiply ; CS.WTM =: ^O<305> ; Write Multiply ; CS.SMM =: ^O<306> ; Set Multiply Mode .IF NE CF$MM LET CMD := #CS.RDM ; Read command .IFF LET CMD := #CS.RD ; Read command .ENDC LET R1 := Q$WCNT(R5) ; Word count (positive - reading, negative - writing) IF RESULT IS MI THEN ; Reading? LET R1 := - R1 ; No, writing, invert word count .IF NE CF$MM LET CMD := #CS.WTM ; Write command .IFF LET CMD := #CS.WT ; Write command .ENDC END LET R4 := R4 + #P$STAT-P$CSR2 ; CALL DVINI CALL CFWAIT ; 1. P$DH - 34 .ASSUME P$CMD EQ P$STAT .ASSUME P$DH EQ .IF NDF CF$SLV LET -(R4) := #DH.PRM ; Master .IFF LET -(R4) := #DH.SLV ; Slave .ENDC ; 2. P$CYLH - 32 LET R0 :B= Q$UNIT(R5) ; Unit LET R0 := R0 OFF.BY #^C<7> ; number .IF NDF RT$OLD .IF NE CF$N64 LET R3 :B= Q$2UNI(R5) ; 10..77 ? IF RESULT IS MI THEN ; MI - yes LET R3 :B= NOT R3 END LET R3 := R3 OFF.BY #^C R.SHIFT 1 ; High 3 bits of unit number mask to proper position LET R0 :B= R0 SET.BY R3 ; High and low bits of unit number .ENDC .ENDC .ASSUME P$CYLH EQ LET -(R4) := R0 ; .ASSUME Q$BLKN EQ 0 LET R0 := (R5) ; Block number ; 4. P$CYLL - 30 .ASSUME P$CYLL EQ PUSH R0 ; Block number - cyl low - high byte SWAB (SP) ; .. to low byte LET -(R4) := POP ; 3. P$SNUM - 26 .ASSUME P$SNUM EQ LET -(R4) := R0 ; Block number - sector - low byte ; 5. P$SCNT - 24 LET R2 := R1 + #^O<377> ; round up to next sector count SWAB R2 ; .. to low byte .ASSUME P$SCNT EQ LET -(R4) := R2 LET R2 := Q$BUFF(R5) ; Buffer address .IF NE MMG$T .IF DF RT$OLD LET PARVAL := Q$PAR(R5) ; Save the par1 value for mapping user buffer .IFF LET PARVAL := Q$MEM(R5) ; Save the par1 value for mapping user buffer .ENDC .ENDC ;NE MMG$T ; 6. P$CMD - 36 LET R4 := R4 + #P$STAT-P$SCNT LET (R4) := CMD ; 36 .IF NE CF$INT IF CMD EQ #CS.WT THEN NOP NOP NOP NOP CALL CFTRNF END LET ABUF := R2 LET WCNT := R1 RETURN .IFF GOTO INTRP2 .ENDC END DRIVER $DRAST CFPRI, CFFIN ; PR4 !!! PROCEDURE INTRPT BEGIN LET R4 := CSR2 + #P$STAT-P$CSR2 TST (R4) ; reading status clear interrup request .FORK CFFBLK .IF NE CF$INT $GOTO INTRP2 .IFF GOTO CFABRT .ENDC END INTRPT PROCEDURE INTRP2 BEGIN .IF NE CF$INT IF #CS.ERR SET.IN (R4) GOTO CFABRT LET R5 := CFCQE LET R2 := ABUF LET R1 := WCNT IF RESULT IS EQ GOTO CFFIN .IFF REPEAT .ENDC CALL CFTRNF .IF NE CF$INT LET ABUF := R2 LET WCNT := R1 IF RESULT IS EQ AND CMD EQ #CS.RD GOTO CFFIN RETURN .IFF UNTIL R1 EQ #0 GOTO CFFIN .ENDC END INTRP2 PROCEDURE CFABRT BEGIN .ASSUME Q$CSW EQ Q$BLKN-2 BIS #HDERR$,@-(R5) LET R4 := CSR2 LET (R4) := #DC.STA!DC.SRS!DC.NIE $GOTO CFFIN END CFABRT PROCEDURE CFFIN BEGIN $GOTO CFDONE END CFFIN PROCEDURE CFDONE BEGIN $DRFIN END CFDONE PROCEDURE CFTRNF ; ; R1 Word Count ; R2 #BUF (and PARVAL) ; R3 ; R4 P$STAT ; BEGIN REPEAT LET R0 :B= (R4) .ASSUME CS.BSY EQ <^O200> UNTIL RESULT IS PL AND #CS.DRQ SET.IN R0 IF #CS.ERR SET.IN (R4) GOTO CFABRT IF CMD EQ #CS.RD THEN JSR R0, CFFILL LET (R2)+ := (R4) TST (R4) ELSE JSR R0, CFFILL LET (R4) := (R2)+ LET (R4) := #0 END RETURN END CFTRNF PROCEDURE CFFILL BEGIN LET 10$ := (R0)+ LET 20$ := (R0)+ PUSH R4 LET R4 := R4 + #P$DBUF-P$STAT .IF NE CF$MM REPEAT LET R3 := <#^O<<20000-100>/2>> .IFF LET R3 := #256. .ENDC LET R5 := #0 IF R1 LO R3 THEN LET R5 := R3 - R1 LET R3 := R1 END LET R1 := R1 - R3 .IF NE MMG$T BREAKP JSR R0, @$P1EXT ;Let the monitor execute the following code. ; .WORD P1$EXT .WORD PARVAL-. ;Number of instructions in bytes plus 2. .ENDC ;NE MMG$T THRU R3 10$: .WORD 0 END IF R5 HI #0 THEN THRU R5 20$: .WORD 0 END END .IF NE MMG$T PARVAL: .WORD 0 ; Using this value for the PAR 1 bias .ENDC ;NE MMG$T .IF NE MMG$T .IF EQ CF$MM LET PARVAL := PARVAL + <#^D<256>*^O<2>/^O<100>> ; Map to next block in buffer next time LET R2 := R2 - <#^D<256>*^O<2>> .IFF LET PARVAL := PARVAL + <#^O<<20000-100>/100>> ; Map to next block in buffer next time LET R2 := R2 - <#^O<20000-100>> UNTIL R1 EQ #0 .ENDC .ENDC ;NE MMG$T POP R4 RTS R0 END CFFILL PROCEDURE DRVINI BEGIN .IF NE MMG$T LET R1 := @#$SYPTR ; R1 -> monitor base LET $P1EXT := P1$EXT(R1) ; Get address of externalization routine .ENDC ;NE MMG$T GOTO CLNCAL END DRVINI ; PROCEDURE DVINI ; BEGIN ; CALL CFWAIT ; ; LET P$FR-P$STAT(R4) := #FR.APM ; LET P$SCNT-P$STAT(R4) := #254 ; LET (R4) := #CS.SF ; ; CALL CFWAIT ; ; .IF NE CF$MM ; ; LET P$SCNT-P$STAT(R4) := #BL$CNT ; LET (R4) := #CS.SMM ; ; ; CALL CFWAIT ; ; IF #CS.ERR SET.IN (R4) THEN ; HALT ; .ASSUME P$CMD EQ P$STAT ; END ; .ENDC ; ; $GOTO CLNCAL ; END DVINI PROCEDURE CLNCAL BEGIN LET R0 := (SP) LET -(R0) := #NOP LET -(R0) := #NOP RETURN END CLNCAL PROCEDURE CFWAIT BEGIN REPEAT LET R0 :B= (R4) .ASSUME CS.BSY EQ <^O200> UNTIL RESULT IS PL AND #CS.DRD SET.IN R0 RETURN END CFWAIT $P1EXT: .WORD 0 ; Pointer to externalization routine ABUF: .WORD 0 WCNT: .WORD 0 CMD: .WORD 0 CFFBLK: .BLKW 4 ; Fork block .SBTTL Boot driver $DRBOT PENTRY=, PREAD= .=CFBOOT+^O<40> ; Put the "JMP BOOT" into SYSCOM area PROCEDURE BOOT1 BEGIN JMP @#BOOT-CFBOOT END BOOT1 .=CFBOOT+^O<210> PROCEDURE READ BEGIN LET @#JSW := #0 ; ?? LET @#B$READ := #READ1-CFBOOT $GOTO READ1 END READ PROCEDURE READ1 ; ; R0 - sector num ; R1 - word count - zeroed ; R2 - memory address - updated ; ; in work ; R3 - sector count ; BEGIN ; LET R4 := @#B$DEVU ?? ; HALT LET R4 := BTCSR2 LET (R4) := #DC.STA!DC.NIE LET R3 := R1 + #^O<377> SWAB R3 ; R3 sector count LET R4 := R4 + #P$STAT-P$CSR2 REPEAT LET R5 :B= (R4) .ASSUME CS.BSY EQ <^O200> UNTIL RESULT IS PL AND #CS.DRD SET.IN R5 LET R4 := R4 + #P$SCNT-P$STAT LET (R4)+ := R3 ; 24 .ASSUME P$SNUM EQ LET (R4)+ := R0 ; 26 .ASSUME P$CYLL EQ SWAB R0 LET (R4)+ := R0 ; 30 .ASSUME P$CYLH EQ LET (R4)+ := @#B$DEVU ; 32 .ASSUME P$DH EQ LET (R4)+ := #DH.PRM ; 34 .ASSUME P$CMD EQ LET (R4) := #CS.RD ; 36 REPEAT REPEAT LET R5 :B= (R4) .ASSUME CS.BSY EQ <^O200> UNTIL RESULT IS PL AND #CS.DRQ SET.IN R5 IF #CS.ERR SET.IN (R4) GOTO 80$ LET R4 := R4 + #P$DBUF-P$STAT ; 356 - 334 ; THRU R3 := #256. ; IF R1 NE #0 THEN ; LET (R2)+ := (R4) ; LET R1 := R1 - #1 ; ELSE ; TST (R4) ; END ; END ; 372 - 334 LET R3 := #256. LET R5 := #0 IF R1 LO R3 THEN LET R5 := R3 - R1 LET R3 := R1 END LET R1 := R1 - R3 THRU R3 LET (R2)+ := (R4) END IF R5 HI #0 THEN THRU R5 TST (R4) END END LET R4 := R4 + #P$STAT-P$DBUF UNTIL R1 EQ #0 LET CARRY := OFF RETURN 80$: RESET JMP BIOERR END READ1 BTCSR2: .WORD CFBASE+P$CSR2 .=CFBOOT+^O<506> ; ; Standard ; R0 - device unit number ; R1 - CSR2 ; 1 ; Non-standard ; R2 - no usable data ; R3 - 340 (master device) or 360 (slave device) - CF not used slave device ; R4 - no usable data ; R5 - 100200 (CF not used) ; PROCEDURE BOOT BEGIN LET SP := #10000 PUSH R0 IF R1 EQ #WQSTAT THEN LET R1 := R1 + #P$CSR2-P$STAT END LET BTCSR2 := R1 LET @#B$DEVU := R0 ; device unit number for read subroutine LET R0 := #2 ; R0 - sector num LET R1 := #256.*4 ; R1 - word count (4 sectors) LET R2 := #B$BOOT ; R2 - memory address CALL READ1 IF BTCSR2 NE #WQCSR2 THEN LET R3 := BTCSR2 - #ZABASE+P$CSR2 R.SHIFT 5 LET R2 := #0 WHILE R3 GT #0 LET R2 := R2 + #<^RZB>-<^RZA> DEC R3 END LET R2 := R2 + #<^RZA> ELSE LET R2 := #<^RWQ> END LET @#B$READ := #READ1-CFBOOT ; for secondary boot LET @#B$DEVN := R2 ; #CF$NAM ; for secondary boot POP R0 LET @#B$DEVU := R0 ; for secondary boot JMP @#B$BOOT END BOOT $DREND .SBTTL Code for support more than 8 devices .IF NDF RT$OLD .IF NE CF$N64 .PSECT SETOVR .SBTTL Load/fetch and unload/release one-time code ;+ ; Example LOAD/FETCH routine for a extended device-unit Handler. ; ; INPUT ; ; R0 -> handler routine being called ; R1 -> GETVEC routine ; R2 $SLOT*2 ; R3 type code ; 0 -- .FETCH ; 2 -- .RELEASE ; 4 -- $LOAD ; 6 -- $UNLOAD ; 10-- Job Abort ; 12-- BSTRAP ; R4 -> read routine ; R5 -> $ENTRY word as above ; ; ; BSTRAP or KMON INSTALL modifies $PNAME, $PNAM2, and $OWNER+0 ; for an extended device-unit handler. You need to insert only the ; address of the extended-ownership table into $OWNER+2 here. ; ; ; OUTPUT ; Registers need not be saved by the handler code ; Carry clear, unless an error was detected by ; $SYS or the handler code. ; If an I/O error occurred, R0 is cleared and Carry set. ; If the handler returns with Carry set, R0 is passed, as it was returned by the handler. ;- PROCEDURE LOAD BEGIN $GOTO FETCH END LOAD PROCEDURE FETCH BEGIN LET R0 := @#$SYPTR ; R0 -> Base of RMON IF #CF3.64 SET.IN $CNFG3(R0) AND #CF3.OW SET.IN $CNFG3(R0) ; Extended unit and Owner table support in monitor? LET R3 := R2 L.SHIFT 2 + R2 ; R3 = $SLOT*10 CALL FIXOWN ; Insert extended ownership table addr into $OWNER word #2. R1 -> $OWNER+2 END LET CARRY := OFF RETURN END FETCH .SBTTL UNLOAD - Unload/release code for a extended device-unit handler ;+ ; Example UNLOAD/RELEASE routine for a extended device-unit Handler. ; ; INPUT ; ; R0 -> handler routine being called ; R1 -> GETVEC routine ; R2 $SLOT*2 ; R3 type code ; 0 -- .FETCH ; 2 -- .RELEASE ; 4 -- $LOAD ; 6 -- $UNLOAD ; 10-- Job Abort ; 12-- BSTRAP ; R4 -> read routine ; R5 -> $ENTRY word as above ; ; ; This routine should zero the $OWNER+2 pointer to the extended ownership ; table of an extended device-unit handler. ; ; OUTPUT ; Registers need not be saved by the handler code ; Carry clear, unless an error was detected by $SYS or the handler code ; If an I/O error occurred, R0 will be cleared and Carry set. ; If the handler returns with carry set, R0 will be passed as it was returned by the handler. ;- PROCEDURE RELEASE BEGIN $GOTO UNLOAD END RELEASE PROCEDURE UNLOAD BEGIN LET R0 := @#$SYPTR ; R0 -> base of RMON IF #CF3.64 SET.IN $CNFG3(R0) AND #CF3.OW SET.IN $CNFG3(R0) ; Extended unit and Owner table support in monitor? LET R3 := R2 L.SHIFT 2 + R2 ; R3 = $SLOT*10 CALL FIXOWN ; Insert extended ownership table addr into $OWNER word #2. R1 -> $OWNER+2 LET @R1 := #0 END LET CARRY := OFF RETURN END UNLOAD .SBTTL FIXOWN - insert pointer to extended ownership table into $OWNER ;+ ; FIXOWN - insert pointer to extended ownership table into second word of $OWNER table (64 UNITS ONLY!!!) ; ; INPUT ; R2 = $SLOT*2 ; R3 = $SLOT*10. ; R5 -> $ENTRY entry for this handler ; dd$X64: extended ownership table ; ; OUTPUT ; $OWNER+2 points to extended ownership table ; R1 points to $OWNER+2 ;- PROCEDURE FIXOWN BEGIN LET R1 := @#$SYPTR ; R1 -> $RMON LET PUSH := $PNPTR(R1) + R1 + R2 ; @SP -> beginning of $PNAME -> beginning of $ENTRY LET R1 := R5 - POP + R5 - R3 ; R1 -> $ENTRY entry for this handler -> byte offset into $ENTRY -> ; $ENTRY + double-word index -> $OWNER of this handler + 8. CMP -(R1), -(R1) ; R1 -> $OWNER of this handler + 4 LET -(R1) := @R5 ; move addr of ddLQE into $OWNER+2, move addr of ddLQE into $OWNER+2 LET @R1 := @R1 + #CF$X64-CFLQE ; make $OWNER (pic) to point to extended ownership table RETURN END FIXOWN .ENDC ;NE CF$N64 .ENDC ;NDF RT$OLD $END