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.
 
 
 
 
 
 

510 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:
PRTS("IDE:$")
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.