        IF      IODRIVERBODY
        PAGE    *** THE SD STORAGE DEMON DRIVER ***
* DRIVES IMI7710 WITH 7711 INTELLIGENT CONTROLLER...
* 1/5/82 CHANGED FOR PSITECH WINCHESTER INTERFACE
*
; EQUATES FOR WINCHESTER DRIVER
        IFUND   WDCNBPS
WDCNBPS EQU     512     ; 512 BYTES PER SECTOR (TRANSFER)
        FIN

        IFUND   WDCNSPT
WDCNSPT EQU     36540   DEFAULT TO 7720C
        FIN
WDCNTPC EQU     1
WDCNCYL EQU     1
WDCFATAL        EQU     $80     ; RETRY TYPE ERROR

WDCFORMAT       EQU     1       ; FORMAT ENTIRE DISK COMMAND
WDCREADCMD      EQU     2       ; CONTROL READ COMMAND
WDCWRITECMD     EQU     3       ; CONTROL WRITE COMMAND

WDCRETRY        EQU     5       ; FAILURE RETRY COUNT


* WINCHESTER DISK CONTROLLER DCB DEFINITIONS
*
::      SET     *
        ORG     DSKINFO:SIZE    TACKS ON TO BOTTOM OF DISK INFO TABLE
WDCREADWRITE    RMB     1       0 IS READ, <>0 IS WRITE
WDCDRIVE        RMB     1       DRIVE NUMBER
WDCSIZE EQU     *
        ORG     ::
        PAGE
; BRANCH TABLE POINTED TO BY DCB AND USED BY SDOS

WDCDRIVER       FDB     WDCINIT ; ROUTINE TO RESET PIA AND WINCHESTER
        FDB     WDCREAD ; READ SINGLE SECTOR
        FDB     WDCWRITE        ; WRITE SINGLE SECTOR
        FDB     WDCWAITDONE
        FDB     WDCSTATUS
        FDB     WDCCONTROL      ; DISMOUNT OR FORMAT COMMAND

WDCCONTROL
        CMPA    #CC:DISMOUNTDISK
        BEQ     WDCDISMOUNT     B/ DISMOUNT.
        CMPA    #CC:FORMAT
        BEQ     WDCFORMATX      B/ FORMAT OPERATION
        JMP     ILLDEVICEOP
WDCDISMOUNT
        LDX     DCBPOINTER
        LDAA    #DSKINFO:OPSCOUNT+2-DSKINFO:SEEKERRCNT+1
LOOPWDCDISMNT
        CLR     DSKINFO:SEEKERRCNT,X
        INX
        DECA
        BNE     LOOPWDCDISMNT
        LDAA    #$FF
        STAA    DSKINFO:SEEKERRCNT,X
        INX
        STAA    DSKINFO:SEEKERRCNT,X
        INX
        STAA    DSKINFO:SEEKERRCNT,X
        OKRTS
WDCFORMATX
        LDAA    #WDCFORMAT      DO A "SECONDARY" FORMAT OPERATION
        LDX     DCBPOINTER
        STAA    WDCREADWRITE,X
        LDAA    #1
        BRA     WDCSETRETRY1

WDCWRITE
        LDAA    #WDCWRITECMD
        BRA     WDCOPSET

WDCREAD
        LDAA    #WDCREADCMD
WDCOPSET
        LDX     DCBPOINTER
        STAA    WDCREADWRITE,X  ; SET THE OPERATION
        LDAA    #WDCRETRY       ; SET RETRY COUNT
WDCSETRETRY1
        STAA    WDCRETRYCNT
        CLR     DCB:LASTERROR,X
        CLR     DCB:LASTERROR+1,X
        LDX     #WDCINTERFACE   ; WAIT FOR INTERFACE FREE
        LDAA    0,X
        BNE     WDCSETUP
        JSR     SDOS+SDOS:WAITEVENT
WDCSETUP
        CLR     WDCINTERFACE    ; SET INTERFACE BUSY
        LDX     DCBPOINTER
        STX     WDCDCBPOINTER   ; INTERRUPTS SERVICE DCB ADDRESS
        CLR     DCB:DONEFLAG,X  ; CLEAR DONE
        LDX     #0
        STX     WDCCONTINUEPC   ; SET INTERRUPTS NO GOOD
        LDX     #WDCSTARTIO
        JSR     SDOS+SDOS:STARTIO       ; ENTER INTERRUPTS SERVICE CODE
        LDX     DCBPOINTER      ; IF FORMAT CONTROL CALL OPERATION
        LDAA    WDCREADWRITE,X
        CMPA    #WDCFORMAT
        BEQ     WDCWAITDONE     B/ GO WAIT FOR FORMAT OPERATION COMPLETE
WDCOKRTS
        OKRTS

WDCWAITDONE
        LDX     DCBPOINTER      ; WAIT FOR TRANSFER DONE
        LDAA    DCB:DONEFLAG,X
        BNE     WDCWAIT1
        JSR     SDOS+SDOS:WAITEVENT
WDCWAIT1
        LDX     DCBPOINTER
        LDX     DCB:LASTERROR,X
        BEQ     WDCOKRTS
        JMP     ERRETX
        OKRTS

WDCSTATUS
        CMPA    #SC:ERRORSTATUS
        BEQ     WDCERSTAT
        JMP     ILLDEVICEOP
WDCERSTAT
        LDX     DCBPOINTER
        STX     WDCSTATX
        JSR     SDOS+SDOS:CHECKRDLEN
        FDB     DSKINFO:ERRLSN+3-DSKINFO:SEEKERRCNT
        LDX     SCBLK:RDBUF,X
        STX     WDCRDBUFX
        LDAB    #(DSKINFO:ERRLSN+3-DSKINFO:SEEKERRCNT)
WDCSTATUSLP
        LDX     WDCSTATX
        LDAA    DSKINFO:SEEKERRCNT,X
        INX
        STX     WDCSTATX
        LDX     WDCRDBUFX
        STAA    0,X
        INX
        STX     WDCRDBUFX
        DECB
        BNE     WDCSTATUSLP
        OKRTS
WDCSTATX        FDB     0
WDCRDBUFX       FDB     0
        PAGE
* PIA REGISTER DEFINITIONS
WDCIND  EQU     $FAA0   ;PIA A DATA REGISTER
WDCINC  EQU     $FAA1   ;PIA A CONTROL REGISTER
WDCOUTD EQU     $FAA2   ;PIA B DATA REGISTER
WDCOUTC EQU     $FAA3   ;PIA B CONTROL REGISTER
*
* PRA= INPUT DATA
* PRB= OUTPUT DATA
* CA1= *READY
* CA2= *STROBE
* CB1= *BUS.DIR
* CB2= *RESET
*
WDCRESET
        LDAA    #$FF
        STAA    WDCOUTD ;MAKE PORT B OUTPUT
        LDAA    #$36
        STAA    WDCOUTC ;PULL DOWN RESET LINE
        LDAA    #$2C
        STAA    WDCINC  ;CA1=NEGATIVE EDGE TRIGGERED,CA2=NEGATIVE PULSE,NO INTERRUPTS
        LDAA    WDCIND  ;CLEAR A FLAGS
        LDX     #5000
WDCRESETLP
        DEX
        BNE     WDCRESETLP      ;WAIT A BIT
        LDAA    #$3E
        STAA    WDCOUTC ;REMOVE RESET,CB1=POSITIVE EDGE TRIGGERED,NO INTERRUPTS
        LDX     #$FFFF
        DEX     WAIT    SOME MORE
        BNE     *-1
        OKRTS
        PAGE
; FEED THE WINCHESTER A COMMAND

WDCFORMSERVJ
        JMP     WDCFORMSERV     ; GO HANDLE "FORMAT" COMMAND

WDCREADSERVJ
        JMP     WDCREADSERV     ; GO DO READ SECTOR LOGIC

WDCSTARTIO      EQU     *       CONTROL TRANSFERS HERE TO START DISK I/O
WDCCMDFEED
        CLI     ; RE-ENABLE INTERRUPTS
        LDAB    WDCOUTD ;CLEAR LAST INTERRUPT
        LDX     WDCDCBPOINTER
        INC     DSKINFO:OPSCOUNT+2,X
        BNE     WDCCMDFEED0
        INC     DSKINFO:OPSCOUNT+1,X
        BNE     WDCCMDFEED0
        INC     DSKINFO:OPSCOUNT,X
WDCCMDFEED0
        JSR     WDCWAITAVAILABLE        ; WAIT FOR COMMAND AND DATA BUS AVAILABLE
        LDX     WDCDCBPOINTER
        LDAA    WDCREADWRITE,X  ; COMMAND TYPE
        JSR     WDCOUTDATA      ; OUTPUT COMMAND BYTE
        LDAA    WDCDRIVE,X      ; DRIVE SELECT
        JSR     WDCOUTDATA
        LDAA    WDCREADWRITE,X  ; CHECK IF FORMAT COMMAND
        CMPA    #WDCFORMAT
        BEQ     WDCFORMSERVJ    ; B/ ALL FORMAT PARAMETERS SENT!
WDCCMDFEED1
        LDX     DSKINFO:SECTORDB,X
        LDAA    RDSI:LSN+2,X    ; FEED LOW BYTE OF
        JSR     WDCOUTDATA      ; DISK ADDRESS OUT
        LDAA    RDSI:LSN+1,X    ; AND HIGH BYTE LOGICAL DISK ADDRESS
        JSR     WDCOUTDATA
        LDX     WDCDCBPOINTER
        LDAA    WDCREADWRITE,X
        CMPA    #WDCREADCMD
        BEQ     WDCREADSERVJ    ; GO DO READ TRANSFER AND CHECK
        PAGE
; WRITE TRANSFER SECTION

WDCWRITESERV
        ; WRITE A SECTOR TO 7710
        JSR     WDCSET4TRANS ; SET X = PAGE ADR
        LDAA    #$FF    ; SET UP 255 CYCLE COUNTER
WDCWRITEWAIT1ST
        ; WAIT FOR 1ST DATA REQUEST
        LDAB    WDCINC  ;READY?
        BMI     WDCWRITELOOP    B/ YES, GIVE THE 7710 ITS DATA
        INX     NO,     DELAY AWHILE (???? Us. MAX)
        DEX
        DECA    DOWN    COUNT FUSE
        BNE     WDCWRITEWAIT1ST B/ MORE TIME TO WAIT
        JMP     WDCQUIET1       FUSE EXPIRED, SO DO WE!

WDCWRITELOOP
        ; OUTPUT BYTES LOOP, OPTIMIZED FOR SPEED!
        LDX     WDCPOINTER      ; GET POINTER TO NEXT BLOCK OF 8 BYTES
        LDAA    0,X     ; FETCH BYTE TO FEED TO CONTROLLER
        LDAB    WDCINC  ;READY FOR NEXT BYTE?
        BMI     WDCWRITE0       B/ USUAL CASE, 7710 IS READY FOR ANOTHER
        JSR     WDCWRITEWAIT    SIGH... GO WAIT FOR 7710 TO BE READY
WDCWRITE0
        STAA    WDCOUTD ; OUTPUT DATA BYTE
        LDAB    WDCIND
        ;ISSUE STROBE
        LDAA    1,X     ; FETCH BYTE TO FEED TO CONTROLLER
        LDAB    WDCINC  ; IS 7710 READY FOR NEXT BYTE ?
        BMI     WDCWRITE1       B/ USUAL CASE, 7710 IS READY FOR ANOTHER
        BSR     WDCWRITEWAIT    SIGH... GO WAIT FOR 7710 TO BE READY
WDCWRITE1
        STAA    WDCOUTD ; OUTPUT DATA BYTE
        LDAB    WDCIND  ;ISSUE STROBE
        LDAA    2,X     ; FETCH BYTE TO FEED TO CONTROLLER
        LDAB    WDCINC  ; IS 7710 READY FOR NEXT BYTE ?
        BMI     WDCWRITE2       B/ USUAL CASE, 7710 IS READY FOR ANOTHER
        BSR     WDCWRITEWAIT    SIGH... GO WAIT FOR 7710 TO BE READY
WDCWRITE2
        ;STAA WDCOUTD ; OUTPUT DATA BYTE
        LDAB    WDCIND  ;ISSUE STROBE
        LDAA    3,X     ; FETCH BYTE TO FEED TO CONTROLLER
        LDAB    WDCINC  ; IS 7710 READY FOR NEXT BYTE ?
        BMI     WDCWRITE3       B/ USUAL CASE, 7710 IS READY FOR ANOTHER
        BSR     WDCWRITEWAIT    SIGH... GO WAIT FOR 7710 TO BE READY
WDCWRITE3
        STAA    WDCOUTD ; OUTPUT DATA BYTE
        LDAB    WDCIND  ;ISSUE STROBE
        LDAA    4,X     ; FETCH BYTE TO FEED TO CONTROLLER
        LDAB    WDCINC  ; IS 7710 READY FOR NEXT BYTE ?
        BMI     WDCWRITE4       B/ USUAL CASE, 7710 IS READY FOR ANOTHER
        BSR     WDCWRITEWAIT    SIGH... GO WAIT FOR 7710 TO BE READY
WDCWRITE4
        STAA    WDCOUTD ; OUTPUT DATA BYTE
        LDAB    WDCIND  ;ISSUE STROBE
        LDAA    5,X     ; FETCH BYTE TO FEED TO CONTROLLER
        LDAB    WDCINC  ; IS 7710 READY FOR NEXT BYTE ?
        BMI     WDCWRITE5       B/ USUAL CASE, 7710 IS READY FOR ANOTHER
        BSR     WDCWRITEWAIT    SIGH... GO WAIT FOR 7710 TO BE READY
WDCWRITE5
        STAA    WDCOUTD ; OUTPUT DATA BYTE
        LDAB    WDCIND  ;ISSUE STROBE
        LDAA    6,X     ; FETCH BYTE TO FEED TO CONTROLLER
        LDAB    WDCINC  ; IS 7710 READY FOR NEXT BYTE ?
        BMI     WDCWRITE6       B/ USUAL CASE, 7710 IS READY FOR ANOTHER
        BSR     WDCWRITEWAIT    SIGH... GO WAIT FOR 7710 TO BE READY
WDCWRITE6
        STAA    WDCOUTD ; OUTPUT DATA BYTE
        LDAB    WDCIND  ;ISSUE STROBE
        LDAA    7,X     ; FETCH BYTE TO FEED TO CONTROLLER
        LDAB    WDCINC  ; IS 7710 READY FOR NEXT BYTE ?
        BMI     WDCWRITE7       B/ USUAL CASE, 7710 IS READY FOR ANOTHER
        BSR     WDCWRITEWAIT    SIGH... GO WAIT FOR 7710 TO BE READY
WDCWRITE7
        STAA    WDCOUTD ; OUTPUT DATA BYTE
        LDAB    WDCIND  ;ISSUE STROBE
        LDAA    WDCPOINTER+1    ADVANCE POINTER BY 8 BYTES
        ADDA    #8
        STAA    WDCPOINTER+1
        BCC     WDCWRITED       B/ UPPER HALF DOES NOT NEED MODIFICATION
        INC     WDCPOINTER      PROPAGATE CARRY TO UPPER HALF
WDCWRITED
        DEC     WDCCOUNT        DOWN COUNT NUMBER OF 8 BYTE BLOCKS TO SEND
        BEQ     WDCFORMSERV     GO WAIT FOR 7710 TO FINISH OPERATION
        JMP     WDCWRITELOOP    B/ MORE 8 BYTE BLOCKS TO WRITE
        PAGE
WDCWRITEWAIT
        ; WAIT FOR 7710 TO BE READY FOR NEXT BYTE
        PSHA    ; SAVE THE DATA BYTE TO SEND
        CLRA    ; SET TIMEOUT LIMIT IN (A)
WDCWRITEWAITLOOP
        LDAB    WDCINC  ; LOOK AGAIN
        BMI     WDCWRITEWAITEXIT        ; B/ FINALLY, IS READY!
        DECA    DOWN    COUNT FUSE
        BNE     WDCWRITEWAITLOOP        B/ SOME FUSE STILL LEFT
        INS     BANG!   TIME'S UP...POP DATA BYTE TO BE SENT
WDCQUIETERR
        ; 7710 DID NOT RESPOND IN REASONABLE LENGTH OF TIME
        IF      2<0     ; POP RETURN ADDRESS
        RPT     -2
        DES
        ELSE
        RPT     2
        INS
        FIN
WDCQUIET1
        ; IMI DRIVE DID NOT RESPOND IN REASONABLE TIME
        JSR     WDCRESET        ; MAYBE HITTING BELOW THE BELT WILL RE-SYNCH
        LDAA    #%1001111       ; PICK UP VERY FUNNY ERROR STATUS
        JMP     WDCFATAL0       ; GO STORE ERROR AND RETRY

WDCWRITEWAITEXIT
        PULA    ; GET THE DATA BYTE BACK
        RTS

WDCFORMSERV     EQU     *
        JSR     WDCWAIT4INT     ; GO START INTERRUPT FOR COMMAND DONE
        JSR     WDCINDATA       ; CHECK DONE STATUS
        JSR     WDCPROCST       ; GO CHECK STATUS RETURN IF OK
WDCDONE EQU     *
        LDX     WDCDCBPOINTER
        INC     DCB:DONEFLAG,X  ; SET DONE
        INC     WDCINTERFACE    ; INTERFACE DONE
        JMP     SDOS+SDOS:RESCHEDULE
        PAGE
; READ TRANSFER SECTION

WDCREADSERV
        JSR     WDCWAIT4INT     ; WAIT FOR 7710 INTERRUPT ON READ COMPLETE
        JSR     WDCINDATA       ; GET STATUS ON BUS
        JSR     WDCPROCST       ; GO PROCESS STATUS RETRY IF NEEDED
        JSR     WDCSET4TRANS
WDCREADLOOP
        ; INPUT BYTES FOR SECTOR LOOP, OPTIMIZED FOR SPEED
        LDX     WDCPOINTER      ; GET POINTER TO NEXT BLOCK OF 8 BYTES
        LDAB    WDCINC  ; IS ANOTHER DATA BYTE READY ?
        BMI     WDCREAD0        B/ DATA IS READY
        BSR     WDCREADWAIT     ; GO WAIT FOR 7710 READY WITH ANOTHER BYTE
WDCREAD0
        LDAA    WDCIND  ; READ DATA AND ISSUE ACKNOWLEDGE PULSE
        STAA    0,X     ; SAVE DATA IN SECTOR BUFFER
        LDAB    WDCINC  ; IS ANOTHER DATA BYTE READY ?
        BMI     WDCREAD1        B/ DATA IS READY
        BSR     WDCREADWAIT     ; GO WAIT FOR 7710 READY WITH ANOTHER BYTE
WDCREAD1
        LDAA    WDCIND  ; READ DATA AND ISSUE ACKNOWLEDGE PULSE
        STAA    1,X     ; SAVE DATA IN SECTOR BUFFER
        LDAB    WDCINC  ; IS ANOTHER DATA BYTE READY ?
        BMI     WDCREAD2        B/ DATA IS READY
        BSR     WDCREADWAIT     ; GO WAIT FOR 7710 READY WITH ANOTHER BYTE
WDCREAD2
        LDAA    WDCIND  ; READ DATA AND ISSUE ACKNOWLEDGE PULSE
        STAA    2,X     ; SAVE DATA IN SECTOR BUFFER
        LDAB    WDCINC  ; IS ANOTHER DATA BYTE READY ?
        BMI     WDCREAD3        B/ DATA IS READY
        BSR     WDCREADWAIT     ; GO WAIT FOR 7710 READY WITH ANOTHER BYTE
WDCREAD3
        LDAA    WDCIND  ; READ DATA AND ISSUE ACKNOWLEDGE PULSE
        STAA    3,X     ; SAVE DATA IN SECTOR BUFFER
        LDAB    WDCINC  ; IS ANOTHER DATA BYTE READY ?
        BMI     WDCREAD4        B/ DATA IS READY
        BSR     WDCREADWAIT     ; GO WAIT FOR 7710 READY WITH ANOTHER BYTE
WDCREAD4
        LDAA    WDCIND  ; READ DATA AND ISSUE ACKNOWLEDGE PULSE
        STAA    4,X     ; SAVE DATA IN SECTOR BUFFER
        LDAB    WDCINC  ; IS ANOTHER DATA BYTE READY ?
        BMI     WDCREAD5        B/ DATA IS READY
        BSR     WDCREADWAIT     ; GO WAIT FOR 7710 READY WITH ANOTHER BYTE
WDCREAD5
        LDAA    WDCIND  ; READ DATA AND ISSUE ACKNOWLEDGE PULSE
        STAA    5,X     ; SAVE DATA IN SECTOR BUFFER
        LDAB    WDCINC  ; IS ANOTHER DATA BYTE READY ?
        BMI     WDCREAD6        B/ DATA IS READY
        BSR     WDCREADWAIT     ; GO WAIT FOR 7710 READY WITH ANOTHER BYTE
WDCREAD6
        LDAA    WDCIND  ; READ DATA AND ISSUE ACKNOWLEDGE PULSE
        STAA    6,X     ; SAVE DATA IN SECTOR BUFFER
        LDAB    WDCINC  ; IS ANOTHER DATA BYTE READY ?
        BMI     WDCREAD7        B/ DATA IS READY
        BSR     WDCREADWAIT     ; GO WAIT FOR 7710 READY WITH ANOTHER BYTE
WDCREAD7
        LDAA    WDCIND  ; READ DATA AND ISSUE ACKNOWLEDGE PULSE
        STAA    7,X     ; SAVE DATA IN SECTOR BUFFER
        LDAA    WDCPOINTER+1    ; ADVANCE BUFFER POINTER BY 8
        ADDA    #8
        STAA    WDCPOINTER+1
        BCC     WDCREADD        B/ DON'T HAVE TO BUMP UPPER HALF
        INC     WDCPOINTER
WDCREADD
        DEC     WDCCOUNT        DOWN COUNT # OF 8 BYTE BLOCKS TO SEND
        BNE     WDCREADLOOP
        JMP     WDCDONE ALL DONE READING SECTOR !

WDCREADWAIT
        ; WAIT FOR 7710 TO BE READY TO GIVE US NEXT BYTE
        CLRA
WDCREADWAITLOOP
        LDAB    WDCINC  ; WAIT FOR READY SIGNAL
        BMI     WDCREADWAITRTS  B/ 7710 IS NOW READY
        DECA    TIMED   OUT ?
        BNE     WDCREADWAITLOOP B/ NOT YET
        JMP     WDCQUIETERR     TIMED OUT, SOMETHING'S WRONG!

WDCREADWAITRTS
        RTS
        PAGE
* WDCOUTDATA --- SEND (A) TO 7710 WHEN 7710 READY
*  USED ONLY FOR PARAMETER BYTES
*
WDCOUTDATA      EQU     *
        STAA    WDCOUTD ; OUTPUT THE DATA, DON'T ISSUE PULSE (YET)
        CLRA    ; SET A LONG FUSE
WDCOUTDATAL
        LDAB    WDCINC  ; IS 7710 READY?
        BMI     WDCOUTDATA1     ; YES
        DECA    ; NO, DOWN COUNT FUSE
        BNE     WDCOUTDATAL
        JMP     WDCQUIETERR

WDCOUTDATA1     EQU     *
        LDAB    WDCIND  ; ISSUE STROBE PULSE TO 7710
        RTS
        PAGE
* WDCINDATA --- GET (A) FROM 7710 WHEN 7710 IS READY
* USED ONLY TO READ STATUS FROM 7710

WDCINDATA       EQU     *
        CLRA    ; SET LONG FUSE
WDCINDATA0
        LDAB    WDCINC  ; IS 7710 READY WITH DATA?
        BMI     WDCINDATA1
        DECA
        BNE     WDCINDATA0      ; B/ SOME MORE TIME LEFT
        JMP     WDCQUIETERR

WDCINDATA1      EQU     *       ; 7710 IS READY WITH DATA FOR US
        LDAA    WDCIND  ; GET STATUS, ACKNOWLEDGE 'READY' SIGNAL
WDCWAITRTS
        RTS
        PAGE
* WDCWAITAVAILABLE -- WAIT FOR 7710 READY
*
WDCWAITAVAILABLE        EQU     *
        IF      M6800
* ;LDX #(2*2500//256)*(1000//(6+4+2+4)) = 2.5 SECONDS AT 2MHZ
        LDX     #$2000  A LONG TIME
        ELSE    (M6809)
        LDX     #(2*2500//256)*(1000//(7+3+2+3)) = 2.5 SECONDS AT 2MHZ
        FIN
WDCWAITAVAILABLELOOP
        ; WAIT AT MOST 2.5 SECONDS FOR DRIVE TO BE READY
        LDAB    WDCINC
        BMI     WDCWAITRTS      ; B/ 7710 IS READY
        DECA    NO,     DOWN COUNT LOWER 8 BITS OF FUSE
        BNE     WDCWAITAVAILABLELOOP    B/ FUSE NOT BURNED UP
        DEX     DOWN    COUNT UPPER 16 BITS OF FUSE
        BNE     WDCWAITAVAILABLELOOP
        IF      2<0     THROW RETURN ADDRESS AWAY
        RPT     -2
        DES
        ELSE
        RPT     2
        INS
        FIN
        LDAB    #(ERR:DEVICENOTREADY)&$FF       DECLARE DEVICE NOT READY
        LDAA    #(ERR:DEVICENOTREADY)/256
        JMP     WDCQUITWITHERR  GO STORE ERROR CODE IN DCB
        PAGE
WDCWAIT4INT     EQU     *       WAIT FOR "DONE" INTERRUPT
        PULA
        PULB
        NOP     PREVENT WDC SELF INTERRUPT
        SEI
        STAB    WDCCONTINUEPC+1 ; SAVE WHERE TO GO ON CMD DONE INTERRUPT
        STAA    WDCCONTINUEPC
        LDX     WDCDCBPOINTER
        LDAA    WDCREADWRITE,X
        CMPA    #WDCFORMAT
        BNE     WDCWAIT4INT2    ; B/ STANDARD 3 SEC WAIT
        LDX     #0      ; FOREVER FOR FORMAT (TAKES 40 MINUTES ON 7710C)
        BRA     WDCWAIT4INT3

WDCWAIT4INT2    EQU     *
        LDX     #5*TICKSPERSECOND+NTIMEOUTBLOCKS
WDCWAIT4INT3
        STX     WDCTIMEOUTCOUNT
        LDAB    #$3F
        STAB    WDCOUTC ;ENABLE INTERRUPT
        LDAB    WDCOUTC ; IS DRIVE DONE WITH TRANSFER ?
        BMI     WDCINTERRUPT    B/ YES (THIS CODE HERE TO SIMPLIFY SINGLESTEPPING)
WDCINTUNEXPECTED
        JMP     SDOS+SDOS:RTI   ; EXIT INTERRUPT SERVICE

WDCINTERRUPT
        LDX     #0
        STX     WDCTIMEOUTCOUNT ; CLEAR TIME OUT
        LDAB    #$3E    ; KILL THE INTERRUPT ENABLE
        STAB    WDCOUTC
        LDAB    WDCOUTD ANSWER INT
        LDX     WDCCONTINUEPC
        LDAB    #(WDCINTUNEXPECTED)&$FF RESET WHERE TO GO IF INTERRUPT
        LDAA    #(WDCINTUNEXPECTED)/256
        STAB    WDCCONTINUEPC+1
        STAA    WDCCONTINUEPC
        CLI     ; RE ENABLE INTERRUPTS - SO FLOPPY AND RTC CAN WORK
        JMP     0,X     ; RETURN TO CALLER
        PAGE
WDCPROCST
        TSTA    PROCESS STATUS BITS
        BEQ     WDCPROCSTOKRTS  B/ NO TROUBLE AT ALL
        BSR     WDCSAVESTATUS   OOPS, HAD SOME KIND OF PROBLEM
        BITA    #WDCFATAL       WAS ERROR FATAL ?
        BNE     WDCFATALERR     B/ YES
WDCPROCSTOKRTS
        RTS     NON-FATAL       ERROR, CONTINUE

WDCFATAL0
        BSR     WDCSAVESTATUS
        BRA     WDCFATAL2

WDCFATALERR
        IF      2<0     ;POP RETURN OFF STACK
        RPT     -2
        DES
        ELSE
        RPT     2
        INS
        FIN
WDCFATAL2
        DEC     WDCRETRYCNT     ; ALL 9 LIVES USED UP ?
        BEQ     WDCQUIT ; B/ YES, WE'RE DEAD
        LDAA    WDCRETRYCNT     ON PENULTIMATE RETRY ?
        CMPA    #1
        BNE     JWDCCMDFEED     B/ NO, JUST SEND COMMANDS AGAIN
        JSR     WDCRESET        ; ON LAST TRY, HIT BELOW THE BELT
JWDCCMDFEED
        JMP     WDCCMDFEED

WDCSAVESTATUS
        LDX     WDCDCBPOINTER   ; SAVE ERROR STATUS
        LDX     DSKINFO:SECTORDB,X      SAVE RDSI:LSN AS DSKINFO:ERRLSN
        LDAB    RDSI:LSN,X
        PSHB    SAVE    ERROR STATUS BYTE, UPPER 8 BITS OF LSN
        PSHA
        LDAB    (RDSI:LSN+1)+1,X
        LDAA    RDSI:LSN+1,X
        LDX     WDCDCBPOINTER
        STAB    (DSKINFO:ERRLSN+1)+1,X
        STAA    DSKINFO:ERRLSN+1,X
        PULA    RESTORE ERROR STATUS BYTE, UPPER 8 BITS OF LSN
        PULB
        STAB    DSKINFO:ERRLSN,X
        LDAB    WDCREADWRITE,X
        CMPB    #WDCREADCMD     #WDCREADCMD IS THIS A READ OR A WRITE COMMAND ?
        BEQ     WDCSAVEREADSTATUS
        STAA    DSKINFO:WRITEERRSTS,X   ; LAST WRITE (OR FORMAT) ERROR STATUS
        INC     DSKINFO:WRITEERRCNT+1,X ; 2 BYTE ERROR COUNT
        BNE     *+4
        INC     DSKINFO:WRITEERRCNT,X
        RTS

WDCSAVEREADSTATUS
        STAA    DSKINFO:READERRSTS,X    ; LOG LAST READ ERROR
        INC     DSKINFO:READERRCNT+1,X
        BNE     *+4
        INC     DSKINFO:READERRCNT,X
        RTS
        PAGE
WDCQUIT
        CMPA    #%10011111      A TIMEOUT IN MIDDLE OF TRANSFER ?
        BEQ     WDCTIMEDOUT1    B/ YES, LET THE USER KNOW!
        CMPB    #WDCREADCMD
        BEQ     WDCQUITREAD
        LDAB    #(ERR:DISKWRITE)&$FF
        LDAA    #(ERR:DISKWRITE)/256
        BRA     WDCQUITWITHERR

WDCQUITREAD
        LDAB    #(ERR:DISKREAD)&$FF
        LDAA    #(ERR:DISKREAD)/256
WDCQUITWITHERR
        LDX     WDCDCBPOINTER   JUST TO BE SAFE...
        STAB    (DCB:LASTERROR)+1,X
        STAA    DCB:LASTERROR,X
        JMP     WDCDONE

WDCTIMEDOUT     EQU     *
WDCTIMEDOUT1
        LDX     #WDCINTUNEXPECTED       REMEMBER THAT WE DON'T EXPECT AN INTERRUPT!
        STX     WDCCONTINUEPC
        JSR     WDCRESET        ; HIT HIM SO MAYBE HE WILL WAKE UP
        LDAB    #(ERR:DEVICETIMEDOUT)&$FF
        LDAA    #(ERR:DEVICETIMEDOUT)/256
        BRA     WDCQUITWITHERR

WDCSET4TRANS
        LDAA    #WDCNBPS/8      ; SET NUMBER OF 8 BYTE BLOCKS TO TRANSFER
        STAA    WDCCOUNT
        LDX     WDCDCBPOINTER
        LDX     DSKINFO:SECTORDB,X
        LDX     RDSI:SECTORBASE,X
        STX     WDCPOINTER      ; SET UP POINTER TO 1ST BLOCK OF 8 TO MOVE
        RTS
        FIN     IODRIVERBODY
        IF      IODRIVERPOLL
        LDAB    WDCOUTC ;DISK INTERRUPTING?
        BPL     WDCPOLLNEXT     B/ NO
        JMP     WDCINTERRUPT    YES, GO SERVICE DISK INTERRUPT
WDCPOLLNEXT     EQU     *
        FIN     IODRIVERPOLL
        IF      IODRIVERINIT
WDCINIT
        LDX     #OKRTS  INITIALIZE 7710 INTELLIGENT CONTROLLER
        STX     WDCINIT SO WE DON'T DO THIS MORE THAN ONCE!
        JMP     WDCRESET        INITIALIZE 7710 INTELLIGENT CONTROLLER
        FIN     IODRIVERINIT
        IF      IODRIVERRAM
        PAGE    *** STORAGE DEMON WORKING RAM ***
WDCINTERFACE    FCB     1       ; WDC CONTROLLER IS AVAILABLE
WDCDCBPOINTER   FDB     0       ; CURRENT UNIT IN USE BY INTERRUPT ROUTINES
WDCCONTINUEPC   FDB     WDCINTUNEXPECTED        ; WHERE TO GO WHEN TRANSFER DONE INTERRUPT
WDCCOUNT        FCB     0       ; COUNTS # OF 8 BYTE BLOCKS TO XFER TO 7710
WDCPOINTER      FDB     0       ; POINTER TO NEXT BLOCK OF 8 BYTES TO XFER
WDCRETRYCNT     FCB     0       ; USED TO COUNT # OF READ/WRITE ATTEMPTS

WDC1DCB FCB     1       DCB:DONEFLAG
        FDB     0       DCB:LASTERROR
        FDB     WDC1STR
        FDB     NEXTDISKDCB     DCB:NEXT
        FDB     WDCDRIVER       DCB:DRIVER
        FDB     WDCNBPS
        FDB     WDCNSPT DSKINFO:NSPT
        FDB     WDCNTPC DSKINFO:NTPC
        FDB     WDCNCYL DSKINFO:NCYL
        RPT     WDC1DCB+DSKINFO:SIZE-*
        FCB     0
        ORG     WDC1DCB+DSKINFO:ERRLSN
        FCB     $FF,$FF,$FF     LAST SOFT ERROR
        FCB     0       WDCREADWRITE: 2 IS READ 3 IS WRITE ETC.
        FCB     1       DRIVE SELECT 1
WDC1STR FCC     'WD1:'
        FCB     0
NEXTDISKDCB     SET     WDC1DCB
NDISKDCBS       SET     NDISKDCBS+1
WDC0DCB FCB     1       DCB:DONEFLAG
        FDB     0       DCB:LASTERROR
        FDB     WDC0STR
        FDB     NEXTDISKDCB     DCB:NEXT
        FDB     WDCDRIVER       DCB:DRIVER
        FDB     WDCNBPS
        FDB     WDCNSPT DSKINFO:NSPT
        FDB     WDCNTPC DSKINFO:NTPC
        FDB     WDCNCYL DSKINFO:NCYL
        RPT     WDC0DCB+DSKINFO:SIZE-*
        FCB     0
        ORG     WDC0DCB+DSKINFO:ERRLSN
        FCB     $FF,$FF,$FF     LAST SOFT ERROR
        FCB     0       WDCREADWRITE: CONTAINS DESIRED DISK OPCODE
        FCB     0       DRIVE 0
WDC0STR FCC     'WD0:'
        FCB     0
NEXTDISKDCB     SET     WDC0DCB
NDISKDCBS       SET     NDISKDCBS+1

WDCTIMEOUTBLOCK FDB     NEXTTIMEOUT
WDCTIMEOUTCOUNT FDB     0
        FDB     WDCTIMEDOUT

*
NEXTTIMEOUT     SET     WDCTIMEOUTBLOCK
NTIMEOUTS       SET     NTIMEOUTS+1
        FIN     IODRIVERRAM
        END

