 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
        LDX     #WDCINTERFACE
        LDAA    0,X
 BNE WDCSETUP
        JSR     SDOS+SDOS:WAITEVENT
WDCSETUP ;CLR WDCINTERFACE ; SET INTERFACE BUSY
        CLR     WDCINTERFACE
        LDX     DCBPOINTER
 STX WDCDCBPOINTER ; INTERRUPTS SERVICE DCB ADDRESS
 ;CLR DCB:DONEFLAG,X ; CLEAR DONE
        CLR     DCB:DONEFLAG,X
        LDX     #0
 STX WDCCONTINUEPC ; SET INTERRUPTS NO GOOD
        LDX     #WDCSTARTIO
 ;JSR SDOS+SDOS:STARTIO ; ENTER INTERRUPTS SERVICE CODE
        JSR     SDOS+SDOS:STARTIO
 ;LDX DCBPOINTER ; IF FORMAT CONTROL CALL OPERATION
        LDX     DCBPOINTER
        LDAA    WDCREADWRITE,X
        CMPA    #WDCFORMAT
 BEQ WDCWAITDONE B/ GO WAIT FOR FORMAT OPERATION COMPLETE
WDCOKRTS OKRTS

WDCWAITDONE ;LDX DCBPOINTER ; WAIT FOR TRANSFER DONE
        LDX     DCBPOINTER
        LDAA    DCB:DONEFLAG,X
 BNE WDCWAIT1
        JSR     SDOS+SDOS:WAITEVENT
WDCWAIT1 ;LDX DCBPOINTER
        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
        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 ;LDA #$FF
        LDAA    #$FF
 ;STA WDCOUTD ;MAKE PORT B OUTPUT
        STAA    WDCOUTD
        LDAA    #$36
 ;STA WDCOUTC ;PULL DOWN RESET LINE
        STAA    WDCOUTC
        LDAA    #$2C
 ;STA WDCINC ;CA1=NEGATIVE EDGE TRIGGERED,CA2=NEGATIVE PULSE,NO INTERRUPTS
        STAA    WDCINC
 ;LDA WDCIND ;CLEAR A FLAGS
        LDAA    WDCIND
        LDX     #5000
WDCRESETLP DEX
 BNE WDCRESETLP ;WAIT A BIT
 ;LDA #$3E
        LDAA    #$3E
 ;STA WDCOUTC ;REMOVE RESET,CB1=POSITIVE EDGE TRIGGERED,NO INTERRUPTS
        STAA    WDCOUTC
        LDX     #$FFFF
        DEX             WAIT SOME MORE
        BNE     *-1
 OKRTS
 PAGE
; FEED THE WINCHESTER A COMMAND

WDCFORMSERVJ ;JMP WDCFORMSERV ; GO HANDLE "FORMAT" COMMAND
        JMP     WDCFORMSERV

WDCREADSERVJ ;JMP WDCREADSERV ; GO DO READ SECTOR LOGIC
        JMP     WDCREADSERV

WDCSTARTIO EQU * CONTROL TRANSFERS HERE TO START DISK I/O
WDCCMDFEED CLI  ; RE-ENABLE INTERRUPTS
 ;LDB WDCOUTD ;CLEAR LAST INTERRUPT
        LDAB    WDCOUTD
        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
        JSR     WDCWAITAVAILABLE
        LDX     WDCDCBPOINTER
 ;LDA WDCREADWRITE,X ; COMMAND TYPE
        LDAA    WDCREADWRITE,X
 ;JSR WDCOUTDATA ; OUTPUT COMMAND BYTE
        JSR     WDCOUTDATA
 ;LDA WDCDRIVE,X ; DRIVE SELECT
        LDAA    WDCDRIVE,X
        JSR     WDCOUTDATA
 ;LDA WDCREADWRITE,X ; CHECK IF FORMAT COMMAND
        LDAA    WDCREADWRITE,X
        CMPA    #WDCFORMAT
 BEQ WDCFORMSERVJ ; B/ ALL FORMAT PARAMETERS SENT!
WDCCMDFEED1 ;LDX DSKINFO:SECTORDB,X
        LDX     DSKINFO:SECTORDB,X
 ;LDA RDSI:LSN+2,X ; FEED LOW BYTE OF
        LDAA    RDSI:LSN+2,X
 ;JSR WDCOUTDATA ; DISK ADDRESS OUT
        JSR     WDCOUTDATA
 ;LDA RDSI:LSN+1,X ; AND HIGH BYTE LOGICAL DISK ADDRESS
        LDAA    RDSI:LSN+1,X
        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
        JSR     WDCSET4TRANS
 ;LDA #$FF ; SET UP 255 CYCLE COUNTER
        LDAA    #$FF
WDCWRITEWAIT1ST ; WAIT FOR 1ST DATA REQUEST
 ;LDB WDCINC ;READY?
        LDAB    WDCINC
 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!
        JMP     WDCQUIET1

WDCWRITELOOP ; OUTPUT BYTES LOOP, OPTIMIZED FOR SPEED!
 ;LDX WDCPOINTER ; GET POINTER TO NEXT BLOCK OF 8 BYTES
        LDX     WDCPOINTER
 ;LDA ,X ; FETCH BYTE TO FEED TO CONTROLLER
        LDAA    0,X
 ;LDB WDCINC ;READY FOR NEXT BYTE?
        LDAB    WDCINC
 BMI WDCWRITE0 B/ USUAL CASE, 7710 IS READY FOR ANOTHER
 ;JSR WDCWRITEWAIT SIGH... GO WAIT FOR 7710 TO BE READY
        JSR     WDCWRITEWAIT
WDCWRITE0 ;STA WDCOUTD ; OUTPUT DATA BYTE
        STAA    WDCOUTD
 ;LDB WDCIND ;ISSUE STROBE
        LDAB    WDCIND
 ;LDA 1,X ; FETCH BYTE TO FEED TO CONTROLLER
        LDAA    1,X
 ;LDB WDCINC ; IS 7710 READY FOR NEXT BYTE ?
        LDAB    WDCINC
 BMI WDCWRITE1 B/ USUAL CASE, 7710 IS READY FOR ANOTHER
 BSR WDCWRITEWAIT SIGH... GO WAIT FOR 7710 TO BE READY
WDCWRITE1 ;STA WDCOUTD ; OUTPUT DATA BYTE
        STAA    WDCOUTD
 ;LDB WDCIND ;ISSUE STROBE
        LDAB    WDCIND
 ;LDA 2,X ; FETCH BYTE TO FEED TO CONTROLLER
        LDAA    2,X
 ;LDB WDCINC ; IS 7710 READY FOR NEXT BYTE ?
        LDAB    WDCINC
 BMI WDCWRITE2 B/ USUAL CASE, 7710 IS READY FOR ANOTHER
 BSR WDCWRITEWAIT SIGH... GO WAIT FOR 7710 TO BE READY
WDCWRITE2 ;STA WDCOUTD ; OUTPUT DATA BYTE
        STAA    WDCOUTD
 ;LDB WDCIND ;ISSUE STROBE
        LDAB    WDCIND
 ;LDA 3,X ; FETCH BYTE TO FEED TO CONTROLLER
        LDAA    3,X
 ;LDB WDCINC ; IS 7710 READY FOR NEXT BYTE ?
        LDAB    WDCINC
 BMI WDCWRITE3 B/ USUAL CASE, 7710 IS READY FOR ANOTHER
 BSR WDCWRITEWAIT SIGH... GO WAIT FOR 7710 TO BE READY
WDCWRITE3 ;STA WDCOUTD ; OUTPUT DATA BYTE
        STAA    WDCOUTD
 ;LDB WDCIND ;ISSUE STROBE
        LDAB    WDCIND
 ;LDA 4,X ; FETCH BYTE TO FEED TO CONTROLLER
        LDAA    4,X
 ;LDB WDCINC ; IS 7710 READY FOR NEXT BYTE ?
        LDAB    WDCINC
 BMI WDCWRITE4 B/ USUAL CASE, 7710 IS READY FOR ANOTHER
 BSR WDCWRITEWAIT SIGH... GO WAIT FOR 7710 TO BE READY
WDCWRITE4 ;STA WDCOUTD ; OUTPUT DATA BYTE
        STAA    WDCOUTD
 ;LDB WDCIND ;ISSUE STROBE
        LDAB    WDCIND
 ;LDA 5,X ; FETCH BYTE TO FEED TO CONTROLLER
        LDAA    5,X
 ;LDB WDCINC ; IS 7710 READY FOR NEXT BYTE ?
        LDAB    WDCINC
 BMI WDCWRITE5 B/ USUAL CASE, 7710 IS READY FOR ANOTHER
 BSR WDCWRITEWAIT SIGH... GO WAIT FOR 7710 TO BE READY
WDCWRITE5 ;STA WDCOUTD ; OUTPUT DATA BYTE
        STAA    WDCOUTD
 ;LDB WDCIND ;ISSUE STROBE
        LDAB    WDCIND
 ;LDA 6,X ; FETCH BYTE TO FEED TO CONTROLLER
        LDAA    6,X
 ;LDB WDCINC ; IS 7710 READY FOR NEXT BYTE ?
        LDAB    WDCINC
 BMI WDCWRITE6 B/ USUAL CASE, 7710 IS READY FOR ANOTHER
 BSR WDCWRITEWAIT SIGH... GO WAIT FOR 7710 TO BE READY
WDCWRITE6 ;STA WDCOUTD ; OUTPUT DATA BYTE
        STAA    WDCOUTD
 ;LDB WDCIND ;ISSUE STROBE
        LDAB    WDCIND
 ;LDA 7,X ; FETCH BYTE TO FEED TO CONTROLLER
        LDAA    7,X
 ;LDB WDCINC ; IS 7710 READY FOR NEXT BYTE ?
        LDAB    WDCINC
 BMI WDCWRITE7 B/ USUAL CASE, 7710 IS READY FOR ANOTHER
 BSR WDCWRITEWAIT SIGH... GO WAIT FOR 7710 TO BE READY
WDCWRITE7 ;STA WDCOUTD ; OUTPUT DATA BYTE
        STAA    WDCOUTD
 ;LDB WDCIND ;ISSUE STROBE
        LDAB    WDCIND
 ;LDA WDCPOINTER+1 ADVANCE POINTER BY 8 BYTES
        LDAA    WDCPOINTER+1
 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
        JMP     WDCWRITELOOP
  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 ;LDB WDCINC ; LOOK AGAIN
        LDAB    WDCINC
 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
 ;LEAS 2,S POP RETURN ADDRESS
        IF      2<0
        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
        JSR     WDCRESET
 ;LDA #%1001111 ; PICK UP VERY FUNNY ERROR STATUS
        LDAA    #%1001111
 ;JMP WDCFATAL0 ; GO STORE ERROR AND RETRY
        JMP     WDCFATAL0

WDCWRITEWAITEXIT PULA  ; GET THE DATA BYTE BACK
 RTS

WDCFORMSERV EQU *
 ;JSR WDCWAIT4INT ; GO START INTERRUPT FOR COMMAND DONE
        JSR     WDCWAIT4INT
 ;JSR WDCINDATA ; CHECK DONE STATUS
        JSR     WDCINDATA
 ;JSR WDCPROCST ; GO CHECK STATUS RETURN IF OK
        JSR     WDCPROCST
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     WDCWAIT4INT
 ;JSR WDCINDATA ; GET STATUS ON BUS
        JSR     WDCINDATA
 ;JSR WDCPROCST ; GO PROCESS STATUS RETRY IF NEEDED
        JSR     WDCPROCST
        JSR     WDCSET4TRANS
WDCREADLOOP ; INPUT BYTES FOR SECTOR LOOP, OPTIMIZED FOR SPEED
 ;LDX WDCPOINTER ; GET POINTER TO NEXT BLOCK OF 8 BYTES
        LDX     WDCPOINTER
 ;LDB WDCINC ; IS ANOTHER DATA BYTE READY ?
        LDAB    WDCINC
 BMI WDCREAD0 B/ DATA IS READY
 BSR WDCREADWAIT ; GO WAIT FOR 7710 READY WITH ANOTHER BYTE
WDCREAD0 ;LDA WDCIND ; READ DATA AND ISSUE ACKNOWLEDGE PULSE
        LDAA    WDCIND
 ;STA ,X ; SAVE DATA IN SECTOR BUFFER
        STAA    0,X
 ;LDB WDCINC ; IS ANOTHER DATA BYTE READY ?
        LDAB    WDCINC
 BMI WDCREAD1 B/ DATA IS READY
 BSR WDCREADWAIT ; GO WAIT FOR 7710 READY WITH ANOTHER BYTE
WDCREAD1 ;LDA WDCIND ; READ DATA AND ISSUE ACKNOWLEDGE PULSE
        LDAA    WDCIND
 ;STA 1,X ; SAVE DATA IN SECTOR BUFFER
        STAA    1,X
 ;LDB WDCINC ; IS ANOTHER DATA BYTE READY ?
        LDAB    WDCINC
 BMI WDCREAD2 B/ DATA IS READY
 BSR WDCREADWAIT ; GO WAIT FOR 7710 READY WITH ANOTHER BYTE
WDCREAD2 ;LDA WDCIND ; READ DATA AND ISSUE ACKNOWLEDGE PULSE
        LDAA    WDCIND
 ;STA 2,X ; SAVE DATA IN SECTOR BUFFER
        STAA    2,X
 ;LDB WDCINC ; IS ANOTHER DATA BYTE READY ?
        LDAB    WDCINC
 BMI WDCREAD3 B/ DATA IS READY
 BSR WDCREADWAIT ; GO WAIT FOR 7710 READY WITH ANOTHER BYTE
WDCREAD3 ;LDA WDCIND ; READ DATA AND ISSUE ACKNOWLEDGE PULSE
        LDAA    WDCIND
 ;STA 3,X ; SAVE DATA IN SECTOR BUFFER
        STAA    3,X
 ;LDB WDCINC ; IS ANOTHER DATA BYTE READY ?
        LDAB    WDCINC
 BMI WDCREAD4 B/ DATA IS READY
 BSR WDCREADWAIT ; GO WAIT FOR 7710 READY WITH ANOTHER BYTE
WDCREAD4 ;LDA WDCIND ; READ DATA AND ISSUE ACKNOWLEDGE PULSE
        LDAA    WDCIND
 ;STA 4,X ; SAVE DATA IN SECTOR BUFFER
        STAA    4,X
 ;LDB WDCINC ; IS ANOTHER DATA BYTE READY ?
        LDAB    WDCINC
 BMI WDCREAD5 B/ DATA IS READY
 BSR WDCREADWAIT ; GO WAIT FOR 7710 READY WITH ANOTHER BYTE
WDCREAD5 ;LDA WDCIND ; READ DATA AND ISSUE ACKNOWLEDGE PULSE
        LDAA    WDCIND
 ;STA 5,X ; SAVE DATA IN SECTOR BUFFER
        STAA    5,X
 ;LDB WDCINC ; IS ANOTHER DATA BYTE READY ?
        LDAB    WDCINC
 BMI WDCREAD6 B/ DATA IS READY
 BSR WDCREADWAIT ; GO WAIT FOR 7710 READY WITH ANOTHER BYTE
WDCREAD6 ;LDA WDCIND ; READ DATA AND ISSUE ACKNOWLEDGE PULSE
        LDAA    WDCIND
 ;STA 6,X ; SAVE DATA IN SECTOR BUFFER
        STAA    6,X
 ;LDB WDCINC ; IS ANOTHER DATA BYTE READY ?
        LDAB    WDCINC
 BMI WDCREAD7 B/ DATA IS READY
 BSR WDCREADWAIT ; GO WAIT FOR 7710 READY WITH ANOTHER BYTE
WDCREAD7 ;LDA WDCIND ; READ DATA AND ISSUE ACKNOWLEDGE PULSE
        LDAA    WDCIND
 ;STA 7,X ; SAVE DATA IN SECTOR BUFFER
        STAA    7,X
 ;LDA WDCPOINTER+1 ; ADVANCE BUFFER POINTER BY 8
        LDAA    WDCPOINTER+1
 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 !
        JMP     WDCDONE

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

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

WDCOUTDATA1 EQU *
 ;LDB WDCIND ; ISSUE STROBE PULSE TO 7710
        LDAB    WDCIND
 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 ;LDB WDCINC ; IS 7710 READY WITH DATA?
        LDAB    WDCINC
 BMI WDCINDATA1
 DECA
 BNE WDCINDATA0 ; B/ SOME MORE TIME LEFT
        JMP     WDCQUIETERR

WDCINDATA1 EQU * ; 7710 IS READY WITH DATA FOR US
 ;LDA WDCIND ; GET STATUS, ACKNOWLEDGE 'READY' SIGNAL
        LDAA    WDCIND
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
        LDX     #(2*2500//256)*1000//(7+3+2+3))
 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
 ;LEAS 2,S THROW RETURN ADDRESS AWAY
        IF      2<0
        RPT     -2
        DES
        ELSE
        RPT     2
        INS
        FIN
 ;LDD #ERR:DEVICENOTREADY DECLARE DEVICE NOT READY
        LDAB    #(ERR:DEVICENOTREADY)&$FF
        LDAA    #(ERR:DEVICENOTREADY)/256
 ;JMP WDCQUITWITHERR GO STORE ERROR CODE IN DCB
        JMP     WDCQUITWITHERR
 PAGE
WDCWAIT4INT EQU * WAIT FOR "DONE" INTERRUPT
        PULA
        PULB
 NOP  PREVENT WDC SELF INTERRUPT
 SEI
 ;STD WDCCONTINUEPC ; SAVE WHERE TO GO ON CMD DONE INTERRUPT
        STAB    WDCCONTINUEPC+1
        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)
        LDX     #0
 BRA WDCWAIT4INT3

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

WDCINTERRUPT ;LDX #0
        LDX     #0
 STX WDCTIMEOUTCOUNT ; CLEAR TIME OUT
 ;LDB #$3E ; KILL THE INTERRUPT ENABLE
        LDAB    #$3E
        STAB    WDCOUTC
        LDAB    WDCOUTD ANSWER INT
        LDX     WDCCONTINUEPC
 ;LDD #WDCINTUNEXPECTED RESET WHERE TO GO IF INTERRUPT
        LDAB    #(WDCINTUNEXPECTED)&$FF
        LDAA    #(WDCINTUNEXPECTED)/256
        STAB    WDCCONTINUEPC+1
        STAA    WDCCONTINUEPC
 CLI  ; RE ENABLE INTERRUPTS - SO FLOPPY AND RTC CAN WORK
 ;JMP 0,X ; RETURN TO CALLER
        JMP     0,X
 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 ;LEAS 2,S ;POP RETURN OFF STACK
        IF      2<0
        RPT     -2
        DES
        ELSE
        RPT     2
        INS
        FIN
WDCFATAL2 DEC WDCRETRYCNT ; ALL 9 LIVES USED UP ?
 BEQ WDCQUIT ; B/ YES, WE'RE DEAD
 ;LDA WDCRETRYCNT ON PENULTIMATE RETRY ?
        LDAA    WDCRETRYCNT
        CMPA    #1
 BNE JWDCCMDFEED B/ NO, JUST SEND COMMANDS AGAIN
 ;JSR WDCRESET ; ON LAST TRY, HIT BELOW THE BELT
        JSR     WDCRESET
JWDCCMDFEED         JMP     WDCCMDFEED

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

WDCSAVEREADSTATUS ;STA DSKINFO:READERRSTS,X ; LOG LAST READ ERROR
        STAA    DSKINFO:READERRSTS,X
 INC DSKINFO:READERRCNT+1,X
 BNE *+4
 INC DSKINFO:READERRCNT,X
 RTS
 PAGE
WDCQUIT ;CMPA #%10011111 A TIMEOUT IN MIDDLE OF TRANSFER ?
        CMPA    #%10011111
 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...
        LDX     WDCDCBPOINTER
        STAB    (DCB:LASTERROR)+1,X
        STAA    DCB:LASTERROR,X
        JMP     WDCDONE

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

WDCSET4TRANS ;LDA #WDCNBPS/8 ; SET NUMBER OF 8 BYTE BLOCKS TO TRANSFER
        LDAA    #WDCNBPS/8
        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
 ;LDB WDCOUTC ;DISK INTERRUPTING?
        LDAB    WDCOUTC
 BPL WDCPOLLNEXT B/ NO
 ;JMP WDCINTERRUPT YES, GO SERVICE DISK INTERRUPT
        JMP     WDCINTERRUPT
WDCPOLLNEXT EQU *
 FIN IODRIVERPOLL
 IF IODRIVERINIT
WDCINIT ;LDX #OKRTS INITIALIZE 7710 INTELLIGENT CONTROLLER
        LDX     #OKRTS
 STX WDCINIT SO WE DON'T DO THIS MORE THAN ONCE!
 ;JMP WDCRESET INITIALIZE 7710 INTELLIGENT CONTROLLER
        JMP     WDCRESET
 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

