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.
 
 
 
 
 
 

1577 lines
38 KiB

;
;=============================================================================
; IDE DISK DRIVER
;=============================================================================
;
; TODO:
; - FIX SCALER CONSTANT
; - GOPARTNER NEEDS TO HANDLE "NO PARTNER" CONDITION
; - IMPLEMENT H/W PROBES FOR DIO AND DIDE
;
; NOTES:
; - WELL KNOWN IDE PORT ADDRESSES:
; BOARD BASE DATLO DATHI
; ------ ------ ------ ------
; DIO $20 $20 $28
; DIDE-A $20 $28 $28
; DIDE-B $30 $38 $38
; MK4 $80 N/A N/A
; RC $10 N/A N/A
; SMB $E0 N/A N/A
;
; +-----------------------------------------------------------------------+
; | CONTROL BLOCK REGISTERS |
; +-----------------------+-------+-------+-------------------------------+
; | REGISTER | PORT | DIR | DESCRIPTION |
; +-----------------------+-------+-------+-------------------------------+
; | IDE_IO_ALTSTAT | 0x0E | R | ALTERNATE STATUS REGISTER |
; | IDE_IO_CTRL | 0x0E | W | DEVICE CONTROL REGISTER |
; | IDE_IO_DRVADR | 0x0F | R | DRIVE ADDRESS REGISTER |
; +-----------------------+-------+-------+-------------------------------+
;
; +-----------------------+-------+-------+-------------------------------+
; | COMMAND BLOCK REGISTERS |
; +-----------------------+-------+-------+-------------------------------+
; | REGISTER | PORT | DIR | DESCRIPTION |
; +-----------------------+-------+-------+-------------------------------+
; | IDE_IO_DATA | 0x00 | R/W | DATA INPUT/OUTPUT |
; | IDE_IO_ERR | 0x01 | R | ERROR REGISTER |
; | IDE_IO_FEAT | 0x01 | W | FEATURES REGISTER |
; | IDE_IO_COUNT | 0x02 | R/W | SECTOR COUNT REGISTER |
; | IDE_IO_SECT | 0x03 | R/W | SECTOR NUMBER REGISTER |
; | IDE_IO_CYLLO | 0x04 | R/W | CYLINDER NUM REGISTER (LSB) |
; | IDE_IO_CYLHI | 0x05 | R/W | CYLINDER NUM REGISTER (MSB) |
; | IDE_IO_DRVHD | 0x06 | R/W | DRIVE/HEAD REGISTER |
; | IDE_IO_LBA0* | 0x03 | R/W | LBA BYTE 0 (BITS 0-7) |
; | IDE_IO_LBA1* | 0x04 | R/W | LBA BYTE 1 (BITS 8-15) |
; | IDE_IO_LBA2* | 0x05 | R/W | LBA BYTE 2 (BITS 16-23) |
; | IDE_IO_LBA3* | 0x06 | R/W | LBA BYTE 3 (BITS 24-27) |
; | IDE_IO_STAT | 0x07 | R | STATUS REGISTER |
; | IDE_IO_CMD | 0x07 | W | COMMAND REGISTER (EXECUTE) |
; +-----------------------+-------+-------+-------------------------------+
; * LBA0-3 ARE ALTERNATE DEFINITIONS OF SECT, CYL, AND DRVHD PORTS
;
; === STATUS REGISTER ===
;
; 7 6 5 4 3 2 1 0
; +-------+-------+-------+-------+-------+-------+-------+-------+
; | BSY | DRDY | DWF | DSC | DRQ | CORR | IDX | ERR |
; +-------+-------+-------+-------+-------+-------+-------+-------+
;
; BSY: BUSY
; DRDY: DRIVE READY
; DWF: DRIVE WRITE FAULT
; DSC: DRIVE SEEK COMPLETE
; DRQ: DATA REQUEST
; CORR: CORRECTED DATA
; IDX: INDEX
; ERR: ERROR
;
; === ERROR REGISTER ===
;
; 7 6 5 4 3 2 1 0
; +-------+-------+-------+-------+-------+-------+-------+-------+
; | BBK | UNC | MC | IDNF | MCR | ABRT | TK0NF | AMNF |
; +-------+-------+-------+-------+-------+-------+-------+-------+
; (VALID WHEN ERR BIT IS SET IN STATUS REGISTER)
;
; BBK: BAD BLOCK DETECTED
; UNC: UNCORRECTABLE DATA ERROR
; MC: MEDIA CHANGED
; IDNF: ID NOT FOUND
; MCR: MEDIA CHANGE REQUESTED
; ABRT: ABORTED COMMAND
; TK0NF: TRACK 0 NOT FOUND
; AMNF: ADDRESS MARK NOT FOUND
;
; === DRIVE/HEAD / LBA3 REGISTER ===
;
; 7 6 5 4 3 2 1 0
; +-------+-------+-------+-------+-------+-------+-------+-------+
; | 1 | L | 1 | DRV | HS3 | HS2 | HS1 | HS0 |
; +-------+-------+-------+-------+-------+-------+-------+-------+
;
; L: 0 = CHS ADDRESSING, 1 = LBA ADDRESSING
; DRV: 0 = DRIVE 0 (PRIMARY) SELECTED, 1 = DRIVE 1 (SLAVE) SELECTED
; HS: CHS = HEAD ADDRESS (0-15), LBA = BITS 24-27 OF LBA
;
; === DEVICE CONTROL REGISTER ===
;
; 7 6 5 4 3 2 1 0
; +-------+-------+-------+-------+-------+-------+-------+-------+
; | X | X | X | X | 1 | SRST | ~IEN | 0 |
; +-------+-------+-------+-------+-------+-------+-------+-------+
;
; SRST: SOFTWARE RESET
; ~IEN: INTERRUPT ENABLE
;
IDE_REG_DATA .EQU $00 ; DATA /OUTPUT (R/W)
IDE_REG_ERR .EQU $01 ; ERROR REGISTER (R)
IDE_REG_FEAT .EQU $01 ; FEATURES REGISTER (W)
IDE_REG_COUNT .EQU $02 ; SECTOR COUNT REGISTER (R/W)
IDE_REG_SECT .EQU $03 ; SECTOR NUMBER REGISTER (R/W)
IDE_REG_CYLLO .EQU $04 ; CYLINDER NUM REGISTER (LSB) (R/W)
IDE_REG_CYLHI .EQU $05 ; CYLINDER NUM REGISTER (MSB) (R/W)
IDE_REG_DRVHD .EQU $06 ; DRIVE/HEAD REGISTER (R/W)
IDE_REG_LBA0 .EQU $03 ; LBA BYTE 0 (BITS 0-7) (R/W)
IDE_REG_LBA1 .EQU $04 ; LBA BYTE 1 (BITS 8-15) (R/W)
IDE_REG_LBA2 .EQU $05 ; LBA BYTE 2 (BITS 16-23) (R/W)
IDE_REG_LBA3 .EQU $06 ; LBA BYTE 3 (BITS 24-27) (R/W)
IDE_REG_STAT .EQU $07 ; STATUS REGISTER (R)
IDE_REG_CMD .EQU $07 ; COMMAND REGISTER (EXECUTE) (W)
IDE_REG_XAR .EQU $08 ; ECB DIDE EXTERNAL ADDRESS REGISTER (W)
IDE_REG_ALTSTAT .EQU $0E ; ALTERNATE STATUS REGISTER (R)
IDE_REG_CTRL .EQU $0E ; DEVICE CONTROL REGISTER (W)
IDE_REG_DRVADR .EQU $0F ; DRIVE ADDRESS REGISTER (R)
;
; COMMAND BYTES
;
IDE_CIDE_RECAL .EQU $10
IDE_CIDE_READ .EQU $20
IDE_CIDE_WRITE .EQU $30
IDE_CIDE_IDDEV .EQU $EC
IDE_CIDE_SETFEAT .EQU $EF
;
; FEATURE BYTES
;
IDE_FEAT_ENABLE8BIT .EQU $01
IDE_FEAT_DISABLE8BIT .EQU $81
;
; IDE DEVICE TYPES
;
IDE_TYPEUNK .EQU 0
IDE_TYPEATA .EQU 1
IDE_TYPEATAPI .EQU 2
;
; IDE DEVICE STATUS
;
IDE_STOK .EQU 0
IDE_STINVUNIT .EQU -1
IDE_STNOMEDIA .EQU -2
IDE_STCMDERR .EQU -3
IDE_STIOERR .EQU -4
IDE_STRDYTO .EQU -5
IDE_STDRQTO .EQU -6
IDE_STBSYTO .EQU -7
;
; DRIVE SELECTION BYTES (FOR USE IN DRIVE/HEAD REGISTER)
;
;IDE_DRVSEL:
IDE_DRVMASTER .EQU %11100000 ; LBA, MASTER DEVICE
IDE_DRVSLAVE .EQU %11110000 ; LBA, SLAVE DEVICE
;
; IDE DEVICE CONFIGURATION
;
IDE_CFGSIZ .EQU 19 ; SIZE OF CFG TBL ENTRIES
;
; PER DEVICE DATA OFFSETS
;
IDE_DEV .EQU 0 ; OFFSET OF DEVICE NUMBER (BYTE)
IDE_MODE .EQU 1 ; OPERATION MODE: IDE MODE (BYTE)
IDE_STAT .EQU 2 ; LAST STATUS (BYTE)
IDE_TYPE .EQU 3 ; DEVICE TYPE (BYTE)
IDE_ACC .EQU 4 ; ACCESS FLAG BITS BIT 0=MASTER, 1=8BIT (BYTE)
IDE_MED .EQU 5 ; MEDIA FLAG BITS BIT 0=CF, 1=LBA (BYTE)
IDE_MEDCAP .EQU 6 ; MEDIA CAPACITY (DWORD)
IDE_LBA .EQU 10 ; OFFSET OF LBA (DWORD)
IDE_IOBASE .EQU 14 ; IO BASE ADDRESS (BYTE)
IDE_DATALO .EQU 15 ; 16 BIT DATA LO BYTE
IDE_DATAHI .EQU 16 ; 16 BIT DATA HI BYTE
IDE_PARTNER .EQU 17 ; PARTNER DEVICE (MASTER <-> SLAVE) (WORD)
;
IDE_ACC_MAS .EQU %00000001 ; UNIT IS MASTER (ELSE SLAVE)
IDE_ACC_8BIT .EQU %00000010 ; UNIT WANTS 8 BIT I/O (ELSE 16 BIT)
;
IDE_MED_CF .EQU %00000001 ; MEDIA IS CF CARD
IDE_MED_LBA .EQU %00000010 ; MEDIA HAS LBA CAPABILITY
;
IDE_DEVCNT .EQU IDECNT * 2
;
IDE_CFGTBL:
;
#IF (IDECNT >= 1)
;
IDE_DEV0M: ; DEVICE 0, MASTER
.DB 0 ; DRIVER DEVICE NUMBER
.DB IDE0MODE ; DRIVER DEVICE MODE
.DB 0 ; DEVICE STATUS
.DB 0 ; DEVICE TYPE
.DB IDE_ACC_MAS | (IDE0A8BIT & IDE_ACC_8BIT) ; UNIT ACCESS FLAGS
.DB 0 ; MEDIA FLAGS
.DW 0,0 ; DEVICE CAPACITY
.DW 0,0 ; CURRENT LBA
.DB IDE0BASE ; IO BASE ADDRESS
.DB IDE0DATLO ; IO BASE ADDRESS
.DB IDE0DATHI ; IO BASE ADDRESS
.DW IDE_DEV0S ; PARTNER
;
IDE_DEV0S: ; DEVICE 0, SLAVE
.DB 0 ; DRIVER DEVICE NUMBER
.DB IDE0MODE ; DRIVER DEVICE MODE
.DB 0 ; DEVICE STATUS
.DB 0 ; DEVICE TYPE
.DB (IDE0B8BIT & IDE_ACC_8BIT) ; UNIT ACCESS FLAGS
.DB 0 ; MEDIA FLAGS
.DW 0,0 ; DEVICE CAPACITY
.DW 0,0 ; CURRENT LBA
.DB IDE0BASE ; IO BASE ADDRESS
.DB IDE0DATLO ; IO BASE ADDRESS
.DB IDE0DATHI ; IO BASE ADDRESS
.DW IDE_DEV0M ; PARTNER
#ENDIF
;
#IF (IDECNT >= 2)
;
IDE_DEV1M: ; DEVICE 1, MASTER
.DB 0 ; DRIVER DEVICE NUMBER
.DB IDE1MODE ; DRIVER DEVICE MODE
.DB 0 ; DEVICE STATUS
.DB 0 ; DEVICE TYPE
.DB IDE_ACC_MAS | (IDE1A8BIT & IDE_ACC_8BIT) ; UNIT ACCESS FLAGS
.DB 0 ; MEDIA FLAGS
.DW 0,0 ; DEVICE CAPACITY
.DW 0,0 ; CURRENT LBA
.DB IDE1BASE ; IO BASE ADDRESS
.DB IDE1DATLO ; IO BASE ADDRESS
.DB IDE1DATHI ; IO BASE ADDRESS
.DW IDE_DEV1S ; PARTNER
;
IDE_DEV1S: ; DEVICE 1, SLAVE
.DB 0 ; DRIVER DEVICE NUMBER
.DB IDE1MODE ; DRIVER DEVICE MODE
.DB 0 ; DEVICE STATUS
.DB 0 ; DEVICE TYPE
.DB (IDE1B8BIT & IDE_ACC_8BIT) ; UNIT ACCESS FLAGS
.DB 0 ; MEDIA FLAGS
.DW 0,0 ; DEVICE CAPACITY
.DW 0,0 ; CURRENT LBA
.DB IDE1BASE ; IO BASE ADDRESS
.DB IDE1DATLO ; IO BASE ADDRESS
.DB IDE1DATHI ; IO BASE ADDRESS
.DW IDE_DEV1M ; PARTNER
#ENDIF
;
#IF (IDECNT >= 3)
;
IDE_DEV2M: ; DEVICE 2, MASTER
.DB 0 ; DRIVER DEVICE NUMBER
.DB IDE2MODE ; DRIVER DEVICE MODE
.DB 0 ; DEVICE STATUS
.DB 0 ; DEVICE TYPE
.DB IDE_ACC_MAS | (IDE2A8BIT & IDE_ACC_8BIT) ; UNIT ACCESS FLAGS
.DB 0 ; MEDIA FLAGS
.DW 0,0 ; DEVICE CAPACITY
.DW 0,0 ; CURRENT LBA
.DB IDE2BASE ; IO BASE ADDRESS
.DB IDE2DATLO ; IO BASE ADDRESS
.DB IDE2DATHI ; IO BASE ADDRESS
.DW IDE_DEV2S ; PARTNER
;
IDE_DEV2S: ; DEVICE 2, SLAVE
.DB 0 ; DRIVER DEVICE NUMBER
.DB IDE2MODE ; DRIVER DEVICE MODE
.DB 0 ; DEVICE STATUS
.DB 0 ; DEVICE TYPE
.DB (IDE2B8BIT & IDE_ACC_8BIT) ; UNIT ACCESS FLAGS
.DB 0 ; MEDIA FLAGS
.DW 0,0 ; DEVICE CAPACITY
.DW 0,0 ; CURRENT LBA
.DB IDE2BASE ; IO BASE ADDRESS
.DB IDE2DATLO ; IO BASE ADDRESS
.DB IDE2DATHI ; IO BASE ADDRESS
.DW IDE_DEV1M ; PARTNER
#ENDIF
;
#IF ($ - IDE_CFGTBL) != (IDE_DEVCNT * IDE_CFGSIZ)
.ECHO "*** INVALID IDE CONFIG TABLE ***\n"
#ENDIF
;
.DB $FF ; END MARKER
;
; THE IDE_WAITXXX FUNCTIONS ARE BUILT TO TIMEOUT AS NEEDED SO DRIVER WILL
; NOT HANG IF DEVICE IS UNRESPONSIVE. DIFFERENT TIMEOUTS ARE USED DEPENDING
; ON THE SITUATION. GENERALLY, THE FAST TIMEOUT IS USED TO PROBE FOR DEVICES
; USING FUNCTIONS THAT PERFORM NO I/O. OTHERWISE THE NORMAL TIMEOUT IS USED.
; IDE SPEC ALLOWS FOR UP TO 30 SECS MAX TO RESPOND. IN PRACTICE, THIS IS WAY
; TOO LONG, BUT IF YOU ARE USING A VERY OLD DEVICE, THESE TIMEOUTS MAY NEED TO
; BE ADJUSTED. NOTE THAT THESE ARE BYTE VALUES, SO YOU CANNOT EXCEED 255.
; THE TIMEOUTS ARE IN UNITS OF .05 SECONDS.
;
IDE_TONORM .EQU 200 ; NORMAL TIMEOUT IS 10 SECS
IDE_TOFAST .EQU 10 ; FAST TIMEOUT IS 0.5 SECS
;
;=============================================================================
; INITIALIZATION ENTRY POINT
;=============================================================================
;
IDE_INIT:
; COMPUTE CPU SPEED COMPENSATED TIMEOUT SCALER
; AT 1MHZ, THE SCALER IS 218 (50000US / 229TS = 218)
; SCALER IS THEREFORE 218 * CPU SPEED IN MHZ
LD DE,961 ; LOAD SCALER FOR 1MHZ
LD A,(CB_CPUMHZ) ; LOAD CPU SPEED IN MHZ
CALL MULT8X16 ; HL := DE * A
LD (IDE_TOSCALER),HL ; SAVE IT
;
XOR A ; ZERO ACCUM
LD (IDE_DEVNUM),A ; INIT DEV UNIT NUM FOR DYNAMIC ASSIGNMENT
LD IY,IDE_CFGTBL ; POINT TO START OF CONFIG TABLE
;
IDE_INIT1:
LD A,(IY) ; LOAD FIRST BYTE TO CHECK FOR END
CP $FF ; CHECK FOR END OF TABLE VALUE
JR NZ,IDE_INIT2 ; IF NOT END OF TABLE, CONTINUE
XOR A ; SIGNAL SUCCESS
RET ; AND RETURN
;
IDE_INIT2:
BIT 0,(IY+IDE_ACC) ; MASTER?
JR Z,IDE_INIT4 ; IF NOT MASTER, SKIP AHEAD
;
CALL NEWLINE ; FORMATTING
PRTS("IDE:$") ; LABEL FOR IO ADDRESS
;
PRTS(" IO=0x$") ; LABEL FOR IO ADDRESS
LD A,(IY+IDE_IOBASE) ; GET IO BASE ADDRES
CALL PRTHEXBYTE ; DISPLAY IT
;
PRTS(" MODE=$") ; LABEL FOR MODE
LD A,(IY+IDE_MODE) ; GET MODE BITS
LD DE,IDE_STR_MODE_DIO ; MODE LABEL
CP IDEMODE_DIO ; TEST FOR MODE
JR Z,IDE_INIT2A ; IF SO, DISPLAY IT
LD DE,IDE_STR_MODE_DIDE ; MODE LABEL
CP IDEMODE_DIDE ; TEST FOR MODE
JR Z,IDE_INIT2A ; IF SO, DISPLAY IT
LD DE,IDE_STR_MODE_MK4 ; MODE LABEL
CP IDEMODE_MK4 ; TEST FOR MODE
JR Z,IDE_INIT2A ; IF SO, DISPLAY IT
LD DE,IDE_STR_MODE_RC ; MODE LABEL
CP IDEMODE_RC ; TEST FOR MODE
JR Z,IDE_INIT2A ; IF SO, DISPLAY IT
JR IDE_INIT4 ; NO MODE? BYPASS ENTRY
IDE_INIT2A:
CALL WRITESTR ; DISPLAY MODE
;
CALL IDE_DETECT ; PROBE FOR INTERFACE
JR Z,IDE_INIT3 ; GOT IT, MOVE ON TO INIT UNITS
CALL PC_SPACE ; FORMATTING
LD DE,IDE_STR_NOHW ; NOT PRESENT MESSAGE
CALL WRITESTR ; DISPLAY IT
JR IDE_INIT4 ; SKIP CFG ENTRY
;
IDE_INIT3:
CALL IDE_RESET ; RESET THE BUS
CALL IDE_INIT5 ; DETECT/INIT MASTER
PUSH IY ; SAVE CFG PTR
CALL IDE_GOPARTNER ; SWITCH IY TO PARTNER CFG
CALL IDE_INIT5 ; DETECT/INIT SLAVE
POP IY ; RESTORE CFG PTR
;
IDE_INIT4:
LD DE,IDE_CFGSIZ ; SIZE OF CFG TABLE ENTRY
ADD IY,DE ; BUMP POINTER
JP IDE_INIT1 ; AND LOOP
;
IDE_INIT5:
; UPDATE DRIVER RELATIVE UNIT NUMBER IN CONFIG TABLE
LD A,(IDE_DEVNUM) ; GET NEXT UNIT NUM TO ASSIGN
LD (IY+IDE_DEV),A ; UPDATE IT
INC A ; BUMP TO NEXT UNIT NUM TO ASSIGN
LD (IDE_DEVNUM),A ; SAVE IT
;
; ADD UNIT TO GLOBAL DISK UNIT TABLE
LD BC,IDE_FNTBL ; BC := FUNC TABLE ADR
PUSH IY ; CFG ENTRY POINTER
POP DE ; COPY TO DE
CALL DIO_ADDENT ; ADD ENTRY TO GLOBAL DISK DEV TABLE
;
; CHECK FOR BAD STATUS
LD A,(IY+IDE_STAT) ; GET STATUS
OR A ; SET FLAGS
JP NZ,IDE_PRTSTAT ; EXIT VIA PRINT STATUS
;
CALL IDE_PRTPREFIX ; PRINT DEVICE PREFIX
;
LD DE,IDE_STR_8BIT
BIT 1,(IY+IDE_ACC) ; 8 BIT ACCESS?
CALL NZ,WRITESTR
;
; PRINT LBA/NOLBA
CALL PC_SPACE ; FORMATTING
BIT 1,(IY+IDE_MED) ; TEST LBA FLAG
LD DE,IDE_STR_NO ; POINT TO "NO" STRING
CALL Z,WRITESTR ; PRINT "NO" BEFORE "LBA" IF LBA NOT SUPPORTED
PRTS("LBA$") ; PRINT "LBA" REGARDLESS
;
; PRINT STORAGE CAPACITY (BLOCK COUNT)
PRTS(" BLOCKS=0x$") ; PRINT FIELD LABEL
LD A,IDE_MEDCAP ; OFFSET TO CAPACITY FIELD
CALL LDHLIYA ; HL := IY + A, REG A TRASHED
CALL LD32 ; GET THE CAPACITY VALUE
CALL PRTHEX32 ; PRINT HEX VALUE
;
; PRINT STORAGE SIZE IN MB
PRTS(" SIZE=$") ; PRINT FIELD LABEL
LD B,11 ; 11 BIT SHIFT TO CONVERT BLOCKS --> MB
CALL SRL32 ; RIGHT SHIFT
CALL PRTDEC ; PRINT LOW WORD IN DECIMAL (HIGH WORD DISCARDED)
PRTS("MB$") ; PRINT SUFFIX
;
RET
;
;----------------------------------------------------------------------
; PROBE FOR IDE HARDWARE
;----------------------------------------------------------------------
;
; ON RETURN, ZF SET INDICATES HARDWARE FOUND
;
IDE_DETECT:
;
;#IF (IDEMODE == IDEMODE_DIDE)
;#ENDIF
;;
;#IF (IDEMODE == IDEMODE_DIO)
;#ENDIF
;
XOR A ; SIGNAL SUCCESS
RET ; AND RETURN
;
;=============================================================================
; DRIVER FUNCTION TABLE
;=============================================================================
;
IDE_FNTBL:
.DW IDE_STATUS
.DW IDE_RESET
.DW IDE_SEEK
.DW IDE_READ
.DW IDE_WRITE
.DW IDE_VERIFY
.DW IDE_FORMAT
.DW IDE_DEVICE
.DW IDE_MEDIA
.DW IDE_DEFMED
.DW IDE_CAP
.DW IDE_GEOM
#IF (($ - IDE_FNTBL) != (DIO_FNCNT * 2))
.ECHO "*** INVALID IDE FUNCTION TABLE ***\n"
#ENDIF
;
IDE_VERIFY:
IDE_FORMAT:
IDE_DEFMED:
CALL PANIC ; NOT IMPLEMENTED
;
;
;
IDE_READ:
CALL HB_DSKREAD ; HOOK HBIOS DISK READ SUPERVISOR
LD BC,IDE_RDSEC ; GET ADR OF SECTOR READ FUNC
LD (IDE_IOFNADR),BC ; SAVE IT AS PENDING IO FUNC
JR IDE_IO ; CONTINUE TO GENERIC IO ROUTINE
;
;
;
IDE_WRITE:
CALL HB_DSKWRITE ; HOOK HBIOS DISK WRITE SUPERVISOR
LD BC,IDE_WRSEC ; GET ADR OF SECTOR WRITE FUNC
LD (IDE_IOFNADR),BC ; SAVE IT AS PENDING IO FUNC
JR IDE_IO ; CONTINUE TO GENERIC IO ROUTINE
;
;
;
IDE_IO:
LD (IDE_DSKBUF),HL ; SAVE DISK BUFFER ADDRESS
LD A,E ; BLOCK COUNT TO A
OR A ; SET FLAGS
RET Z ; ZERO SECTOR I/O, RETURN W/ E=0 & A=0
LD B,A ; INIT SECTOR DOWNCOUNTER
LD C,0 ; INIT SECTOR READ/WRITE COUNT
#IF (IDETRACE == 1)
LD HL,IDE_PRTERR ; SET UP IDE_PRTERR
PUSH HL ; ... TO FILTER ALL EXITS
#ENDIF
PUSH BC ; SAVE COUNTERS
CALL IDE_SELUNIT ; HARDWARE SELECTION OF TARGET UNIT
CALL IDE_CHKERR ; CHECK FOR ERR STATUS AND RESET IF SO
POP BC ; RESTORE COUNTERS
JR NZ,IDE_IO3 ; BAIL OUT ON ERROR
IDE_IO1:
PUSH BC ; SAVE COUNTERS
LD HL,(IDE_IOFNADR) ; GET PENDING IO FUNCTION ADDRESS
CALL JPHL ; ... AND CALL IT
JR NZ,IDE_IO2 ; IF ERROR, SKIP INCREMENT
; INCREMENT LBA
LD A,IDE_LBA ; LBA OFFSET
CALL LDHLIYA ; HL := IY + A, REG A TRASHED
CALL INC32HL ; INCREMENT THE VALUE
; INCREMENT DMA
LD HL,IDE_DSKBUF+1 ; POINT TO MSB OF BUFFER ADR
INC (HL) ; BUMP DMA BY
INC (HL) ; ... 512 BYTES
XOR A ; SIGNAL SUCCESS
IDE_IO2:
POP BC ; RECOVER COUNTERS
JR NZ,IDE_IO3 ; IF ERROR, BAIL OUT
INC C ; BUMP COUNT OF SECTORS READ
DJNZ IDE_IO1 ; LOOP AS NEEDED
IDE_IO3:
LD E,C ; SECTOR READ COUNT TO E
LD HL,(IDE_DSKBUF) ; CURRENT DMA TO HL
OR A ; SET FLAGS BASED ON RETURN CODE
RET ; AND RETURN, A HAS RETURN CODE
;
;
;
IDE_STATUS:
; RETURN UNIT STATUS
LD A,(IY+IDE_STAT) ; GET STATUS OF SELECTED DEVICE
OR A ; SET FLAGS
RET ; AND RETURN
;
;
;
IDE_DEVICE:
LD D,DIODEV_IDE ; D := DEVICE TYPE
LD E,(IY+IDE_DEV) ; E := PHYSICAL DEVICE NUMBER
BIT 0,(IY+IDE_MED) ; TEST CF BIT IN FLAGS
LD C,%00000000 ; ASSUME NON-REMOVABLE HARD DISK
JR Z,IDE_DEVICE1 ; IF Z, WE ARE DONE
LD C,%01001000 ; OTHERWISE REMOVABLE COMPACT FLASH
IDE_DEVICE1:
XOR A ; SIGNAL SUCCESS
RET
;
; IDE_GETMED
;
IDE_MEDIA:
LD A,E ; GET FLAGS
OR A ; SET FLAGS
JR Z,IDE_MEDIA2 ; JUST REPORT CURRENT STATUS AND MEDIA
;
; GET CURRENT STATUS
LD A,(IY+IDE_STAT) ; GET STATUS
OR A ; SET FLAGS
JR NZ,IDE_MEDIA1 ; ERROR ACTIVE, GO RIGHT TO RESET
;
; USE IDENTIFY COMMAND TO CHECK DEVICE
LD HL,IDE_TIMEOUT ; POINT TO TIMEOUT
LD (HL),IDE_TOFAST ; USE FAST TIMEOUT DURING IDENTIFY COMMAND
CALL IDE_SELUNIT ; HARDWARE SELECTION OF TARGET UNIT
CALL IDE_IDENTIFY ; EXECUTE IDENTIFY COMMAND
LD HL,IDE_TIMEOUT ; POINT TO TIMEOUT
LD (HL),IDE_TONORM ; BACK TO NORMAL TIMEOUT
JR Z,IDE_MEDIA2 ; IF SUCCESS, BYPASS RESET
;
IDE_MEDIA1:
CALL IDE_RESET ; RESET IDE INTERFACE
;
IDE_MEDIA2:
LD A,(IY+IDE_STAT) ; GET STATUS
OR A ; SET FLAGS
LD D,0 ; NO MEDIA CHANGE DETECTED
LD E,MID_HD ; ASSUME WE ARE OK
RET Z ; RETURN IF GOOD INIT
LD E,MID_NONE ; SIGNAL NO MEDIA
RET ; AND RETURN
;
;
;
IDE_SEEK:
BIT 7,D ; CHECK FOR LBA FLAG
CALL Z,HB_CHS2LBA ; CLEAR MEANS CHS, CONVERT TO LBA
RES 7,D ; CLEAR FLAG REGARDLESS (DOES NO HARM IF ALREADY LBA)
LD (IY+IDE_LBA+0),L ; SAVE NEW LBA
LD (IY+IDE_LBA+1),H ; ...
LD (IY+IDE_LBA+2),E ; ...
LD (IY+IDE_LBA+3),D ; ...
XOR A ; SIGNAL SUCCESS
RET ; AND RETURN
;
;
;
IDE_CAP:
LD A,(IY+IDE_STAT) ; GET STATUS
PUSH AF ; SAVE IT
LD A,IDE_MEDCAP ; OFFSET TO CAPACITY FIELD
CALL LDHLIYA ; HL := IY + A, REG A TRASHED
CALL LD32 ; GET THE CURRENT CAPACITY INTO DE:HL
LD BC,512 ; 512 BYTES PER BLOCK
POP AF ; RECOVER STATUS
OR A ; SET FLAGS
RET
;
;
;
IDE_GEOM:
; FOR LBA, WE SIMULATE CHS ACCESS USING 16 HEADS AND 16 SECTORS
; RETURN HS:CC -> DE:HL, SET HIGH BIT OF D TO INDICATE LBA CAPABLE
CALL IDE_CAP ; GET TOTAL BLOCKS IN DE:HL, BLOCK SIZE TO BC
LD L,H ; DIVIDE BY 256 FOR # TRACKS
LD H,E ; ... HIGH BYTE DISCARDED, RESULT IN HL
LD D,16 | $80 ; HEADS / CYL = 16, SET LBA CAPABILITY BIT
LD E,16 ; SECTORS / TRACK = 16
RET ; DONE, A STILL HAS IDE_CAP STATUS
;
;=============================================================================
; FUNCTION SUPPORT ROUTINES
;=============================================================================
;
IDE_SETFEAT:
PUSH AF
#IF (IDETRACE >= 3)
CALL IDE_PRTPREFIX
PRTS(" SETFEAT$")
#ENDIF
LD A,(IDE_DRVHD)
;OUT (IDE_IO_DRVHD),A
CALL IDE_OUT
.DB IDE_REG_DRVHD
#IF (IDETRACE >= 3)
CALL PC_SPACE
CALL PRTHEXBYTE
#ENDIF
POP AF
;OUT (IDE_IO_FEAT),A ; SET THE FEATURE VALUE
CALL IDE_OUT
.DB IDE_REG_FEAT
#IF (IDETRACE >= 3)
CALL PC_SPACE
CALL PRTHEXBYTE
#ENDIF
LD A,IDE_CIDE_SETFEAT ; CMD = SETFEAT
LD (IDE_CMD),A ; SAVE IT
JP IDE_RUNCMD ; RUN COMMAND AND EXIT
;
;
;
IDE_IDENTIFY:
#IF (IDETRACE >= 3)
CALL IDE_PRTPREFIX
PRTS(" IDDEV$")
#ENDIF
LD A,(IDE_DRVHD)
;OUT (IDE_IO_DRVHD),A
CALL IDE_OUT
.DB IDE_REG_DRVHD
#IF (IDETRACE >= 3)
CALL PC_SPACE
CALL PRTHEXBYTE
#ENDIF
LD A,IDE_CIDE_IDDEV
LD (IDE_CMD),A
CALL IDE_RUNCMD
RET NZ
LD HL,HB_WRKBUF
JP IDE_GETBUF ; EXIT THRU BUFRD
;
;
;
IDE_RDSEC:
;
#IF (IDETRACE >= 3)
CALL IDE_PRTPREFIX
PRTS(" READ$")
#ENDIF
LD A,(IDE_DRVHD)
;OUT (IDE_IO_DRVHD),A
CALL IDE_OUT
.DB IDE_REG_DRVHD
#IF (IDETRACE >= 3)
CALL PC_SPACE
CALL PRTHEXBYTE
#ENDIF
CALL IDE_SETADDR ; SETUP CYL, TRK, HEAD
LD A,IDE_CIDE_READ
LD (IDE_CMD),A
CALL IDE_RUNCMD
RET NZ
LD HL,(IDE_DSKBUF)
JP IDE_GETBUF
;
;
;
IDE_WRSEC:
;
#IF (IDETRACE >= 3)
CALL IDE_PRTPREFIX
PRTS(" WRITE$")
#ENDIF
LD A,(IDE_DRVHD)
;OUT (IDE_IO_DRVHD),A
CALL IDE_OUT
.DB IDE_REG_DRVHD
#IF (IDETRACE >= 3)
CALL PC_SPACE
CALL PRTHEXBYTE
#ENDIF
CALL IDE_SETADDR ; SETUP CYL, TRK, HEAD
LD A,IDE_CIDE_WRITE
LD (IDE_CMD),A
CALL IDE_RUNCMD
RET NZ
LD HL,(IDE_DSKBUF)
JP IDE_PUTBUF
;
;
;
IDE_SETADDR:
; SEND 3 LOWEST BYTES OF LBA IN REVERSE ORDER
; IDE_IO_LBA3 HAS ALREADY BEEN SET
; HSTLBA2-0 --> IDE_IO_LBA2-0
LD A,(IY+IDE_LBA+2)
#IF (IDETRACE >= 3)
CALL PC_SPACE
CALL PRTHEXBYTE
#ENDIF
CALL IDE_OUT
.DB IDE_REG_LBA2
;
LD A,(IY+IDE_LBA+1)
#IF (IDETRACE >= 3)
CALL PC_SPACE
CALL PRTHEXBYTE
#ENDIF
CALL IDE_OUT
.DB IDE_REG_LBA1
;
LD A,(IY+IDE_LBA+0)
#IF (IDETRACE >= 3)
CALL PC_SPACE
CALL PRTHEXBYTE
#ENDIF
CALL IDE_OUT
.DB IDE_REG_LBA0
;
LD A,1
#IF (IDETRACE >= 3)
CALL PC_SPACE
CALL PRTHEXBYTE
#ENDIF
CALL IDE_OUT
.DB IDE_REG_COUNT
;
#IF (DSKYENABLE)
CALL IDE_DSKY
#ENDIF
;
RET
;
;=============================================================================
; COMMAND PROCESSING
;=============================================================================
;
IDE_RUNCMD:
CALL IDE_WAITRDY ; WAIT FOR DRIVE READY
RET NZ ; BAIL OUT ON TIMEOUT
;
LD A,(IDE_CMD) ; GET THE COMMAND
#IF (IDETRACE >= 3)
CALL PC_SPACE
CALL PRTHEXBYTE
#ENDIF
;OUT (IDE_IO_CMD),A ; SEND IT (STARTS EXECUTION)
CALL IDE_OUT
.DB IDE_REG_CMD
#IF (IDETRACE >= 3)
PRTS(" -->$")
#ENDIF
;
CALL IDE_WAITBSY ; WAIT FOR DRIVE READY (COMMAND DONE)
RET NZ ; BAIL OUT ON TIMEOUT
;
CALL IDE_GETRES
JP NZ,IDE_CMDERR
RET
;
;
;
IDE_GETBUF:
#IF (IDETRACE >= 3)
PRTS(" GETBUF$")
#ENDIF
;
CALL IDE_WAITDRQ ; WAIT FOR BUFFER READY
RET NZ ; BAIL OUT IF TIMEOUT
;
LD B,0
;
BIT 1,(IY+IDE_ACC) ; 8 BIT?
JR Z,IDE_GETBUF1 ; IF NOT, DO 16 BIT
CALL IDE_GETBUF8 ; DO 8 BIT
JR IDE_GETBUF2
;
IDE_GETBUF1:
CALL IDE_GETBUF16
;
IDE_GETBUF2:
CALL IDE_WAITRDY ; PROBLEMS IF THIS IS REMOVED!
CALL IDE_GETRES
JP NZ,IDE_IOERR
RET
;
IDE_GETBUF8:
; 8 BIT I/O
;LD C,IDE_IO_DATA
LD C,(IY+IDE_IOBASE)
INIR
INIR
RET
;
IDE_GETBUF16:
; 16 BIT I/O
;LD C,IDE_IO_DATAHI
LD D,(IY+IDE_DATALO)
LD E,(IY+IDE_DATAHI)
CALL IDE_GETBUF16A ; GET FIRST 256 BYTES
CALL IDE_GETBUF16A ; GET SECOND 256 BYTES
RET
;
IDE_GETBUF16A:
LD C,D ; PORT FOR LSB
INI ; GET IT, SAVE IT, AND DEC B
LD C,E ; PORT FOR MSB
INI ; GET IT, SAVE IT, AND DEC B
JR NZ,IDE_GETBUF16A ; LOOP TILL COUNTER EXHAUSTED
RET
;
;
;
IDE_PUTBUF:
#IF (IDETRACE >= 3)
PRTS(" PUTBUF$")
#ENDIF
;
CALL IDE_WAITDRQ ; WAIT FOR BUFFER READY
RET NZ ; BAIL OUT IF TIMEOUT
;
LD B,0
;
BIT 1,(IY+IDE_ACC) ; 8 BIT?
JR Z,IDE_PUTBUF1 ; IF NOT, DO 16 BIT
CALL IDE_PUTBUF8 ; DO 8 BIT
JR IDE_PUTBUF2
;
IDE_PUTBUF1:
CALL IDE_PUTBUF16
;
IDE_PUTBUF2:
CALL IDE_WAITRDY ; PROBLEMS IF THIS IS REMOVED!
CALL IDE_GETRES
JP NZ,IDE_IOERR
RET
;
IDE_PUTBUF8:
; 8 BIT I/O
;LD C,IDE_IO_DATA
LD C,(IY+IDE_IOBASE)
OTIR
OTIR
RET
;
IDE_PUTBUF16:
; 16 BIT I/O
;LD C,IDE_IO_DATAHI
LD D,(IY+IDE_DATALO)
LD E,(IY+IDE_DATAHI)
CALL IDE_PUTBUF16A ; PUT FIRST 256 BYTES
CALL IDE_PUTBUF16A ; PUT SECOND 256 BYTES
RET
;
IDE_PUTBUF16A:
LD C,D ; PORT FOR LSB
OUTI ; PUT IT AND DEC B
LD C,E ; PORT FOR MSB
OUTI ; PUT IT AND DEC B
JR NZ,IDE_PUTBUF16A ; LOOP TILL COUNTER EXHAUSTED
RET
;
;
;
IDE_GETRES:
;IN A,(IDE_IO_STAT) ; GET STATUS
CALL IDE_IN
.DB IDE_REG_STAT
#IF (IDETRACE >= 3)
CALL PC_SPACE
CALL PRTHEXBYTE
#ENDIF
AND %00000001 ; ERROR BIT SET?
RET Z ; NOPE, RETURN WITH ZF
;
;IN A,(IDE_IO_ERR) ; READ ERROR REGISTER
CALL IDE_IN
.DB IDE_REG_ERR
#IF (IDETRACE >= 3)
CALL PC_SPACE
CALL PRTHEXBYTE
#ENDIF
OR $FF ; FORCE NZ TO SIGNAL ERROR
RET ; RETURN
;
;=============================================================================
; HARDWARE INTERFACE ROUTINES
;=============================================================================
;
; RESET ALL DEVICES ON BUS
;
IDE_RESET:
#IF (IDETRACE >= 3)
CALL IDE_PRTPREFIX
PRTS(" RESET$")
#ENDIF
;
;#IF (IDEMODE == IDEMODE_MK4)
;
LD A,(IY+IDE_MODE) ; GET MODE
CP IDEMODE_MK4 ; MK4?
JR NZ,IDE_RESET1 ; IF NOT, BYPASS
;
; USE HARDWARE RESET LINE
#IF (IDETRACE >= 3)
PRTS(" HARD$")
#ENDIF
LD A,$80 ; HIGH BIT OF XAR IS IDE RESET
;OUT (IDE_IO_XAR),A
CALL IDE_OUT
.DB IDE_REG_XAR
LD DE,2 ; DELAY 32US (SPEC IS >= 25US)
CALL VDELAY
XOR A ; CLEAR RESET BIT
;OUT (IDE_IO_XAR),A
CALL IDE_OUT
.DB IDE_REG_XAR
;
IDE_RESET1:
;
;#ENDIF
;
;#IF (IDEMODE == IDEMODE_RC)
;
LD A,(IY+IDE_MODE) ; GET MODE
CP IDEMODE_RC ; RC2014?
JR NZ,IDE_RESET2 ; IF NOT, BYPASS
;
; RC2014 CANNOT ADDRESS THE DEVICE CONTROL PORT AND
; HAS NO WAY TO PERFORM A HARD RESET FROM SOFTWARE,
; SO FAKE IT BY SETTING THE REGISTERS TO THE SAME
; VALUES THAT A RESET WOULD CAUSE.
#IF (IDETRACE >= 3)
PRTS(" FAKE$")
#ENDIF
XOR A
;OUT (IDE_IO_CYLLO),A
CALL IDE_OUT
.DB IDE_REG_CYLLO
;OUT (IDE_IO_CYLHI),A
CALL IDE_OUT
.DB IDE_REG_CYLHI
INC A
;OUT (IDE_IO_COUNT),A
CALL IDE_OUT
.DB IDE_REG_COUNT
;OUT (IDE_IO_SECT),A
CALL IDE_OUT
.DB IDE_REG_SECT
;
IDE_RESET2:
;
;#ENDIF
;
;#IF ((IDEMODE != IDEMODE_MK4) & (IDEMODE != IDEMODE_RC))
;
LD A,(IY+IDE_MODE) ; GET MODE
CP IDEMODE_MK4 ; MK4?
JR Z,IDE_RESET3 ; IF SO, BYPASS
CP IDEMODE_RC ; RC2014?
JR Z,IDE_RESET3 ; IF SO, BYPASS
;
; INITIATE SOFT RESET
#IF (IDETRACE >= 3)
PRTS(" SOFT$")
#ENDIF
LD A,%00001110 ; NO INTERRUPTS, ASSERT RESET BOTH DRIVES
;OUT (IDE_IO_CTRL),A
CALL IDE_OUT
.DB IDE_REG_CTRL
;
IDE_RESET3:
;
;#ENDIF
;
LD DE,2 ; DELAY 32US (SPEC IS >= 25US)
CALL VDELAY
;
;#IF (IDEMODE != IDEMODE_RC)
;
LD A,(IY+IDE_MODE) ; GET MODE
CP IDEMODE_RC ; RC2014?
JR Z,IDE_RESET4 ; IF SO, BYPASS
;
; CONFIGURE OPERATION AND END SOFT RESET
#IF (IDETRACE >= 3)
PRTS(" CONFIG$")
#ENDIF
LD A,%00001010 ; NO INTERRUPTS, DEASSERT RESET
;OUT (IDE_IO_CTRL),A ; PUSH TO REGISTER
CALL IDE_OUT
.DB IDE_REG_CTRL
;
IDE_RESET4:
;
;#ENDIF
;
; SPEC ALLOWS UP TO 450MS FOR DEVICES TO ASSERT THEIR PRESENCE
; VIA -DASP. I ENCOUNTER PROBLEMS LATER ON IF I DON'T WAIT HERE
; FOR THAT TO OCCUR. THUS FAR, IT APPEARS THAT 150MS IS SUFFICIENT
; FOR ANY DEVICE ENCOUNTERED. MAY NEED TO EXTEND BACK TO 500MS
; IF A SLOWER DEVICE IS ENCOUNTERED.
;
;LD DE,500000/16 ; ~500MS
LD DE,150000/16 ; ~???MS
CALL VDELAY
;
; INITIALIZE THE INDIVIDUAL UNITS (MASTER AND SLAVE).
; BASED ON TESTING, IT APPEARS THAT THE MASTER UNIT MUST
; BE DONE FIRST OR THIS BEHAVES BADLY.
PUSH IY ; SAVE CFG PTR
BIT 0,(IY+IDE_ACC) ; MASTER?
CALL Z,IDE_GOPARTNER ; IF NOT, SWITCH TO MASTER
CALL IDE_INITUNIT ; INIT CURRENT UNIT
CALL IDE_GOPARTNER ; POINT TO SLAVE
CALL IDE_INITUNIT ; INIT PARTNER UNIT
POP IY ; RECOVER ORIG CFG PTR
;
XOR A ; SIGNAL SUCCESS
RET ; AND DONE
;
;
;
IDE_INITUNIT:
CALL IDE_SELUNIT ; SELECT UNIT
RET NZ ; ABORT IF ERROR
LD HL,IDE_TIMEOUT ; POINT TO TIMEOUT
LD (HL),IDE_TONORM ; SET NORMAL TIMEOUT
CALL IDE_PROBE ; DO PROBE
RET NZ ; JUST RETURN IF NOTHING THERE
CALL IDE_INITDEV ; IF FOUND, ATTEMPT TO INIT DEVICE
RET ; DONE
;
; TAKE ANY ACTIONS REQUIRED TO SELECT DESIRED PHYSICAL UNIT
; UNIT IS SPECIFIED IN IDE_UNIT
; REGISTER A IS DESTROYED
;
IDE_SELUNIT:
#IF (IDETRACE >= 3)
CALL IDE_PRTPREFIX
PRTS(" SELUNIT$")
#ENDIF
;
BIT 0,(IY+IDE_ACC) ; MASTER?
JR Z,IDE_SELUNIT1 ; HANDLE SLAVE
LD A,IDE_DRVMASTER ; MASTER
JR IDE_SELUNIT2
IDE_SELUNIT1:
LD A,IDE_DRVSLAVE ; SLAVE
IDE_SELUNIT2:
LD (IDE_DRVHD),A ; SAVE IT
XOR A ; SUCCESS
RET
;
;
;
IDE_PROBE:
#IF (IDETRACE >= 3)
CALL IDE_PRTPREFIX
PRTS(" PROBE$") ; LABEL FOR IO ADDRESS
#ENDIF
;
LD A,(IDE_DRVHD)
;OUT (IDE_IO_DRVHD),A
CALL IDE_OUT
.DB IDE_REG_DRVHD
#IF (IDETRACE >= 3)
CALL PC_SPACE
CALL PRTHEXBYTE
#ENDIF
CALL DELAY ; DELAY ~16US
;
;LD C,IDE_IO_STAT
;IN A,(C)
CALL IDE_IN
.DB IDE_REG_STAT
#IF (IDETRACE >= 3)
CALL PC_SPACE
CALL PRTHEXBYTE
#ENDIF
CP $FF
JP Z,IDE_NOMEDIA
CP $78
JP Z,IDE_NOMEDIA
;
#IF (IDETRACE >= 3)
CALL IDE_REGDUMP
#ENDIF
;
;JR IDE_PROBE1 ; *DEBUG*
;
IDE_PROBE0:
CALL IDE_WAITBSY ; WAIT FOR BUSY TO CLEAR
JP NZ,IDE_NOMEDIA ; CONVERT TIMEOUT TO NO MEDIA AND RETURN
;
#IF (IDETRACE >= 3)
CALL IDE_REGDUMP
#ENDIF
;
; CHECK STATUS
;IN A,(IDE_IO_STAT) ; GET STATUS
CALL IDE_IN
.DB IDE_REG_STAT
#IF (IDETRACE >= 3)
CALL PC_SPACE
CALL PRTHEXBYTE ; IF DEBUG, PRINT STATUS
#ENDIF
OR A ; SET FLAGS TO TEST FOR ZERO
JP Z,IDE_NOMEDIA
;
; CHECK SIGNATURE
#IF (IDETRACE >= 3)
CALL PC_SPACE
#ENDIF
;IN A,(IDE_IO_COUNT)
CALL IDE_IN
.DB IDE_REG_COUNT
#IF (IDETRACE >= 3)
CALL PRTHEXBYTE
#ENDIF
CP $01
JP NZ,IDE_NOMEDIA
#IF (IDETRACE >= 3)
CALL PC_SPACE
#ENDIF
;IN A,(IDE_IO_SECT)
CALL IDE_IN
.DB IDE_REG_SECT
#IF (IDETRACE >= 3)
CALL PRTHEXBYTE
#ENDIF
CP $01
JP NZ,IDE_NOMEDIA
#IF (IDETRACE >= 3)
CALL PC_SPACE
#ENDIF
;IN A,(IDE_IO_CYLLO)
CALL IDE_IN
.DB IDE_REG_CYLLO
#IF (IDETRACE >= 3)
CALL PRTHEXBYTE
#ENDIF
CP $00
JP NZ,IDE_NOMEDIA
#IF (IDETRACE >= 3)
CALL PC_SPACE
#ENDIF
;IN A,(IDE_IO_CYLHI)
CALL IDE_IN
.DB IDE_REG_CYLHI
#IF (IDETRACE >= 3)
CALL PRTHEXBYTE
#ENDIF
CP $00
JP NZ,IDE_NOMEDIA
;
IDE_PROBE1:
; SIGNATURE MATCHES ATA DEVICE, RECORD TYPE AND RETURN SUCCESS
LD A,IDE_TYPEATA ; TYPE = ATA
LD (IY+IDE_TYPE),A ; SET IT IN INSTANCE DATA
XOR A ; SIGNAL SUCCESS
RET ; DONE, NOTE THAT A=0 AND Z IS SET
;
; (RE)INITIALIZE DEVICE
;
IDE_INITDEV:
;
LD A,(IY+IDE_TYPE) ; GET THE DEVICE TYPE
OR A ; SET FLAGS
JP Z,IDE_NOMEDIA ; EXIT SETTING NO MEDIA STATUS
;
BIT 1,(IY+IDE_ACC) ; 8 BIT ACCESS?
JR Z,IDE_INITDEV0 ; NO, DO 16 BIT INIT
LD A,IDE_FEAT_ENABLE8BIT ; FEATURE VALUE = ENABLE 8-BIT PIO
CALL IDE_SETFEAT ; SET FEATURE
RET NZ ; BAIL OUT ON ERROR
JR IDE_INITDEV00 ; CONTINUE
;
IDE_INITDEV0:
; "REAL" IDE DRIVES MAY NOT ACCEPT THE DISABLE8BIT FEATURE COMMAND,
; SO IT IS ONLY AN ERROR IF WE ARE ATTEMPTING TO ENABLE8BIT.
; CREDIT TO ED BRINDLEY FOR THIS CORRECTION. SO ERROR RETURN IGNORED HERE.
LD A,IDE_FEAT_DISABLE8BIT ; FEATURE VALUE = ENABLE 8-BIT PIO
CALL IDE_SETFEAT ; SET FEATURE, IGNORE ERRORS
;
IDE_INITDEV00:
;
CALL IDE_IDENTIFY ; EXECUTE IDENTIFY COMMAND
RET NZ ; BAIL OUT ON ERROR
;
LD DE,HB_WRKBUF ; POINT TO BUFFER
#IF (IDETRACE >= 3)
CALL DUMP_BUFFER ; DUMP IT IF DEBUGGING
#ENDIF
;
XOR A
LD (IY+IDE_MED),0 ; CLEAR FLAGS
; DETERMINE IF CF DEVICE
LD HL,HB_WRKBUF ; FIRST WORD OF IDENTIFY DATA HAS CF FLAG
LD A,$8A ; FIRST BYTE OF MARKER IS $8A
CP (HL) ; COMPARE
JR NZ,IDE_INITDEV1 ; IF NO MATCH, NOT CF
INC HL
LD A,$84 ; SECOND BYTE OF MARKER IS $84
CP (HL) ; COMPARE
JR NZ,IDE_INITDEV1 ; IF NOT MATCH, NOT CF
SET 0,(IY+IDE_MED) ; SET FLAGS BIT FOR CF MEDIA
;
IDE_INITDEV1:
; DETERMINE IF LBA CAPABLE
LD A,(HB_WRKBUF+98+1) ; GET BYTE WITH LBA BIT FROM BUFFER
BIT 1,A ; CHECK THE LBA BIT
JR Z,IDE_INITDEV2 ; NOT SET, BYPASS
SET 1,(IY+IDE_MED) ; SET FLAGS BIT FOR LBA
;
IDE_INITDEV2:
; GET DEVICE CAPACITY AND SAVE IT
LD A,IDE_MEDCAP ; OFFSET TO CAPACITY FIELD
CALL LDHLIYA ; HL := IY + A, REG A TRASHED
PUSH HL ; SAVE POINTER
LD HL,HB_WRKBUF ; POINT TO BUFFER START
LD A,120 ; OFFSET OF SECTOR COUNT
CALL ADDHLA ; POINT TO ADDRESS OF SECTOR COUNT
CALL LD32 ; LOAD IT TO DE:HL
POP BC ; RECOVER POINTER TO CAPACITY ENTRY
CALL ST32 ; SAVE CAPACITY
;
; RESET CARD STATUS TO 0 (OK)
XOR A ; A := 0 (STATUS = OK)
LD (IY+IDE_STAT),A ; SAVE IT
;
RET ; RETURN, A=0, Z SET
;
; SWITCH IY POINTER FROM CURRENT UNIT CFG TO PARTNER UNIT CFG
;
IDE_GOPARTNER:
PUSH HL ; SAVE HL
LD L,(IY+IDE_PARTNER) ; GET PARTNER ENTRY
LD H,(IY+IDE_PARTNER+1) ; ...
PUSH HL ; MOVE HL
POP IY ; ... TO IY
POP HL ; RESTORE INCOMING HL
RET ; AND DONE
;
; CHECK CURRENT DEVICE FOR ERROR STATUS AND ATTEMPT TO RECOVER
; VIA RESET IF DEVICE IS IN ERROR.
;
IDE_CHKERR:
LD A,(IY+IDE_STAT) ; GET STATUS
OR A ; SET FLAGS
CALL NZ,IDE_RESET ; IF ERROR STATUS, RESET BUS
RET
;
;
;
IDE_WAITRDY:
LD A,(IDE_TIMEOUT) ; GET TIMEOUT IN 0.05 SECS
LD B,A ; PUT IN OUTER LOOP VAR
IDE_WAITRDY1:
LD DE,(IDE_TOSCALER) ; CPU SPPED SCALER TO INNER LOOP VAR
IDE_WAITRDY2:
;IN A,(IDE_IO_STAT) ; READ STATUS
CALL IDE_IN
.DB IDE_REG_STAT
LD C,A ; SAVE IT
AND %11000000 ; ISOLATE BUSY AND RDY BITS
XOR %01000000 ; WE WANT BUSY(7) TO BE 0 AND RDY(6) TO BE 1
RET Z ; ALL SET, RETURN WITH Z SET
DEC DE
LD A,D
OR E
JR NZ,IDE_WAITRDY2 ; INNER LOOP RETURN
DJNZ IDE_WAITRDY1 ; OUTER LOOP RETURN
JP IDE_RDYTO ; EXIT WITH RDYTO ERR
;
;
;
IDE_WAITDRQ:
LD A,(IDE_TIMEOUT) ; GET TIMEOUT IN 0.05 SECS
LD B,A ; PUT IN OUTER LOOP VAR
IDE_WAITDRQ1:
LD DE,(IDE_TOSCALER) ; CPU SPPED SCALER TO INNER LOOP VAR
IDE_WAITDRQ2:
;IN A,(IDE_IO_STAT) ; WAIT FOR DRIVE'S 512 BYTE READ BUFFER
CALL IDE_IN
.DB IDE_REG_STAT
LD C,A ; SAVE IT
AND %10001000 ; TO FILL (OR READY TO FILL)
XOR %00001000
RET Z
DEC DE
LD A,D
OR E
JR NZ,IDE_WAITDRQ2
DJNZ IDE_WAITDRQ1
JP IDE_DRQTO ; EXIT WITH BUFTO ERR
;
;
;
IDE_WAITBSY:
LD A,(IDE_TIMEOUT) ; GET TIMEOUT IN 0.05 SECS
LD B,A ; PUT IN OUTER LOOP VAR
IDE_WAITBSY1:
LD DE,(IDE_TOSCALER) ; CPU SPPED SCALER TO INNER LOOP VAR
IDE_WAITBSY2:
;IN A,(IDE_IO_STAT) ; WAIT FOR DRIVE'S 512 BYTE READ BUFFER ; 11TS
CALL IDE_IN ; 17TS + ???TS
.DB IDE_REG_STAT ; 0TS
LD C,A ; SAVE IT ; 4TS
AND %10000000 ; TO FILL (OR READY TO FILL) ; 7TS
RET Z ; 5TS
DEC DE ; 6TS
LD A,D ; 4TS
OR E ; 4TS
JR NZ,IDE_WAITBSY2 ; 12TS
DJNZ IDE_WAITBSY1 ; -----
JP IDE_BSYTO ; EXIT WITH BSYTO ERR ; ??TS
;
; READ A VALUE FROM THE DEVICE POINTED TO BY IY AND RETURN IT IN A
;
IDE_IN:
EX (SP),HL ; GET PARM POINTER
PUSH BC
LD A,(HL)
INC HL
LD C,(IY+IDE_IOBASE)
ADD A,C
LD C,A
IN A,(C)
POP BC
EX (SP),HL ; RESTORE STACK
RET
;
; OUTPUT VALUE IN A TO THE DEVICE POINTED TO BY IY
;
IDE_OUT:
EX (SP),HL ; GET PARM POINTER
PUSH BC
PUSH AF
LD A,(HL)
INC HL
LD C,(IY+IDE_IOBASE)
ADD A,C
LD C,A
POP AF
OUT (C),A
POP BC
EX (SP),HL ; RESTORE STACK
RET
;
;=============================================================================
; ERROR HANDLING AND DIAGNOSTICS
;=============================================================================
;
; ERROR HANDLERS
;
IDE_INVUNIT:
LD A,IDE_STINVUNIT
JR IDE_ERR2 ; SPECIAL CASE FOR INVALID UNIT
;
IDE_NOMEDIA:
LD A,IDE_STNOMEDIA
JR IDE_ERR
;
IDE_CMDERR:
LD A,IDE_STCMDERR
JR IDE_ERR
;
IDE_IOERR:
LD A,IDE_STIOERR
JR IDE_ERR
;
IDE_RDYTO:
LD A,IDE_STRDYTO
JR IDE_ERR
;
IDE_DRQTO:
LD A,IDE_STDRQTO
JR IDE_ERR
;
IDE_BSYTO:
LD A,IDE_STBSYTO
JR IDE_ERR
;
IDE_ERR:
LD (IY+IDE_STAT),A ; SAVE NEW STATUS
;
IDE_ERR2:
#IF (IDETRACE >= 2)
CALL IDE_PRTSTAT
CALL IDE_REGDUMP
#ENDIF
OR A ; SET FLAGS
RET
;
;
;
IDE_PRTERR:
RET Z ; DONE IF NO ERRORS
; FALL THRU TO IDE_PRTSTAT
;
; PRINT STATUS STRING (STATUS NUM IN A)
;
IDE_PRTSTAT:
PUSH AF
PUSH DE
PUSH HL
OR A
LD DE,IDE_STR_STOK
JR Z,IDE_PRTSTAT1
INC A
LD DE,IDE_STR_STINVUNIT
JR Z,IDE_PRTSTAT2 ; INVALID UNIT IS SPECIAL CASE
INC A
LD DE,IDE_STR_STNOMEDIA
JR Z,IDE_PRTSTAT1
INC A
LD DE,IDE_STR_STCMDERR
JR Z,IDE_PRTSTAT1
INC A
LD DE,IDE_STR_STIOERR
JR Z,IDE_PRTSTAT1
INC A
LD DE,IDE_STR_STRDYTO
JR Z,IDE_PRTSTAT1
INC A
LD DE,IDE_STR_STDRQTO
JR Z,IDE_PRTSTAT1
INC A
LD DE,IDE_STR_STBSYTO
JR Z,IDE_PRTSTAT1
LD DE,IDE_STR_STUNK
IDE_PRTSTAT1:
CALL IDE_PRTPREFIX ; PRINT UNIT PREFIX
JR IDE_PRTSTAT3
IDE_PRTSTAT2:
CALL NEWLINE
PRTS("IDE:$") ; NO UNIT NUM IN PREFIX FOR INVALID UNIT
IDE_PRTSTAT3:
CALL PC_SPACE ; FORMATTING
CALL WRITESTR
POP HL
POP DE
POP AF
RET
;
; PRINT ALL REGISTERS DIRECTLY FROM DEVICE
; DEVICE MUST BE SELECTED PRIOR TO CALL
;
IDE_REGDUMP:
PUSH AF
PUSH BC
CALL PC_SPACE
CALL PC_LBKT
;LD C,IDE_IO_CMD
LD A,(IY+IDE_IOBASE)
ADD A,IDE_REG_CMD
LD C,A
LD B,7
IDE_REGDUMP1:
IN A,(C)
CALL PRTHEXBYTE
DEC C
DEC B
CALL NZ,PC_SPACE
JR NZ,IDE_REGDUMP1
CALL PC_RBKT
POP BC
POP AF
RET
;
; PRINT DIAGNONSTIC PREFIX
;
IDE_PRTPREFIX:
PUSH AF
CALL NEWLINE
PRTS("IDE$")
LD A,(IY+IDE_DEV) ; GET CURRENT DEVICE NUM
ADD A,'0'
CALL COUT
CALL PC_COLON
POP AF
RET
;
;
;
#IF (DSKYENABLE)
IDE_DSKY:
LD HL,DSKY_HEXBUF ; POINT TO DSKY BUFFER
CALL IDE_IN
.DB IDE_REG_DRVHD
LD (HL),A ; SAVE IN BUFFER
INC HL ; INCREMENT BUFFER POINTER
CALL IDE_IN
.DB IDE_REG_CYLHI
LD (HL),A ; SAVE IN BUFFER
INC HL ; INCREMENT BUFFER POINTER
CALL IDE_IN
.DB IDE_REG_CYLLO
LD (HL),A ; SAVE IN BUFFER
INC HL ; INCREMENT BUFFER POINTER
CALL IDE_IN
.DB IDE_REG_SECT
LD (HL),A ; SAVE IN BUFFER
CALL DSKY_HEXOUT ; SEND IT TO DSKY
RET
#ENDIF
;
;=============================================================================
; STRING DATA
;=============================================================================
;
IDE_STR_STOK .TEXT "OK$"
IDE_STR_STINVUNIT .TEXT "INVALID UNIT$"
IDE_STR_STNOMEDIA .TEXT "NO MEDIA$"
IDE_STR_STCMDERR .TEXT "COMMAND ERROR$"
IDE_STR_STIOERR .TEXT "IO ERROR$"
IDE_STR_STRDYTO .TEXT "READY TIMEOUT$"
IDE_STR_STDRQTO .TEXT "DRQ TIMEOUT$"
IDE_STR_STBSYTO .TEXT "BUSY TIMEOUT$"
IDE_STR_STUNK .TEXT "UNKNOWN ERROR$"
;
IDE_STR_NO .TEXT "NO$"
IDE_STR_NOHW .TEXT "NOT PRESENT$"
IDE_STR_8BIT .TEXT " 8-BIT$"
;
IDE_STR_MODE_DIO .TEXT "DIO$"
IDE_STR_MODE_DIDE .TEXT "DIDE$"
IDE_STR_MODE_MK4 .TEXT "MK4$"
IDE_STR_MODE_RC .TEXT "RC$"
;
;=============================================================================
; DATA STORAGE
;=============================================================================
;
IDE_TIMEOUT .DB IDE_TONORM ; WAIT FUNCS TIMEOUT IN TENTHS OF SEC
IDE_TOSCALER .DW CPUMHZ * 961 ; WAIT FUNCS SCALER FOR CPU SPEED
;
IDE_CMD .DB 0 ; PENDING COMMAND TO PROCESS
IDE_IOFNADR .DW 0 ; PENDING IO FUNCTION ADDRESS
IDE_DRVHD .DB 0 ; CURRENT DRIVE/HEAD MASK
;
IDE_DSKBUF .DW 0 ; ACTIVE DISK BUFFER
;
IDE_DEVNUM .DB 0 ; TEMP DEVICE NUM USED DURING INIT