forked from MirrorRepos/RomWBW
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
509 lines
9.9 KiB
509 lines
9.9 KiB
;
|
|
;==================================================================================================
|
|
; IDE DISK DRIVER
|
|
;==================================================================================================
|
|
;
|
|
; IO PORT ADDRESSES
|
|
;
|
|
#IF (IDEMODE == IDEMODE_DIO)
|
|
#IF (IDE8BIT)
|
|
IDEDATA: .EQU 20H ; DATA PORT (8 BIT)
|
|
#ELSE
|
|
IDEDATALO: .EQU 20H ; DATA PORT (16 BIT LO BYTE)
|
|
IDEDATAHI: .EQU 28H ; DATA PORT (16 BIT HI BYTE)
|
|
#ENDIF
|
|
#ENDIF
|
|
;
|
|
#IF (IDEMODE == IDEMODE_DIDE)
|
|
#IF (IDE8BIT)
|
|
IDEDATA: .EQU 20H ; DATA PORT (8 BIT OR 16 BIT PIO LO/HI BYTES)
|
|
#ELSE
|
|
IDEDATA: .EQU 28H ; DATA PORT (16 BIT PIO LO/HI BYTES)
|
|
IDEDMA: .EQU 29H ; DATA PORT (16 BIT DMA LO/HI BYTES)
|
|
#ENDIF
|
|
#ENDIF
|
|
;
|
|
IDEERR: .EQU 21H ; READ: ERROR REGISTER; WRITE: PRECOMP
|
|
IDESECTC: .EQU 22H ; SECTOR COUNT
|
|
IDESECTN: .EQU 23H ; SECTOR NUMBER
|
|
IDECYLLO: .EQU 24H ; CYLINDER LOW
|
|
IDECYLHI: .EQU 25H ; CYLINDER HIGH
|
|
IDEDEVICE: .EQU 26H ; DRIVE/HEAD
|
|
IDESTTS: .EQU 27H ; READ: STATUS; WRITE: COMMAND
|
|
IDECTRL: .EQU 2EH ; READ: ALTERNATIVE STATUS; WRITE; DEVICE CONTROL
|
|
IDEADDR: .EQU 2FH ; DRIVE ADDRESS (READ ONLY)
|
|
;
|
|
;
|
|
;
|
|
IDECMD_READ .EQU 020H
|
|
IDECMD_WRITE .EQU 030H
|
|
IDECMD_SETFEAT .EQU 0EFH
|
|
;
|
|
IDERC_OK .EQU 0
|
|
IDERC_CMDERR .EQU 1
|
|
IDERC_RDYTO .EQU 2
|
|
IDERC_BUFTO .EQU 3
|
|
;
|
|
; UNIT CONFIGURATION
|
|
;
|
|
IDE0_DEVICE .DB 11100000B ; LBA, MASTER DEVICE
|
|
IDE1_DEVICE .DB 11110000B ; LBA, SLAVE DEVICE
|
|
;
|
|
;
|
|
;
|
|
IDE_DISPATCH:
|
|
LD A,B ; GET REQUESTED FUNCTION
|
|
AND $0F
|
|
JR Z,IDE_RD
|
|
DEC A
|
|
JR Z,IDE_WR
|
|
DEC A
|
|
JR Z,IDE_ST
|
|
DEC A
|
|
JR Z,IDE_MED
|
|
CALL PANIC
|
|
;
|
|
IDE_RD:
|
|
JP IDE_READ
|
|
IDE_WR:
|
|
JP IDE_WRITE
|
|
IDE_ST:
|
|
JP IDE_STATUS
|
|
IDE_MED:
|
|
JP IDE_MEDIA
|
|
;
|
|
; IDE_MEDIA
|
|
;
|
|
IDE_MEDIA:
|
|
LD A,MID_HD
|
|
RET
|
|
;
|
|
;
|
|
;
|
|
IDE_INIT:
|
|
CALL IDE_RESET
|
|
XOR A
|
|
DEC A ; INITIAL STATUS IS NOT READY $FF
|
|
LD (IDE_STAT),A ; SAVE IT
|
|
RET
|
|
;
|
|
;
|
|
;
|
|
IDE_STATUS:
|
|
LD A,(IDE_STAT) ; LOAD STATUS
|
|
OR A ; SET FLAGS
|
|
RET
|
|
;
|
|
;
|
|
;
|
|
IDE_READ:
|
|
LD A,IDECMD_READ
|
|
LD (IDE_CMD),A
|
|
JP IDE_RW
|
|
;
|
|
;
|
|
;
|
|
IDE_WRITE:
|
|
LD A,IDECMD_WRITE
|
|
LD (IDE_CMD),A
|
|
JP IDE_RW
|
|
;
|
|
;
|
|
;
|
|
IDE_RW:
|
|
; CLEAR RESULTS
|
|
XOR A ; A = 0
|
|
LD (IDE_RC),A ; CLEAR RETURN CODE
|
|
LD (IDE_STTS),A ; CLEAR SAVED STTS
|
|
LD (IDE_ERRS),A ; CLEAR SAVED ERR
|
|
|
|
; INIT REQUIRED?
|
|
LD A,(IDE_STAT) ; GET CURRENT STATUS
|
|
OR A ; SET FLAGS
|
|
JR Z,IDE_RW0 ; IF STATUS OK, BYPASS RESET
|
|
|
|
CALL IDE_RESET ; DO THE RESET
|
|
|
|
#IF (IDE8BIT)
|
|
CALL IDE_WAITRDY
|
|
|
|
LD A,01H
|
|
OUT (IDEERR),A
|
|
LD A,IDECMD_SETFEAT
|
|
OUT (IDESTTS),A
|
|
CALL IDE_WAITRDY
|
|
JP NC,IDE_ERR
|
|
CALL IDE_CHKERR ; CHECK FOR ERRORS
|
|
JP NC,IDE_ERR
|
|
#IF (IDETRACE >= 2)
|
|
CALL IDE_PRT
|
|
#ENDIF
|
|
#ENDIF
|
|
|
|
IDE_RW0:
|
|
CALL IDE_WAITRDY ; WAIT FOR DRIVE READY
|
|
JP NC,IDE_ERR
|
|
CALL IDE_SETUP ; SETUP CYL, TRK, HEAD
|
|
LD A,(IDE_CMD)
|
|
OUT (IDESTTS),A
|
|
CALL IDE_WAITRDY ; WAIT FOR DRIVE READY
|
|
JP NC,IDE_ERR
|
|
CALL IDE_CHKERR ; CHECK FOR ERRORS
|
|
JP NC,IDE_ERR
|
|
CALL IDE_WAITBUF ; WAIT FOR BUFFER READY
|
|
JP NC,IDE_ERR
|
|
|
|
LD A,(IDE_CMD) ; DISPATCH TO READ OR WRITE SPECIFIC LOGIC
|
|
CP IDECMD_WRITE
|
|
JP Z,IDE_RW1
|
|
|
|
CALL IDE_BUFRD ; READ BUFFER
|
|
CALL IDE_WAITRDY ; WAIT FOR DRIVE READY
|
|
JP NC,IDE_ERR
|
|
CALL IDE_CHKERR ; CHECK FOR ERRORS
|
|
JP NC,IDE_ERR
|
|
JP IDE_OK
|
|
|
|
IDE_RW1:
|
|
CALL IDE_BUFWR ; WRITE BUFFER
|
|
CALL IDE_WAITRDY ; WAIT FOR DRIVE READY
|
|
JP NC,IDE_ERR
|
|
CALL IDE_CHKERR ; CHECK FOR ERRORS
|
|
JP NC,IDE_ERR
|
|
JP IDE_OK
|
|
|
|
IDE_ERR:
|
|
XOR A
|
|
DEC A ; A = $FF TO SIGNAL ERROR
|
|
LD (IDE_STAT),A ; SAVE IT
|
|
#IF (IDETRACE >= 1)
|
|
PUSH AF
|
|
CALL IDE_PRT
|
|
POP AF
|
|
#ENDIF
|
|
RET
|
|
|
|
IDE_OK:
|
|
#IF (IDETRACE >= 2)
|
|
CALL IDE_PRT
|
|
#ENDIF
|
|
XOR A
|
|
RET
|
|
;
|
|
;
|
|
;
|
|
IDE_RESET:
|
|
LD A,000001110B ; NO INTERRUPTS, ASSERT RESET BOTH DRIVES
|
|
OUT (IDECTRL),A
|
|
LD DE,8 ; DELAY ABOUT 200ms
|
|
CALL VDELAY
|
|
LD A,000001010B ; NO INTERRUPTS, DEASSERT RESET
|
|
OUT (IDECTRL),A
|
|
XOR A
|
|
LD (IDE_STAT),A ; STATUS OK
|
|
RET ; SAVE IT
|
|
;
|
|
;
|
|
;
|
|
IDE_WAITRDY:
|
|
LD DE,0 ; TIMEOUT IS 250us * 65536 = 15 SECONDS
|
|
IDE_WBSY:
|
|
PUSH DE
|
|
LD DE,10 ; INNER LOOP DELAY IS 250us (25us * 10)
|
|
CALL VDELAY
|
|
POP DE
|
|
DEC DE
|
|
LD A,D
|
|
OR E
|
|
JP Z,IDE_TO
|
|
IN A,(IDESTTS) ; READ STATUS
|
|
LD (IDE_STTS),A ; SAVE IT
|
|
AND 011000000b ; ISOLATE BUSY AND RDY BITS
|
|
XOR 001000000b ; WE WANT BUSY(7) TO BE 0 AND RDY(6) TO BE 1
|
|
JP NZ,IDE_WBSY
|
|
SCF ; CARRY 1 = OK
|
|
RET
|
|
IDE_TO:
|
|
LD A,IDERC_RDYTO
|
|
LD (IDE_RC),A
|
|
XOR A ; CARRY 0 = TIMEOUT
|
|
RET
|
|
;
|
|
;
|
|
;
|
|
IDE_CHKERR:
|
|
IN A,(IDESTTS) ; GET STATUS
|
|
LD (IDE_STTS),A ; SAVE IT
|
|
AND 000000001B ; ERROR BIT SET?
|
|
SCF ; ASSUME NO ERR
|
|
RET Z ; NO ERR, RETURN WITH CF SET
|
|
|
|
IN A,(IDEERR) ; READ ERROR FLAGS
|
|
LD (IDE_ERRS),A ; SAVE IT
|
|
|
|
LD A,IDERC_CMDERR ; COMMAND ERROR
|
|
LD (IDE_RC),A ; SAVE IT
|
|
|
|
OR A ; CLEAR CF TO SIGNAL ERROR
|
|
RET
|
|
;
|
|
;
|
|
;
|
|
IDE_WAITBUF:
|
|
LD DE,0
|
|
IDE_WDRQ:
|
|
CALL DELAY
|
|
INC DE
|
|
LD A,D
|
|
OR E
|
|
JP Z,IDE_TO2
|
|
IN A,(IDESTTS) ; WAIT FOR DRIVE'S 512 BYTE READ BUFFER
|
|
LD (IDE_STTS),A ; SAVE IT
|
|
AND 000001000B ; TO FILL (OR READY TO FILL)
|
|
JP Z,IDE_WDRQ
|
|
SCF ; CARRY 1 = OK
|
|
RET
|
|
IDE_TO2:
|
|
LD A,IDERC_BUFTO
|
|
LD (IDE_RC),A
|
|
XOR A ; CARRY 0 = TIMED OUT
|
|
RET
|
|
;
|
|
;
|
|
;
|
|
IDE_BUFRD:
|
|
LD HL,(DIOBUF)
|
|
LD B,0
|
|
|
|
#IF (IDE8BIT | (IDEMODE == IDEMODE_DIDE))
|
|
LD C,IDEDATA
|
|
INIR
|
|
INIR
|
|
#ELSE
|
|
LD C,IDEDATAHI
|
|
IDE_BUFRD1:
|
|
IN A,(IDEDATALO) ; READ THE LO BYTE
|
|
LD (HL),A ; SAVE IN BUFFER
|
|
INC HL ; INC BUFFER POINTER
|
|
INI ; READ AND SAVE HI BYTE, INC HL, DEC B
|
|
JP NZ,IDE_BUFRD1 ; LOOP AS NEEDED
|
|
#ENDIF
|
|
RET
|
|
;
|
|
;
|
|
;
|
|
IDE_BUFWR:
|
|
LD HL,(DIOBUF)
|
|
LD B,0
|
|
|
|
#IF (IDE8BIT | (IDEMODE == IDEMODE_DIDE))
|
|
LD C,IDEDATA
|
|
OTIR
|
|
OTIR
|
|
#ELSE
|
|
LD C,IDEDATAHI
|
|
IDE_BUFWR1:
|
|
LD A,(HL) ; GET THE LO BYTE AND KEEP IT IN A FOR LATER
|
|
INC HL ; BUMP TO NEXT BYTE IN BUFFER
|
|
OUTI ; WRITE HI BYTE, INC HL, DEC B
|
|
OUT (IDEDATALO),A ; NOW WRITE THE SAVED LO BYTE TO LO BYTE
|
|
JP NZ,IDE_BUFWR1 ; LOOP AS NEEDED
|
|
#ENDIF
|
|
RET
|
|
;
|
|
;
|
|
;
|
|
IDE_SETUP:
|
|
LD A,1
|
|
OUT (IDESECTC),A
|
|
|
|
LD A,(HSTDSK) ; HSTDSK -> HEAD BIT 4 TO SELECT UNIT
|
|
AND 0FH
|
|
CP 0
|
|
JP Z,IDE_SETUP_UNIT0
|
|
CP 1
|
|
JP Z,IDE_SETUP_UNIT1
|
|
CALL NC,PANIC
|
|
IDE_SETUP_UNIT0:
|
|
LD A,(IDE0_DEVICE)
|
|
; LD DE,(IDE0_OFFSET)
|
|
JP IDE_SETUP1
|
|
IDE_SETUP_UNIT1:
|
|
LD A,(IDE1_DEVICE)
|
|
; LD DE,(IDE1_OFFSET)
|
|
JP IDE_SETUP1
|
|
IDE_SETUP1:
|
|
LD (IDE_DEVICE),A
|
|
OUT (IDEDEVICE),A
|
|
|
|
LD HL,(HSTTRK) ; HSTTRK -> IDECYLHI/LO
|
|
LD A,H
|
|
LD (IDE_CYLHI),A
|
|
OUT (IDECYLHI),A
|
|
LD A,L
|
|
LD (IDE_CYLLO),A
|
|
OUT (IDECYLLO),A
|
|
|
|
LD BC,(HSTSEC) ; HSTSEC -> IDESECTN
|
|
LD A,C
|
|
LD (IDE_SEC),A
|
|
OUT (IDESECTN),A
|
|
|
|
#IF (DSKYENABLE)
|
|
CALL IDE_DSKY
|
|
#ENDIF
|
|
|
|
RET
|
|
;
|
|
;
|
|
;
|
|
#IF (DSKYENABLE)
|
|
IDE_DSKY:
|
|
LD HL,DSKY_HEXBUF
|
|
LD A,(IDE_DEVICE)
|
|
LD (HL),A
|
|
INC HL
|
|
LD A,(IDE_CYLHI)
|
|
LD (HL),A
|
|
INC HL
|
|
LD A,(IDE_CYLLO)
|
|
LD (HL),A
|
|
INC HL
|
|
LD A,(IDE_SEC)
|
|
LD (HL),A
|
|
CALL DSKY_HEXOUT
|
|
RET
|
|
#ENDIF
|
|
;
|
|
;
|
|
;
|
|
IDE_PRT:
|
|
CALL NEWLINE
|
|
|
|
LD DE,IDESTR_PREFIX
|
|
CALL WRITESTR
|
|
|
|
CALL PC_SPACE
|
|
LD DE,IDESTR_CMD
|
|
CALL WRITESTR
|
|
LD A,(IDE_CMD)
|
|
CALL PRTHEXBYTE
|
|
|
|
CALL PC_SPACE
|
|
CALL PC_LBKT
|
|
LD A,(IDE_CMD)
|
|
LD DE,IDESTR_READ
|
|
CP IDECMD_READ
|
|
JP Z,IDE_PRTCMD
|
|
LD DE,IDESTR_WRITE
|
|
CP IDECMD_WRITE
|
|
JP Z,IDE_PRTCMD
|
|
LD DE,IDESTR_UNKCMD
|
|
IDE_PRTCMD:
|
|
CALL WRITESTR
|
|
CALL PC_RBKT
|
|
|
|
CALL PC_SPACE
|
|
LD A,(IDE_DEVICE)
|
|
CALL PRTHEXBYTE
|
|
LD A,(IDE_CYLHI)
|
|
CALL PRTHEXBYTE
|
|
LD A,(IDE_CYLLO)
|
|
CALL PRTHEXBYTE
|
|
LD A,(IDE_SEC)
|
|
CALL PRTHEXBYTE
|
|
|
|
CALL PC_SPACE
|
|
LD DE,IDESTR_ARROW
|
|
CALL WRITESTR
|
|
|
|
CALL PC_SPACE
|
|
IN A,(IDESTTS)
|
|
CALL PRTHEXBYTE
|
|
|
|
CALL PC_SPACE
|
|
IN A,(IDEERR)
|
|
CALL PRTHEXBYTE
|
|
|
|
CALL PC_SPACE
|
|
LD DE,IDESTR_RC
|
|
CALL WRITESTR
|
|
LD A,(IDE_RC)
|
|
CALL PRTHEXBYTE
|
|
|
|
CALL PC_SPACE
|
|
CALL PC_LBKT
|
|
LD A,(IDE_RC)
|
|
LD DE,IDESTR_RCOK
|
|
CP IDERC_OK
|
|
JP Z,IDE_PRTRC
|
|
LD DE,IDESTR_RCCMDERR
|
|
CP IDERC_CMDERR
|
|
JP Z,IDE_PRTRC
|
|
LD DE,IDESTR_RCRDYTO
|
|
CP IDERC_RDYTO
|
|
JP Z,IDE_PRTRC
|
|
LD DE,IDESTR_RCBUFTO
|
|
CP IDERC_BUFTO
|
|
JP Z,IDE_PRTRC
|
|
LD DE,IDESTR_RCUNK
|
|
IDE_PRTRC:
|
|
CALL WRITESTR
|
|
CALL PC_RBKT
|
|
|
|
RET
|
|
;
|
|
;
|
|
;
|
|
IDESTR_PREFIX .TEXT "IDE:$"
|
|
IDESTR_CMD .TEXT "CMD=$"
|
|
IDESTR_RC .TEXT "RC=$"
|
|
IDESTR_ARROW .TEXT "-->$"
|
|
IDESTR_READ .TEXT "READ$"
|
|
IDESTR_WRITE .TEXT "WRITE$"
|
|
IDESTR_UNKCMD .TEXT "UNKCMD$"
|
|
IDESTR_RCOK .TEXT "OK$"
|
|
IDESTR_RCCMDERR .TEXT "COMMAND ERROR$"
|
|
IDESTR_RCRDYTO .TEXT "READY TIMEOUT$"
|
|
IDESTR_RCBUFTO .TEXT "BUFFER TIMEOUT$"
|
|
IDESTR_RCUNK .TEXT "UNKNOWN ERROR$"
|
|
;
|
|
;==================================================================================================
|
|
; IDE DISK DRIVER - DATA
|
|
;==================================================================================================
|
|
;
|
|
IDE_STAT .DB 0
|
|
IDE_RC .DB 0
|
|
;
|
|
IDE_CMD: .DB 0
|
|
IDE_DEVICE .DB 0
|
|
IDE_CYLHI: .DB 0
|
|
IDE_CYLLO: .DB 0
|
|
IDE_SEC: .DB 0
|
|
IDE_STTS: .DB 0
|
|
IDE_ERRS .DB 0
|
|
;
|
|
;
|
|
;
|
|
;
|
|
; Error Register (ERR bit being set in the Status Register)
|
|
;
|
|
; Bit 7: BBK (Bad Block Detected) Set when a Bad Block is detected.
|
|
; Bit 6: UNC (Uncorrectable Data Error) Set when Uncorrectable Error is encountered.
|
|
; Bit 5: MC (Media Changed) Set to 0.
|
|
; Bit 4: IDNF (ID Not Found) Set when Sector ID not found.
|
|
; Bit 3: MCR (Media Change Request) Set to 0.
|
|
; Bit 2: ABRT (Aborted Command) Set when Command Aborted due to drive error.
|
|
; Bit 1: TKONF (Track 0 Not Found) Set when Executive Drive Diagnostic Command.
|
|
; Bit 0: AMNF (Address mark Not Found) Set in case of a general error.
|
|
;
|
|
; Status Register (When the contents of this register are read by the host, the IREQ# bit is cleared)
|
|
;
|
|
; Bit 7: BSY (Busy) Set when the drive is busy and unable to process any new ATA commands.
|
|
; Bit 6: DRDY (Data Ready) Set when the device is ready to accept ATA commands from the host.
|
|
; Bit 5: DWF (Drive Write Fault) Always set to 0.
|
|
; Bit 4: DSC (Drive Seek Complete) Set when the drive heads have been positioned over a specific track.
|
|
; Bit 3: DRQ (Data Request) Set when device is ready to transfer a word or byte of data to or from the host and the device.
|
|
; Bit 2: CORR (Corrected Data) Always set to 0.
|
|
; Bit 1: IDX (Index) Always set to 0.
|
|
; Bit 0: ERR (Error) Set when an error occurred during the previous ATA command.
|