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.
 
 
 
 
 
 

2336 lines
60 KiB

;
;=============================================================================
; PPIDE DISK DRIVER
;=============================================================================
;
; TODO:
; - GOPARTNER NEEDS TO HANDLE "NO PARTNER" CONDITION
; - DATA TRANSFERS LIMITED TO 512 BYTES WHICH IS INSUFFICIENT FOR CD=ROM MEDIA
;
; NOTES:
; - WELL KNOWN PPIDE PORT ADDRESSES:
; $60 - SBC/ZETA ONBOARD PPI
; $20 - ECB DISKIO3, RC FAMILY
; $44 - ECB MULTI-FUNCTION PIC
; $80 - N8 ONBOARD PPI
; $4C - DYNO ONBOARD PPI
;
; THE CONTROL PORT OF THE 8255 IS PROGRAMMED AS NEEDED TO READ OR WRITE
; DATA ON THE IDE BUS. PORT C OF THE 8255 IS ALWAYS IN OUTPUT MODE BECAUSE
; IT IS DRIVING THE ADDRESS BUS AND CONTROL SIGNALS. PORTS A & B WILL BE
; PLACED IN READ OR WRITE MODE DEPENDING ON THE DIRECTION OF THE DATA BUS.
;
PPIDE_DIR_READ .EQU %10010010 ; IDE BUS DATA INPUT MODE
PPIDE_DIR_WRITE .EQU %10000000 ; IDE BUS DATA OUTPUT MODE
;
; PORT C OF THE 8255 IS USED TO DRIVE THE IDE INTERFACE ADDRESS BUS
; AND VARIOUS CONTROL SIGNALS. THE CONSTANTS BELOW REFLECT THESE
; ASSIGNMENTS.
;
PPIDE_CTL_DA0 .EQU %00000001 ; DRIVE ADDRESS BUS - BIT 0 (DA0)
PPIDE_CTL_DA1 .EQU %00000010 ; DRIVE ADDRESS BUS - BIT 1 (DA1)
PPIDE_CTL_DA2 .EQU %00000100 ; DRIVE ADDRESS BUS - BIT 2 (DA2)
PPIDE_CTL_CS1 .EQU %00001000 ; DRIVE CHIP SELECT 0 (ACTIVE LOW, INVERTED)
PPIDE_CTL_CS3 .EQU %00010000 ; DRIVE CHIP SELECT 1 (ACTIVE LOW, INVERTED)
PPIDE_CTL_DIOW .EQU %00100000 ; DRIVE I/O WRITE (ACTIVE LOW, INVERTED)
PPIDE_CTL_DIOR .EQU %01000000 ; DRIVE I/O READ (ACTIVE LOW, INVERTED)
PPIDE_CTL_RESET .EQU %10000000 ; DRIVE RESET (ACTIVE LOW, INVERTED)
;
; +-----------------------------------------------------------------------+
; | CONTROL BLOCK REGISTERS (CS3FX) |
; +-----------------------+-------+-------+-------------------------------+
; | REGISTER | PORT | DIR | DESCRIPTION |
; +-----------------------+-------+-------+-------------------------------+
; | PPIDE_REG_ALTSTAT | 0x06 | R | ALTERNATE STATUS REGISTER |
; | PPIDE_REG_CTRL | 0x06 | W | DEVICE CONTROL REGISTER |
; | PPIDE_REG_DRVADR | 0x07 | R | DRIVE ADDRESS REGISTER |
; +-----------------------+-------+-------+-------------------------------+
;
; +-----------------------+-------+-------+-------------------------------+
; | COMMAND BLOCK REGISTERS (CS1FX) |
; +-----------------------+-------+-------+-------------------------------+
; | REGISTER | PORT | DIR | DESCRIPTION |
; +-----------------------+-------+-------+-------------------------------+
; | PPIDE_REG_DATA | 0x00 | R/W | DATA INPUT/OUTPUT |
; | PPIDE_REG_ERR | 0x01 | R | ERROR REGISTER |
; | PPIDE_REG_FEAT | 0x01 | W | FEATURES REGISTER |
; | PPIDE_REG_COUNT | 0x02 | R/W | SECTOR COUNT REGISTER |
; | PPIDE_REG_SECT | 0x03 | R/W | SECTOR NUMBER REGISTER |
; | PPIDE_REG_CYLLO | 0x04 | R/W | CYLINDER NUM REGISTER (LSB) |
; | PPIDE_REG_CYLHI | 0x05 | R/W | CYLINDER NUM REGISTER (MSB) |
; | PPIDE_REG_DRVHD | 0x06 | R/W | DRIVE/HEAD REGISTER |
; | PPIDE_REG_LBA0* | 0x03 | R/W | LBA BYTE 0 (BITS 0-7) |
; | PPIDE_REG_LBA1* | 0x04 | R/W | LBA BYTE 1 (BITS 8-15) |
; | PPIDE_REG_LBA2* | 0x05 | R/W | LBA BYTE 2 (BITS 16-23) |
; | PPIDE_REG_LBA3* | 0x06 | R/W | LBA BYTE 3 (BITS 24-27) |
; | PPIDE_REG_STAT | 0x07 | R | STATUS REGISTER |
; | PPIDE_REG_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
;
; CONTROL VALUES TO USE WHEN ACCESSING THE VARIOUS IDE DEVICE REGISTERS
;
PPIDE_REG_DATA .EQU PPIDE_CTL_CS1 | $00 ; DATA INPUT/OUTPUT (R/W)
PPIDE_REG_ERR .EQU PPIDE_CTL_CS1 | $01 ; ERROR REGISTER (R)
PPIDE_REG_FEAT .EQU PPIDE_CTL_CS1 | $01 ; FEATURES REGISTER (W)
PPIDE_REG_COUNT .EQU PPIDE_CTL_CS1 | $02 ; SECTOR COUNT REGISTER (R/W)
PPIDE_REG_SECT .EQU PPIDE_CTL_CS1 | $03 ; SECTOR NUMBER REGISTER (R/W)
PPIDE_REG_CYLLO .EQU PPIDE_CTL_CS1 | $04 ; CYLINDER NUM REGISTER (LSB) (R/W)
PPIDE_REG_CYLHI .EQU PPIDE_CTL_CS1 | $05 ; CYLINDER NUM REGISTER (MSB) (R/W)
PPIDE_REG_DRVHD .EQU PPIDE_CTL_CS1 | $06 ; DRIVE/HEAD REGISTER (R/W)
PPIDE_REG_LBA0 .EQU PPIDE_CTL_CS1 | $03 ; LBA BYTE 0 (BITS 0-7) (R/W)
PPIDE_REG_LBA1 .EQU PPIDE_CTL_CS1 | $04 ; LBA BYTE 1 (BITS 8-15) (R/W)
PPIDE_REG_LBA2 .EQU PPIDE_CTL_CS1 | $05 ; LBA BYTE 2 (BITS 16-23) (R/W)
PPIDE_REG_LBA3 .EQU PPIDE_CTL_CS1 | $06 ; LBA BYTE 3 (BITS 24-27) (R/W)
PPIDE_REG_BCL .EQU PPIDE_CTL_CS1 | $04 ; PKT BYTE COUNT LOW (BITS 0-7) (R/W)
PPIDE_REG_BCH .EQU PPIDE_CTL_CS1 | $05 ; PKT BYTE COUNT HIGH (BITS 8-15) (R/W)
PPIDE_REG_STAT .EQU PPIDE_CTL_CS1 | $07 ; STATUS REGISTER (R)
PPIDE_REG_CMD .EQU PPIDE_CTL_CS1 | $07 ; COMMAND REGISTER (EXECUTE) (W)
PPIDE_REG_ALTSTAT .EQU PPIDE_CTL_CS3 | $06 ; ALTERNATE STATUS REGISTER (R)
PPIDE_REG_CTRL .EQU PPIDE_CTL_CS3 | $06 ; DEVICE CONTROL REGISTER (W)
PPIDE_REG_DRVADR .EQU PPIDE_CTL_CS3 | $07 ; DRIVE ADDRESS REGISTER (R)
;
; COMMAND BYTES
;
PPIDE_CMD_NOP .EQU $00
PPIDE_CMD_DEVRES .EQU $08
PPIDE_CMD_RECAL .EQU $10
PPIDE_CMD_READ .EQU $20
PPIDE_CMD_WRITE .EQU $30
PPIDE_CMD_DEVDIAG .EQU $90
PPIDE_CMD_PACKET .EQU $A0
PPIDE_CMD_IDPKTDEV .EQU $A1
PPIDE_CMD_IDDEV .EQU $EC
PPIDE_CMD_SETFEAT .EQU $EF
;
; FEATURE BYTES
;
PPIDE_FEAT_ENABLE8BIT .EQU $01
PPIDE_FEAT_DISABLE8BIT .EQU $81
;
; PPIDE DEVICE TYPES
;
PPIDE_TYPEUNK .EQU 0
PPIDE_TYPEATA .EQU 1
PPIDE_TYPEATAPI .EQU 2
;
; PPIDE DEVICE STATUS CODES
;
PPIDE_STOK .EQU 0
PPIDE_STINVUNIT .EQU -1
PPIDE_STNOMEDIA .EQU -2
PPIDE_STCMDERR .EQU -3
PPIDE_STIOERR .EQU -4
PPIDE_STRDYTO .EQU -5
PPIDE_STDRQTO .EQU -6
PPIDE_STBSYTO .EQU -7
PPIDE_STNOTSUP .EQU -8
PPIDE_STNOTRDY .EQU -9
;
; DRIVE SELECTION BYTES (FOR USE IN DRIVE/HEAD REGISTER)
;
;PPIDE_DRVSEL:
PPIDE_DRVMASTER .EQU %11100000 ; LBA, MASTER DEVICE
PPIDE_DRVSLAVE .EQU %11110000 ; LBA, SLAVE DEVICE
;
; PPIDE DEVICE CONFIGURATION
;
PPIDE_CFGSIZ .EQU 19 ; SIZE OF CFG TBL ENTRIES
;
; PER DEVICE DATA OFFSETS
;
PPIDE_DEV .EQU 0 ; OFFSET OF DEVICE NUMBER (BYTE)
PPIDE_MODE .EQU 1 ; OPERATION MODE: PPIDE MODE (BYTE)
PPIDE_STAT .EQU 2 ; LAST STATUS (BYTE)
PPIDE_TYPE .EQU 3 ; DEVICE TYPE (BYTE)
PPIDE_ACC .EQU 4 ; ACCESS FLAG BITS BIT 0=MASTER, 1=8BIT (BYTE)
PPIDE_MED .EQU 5 ; MEDIA FLAG BITS BIT 0=CF, 1=LBA (BYTE)
PPIDE_MEDCAP .EQU 6 ; MEDIA CAPACITY (DWORD)
PPIDE_LBA .EQU 10 ; OFFSET OF LBA (DWORD)
PPIDE_DATALO .EQU 14 ; BASE PORT AND IDE DATA BUS LSB (8255 PORT A) (BYTE)
PPIDE_CTL .EQU 15 ; IDE ADDRESS BUS AND CONTROL SIGNALS (8255 PORT C)(BYTE)
PPIDE_PPI .EQU 16 ; 8255 CONTROL PORT(BYTE)
PPIDE_PARTNER .EQU 17 ; PARTNER DEVICE (MASTER <-> SLAVE) (WORD)
;
PPIDE_ACC_MAS .EQU %00000001 ; UNIT IS MASTER (ELSE SLAVE)
PPIDE_ACC_8BIT .EQU %00000010 ; UNIT WANTS 8 BIT I/O (ELSE 16 BIT)
;
PPIDE_MED_CF .EQU %00000001 ; MEDIA IS CF CARD
PPIDE_MED_LBA .EQU %00000010 ; MEDIA HAS LBA CAPABILITY
;
PPIDE_DEVCNT .EQU PPIDECNT * 2
;
PPIDE_CFGTBL:
;
#IF (PPIDECNT >= 1)
;
PPIDE_DEV0M: ; DEVICE 0, MASTER
.DB $FE ; DRIVER DEVICE NUMBER (FILLED DYNAMICALLY)
.DB PPIDE0MODE ; DRIVER DEVICE MODE
.DB 0 ; DEVICE STATUS
.DB 0 ; DEVICE TYPE
.DB PPIDE_ACC_MAS | (PPIDE0A8BIT & PPIDE_ACC_8BIT) ; UNIT ACCESS FLAGS
.DB 0 ; MEDIA FLAGS
.DW 0,0 ; DEVICE CAPACITY
.DW 0,0 ; CURRENT LBA
.DB PPIDE0BASE ; DATALO
.DB PPIDE0BASE+2 ; CTL
.DB PPIDE0BASE+3 ; PPI
.DW PPIDE_DEV0S ; PARTNER
;
DEVECHO "PPIDE: MODE="
#IF (PPIDE0MODE == PPIDEMODE_NONE)
DEVECHO "NONE"
#ENDIF
#IF (PPIDE0MODE == PPIDEMODE_STD)
DEVECHO "STD"
#ENDIF
#IF (PPIDE0MODE == PPIDEMODE_S100A)
DEVECHO "S100A"
#ENDIF
#IF (PPIDE0MODE == PPIDEMODE_S100B)
DEVECHO "S100B"
#ENDIF
DEVECHO ", IO="
DEVECHO PPIDE0BASE
DEVECHO ", MASTER"
DEVECHO "\n"
;
PPIDE_DEV0S: ; DEVICE 0, SLAVE
.DB $FE ; DRIVER DEVICE NUMBER (FILLED DYNAMICALLY)
.DB PPIDE0MODE ; DRIVER DEVICE MODE
.DB 0 ; DEVICE STATUS
.DB 0 ; DEVICE TYPE
.DB (PPIDE0B8BIT & PPIDE_ACC_8BIT) ; UNIT ACCESS FLAGS
.DB 0 ; MEDIA FLAGS
.DW 0,0 ; DEVICE CAPACITY
.DW 0,0 ; CURRENT LBA
.DB PPIDE0BASE ; DATALO
.DB PPIDE0BASE+2 ; CTL
.DB PPIDE0BASE+3 ; PPI
.DW PPIDE_DEV0M ; PARTNER
;
DEVECHO "PPIDE: MODE="
#IF (PPIDE0MODE == PPIDEMODE_NONE)
DEVECHO "NONE"
#ENDIF
#IF (PPIDE0MODE == PPIDEMODE_STD)
DEVECHO "STD"
#ENDIF
#IF (PPIDE0MODE == PPIDEMODE_S100A)
DEVECHO "S100A"
#ENDIF
#IF (PPIDE0MODE == PPIDEMODE_S100B)
DEVECHO "S100B"
#ENDIF
DEVECHO ", IO="
DEVECHO PPIDE0BASE
DEVECHO ", SLAVE"
DEVECHO "\n"
;
#ENDIF
;
#IF (PPIDECNT >= 2)
;
PPIDE_DEV1M: ; DEVICE 1, MASTER
.DB $FE ; DRIVER DEVICE NUMBER (FILLED DYNAMICALLY)
.DB PPIDE1MODE ; DRIVER DEVICE MODE
.DB 0 ; DEVICE STATUS
.DB 0 ; DEVICE TYPE
.DB PPIDE_ACC_MAS | (PPIDE1A8BIT & PPIDE_ACC_8BIT) ; UNIT ACCESS FLAGS
.DB 0 ; MEDIA FLAGS
.DW 0,0 ; DEVICE CAPACITY
.DW 0,0 ; CURRENT LBA
.DB PPIDE1BASE ; DATALO
.DB PPIDE1BASE+2 ; CTL
.DB PPIDE1BASE+3 ; PPI
.DW PPIDE_DEV1S ; PARTNER
;
DEVECHO "PPIDE: MODE="
#IF (PPIDE1MODE == PPIDEMODE_NONE)
DEVECHO "NONE"
#ENDIF
#IF (PPIDE1MODE == PPIDEMODE_STD)
DEVECHO "STD"
#ENDIF
#IF (PPIDE1MODE == PPIDEMODE_S100A)
DEVECHO "S100A"
#ENDIF
#IF (PPIDE1MODE == PPIDEMODE_S100B)
DEVECHO "S100B"
#ENDIF
DEVECHO ", IO="
DEVECHO PPIDE1BASE
DEVECHO ", MASTER"
DEVECHO "\n"
;
PPIDE_DEV1S: ; DEVICE 1, SLAVE
.DB $FE ; DRIVER DEVICE NUMBER (FILLED DYNAMICALLY)
.DB PPIDE1MODE ; DRIVER DEVICE MODE
.DB 0 ; DEVICE STATUS
.DB 0 ; DEVICE TYPE
.DB (PPIDE1B8BIT & PPIDE_ACC_8BIT) ; UNIT ACCESS FLAGS
.DB 0 ; MEDIA FLAGS
.DW 0,0 ; DEVICE CAPACITY
.DW 0,0 ; CURRENT LBA
.DB PPIDE1BASE ; DATALO
.DB PPIDE1BASE+2 ; CTL
.DB PPIDE1BASE+3 ; PPI
.DW PPIDE_DEV1M ; PARTNER
;
DEVECHO "PPIDE: MODE="
#IF (PPIDE1MODE == PPIDEMODE_NONE)
DEVECHO "NONE"
#ENDIF
#IF (PPIDE1MODE == PPIDEMODE_STD)
DEVECHO "STD"
#ENDIF
#IF (PPIDE1MODE == PPIDEMODE_S100A)
DEVECHO "S100A"
#ENDIF
#IF (PPIDE1MODE == PPIDEMODE_S100B)
DEVECHO "S100B"
#ENDIF
DEVECHO ", IO="
DEVECHO PPIDE1BASE
DEVECHO ", SLAVE"
DEVECHO "\n"
;
#ENDIF
;
#IF (PPIDECNT >= 3)
;
PPIDE_DEV2M: ; DEVICE 2, MASTER
.DB $FE ; DRIVER DEVICE NUMBER (FILLED DYNAMICALLY)
.DB PPIDE2MODE ; DRIVER DEVICE MODE
.DB 0 ; DEVICE STATUS
.DB 0 ; DEVICE TYPE
.DB PPIDE_ACC_MAS | (PPIDE2A8BIT & PPIDE_ACC_8BIT) ; UNIT ACCESS FLAGS
.DB 0 ; MEDIA FLAGS
.DW 0,0 ; DEVICE CAPACITY
.DW 0,0 ; CURRENT LBA
.DB PPIDE2BASE ; DATALO
.DB PPIDE2BASE+2 ; CTL
.DB PPIDE2BASE+3 ; PPI
.DW PPIDE_DEV2S ; PARTNER
;
DEVECHO "PPIDE: MODE="
#IF (PPIDE2MODE == PPIDEMODE_NONE)
DEVECHO "NONE"
#ENDIF
#IF (PPIDE2MODE == PPIDEMODE_STD)
DEVECHO "STD"
#ENDIF
#IF (PPIDE2MODE == PPIDEMODE_S100A)
DEVECHO "S100A"
#ENDIF
#IF (PPIDE2MODE == PPIDEMODE_S100B)
DEVECHO "S100B"
#ENDIF
DEVECHO ", IO="
DEVECHO PPIDE2BASE
DEVECHO ", MASTER"
DEVECHO "\n"
;
PPIDE_DEV2S: ; DEVICE 2, SLAVE
.DB $FE ; DRIVER DEVICE NUMBER (FILLED DYNAMICALLY)
.DB PPIDE2MODE ; DRIVER DEVICE MODE
.DB 0 ; DEVICE STATUS
.DB 0 ; DEVICE TYPE
.DB (PPIDE2B8BIT & PPIDE_ACC_8BIT) ; UNIT ACCESS FLAGS
.DB 0 ; MEDIA FLAGS
.DW 0,0 ; DEVICE CAPACITY
.DW 0,0 ; CURRENT LBA
.DB PPIDE2BASE ; DATALO
.DB PPIDE2BASE+2 ; CTL
.DB PPIDE2BASE+3 ; PPI
.DW PPIDE_DEV2M ; PARTNER
;
DEVECHO "PPIDE: MODE="
#IF (PPIDE2MODE == PPIDEMODE_NONE)
DEVECHO "NONE"
#ENDIF
#IF (PPIDE2MODE == PPIDEMODE_STD)
DEVECHO "STD"
#ENDIF
#IF (PPIDE2MODE == PPIDEMODE_S100A)
DEVECHO "S100A"
#ENDIF
#IF (PPIDE2MODE == PPIDEMODE_S100B)
DEVECHO "S100B"
#ENDIF
DEVECHO ", IO="
DEVECHO PPIDE2BASE
DEVECHO ", SLAVE"
DEVECHO "\n"
;
#ENDIF
;
#IF ($ - PPIDE_CFGTBL) != (PPIDE_DEVCNT * PPIDE_CFGSIZ)
.ECHO "*** INVALID PPIDE CONFIG TABLE ***\n"
#ENDIF
;
.DB $FF ; END OF TABLE MARKER
;
; THE PPIDE_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. THE SLOW TIMEOUT IS USED TO WAIT FOR A DEVICE TO
; BECOME READY AFTER A HARD RESET (SPIN UP, ETC.). THE NORMAL TIMEOUT
; IS USED DURING NORMAL OPERATION FOR ALL I/O OPERATIONS WHICH SHOULD
; OCCUR PRETTY FAST. NOTE THAT THE ATA SPEC ALLOWS UP TO 30 SECONDS
; FOR DEVICES TO RESPOND. WE ARE USING MUCH MORE AGGRESSIVE VALUES
; BASED ON REAL WORLD EXPERIENCE.
;
PPIDE_TOSLOW .EQU 200 ; SLOW TIMEOUT IS 20 SECS
;PPIDE_TONORM .EQU 5 ; NORMAL TIMEOUT IS 0.5 SECS
PPIDE_TONORM .EQU 200 ; NORMAL TIMEOUT IS 0.5 SECS
;
;=============================================================================
; INITIALIZATION ENTRY POINT
;=============================================================================
;
PPIDE_INIT:
; COMPUTE CPU SPEED COMPENSATED TIMEOUT SCALER
; ONE INTERNAL LOOP IN WAITBSY IS 263TS. ON A 1 MHZ CPU, 1 TS
; TAKES 1NS. SO 1/10 SECOND IS 100000 TS ON A 1 MHZ CPU.
; SINCE 1 INTERNAL LOOP IS 263 TS, IT TAKES 100000 / 263 = 356
; INTERNAL LOOPS FOR 1/10 SECOND. SO, WE WANT TO USE
; 356 * CPU MHZ FOR INTERNAL LOOP COUNT.
LD DE,380 ; LOAD SCALER FOR 1MHZ
LD A,(CB_CPUMHZ) ; LOAD CPU SPEED IN MHZ
CALL MULT8X16 ; HL := DE * A
LD (PPIDE_TOSCALER),HL ; SAVE IT
;
XOR A ; ZERO ACCUM
LD (PPIDE_DEVNUM),A ; INIT DEV UNIT NUM FOR DYNAMIC ASSIGNMENT
LD IY,PPIDE_CFGTBL ; POINT TO START OF CONFIG TABLE
;
PPIDE_INIT1:
LD A,(IY) ; LOAD FIRST BYTE TO CHECK FOR END
CP $FF ; CHECK FOR END OF TABLE VALUE
JR NZ,PPIDE_INIT2 ; IF NOT END OF TABLE, CONTINUE
XOR A ; SIGNAL SUCCESS
RET ; AND RETURN
;
PPIDE_INIT2:
BIT 0,(IY+PPIDE_ACC) ; MASTER?
JR Z,PPIDE_INIT4 ; IF NOT MASTER, SKIP AHEAD
;
CALL NEWLINE ; FORMATTING
PRTS("PPIDE:$") ; LABEL FOR IO ADDRESS
;
PRTS(" IO=0x$") ; LABEL FOR IO ADDRESS
LD A,(IY+PPIDE_DATALO) ; GET IO BASE ADDRES
CALL PRTHEXBYTE ; DISPLAY IT
;
CALL PPIDE_DETECT ; PROBE FOR INTERFACE
JR Z,PPIDE_INIT3 ; GOT IT, MOVE ON TO INIT UNITS
CALL PC_SPACE ; FORMATTING
LD DE,PPIDE_STR_NOPPI ; NO PPI MESSAGE
CALL WRITESTR ; DISPLAY IT
JR PPIDE_INIT4 ; SKIP CFG ENTRY
;
PPIDE_INIT3:
CALL PPIDE_RESET ; RESET THE BUS
CALL PPIDE_INIT5 ; DETECT/INIT MASTER
PUSH IY ; SAVE CFG PTR
CALL PPIDE_GOPARTNER ; SWITCH IY TO PARTNER CFG
CALL PPIDE_INIT5 ; DETECT/INIT SLAVE
POP IY ; RESTORE CFG PTR
;
PPIDE_INIT4:
LD DE,PPIDE_CFGSIZ ; SIZE OF CFG TABLE ENTRY
ADD IY,DE ; BUMP POINTER
JR PPIDE_INIT1 ; AND LOOP
;
PPIDE_INIT5:
; UPDATE DRIVER RELATIVE UNIT NUMBER IN CONFIG TABLE
LD A,(PPIDE_DEVNUM) ; GET NEXT UNIT NUM TO ASSIGN
LD (IY+PPIDE_DEV),A ; UPDATE IT
INC A ; BUMP TO NEXT UNIT NUM TO ASSIGN
LD (PPIDE_DEVNUM),A ; SAVE IT
;
; ADD UNIT TO GLOBAL DISK UNIT TABLE
LD BC,PPIDE_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
;
; START PRINTING DEVICE INFO
CALL PPIDE_PRTPREFIX ; PRINT DEVICE PREFIX
LD A,(IY+PPIDE_TYPE)
LD DE,PPIDE_STR_TYPEATA
CP PPIDE_TYPEATA
CALL Z,WRITESTR
LD DE,PPIDE_STR_TYPEATAPI
CP PPIDE_TYPEATAPI
CALL Z,WRITESTR
;
; CHECK FOR BAD STATUS
LD A,(IY+PPIDE_STAT) ; GET STATUS
OR A ; SET FLAGS
JP Z,PPIDE_INIT6
CALL PC_SPACE
JP NZ,PPIDE_PRTSTATSTR ; EXIT VIA PRINT STATUS STRING
;
PPIDE_INIT6:
LD DE,PPIDE_STR_8BIT
BIT 1,(IY+PPIDE_ACC) ; 8 BIT ACCESS?
CALL NZ,WRITESTR
;
; PRINT LBA/NOLBA
CALL PC_SPACE ; FORMATTING
BIT 1,(IY+PPIDE_MED) ; TEST LBA FLAG
LD DE,PPIDE_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,PPIDE_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)
CALL PRTDEC32 ; PRINT DWORD IN DECIMAL
PRTS("MB$") ; PRINT SUFFIX
;
RET
;
;----------------------------------------------------------------------
; PROBE FOR PPI HARDWARE
;----------------------------------------------------------------------
;
; ON RETURN, ZF SET INDICATES HARDWARE FOUND
;
PPIDE_DETECT:
;
; TEST FOR PPI EXISTENCE
; WE SETUP THE PPI TO WRITE, THEN WRITE A VALUE OF $A5
; TO PORT A (DATALO), THEN READ IT BACK. IF THE PPI IS THERE
; THEN THE BUS HOLD CIRCUITRY WILL READ BACK THE $A5. SINCE
; WE ARE IN WRITE MODE, AN IDE CONTROLLER WILL NOT BE ABLE TO
; INTERFERE WITH THE VALUE BEING READ.
;
LD A,PPIDE_DIR_WRITE ; SET DATA BUS DIRECTION TO WRITE
LD C,(IY+PPIDE_PPI) ; PPI CONTROL WORD
EZ80_IO
OUT (C),A ; WRITE IT
;
LD C,(IY+PPIDE_DATALO) ; PPI PORT A, DATALO
LD A,$A5 ; TEST VALUE
EZ80_IO
OUT (C),A ; PUSH VALUE TO PORT
EZ80_IO
IN A,(C) ; GET PORT VALUE
#IF (PPIDETRACE >= 3)
CALL PC_SPACE
CALL PRTHEXBYTE
#ENDIF
CP $A5 ; CHECK FOR TEST VALUE
RET ; AND RETURN
;
;=============================================================================
; DRIVER FUNCTION TABLE
;=============================================================================
;
PPIDE_FNTBL:
.DW PPIDE_STATUS
.DW PPIDE_RESET
.DW PPIDE_SEEK
.DW PPIDE_READ
.DW PPIDE_WRITE
.DW PPIDE_VERIFY
.DW PPIDE_FORMAT
.DW PPIDE_DEVICE
.DW PPIDE_MEDIA
.DW PPIDE_DEFMED
.DW PPIDE_CAP
.DW PPIDE_GEOM
#IF (($ - PPIDE_FNTBL) != (DIO_FNCNT * 2))
.ECHO "*** INVALID PPIDE FUNCTION TABLE ***\n"
#ENDIF
;
PPIDE_VERIFY:
PPIDE_FORMAT:
PPIDE_DEFMED:
SYSCHKERR(ERR_NOTIMPL) ; NOT IMPLEMENTED
RET
;
;
;
PPIDE_READ:
CALL HB_DSKREAD ; HOOK HBIOS DISK READ SUPERVISOR
LD BC,PPIDE_RDSEC ; GET ADR OF SECTOR READ FUNC
LD (PPIDE_IOFNADR),BC ; SAVE IT AS PENDING IO FUNC
JR PPIDE_IO ; CONTINUE TO GENERIC IO ROUTINE
;
;
;
PPIDE_WRITE:
CALL HB_DSKWRITE ; HOOK HBIOS DISK WRITE SUPERVISOR
LD BC,PPIDE_WRSEC ; GET ADR OF SECTOR WRITE FUNC
LD (PPIDE_IOFNADR),BC ; SAVE IT AS PENDING IO FUNC
JR PPIDE_IO ; CONTINUE TO GENERIC IO ROUTINE
;
;
;
PPIDE_IO:
LD (PPIDE_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 (PPIDETRACE == 1)
LD HL,PPIDE_PRTERR ; SET UP PPIDE_PRTERR
PUSH HL ; ... TO FILTER ALL EXITS
#ENDIF
PUSH BC ; SAVE COUNTERS
CALL PPIDE_CHKERR ; CHECK FOR ERR STATUS AND RESET IF SO
POP BC ; RESTORE COUNTERS
JR NZ,PPIDE_IO3 ; BAIL OUT ON ERROR
PPIDE_IO1:
PUSH BC ; SAVE COUNTERS
CALL PPIDE_SELUNIT ; HARDWARE SELECTION OF TARGET UNIT
LD HL,(PPIDE_IOFNADR) ; GET PENDING IO FUNCTION ADDRESS
CALL JPHL ; ... AND CALL IT
JR NZ,PPIDE_IO2 ; IF ERROR, SKIP INCREMENT
; INCREMENT LBA
LD A,PPIDE_LBA ; LBA OFFSET
CALL LDHLIYA ; HL := IY + A, REG A TRASHED
CALL INC32HL ; INCREMENT THE VALUE
; INCREMENT DMA
LD HL,PPIDE_DSKBUF+1 ; POINT TO MSB OF BUFFER ADR
INC (HL) ; BUMP DMA BY
INC (HL) ; ... 512 BYTES
XOR A ; SIGNAL SUCCESS
PPIDE_IO2:
POP BC ; RECOVER COUNTERS
JR NZ,PPIDE_IO3 ; IF ERROR, BAIL OUT
INC C ; BUMP COUNT OF SECTORS READ
DJNZ PPIDE_IO1 ; LOOP AS NEEDED
PPIDE_IO3:
LD E,C ; SECTOR READ COUNT TO E
LD HL,(PPIDE_DSKBUF) ; CURRENT DMA TO HL
OR A ; SET FLAGS BASED ON RETURN CODE
RET Z ; RETURN IF SUCCESS
LD A,ERR_IO ; SIGNAL IO ERROR
OR A ; SET FLAGS
RET ; AND DONE
;
;
;
PPIDE_STATUS:
; RETURN UNIT STATUS
LD A,(IY+PPIDE_STAT) ; GET STATUS OF SELECTED DEVICE
OR A ; SET FLAGS
RET ; AND RETURN
;
;
;
PPIDE_DEVICE:
LD D,DIODEV_PPIDE ; D := DEVICE TYPE
LD E,(IY+PPIDE_DEV) ; E := PHYSICAL DEVICE NUMBER
LD C,%01111001 ; ATAPI ATTRIBUTES
LD A,(IY+PPIDE_TYPE) ; CHECK TYPE VALUE
CP PPIDE_TYPEATAPI ; ATAPI?
JR Z,PPIDE_DEVICE1 ; IF SO, DONE
LD C,%00110001 ; COMPACTFLASH ATTRIBUTES
BIT 0,(IY+PPIDE_MED) ; TEST CF BIT IN FLAGS
JR NZ,PPIDE_DEVICE1 ; IF SET, DONE
LD C,%00110000 ; GENERIC HARD DISK ATTRIBUTES
PPIDE_DEVICE1:
LD H,0 ; H := 0, DRIVER HAS NO MODES
LD L,(IY+PPIDE_DATALO) ; L := BASE I/O ADDRESS
XOR A ; SIGNAL SUCCESS
RET
;
; IDE_GETMED
;
PPIDE_MEDIA:
LD A,E ; GET FLAGS
OR A ; SET FLAGS
JR Z,PPIDE_MEDIA1 ; JUST REPORT CURRENT STATUS AND MEDIA
;
;CALL PPIDE_RESET ; RESET IDE INTERFACE
CALL PPIDE_INITUNIT ; RE-INITIALIZE UNIT
;
PPIDE_MEDIA1:
LD A,(IY+PPIDE_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
LD A,ERR_NOMEDIA ; NO MEDIA ERROR
OR A ; SET FLAGS
RET ; AND RETURN
;
;
;
PPIDE_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+PPIDE_LBA+0),L ; SAVE NEW LBA
LD (IY+PPIDE_LBA+1),H ; ...
LD (IY+PPIDE_LBA+2),E ; ...
LD (IY+PPIDE_LBA+3),D ; ...
XOR A ; SIGNAL SUCCESS
RET ; AND RETURN
;
;
;
PPIDE_CAP:
LD A,(IY+PPIDE_STAT) ; GET STATUS
PUSH AF ; SAVE IT
LD A,PPIDE_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
;
;
;
PPIDE_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 PPIDE_CAP ; GET TOTAL BLOCKS IN DE:HL, BLOCK SIZE TO BC
LD L,H ; DIVPPIDE 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 PPIDE_CAP STATUS
;
;=============================================================================
; FUNCTION SUPPORT ROUTINES
;=============================================================================
;
PPIDE_SETFEAT:
PUSH AF
#IF (PPIDETRACE >= 3)
CALL PPIDE_PRTPREFIX
PRTS(" SETFEAT$")
#ENDIF
LD A,(PPIDE_DRVHD)
;OUT (PPIDE_REG_DRVHD),A
CALL PPIDE_OUT
.DB PPIDE_REG_DRVHD
#IF (PPIDETRACE >= 3)
CALL PC_SPACE
CALL PRTHEXBYTE
#ENDIF
POP AF
;OUT (PPIDE_REG_FEAT),A ; SET THE FEATURE VALUE
CALL PPIDE_OUT
.DB PPIDE_REG_FEAT
#IF (PPIDETRACE >= 3)
CALL PC_SPACE
CALL PRTHEXBYTE
#ENDIF
LD A,PPIDE_CMD_SETFEAT ; CMD = SETFEAT
LD (PPIDE_CMD),A ; SAVE IT
JP PPIDE_RUNCMD ; RUN COMMAND AND EXIT
;
;
;
PPIDE_IDENTIFY:
#IF (PPIDETRACE >= 3)
CALL PPIDE_PRTPREFIX
PRTS(" IDDEV$")
#ENDIF
LD A,(PPIDE_DRVHD)
;OUT (PPIDE_REG_DRVHD),A
CALL PPIDE_OUT
.DB PPIDE_REG_DRVHD
#IF (PPIDETRACE >= 3)
CALL PC_SPACE
CALL PRTHEXBYTE
#ENDIF
LD A,PPIDE_CMD_IDDEV
LD (PPIDE_CMD),A
CALL PPIDE_RUNCMD_ND
RET NZ
;
CALL PPIDE_IN
.DB PPIDE_REG_STAT
BIT 3,A ; IS DRQ SET?
JP Z,PPIDE_NOMEDIA
;
LD HL,HB_WRKBUF
JP PPIDE_GETBUF ; EXIT THRU BUFRD
;
;
;
PPIDE_IDENTIFYPACKET:
#IF (PPIDETRACE >= 3)
CALL PPIDE_PRTPREFIX
PRTS(" IDPKTDEV$")
#ENDIF
LD A,(PPIDE_DRVHD)
;OUT (PPIDE_REG_DRVHD),A
CALL PPIDE_OUT
.DB PPIDE_REG_DRVHD
#IF (PPIDETRACE >= 3)
CALL PC_SPACE
CALL PRTHEXBYTE
#ENDIF
LD A,PPIDE_CMD_IDPKTDEV
LD (PPIDE_CMD),A
CALL PPIDE_RUNCMD_ND
RET NZ
;
CALL PPIDE_IN
.DB PPIDE_REG_STAT
BIT 3,A ; IS DRQ SET?
JP Z,PPIDE_NOMEDIA
;
LD HL,HB_WRKBUF
JP PPIDE_GETBUF ; EXIT THRU BUFRD
;
;
;
PPIDE_PACKET:
#IF (PPIDETRACE >= 3)
CALL PPIDE_PRTPREFIX
PRTS(" PACKET$")
#ENDIF
LD A,(PPIDE_DRVHD)
;OUT (PPIDE_REG_DRVHD),A
CALL PPIDE_OUT
.DB PPIDE_REG_DRVHD
#IF (PPIDETRACE >= 3)
CALL PC_SPACE
CALL PRTHEXBYTE
#ENDIF
XOR A ; ZERO
CALL PPIDE_OUT
.DB PPIDE_REG_FEAT ; FEATURE REG = 0
CALL PPIDE_OUT
.DB PPIDE_REG_BCL
LD A,8
CALL PPIDE_OUT
.DB PPIDE_REG_BCH ; BYTE COUNT = 512????
LD A,PPIDE_CMD_PACKET
LD (PPIDE_CMD),A
JP PPIDE_RUNCMD_ND
;
;
;
PPIDE_RDSEC:
;
#IF (PPIDETRACE >= 3)
CALL PPIDE_PRTPREFIX
PRTS(" READ$")
#ENDIF
LD A,(PPIDE_DRVHD)
;OUT (PPIDE_REG_DRVHD),A
CALL PPIDE_OUT
.DB PPIDE_REG_DRVHD
#IF (PPIDETRACE >= 3)
CALL PC_SPACE
CALL PRTHEXBYTE
#ENDIF
LD A,(IY+PPIDE_TYPE)
CP PPIDE_TYPEATA
JR Z,PPIDE_ATA_RDSEC
CP PPIDE_TYPEATAPI
JR Z,PPIDE_PKT_RDSEC
JP PPIDE_CMDERR
;
PPIDE_ATA_RDSEC:
#IF (PPIDETRACE >= 3)
PRTS(" ATA$")
#ENDIF
CALL PPIDE_SETADDR ; SETUP CYL, TRK, HEAD
LD A,PPIDE_CMD_READ
LD (PPIDE_CMD),A
CALL PPIDE_RUNCMD
RET NZ
LD HL,(PPIDE_DSKBUF)
JP PPIDE_GETBUF
;
PPIDE_PKT_RDSEC:
#IF (PPIDETRACE >= 3)
PRTS(" PKT$")
#ENDIF
; SETUP LBA
;
;;;#IF (DSKYENABLE)
;;; #IF (DSKYDSKACT)
LD A,PPIDE_LBA
CALL LDHLIYA
CALL HB_DSKACT ; SHOW ACTIVITY
;;; #ENDIF
;;;#ENDIF
;
; 3 BYTES, LITTLE ENDIAN -> BIG ENDIAN
LD HL,PPIDE_PKTCMD_RW10+3 ; START OF LBA FIELD IN CDB (MSB)
LD A,(IY+PPIDE_LBA+2) ; THIRD BYTE OF LBA FIELD IN CFG (MSB)
LD (HL),A
INC HL
LD A,(IY+PPIDE_LBA+1)
LD (HL),A
INC HL
LD A,(IY+PPIDE_LBA+0)
LD (HL),A
INC HL
LD HL,PPIDE_PKTCMD_RW10
LD A,SCSI_CMD_READ10
LD (HL),A
XOR A ; READ DIRECTION
LD (PPIDE_XFRDIR),A ; SAVE IT
CALL PPIDE_RUNPCMD
JP NZ,PPIDE_CHKPCMD
RET
;
;
;
PPIDE_WRSEC:
;
#IF (PPIDETRACE >= 3)
CALL PPIDE_PRTPREFIX
PRTS(" WRITE$")
#ENDIF
LD A,(PPIDE_DRVHD)
;OUT (PPIDE_REG_DRVHD),A
CALL PPIDE_OUT
.DB PPIDE_REG_DRVHD
#IF (PPIDETRACE >= 3)
CALL PC_SPACE
CALL PRTHEXBYTE
#ENDIF
LD A,(IY+PPIDE_TYPE)
CP PPIDE_TYPEATA
JR Z,PPIDE_ATA_WRSEC
CP PPIDE_TYPEATAPI
JR Z,PPIDE_PKT_WRSEC
JP PPIDE_CMDERR
;
PPIDE_ATA_WRSEC:
#IF (PPIDETRACE >= 3)
PRTS(" ATA$")
#ENDIF
CALL PPIDE_SETADDR ; SETUP CYL, TRK, HEAD
LD A,PPIDE_CMD_WRITE
LD (PPIDE_CMD),A
CALL PPIDE_RUNCMD
RET NZ
LD HL,(PPIDE_DSKBUF)
JP PPIDE_PUTBUF
;
PPIDE_PKT_WRSEC:
#IF (PPIDETRACE >= 3)
PRTS(" PKT$")
#ENDIF
; SETUP LBA
;
;;;#IF (DSKYENABLE)
;;; #IF (DSKYDSKACT)
LD A,PPIDE_LBA
CALL LDHLIYA
CALL HB_DSKACT ; SHOW ACTIVITY
;;; #ENDIF
;;;#ENDIF
;
; 3 BYTES, LITTLE ENDIAN -> BIG ENDIAN
LD HL,PPIDE_PKTCMD_RW10+3 ; START OF LBA FIELD IN CDB (MSB)
LD A,(IY+PPIDE_LBA+2) ; THIRD BYTE OF LBA FIELD IN CFG (MSB)
LD (HL),A
INC HL
LD A,(IY+PPIDE_LBA+1)
LD (HL),A
INC HL
LD A,(IY+PPIDE_LBA+0)
LD (HL),A
INC HL
LD HL,PPIDE_PKTCMD_RW10
LD A,SCSI_CMD_WRITE10
LD (HL),A
OR $FF ; WRITE DIRECTION
LD (PPIDE_XFRDIR),A ; SAVE IT
CALL PPIDE_RUNPCMD
JP NZ,PPIDE_CHKPCMD
RET
;
;
;
PPIDE_SETADDR:
;
;;;#IF (DSKYENABLE)
;;; #IF (DSKYDSKACT)
LD A,PPIDE_LBA
CALL LDHLIYA
CALL HB_DSKACT ; SHOW ACTIVITY
;;; #ENDIF
;;;#ENDIF
; SEND 3 LOWEST BYTES OF LBA IN REVERSE ORDER
; IDE_REG_LBA3 HAS ALREADY BEEN SET
; HSTLBA2-0 --> IDE_REG_LBA2-0
LD A,(IY+PPIDE_LBA+2)
#IF (PPIDETRACE >= 3)
CALL PC_SPACE
CALL PRTHEXBYTE
#ENDIF
CALL PPIDE_OUT
.DB PPIDE_REG_LBA2
;
LD A,(IY+PPIDE_LBA+1)
#IF (PPIDETRACE >= 3)
CALL PC_SPACE
CALL PRTHEXBYTE
#ENDIF
CALL PPIDE_OUT
.DB PPIDE_REG_LBA1
;
LD A,(IY+PPIDE_LBA+0)
#IF (PPIDETRACE >= 3)
CALL PC_SPACE
CALL PRTHEXBYTE
#ENDIF
CALL PPIDE_OUT
.DB PPIDE_REG_LBA0
;
LD A,1
#IF (PPIDETRACE >= 3)
CALL PC_SPACE
CALL PRTHEXBYTE
#ENDIF
CALL PPIDE_OUT
.DB PPIDE_REG_COUNT
;
RET
;
;=============================================================================
; COMMAND PROCESSING
;=============================================================================
;
; RUN AN ATA COMMAND. THERE ARE TWO ENTRY POINTS. THE NORMAL ENTRY
; POINT WILL WAIT FOR DRIVE READY. THE _ND ENTRY POINT ONLY WAITS
; FOR THE DEVICE TO BE NOT BUSY. THE CORRECT ENTRY POINT DEPENDS ON
; THE COMMAND.
;
PPIDE_RUNCMD_ND:
CALL PPIDE_WAITBSY ; WAIT WHILE DEVICE BUSY
RET NZ ; BAIL OUT ON TIMEOUT
JR PPIDE_RUNCMD1 ; CONTINUE
PPIDE_RUNCMD:
CALL PPIDE_WAITRDY ; WAIT FOR DRIVE READY
RET NZ ; BAIL OUT ON TIMEOUT
;
PPIDE_RUNCMD1:
LD A,(PPIDE_CMD) ; GET THE COMMAND
#IF (PPIDETRACE >= 3)
CALL PC_SPACE
CALL PRTHEXBYTE
#ENDIF
;OUT (PPIDE_REG_CMD),A ; SEND IT (STARTS EXECUTION)
CALL PPIDE_OUT
.DB PPIDE_REG_CMD
#IF (PPIDETRACE >= 3)
PRTS(" -->$")
#ENDIF
;
CALL PPIDE_WAITBSY ; WAIT FOR DRIVE READY (COMMAND DONE)
RET NZ ; BAIL OUT ON TIMEOUT
;
CALL PPIDE_GETRES
JP NZ,PPIDE_CMDERR
RET
;
; PACKET COMMAND PROCESSOR
; HL: ADDRESS OF PACKET COMMAND BUFFER
;
PPIDE_RUNPCMD:
PUSH HL
CALL PPIDE_PACKET
POP HL
RET NZ ; BAIL OUT ON ERROR
;
#IF (PPIDETRACE >= 3)
PRTS("\r\nPKTCMD:$")
PUSH HL
POP DE
LD A,12
CALL PRTHEXBUF
#ENDIF
;
; IF ZIP DRIVE HAS FALLEN ASLEEP, THEN IT WILL NEED EXTRA
; TIME HERE TO WAKE UP BEFORE ACCEPTING THE COMMAND. USE
; LONG TIMEOUT TO ACCOMMODATE THIS.
LD DE,(PPIDE_TIMEOUT) ; GET CURRENT TIMEOUT
PUSH DE ; SAVE IT
LD DE,PPIDE_TOSLOW ; SLOW TIMEOUT FOR THIS
LD (PPIDE_TIMEOUT),DE ; SET IT
LD B,6 ; 6 WORDS ALWAYS
CALL PPIDE_PUT
POP DE ; RECOVER TIMEOUT
LD (PPIDE_TIMEOUT),DE ; SET IT
RET NZ
;
CALL PPIDE_IN
.DB PPIDE_REG_STAT
BIT 3,A ; IS DRQ SET?
RET Z ; IF NOT, ALL DONE
;
CALL PPIDE_IN
.DB PPIDE_REG_BCL
LD C,A
CALL PPIDE_IN
.DB PPIDE_REG_BCH
LD B,A
;
; BELOW ASSUMES MAX TRANSFER OF 512 BYTES!!!
PUSH BC ; SAVE BYTE COUNT
SRL B ; CONVERT
RR C ; ... TO WORDS
LD B,C
;LD HL,HB_WRKBUF ; SET XFR BUFFER
LD HL,(PPIDE_DSKBUF) ; SET XFR BUFFER
LD A,(PPIDE_XFRDIR)
OR A
JR NZ,PPIDE_RUNPCMD2 ; NZ = WRITE
CALL PPIDE_GET ; GET SOME DATA
JR PPIDE_RUNPCMD3
PPIDE_RUNPCMD2:
CALL PPIDE_PUT ; PUT SOME DATA
PPIDE_RUNPCMD3:
POP BC ; RESTORE BYTE COUNT
RET NZ ; BAIL OUT ON ERRORS
;
XOR A
RET
;
; THE FOLLOWING IS USED TO ASSESS ANY ERROR THAT OCCURS DURING
; RUNCMD AND SET AN APPROPRIATE ERROR CODE.
;
PPIDE_CHKPCMD:
;
LD HL,HB_WRKBUF
LD (PPIDE_DSKBUF),HL
LD HL,PPIDE_PKTCMD_SENSE
CALL PPIDE_RUNPCMD
RET NZ
;
CALL PPIDE_IN
.DB PPIDE_REG_BCL
;
#IF (PPIDETRACE >= 3)
CALL NEWLINE
LD DE,HB_WRKBUF
CALL PRTHEXBUF
#ENDIF
;
; ASSESS SENSE DATA AND SET APPROPRIATE ERROR
LD A,(HB_WRKBUF+12)
CP $3A
JP Z,PPIDE_NOMEDIA
CP $04
JP Z,PPIDE_NOTRDY
;
JP PPIDE_CMDERR
;
; HL=BUFFER
;
PPIDE_GETBUF:
LD B,0
; FALL THRU!!!
;
; HL=BUFFER
; B=WORD COUNT, 0=256
;
PPIDE_GET:
#IF (PPIDETRACE >= 3)
PRTS(" GET$")
#ENDIF
;
; WAIT FOR BUFFER
PUSH BC
PUSH HL
CALL PPIDE_WAITDRQ ; WAIT FOR BUFFER READY
POP HL
POP BC
RET NZ ; BAIL OUT IF TIMEOUT
;
; SETUP PPI TO READ
LD A,PPIDE_DIR_READ ; SET DATA BUS DIRECTION TO READ
;OUT (PPIDE_REG_PPI),A ; DO IT
LD C,(IY+PPIDE_PPI) ; PPI CONTROL WORD
EZ80_IO
OUT (C),A ; WRITE IT
;
; SELECT READ/WRITE IDE REGISTER
LD A,PPIDE_REG_DATA ; DATA REGISTER
;OUT (PPIDE_REG_CTL),A ; DO IT
LD C,(IY+PPIDE_CTL) ; SET IDE ADDRESS
EZ80_IO
OUT (C),A ; DO IT
LD E,A ; E := READ UNASSERTED
XOR PPIDE_CTL_DIOR ; SWAP THE READ LINE BIT
LD D,A ; D := READ ASSERTED
;
LD A,B ; LOOP COUNTER IN A
LD C,(IY+PPIDE_CTL) ; SET IDE ADDRESS
BIT 1,(IY+PPIDE_ACC) ; 8 BIT?
JR Z,PPIDE_GET1 ; IF NOT, DO 16 BIT
CALL PPIDE_GET8 ; 8-BIT READ
JR PPIDE_GET2 ; CONTINUE
PPIDE_GET1:
CALL PPIDE_GET16 ; 16-0BIT READ
PPIDE_GET2:
CALL PPIDE_WAITRDY ; PROBLEMS IF THIS IS REMOVED!
RET NZ
CALL PPIDE_GETRES
JP NZ,PPIDE_IOERR
RET
;
PPIDE_GET8: ; 8 BIT WIDE READ LOOP
; ENTER W/ C = PPIDE_REG_CTL
EZ80_IO
OUT (C),D ; ASSERT READ
DEC C ; CTL -> MSB
DEC C ; MSB -> LSB
EZ80_IO
INI ; READ FROM LSB
INC C ; LSB -> MSB
INC C ; MSB -> CTL
EZ80_IO
OUT (C),E ; DEASSERT READ
EZ80_IO
OUT (C),D ; ASSERT READ
DEC C ; CTL -> MSB
DEC C ; MSB -> LSB
EZ80_IO
INI ; READ FROM LSB
INC C ; LSB -> MSB
INC C ; MSB -> CTL
EZ80_IO
OUT (C),E ; DEASSERT READ
DEC A
JR NZ,PPIDE_GET8 ; LOOP UNTIL DONE
RET
;
PPIDE_GET16: ; 16 BIT WIDE READ LOOP
; ENTER W/ C = PPIDE_REG_CTL
EZ80_IO
OUT (C),D ; ASSERT READ
DEC C ; CTL -> MSB
DEC C ; MSB -> LSB
EZ80_IO
INI ; READ FROM LSB
INC C ; LSB -> MSB
EZ80_IO
INI ; READ MSB FOR 16 BIT
INC C ; MSB -> CTL
EZ80_IO
OUT (C),E ; DEASSERT READ
DEC A
JR NZ,PPIDE_GET16 ; LOOP UNTIL DONE
RET
;
; HL=BUFFER
;
PPIDE_PUTBUF:
LD B,0
; FALL THRU!!!
;
; HL=BUFFER
; B=WORD COUNT, 0=256
;
PPIDE_PUT:
#IF (PPIDETRACE >= 3)
PRTS(" PUT$")
#ENDIF
;
; WAIT FOR BUFFER
PUSH BC
PUSH HL
CALL PPIDE_WAITDRQ ; WAIT FOR BUFFER READY
POP HL
POP BC
RET NZ ; BAIL OUT IF TIMEOUT
;
; SETUP PPI TO WRITE
LD A,PPIDE_DIR_WRITE ; SET DATA BUS DIRECTION TO WRITE
;OUT (PPIDE_REG_PPI),A ; DO IT
LD C,(IY+PPIDE_PPI) ; PPI CONTROL WORD
EZ80_IO
OUT (C),A ; WRITE IT
;
; SELECT READ/WRITE IDE REGISTER
LD A,PPIDE_REG_DATA ; DATA REGISTER
;OUT (PPIDE_REG_CTL),A ; DO IT
LD C,(IY+PPIDE_CTL) ; SET IDE ADDRESS
EZ80_IO
OUT (C),A ; DO IT
LD E,A ; E := WRITE UNASSERTED
XOR PPIDE_CTL_DIOW ; SWAP THE READ LINE BIT
LD D,A ; D := WRITE ASSERTED
;
; LOOP SETUP
LD A,B ; LOOP COUNTER IN A
LD C,(IY+PPIDE_CTL) ; SET IDE ADDRESS
BIT 1,(IY+PPIDE_ACC) ; 8 BIT?
JR Z,PPIDE_PUT1 ; IF NOT, DO 16 BIT
CALL PPIDE_PUT8 ; SECOND PASS (LAST 256 BYTES)
JR PPIDE_PUT2 ; CONTINUE
PPIDE_PUT1:
CALL PPIDE_PUT16 ; FIRST PASS (FIRST 256 BYTES)
PPIDE_PUT2:
CALL PPIDE_WAITRDY ; PROBLEMS IF THIS IS REMOVED!
RET NZ
CALL PPIDE_GETRES
JP NZ,PPIDE_IOERR
RET
;
PPIDE_PUT8: ; 8 BIT WIDE WRITE LOOP
DEC C ; CTL -> MSB
DEC C ; MSB -> LSB
EZ80_IO
OUTI ; WRITE NEXT BYTE (LSB)
INC C ; LSB -> MSB
INC C ; MSB -> CTL
EZ80_IO
OUT (C),D ; ASSERT WRITE
EZ80_IO
OUT (C),E ; DEASSERT WRITE
DEC C ; CTL -> MSB
DEC C ; MSB -> LSB
EZ80_IO
OUTI ; WRITE NEXT BYTE (LSB)
INC C ; LSB -> MSB
INC C ; MSB -> CTL
EZ80_IO
OUT (C),D ; ASSERT WRITE
EZ80_IO
OUT (C),E ; DEASSERT WRITE
DEC A
JR NZ,PPIDE_PUT8 ; LOOP UNTIL DONE
RET
;
PPIDE_PUT16: ; 16 BIT WIDE WRITE LOOP
DEC C ; CTL -> MSB
DEC C ; MSB -> LSB
EZ80_IO
OUTI ; WRITE NEXT BYTE (LSB)
INC C ; LSB -> MSB
EZ80_IO
OUTI ; WRITE NEXT BYTE (MSB)
INC C ; MSB -> CTL
EZ80_IO
OUT (C),D ; ASSERT WRITE
EZ80_IO
OUT (C),E ; DEASSERT WRITE
DEC A
JR NZ,PPIDE_PUT16 ; LOOP UNTIL DONE
RET
;
;
;
PPIDE_GETRES:
;IN A,(PPIDE_REG_STAT) ; READ STATUS
CALL PPIDE_IN
.DB PPIDE_REG_STAT
#IF (PPIDETRACE >= 3)
CALL PC_SPACE
CALL PRTHEXBYTE
#ENDIF
AND %00000001 ; ERROR BIT SET?
RET Z ; NOPE, RETURN WITH ZF
;
;IN A,(PPIDE_REG_ERR) ; READ ERROR REGISTER
CALL PPIDE_IN
.DB PPIDE_REG_ERR
#IF (PPIDETRACE >= 3)
CALL PC_SPACE
CALL PRTHEXBYTE
#ENDIF
OR $FF ; FORCE NZ TO SIGNAL ERROR
RET ; RETURN
;
;=============================================================================
; HARDWARE INTERFACE ROUTINES
;=============================================================================
;
; RESET ALL DEVICES ON BUS
;
PPIDE_RESET:
#IF (PPIDETRACE >= 3)
CALL PPIDE_PRTPREFIX
PRTS(" RESET$")
#ENDIF
;
; HARD RESET
;
; RESET LINE IS NORMALLY PULSED AT POWER ON. HOWEVER, THIS IS NOT
; DONE FOR PPIDE DEVICES, SO WE DO IT NOW.
;
; SETUP PPI TO READ
LD A,PPIDE_DIR_READ ; SET DATA BUS DIRECTION TO READ
;OUT (PPIDE_REG_PPI),A ; DO IT
LD C,(IY+PPIDE_PPI) ; PPI CONTROL WORD
EZ80_IO
OUT (C),A ; WRITE IT
;
; IF A DSKYNG IS ACTIVE AND IS ON THE SAME PPI PORT AS THE PPIDE BEING
; RESET, THEN THE DSKYNG WILL ALSO BE RESET. SO, THE RESET CODE IS
; BRACKETED WITH CODE TO SAVE AND RESTORE THE STATE OF THE DSKYNG.
; THERE IS NO CHECK FOR THE SPECIFIC PPI PORT SINCE IT DOES NO HARM
; IF THE DSKYNG IS SAVED AND RESTORED.
;
;;;#IF (DSKYENABLE)
#IF (PKDENABLE)
; SAVE CONTENTS OF DSKYNG DISPLAY ACROSS RESET
LD A,(PKD_PRESENT) ; GET PKD PRESENCE FLAG
OR A ; TEST FOR ZERO
JR Z,PPIDE_RESET_PKD1 ; IF ZERO, NOT THERE, BYPASS
LD B,8 ; LENGTH
LD C,0 ; START
LD HL,PKD_BUF ; BUFFER
CALL PKD_GETSTR ; GET CURRENT DISPLAY TO BUF
PPIDE_RESET_PKD1:
#ENDIF
;;;#ENDIF
;
; PULSE IDE RESET LINE
#IF (PPIDETRACE >= 3)
PRTS(" HARD$")
#ENDIF
LD A,PPIDE_CTL_RESET
;OUT (PPIDE_REG_CTL),A
LD C,(IY+PPIDE_CTL) ; SET IDE ADDRESS
EZ80_IO
OUT (C),A
LD DE,20 ; DELAY 320US (SPEC IS >= 25US)
CALL VDELAY
XOR A
;OUT (PPIDE_REG_CTL),A
EZ80_IO
OUT (C),A
LD DE,20
CALL VDELAY
;
;;;#IF (DSKYENABLE)
#IF (PKDENABLE)
; REININT DSKYNG AND RESTORE CONTENTS
LD A,(PKD_PRESENT) ; GET PKD PRESENCE FLAG
OR A ; TEST FOR ZERO
JR Z,PPIDE_RESET_PKD2 ; IF ZERO, NOT THERE, BYPASS
CALL PKD_REINIT ; REINIT PKD
LD B,8 ; LENGTH
LD C,0 ; START
LD HL,PKD_BUF ; BUFFER
CALL PKD_PUTSTR ; RESTORE DISPLAY CONTENTS
PPIDE_RESET_PKD2:
#ENDIF
;;;#ENDIF
;
; SOME CF CARDS AND CF CARD EMULATORS NEED A LITTLE TIME TO
; "BOOT" THEIR INTERNAL ELECTRONICS, SO THEY CANNOT ASSERT BUSY
; IMMEDIATELY. A SMALL WAIT IS PERFORMED HERE TO GIVE SUCH DEVICES
; A BETTER CHANCE TO SUCCEED LATER.
;
; LD DE,150000 / 16 ;
LD DE,300000 / 16 ;
CALL VDELAY ; SMALL DELAY
;
JR PPIDE_RESET3 ; SKIP SOFT RESET
;
; SOFT RESET
;
; RC CANNOT ACCESS DEVICE CONTROL REG, SO SKIP THIS
;
PPIDE_RESET2:
; INITIATE SOFT RESET
#IF (IDETRACE >= 3)
PRTS(" SOFT$")
#ENDIF
LD A,%00001110 ; ASSERT RESET, NO INTERRUPTS
;OUT (PPIDE_REG_CTRL),A
CALL PPIDE_OUT
.DB PPIDE_REG_CTRL
LD DE,20 ; DELAY 320US (SPEC IS >= 25US)
CALL VDELAY
;
PPIDE_RESET3:
;
; CONFIGURE OPERATION AND END SOFT RESET
;
#IF (PPIDETRACE >= 3)
PRTS(" CONFIG$")
#ENDIF
LD A,%00001010 ; DEASSERT RESET, NO INTERRUPTS
;OUT (PPIDE_REG_CTRL),A
CALL PPIDE_OUT
.DB PPIDE_REG_CTRL
LD DE,20 ; DELAY 320US (SPEC IS >= 25US)
CALL VDELAY
;
PPIDE_RESET5:
LD HL,PPIDE_TONORM ; NORMAL TIMEOUT NOW
LD (PPIDE_TIMEOUT),HL ; AND RESTORE IT
;
; 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+PPIDE_ACC) ; MASTER?
CALL Z,PPIDE_GOPARTNER ; IF NOT, SWITCH TO MASTER
CALL PPIDE_INITUNIT ; INIT CURRENT UNIT
CALL PPIDE_GOPARTNER ; POINT TO SLAVE
CALL PPIDE_INITUNIT ; INIT PARTNER UNIT
POP IY ; RECOVER ORIG CFG PTR
;
XOR A ; SIGNAL SUCCESS
RET ; AND DONE
;
;
;
PPIDE_INITUNIT:
CALL PPIDE_SELUNIT ; SELECT UNIT
RET NZ ; ABORT IF ERROR
CALL PPIDE_PROBE ; DO PROBE
RET NZ ; JUST RETURN IF NOTHING THERE
JP PPIDE_INITDEV ; EXIT VIA INITDEV
;
; TAKE ANY ACTIONS REQUIRED TO SELECT DESIRED PHYSICAL UNIT
;
PPIDE_SELUNIT:
#IF (PPIDETRACE >= 3)
CALL PPIDE_PRTPREFIX
PRTS(" SELUNIT$")
#ENDIF
LD A,(IY+PPIDE_MODE)
CP PPIDEMODE_S100A
JR Z,PPIDE_SELS100
CP PPIDEMODE_S100B
JR Z,PPIDE_SELS100
JR PPIDE_SELUNIT0
;
PPIDE_SELS100:
LD C,(IY+PPIDE_PPI)
INC C
SUB PPIDEMODE_S100A
OUT (C),A
;
PPIDE_SELUNIT0:
BIT 0,(IY+PPIDE_ACC) ; MASTER?
JR Z,PPIDE_SELUNIT1 ; HANDLE SLAVE
LD A,PPIDE_DRVMASTER ; MASTER
#IF (PPIDETRACE >= 3)
PRTS(" MASTER$")
#ENDIF
JR PPIDE_SELUNIT2
PPIDE_SELUNIT1:
LD A,PPIDE_DRVSLAVE ; SLAVE
#IF (PPIDETRACE >= 3)
PRTS(" SLAVE$")
#ENDIF
PPIDE_SELUNIT2:
LD (PPIDE_DRVHD),A ; SAVE IT
XOR A ; SUCCESS
RET
;
;
;
PPIDE_PROBE:
;
; PROBE FOR A DRIVE ON THE INTERFACE (EITHER MASTER OR SLAVE).
; IDEALLY, THIS IS BEING CALLED IMMEDIATELY AFTER A HARD OR SOFT
; INTERFACE RESET. HOWEVER, THERE ARE SOME HARDWARE IMPLEMENTATTIONS
; WHICH ARE CAPABLE OF NEITHER A HARD NOR SOFT RESET. SO THIS
; CODE SHOULD TRY TO HANDLE THE SCENARIO WHERE NO INTERFACE RESET
; HAS OCCURRED.
;
#IF (PPIDETRACE >= 3)
CALL PPIDE_PRTPREFIX
PRTS(" PROBE$") ; LABEL FOR IO ADDRESS
#ENDIF
;
#IF (PPIDETRACE >= 3)
CALL PPIDE_IN
.DB PPIDE_REG_STAT
CALL PC_SPACE
CALL PRTHEXBYTE
#ENDIF
;
; SELECT DEVICE (MASTER/SLAVE)
LD A,(PPIDE_DRVHD)
;OUT (IDE_REG_DRVHD),A
CALL PPIDE_OUT
.DB PPIDE_REG_DRVHD
#IF (PPIDETRACE >= 3)
CALL PC_SPACE
CALL PRTHEXBYTE
#ENDIF
CALL DELAY ; DELAY ~16US
;
; IF WE GET HERE AND THE DRIVE IS STILL INITIALIZING, WE NEED TO
; WAIT UNTIL THE DRIVE IS READY. IN THIS CASE BUSY *WILL* BE HIGH.
; BASED ON TESTING, DRDY AND DSC VALUES VARY. EVERYTHING ELSE SEEMS
; TO BE ZERO. SO, WE FILTER OUT DRDY & DSC, THEN LOOK FOR BUSY=1
; AND ALL ELSE ZERO. THIS GENERALLY AVOIDS VALUES THAT ARE TYPICAL
; FOR FLOATING PORTS AND SO CAN BE USED TO DETERMINE IF WE NEED TO
; WAIT FOR THE DEVICE TO BE READY. THIS WAIT IS MANDATORY BECAUSE
; SOME (IF NOT ALL) DEVICES WILL NOT PERSIST REGISTER VALUES UNTIL
; THE DRIVE IS READY.
;
; FIRST, WRITE A $7F VALUE TO THE PPIDE STATUS REGISTER. IF
; AN IDE DEVICE EXISTS, THIS WILL DO NO HARM. IF NOT, THIS
; WILL HELP AVOID A FALSE POSITIVE (STALL).
LD A,$7F
CALL PPIDE_OUT
.DB PPIDE_REG_DATA
;
CALL PPIDE_IN
.DB PPIDE_REG_STAT
#IF (PPIDETRACE >= 3)
CALL PC_SPACE
CALL PRTHEXBYTE
#ENDIF
;
AND %10101111 ; FILTER OUT DRDY & DSC
CP $80 ; INIT IN PROGRESS?
JR NZ,PPIDE_PROBE1 ; IF NOT, SKIP AHEAD
;
#IF (PPIDETRACE >= 3)
PRTS(" WAIT$")
#ENDIF
;
LD HL,(PPIDE_TIMEOUT) ; GET CURRENT TIMEOUT
PUSH HL ; SAVE IT
LD HL,PPIDE_TOSLOW ; SLOW TIMEOUT FOR THIS
LD (PPIDE_TIMEOUT),HL ; SET IT
CALL PPIDE_WAITBSY ; WAIT FOR BUSY TO CLEAR
POP HL ; RECOVER TIMEOUT
LD (PPIDE_TIMEOUT),HL ; SET IT
;
#IF (PPIDETRACE >= 3)
CALL PPIDE_IN
.DB PPIDE_REG_STAT
CALL PC_SPACE
CALL PRTHEXBYTE
#ENDIF
;
; TEST FOR PRESENCE OF IDE REGISTERS. USE LBA0/1 TO SEE
; IF VALUE CAN BE PERSISTED. THE USE OF BOTH LBA0 AND LBA1
; IS TO MAINTAIN CONSISTENCY WITH THE THE PPIDE DRIVER BECAUSE
; PPI ITSELF WILL PERSIST THE LAST VALUE WRITTEN, SO WE USE
; MULTIPLE REGISTERS TO WORK AROUND THIS FALSE POSITIVE.
;
PPIDE_PROBE1:
; $AA -> LBA0
LD A,$AA
CALL PPIDE_OUT
.DB PPIDE_REG_LBA0
;
; $55 => LBA1
LD A,$55
CALL PPIDE_OUT
.DB PPIDE_REG_LBA1
;
; TEST LBA0 == $AA
CALL PPIDE_IN
.DB PPIDE_REG_LBA0
#IF (PPIDETRACE >= 3)
CALL PC_SPACE
CALL PRTHEXBYTE
#ENDIF
CP $AA
JP NZ,PPIDE_NOMEDIA
;
; TEST LBA1 == $55
CALL PPIDE_IN
.DB PPIDE_REG_LBA1
#IF (PPIDETRACE >= 3)
CALL PC_SPACE
CALL PRTHEXBYTE
#ENDIF
CP $55
JP NZ,PPIDE_NOMEDIA
;
#IF (PPIDETRACE >= 3)
CALL PPIDE_REGDUMP
#ENDIF
;
XOR A
RET
;
; (RE)INITIALIZE DEVICE
;
PPIDE_INITDEV:
;
#IF (PPIDETRACE >= 3)
CALL PPIDE_PRTPREFIX
PRTS(" INITDEV$") ; LABEL FOR IO ADDRESS
#ENDIF
;
#IF (PPIDETRACE >= 3)
CALL PPIDE_REGDUMP
#ENDIF
;
; ON ENTRY, WE HAVE ALREADY CHECKED THAT THE BUSY BIT IS CLEARED AND
; DRDY SHOULD BE SET. IF DRDY IS NOT SET, IF COULD MEAN EITHER A
; NON-EXISTENT SLAVE DEVICE OR AN ATAPI DEVICE. TO AVOID UNNECESSARY
; TIMEOUTS, WE CHECK FOR DRDY. IF IT IS NOT SET, THEN WE ASSUME THIS
; MUST BE AN ATAPI DEVICE AND GO TRY TO DO THE ATAPI INITIALIZATION.
; IF THIS WAS ACTUALLY A NON-EXISTENT SLAVE, THE ATAPI INITIALIZATION
; WILL HANDLE THIS PRETTY WELL.
;
CALL PPIDE_IN
.DB PPIDE_REG_STAT
BIT 6,A ; DRDY?
JR Z,PPIDE_INITPDEV ; ODD, MIGHT BE ATAPI
;
; WE NEED TO SETUP 8-BIT MODE BEFORE DOING ANYTHING ELSE
;
BIT 1,(IY+PPIDE_ACC) ; 8 BIT ACCESS?
JR Z,PPIDE_INITDEV0 ; NO, DO 16 BIT INIT
LD A,PPIDE_FEAT_ENABLE8BIT ; FEATURE VALUE = ENABLE 8-BIT PIO
CALL PPIDE_SETFEAT ; SET FEATURE
RET NZ ; BAIL OUT ON ERROR
JR PPIDE_INITDEV00 ; CONTINUE
;
PPIDE_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,PPIDE_FEAT_DISABLE8BIT ; FEATURE VALUE = ENABLE 8-BIT PIO
CALL PPIDE_SETFEAT ; SET FEATURE, IGNORE ERRORS
;
PPIDE_INITDEV00:
;
; WE NOW USE AN IDENTIFY DEVICE COMMAND TO CONFIRM THE
; DEVICE IS REALLY THERE AND GET SOME ATTRIBUTES. IF THE
; COMMAND FAILS, IT MAY BE THAT WE HAVE AN ATAPI DEVICE AND
; SO WE GO TO THE ATAPI INITIALIZATION ON FAILURE.
CALL PPIDE_IDENTIFY ; EXECUTE PPIDENTIFY COMMAND
JR NZ,PPIDE_INITPDEV ; TRY ATAPI ON FAILURE
;
; DECLARE WE ARE ATA
LD A,PPIDE_TYPEATA ; OTHERWISE TYPE=ATA
LD (IY+PPIDE_TYPE),A ; SET IT IN INSTANCE DATA
;
LD DE,HB_WRKBUF ; POINT TO BUFFER
#IF (PPIDETRACE >= 4)
CALL DUMP_BUFFER ; DUMP IT IF DEBUGGING
#ENDIF
;
LD (IY+PPIDE_MED),0 ; CLEAR MEDIA FLAGS
;
#IF (PPIDETRACE >= 3)
CALL PPIDE_PRTPREFIX
PRTS(" SIG=0x$")
LD BC,(HB_WRKBUF)
CALL PRTHEXWORD
#ENDIF
;
; DETERMINE IF COMPACTFLASH MEDIA
LD A,(HB_WRKBUF+(83*2)) ; LOW BYTE OF WORD 83
BIT 2,A ; TEST CFA FEATURE SET BIT
JR Z,PPIDE_INITDEV1 ; IF NOT, SKIP
SET 0,(IY+PPIDE_MED) ; ELSE SET FLAGS BIT FOR CF MEDIA
;
PPIDE_INITDEV1:
; DETERMINE IF LBA CAPABLE
LD A,(HB_WRKBUF+98+1) ; HIGH BYTE OF WORD 49
BIT 1,A ; CHECK THE LBA BIT
JR Z,PPIDE_INITDEV2 ; NOT SET, BYPASS
SET 1,(IY+PPIDE_MED) ; SET FLAGS BIT FOR LBA
;
PPIDE_INITDEV2:
; GET DEVICE CAPACITY AND SAVE IT
LD A,PPIDE_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
;
; RECORD STATUS OK
XOR A ; A := 0 (STATUS = OK)
LD (IY+PPIDE_STAT),A ; SAVE IT
;
RET ; RETURN, A=0, Z SET
;
; (RE)INITIALIZE PACKET DEVICE
;
PPIDE_INITPDEV:
;
#IF (PPIDETRACE >= 3)
CALL PPIDE_PRTPREFIX
PRTS(" INITPDEV$") ; LABEL FOR IO ADDRESS
#ENDIF
;
CALL PPIDE_IDENTIFYPACKET ; EXECUTE IDENTIFY COMMAND
RET NZ ; BAIL OUT ON ERROR
;
; DECLARE WE ARE ATAPI
LD A,PPIDE_TYPEATAPI ; OTHERWISE TYPE=ATAPI
LD (IY+PPIDE_TYPE),A ; SET IT IN INSTANCE DATA
;
LD DE,HB_WRKBUF ; POINT TO BUFFER
#IF (PPIDETRACE >= 4)
CALL DUMP_BUFFER ; DUMP IT IF DEBUGGING
#ENDIF
;
LD (IY+PPIDE_MED),0 ; CLEAR FLAGS
SET 1,(IY+PPIDE_MED) ; SET FLAGS BIT FOR LBA (ASSUMED)
;
; WAIT FOR UNIT READY
LD B,0 ; MAX LOOPS
LD C,4 ; MAX ERRORS
PPIDE_INITPDEV1:
DEC B ; CHECK LOOP COUNTER EXCEEDED
JP Z,PPIDE_NOMEDIA ; TREAT AS NO MEDIA
PUSH BC ; SAVE LOOP CONTROL
LD HL,PPIDE_PKTCMD_TSTRDY ; TEST UNIT READY
XOR A ; READ DIRECTION
LD (PPIDE_XFRDIR),A ; SAVE IT
CALL PPIDE_RUNPCMD ; ISSUE PACKET COMMAND
CALL NZ,PPIDE_CHKPCMD ; IF ERROR, DIAGNOSE IT
POP BC ; RESTORE LOOP CONTROL
JR Z,PPIDE_INITPDEV2 ; IF NO ERROR, CONTINUE
CP PPIDE_STNOMEDIA ; EXPLICIT NO MEDIA RESULT?
RET Z ; EXIT REPORTING NO MEDIA
CP PPIDE_STNOTRDY ; BECOMING READY?
JR Z,PPIDE_INITDEVP1A ; IF SO, NOT AN ERROR, LOOP
DEC C ; DEC ERROR LIMIT
RET Z ; BAIL OUT, ERR LIMIT EXCEEDED
JR PPIDE_INITPDEV1 ; LOOP
PPIDE_INITDEVP1A:
LD DE,100000/16 ; WAIT 1/10 SECOND
CALL VDELAY ; DO IT
JR PPIDE_INITPDEV1 ; AND LOOP
;
PPIDE_INITPDEV2:
#IF (PPIDETRACE >= 3)
LD A,B
NEG
PRTS("\r\nLOOPS=$")
CALL PRTHEXBYTE
#ENDIF
;
; GET AND RECORD CAPACITY
LD HL,HB_WRKBUF
LD (PPIDE_DSKBUF),HL
LD HL,PPIDE_PKTCMD_RDCAP
XOR A ; READ DIRECTION
LD (PPIDE_XFRDIR),A ; SAVE IT
CALL PPIDE_RUNPCMD
JP NZ,PPIDE_CHKPCMD
;
#IF (PPIDETRACE >= 3)
PRTS("\r\nRDCAP:$")
LD A,8
LD DE,HB_WRKBUF
CALL PRTHEXBUF
#ENDIF
;
; CAPACITY IS RETURNED IN A 4 BYTE, BIG ENDIAN FIELD AND
; INDICATES THE LAST LBA VALUE. WE NEED TO CONVERT THIS TO
; LITTLE ENDIAN AND INCREMENT THE VALUE TO MAKE IT A CAPACITY
; COUNT INSTEAD OF A LAST LBA VALUE.
LD A,PPIDE_MEDCAP ; OFFSET IN CFG FOR CAPACITY
CALL LDHLIYA ; POINTER TO HL
PUSH HL ; SAVE IT
LD HL,HB_WRKBUF ; POINT TO VALUE IN CMD RESULT
CALL LD32 ; LOAD IT TO DE:HL
LD A,L ; FLIP BYTES
LD L,D ; ... BIG ENDIAN
LD D,A ; ... TO LITTLE ENDIAN
LD A,H
LD H,E
LD E,A
CALL INC32 ; INCREMENT TO FINAL VALUE
POP BC ; RECOVER SAVE LOCATION
CALL ST32 ; STORE VALUE
;
; CHECK BLOCK LENGTH. WE CURRENTLY ONLY SUPPORT 512 BYTE
; BLOCKS. CD-ROM DEVICES (WHICH USE 2k BLOCKS) WILL FAIL
; HERE AS NOT SUPPORTED.
LD HL,HB_WRKBUF+4 ; POINT TO BLK SIZE IN RESULT
CALL LD32 ; LOAD IT TO DE:HL
; VALUE IS BIG ENDIAN, SO LH:ED MUST BE EXACTLY 0000:0200
LD A,L ; CHECK THAT LH
OR H ; ... IS ZERO
JP NZ,PPIDE_NOTSUP ; IF NOT, FAIL AS NOT SUP
LD A,D ; LOAD D
OR A ; SET FLAGS
JP NZ,PPIDE_NOTSUP ; IF NOT ZERO, FAIL AS NOT SUP
LD A,E ; LOAD E
CP 2 ; CHECK IT IF IS 2
JP NZ,PPIDE_NOTSUP ; IF NOT, FAIL AS NOT SUP
;
; RECORD STATUS OK
XOR A ; A := 0 (STATUS = OK)
LD (IY+PPIDE_STAT),A ; SAVE IT
RET
;
; SWITCH IY POINTER FROM CURRENT UNIT CFG TO PARTNER UNIT CFG
;
PPIDE_GOPARTNER:
PUSH HL ; SAVE HL
LD L,(IY+PPIDE_PARTNER) ; GET PARTNER ENTRY
LD H,(IY+PPIDE_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.
;
PPIDE_CHKERR:
LD A,(IY+PPIDE_STAT) ; GET STATUS
OR A ; SET FLAGS
CALL NZ,PPIDE_RESET ; IF ERROR STATUS, RESET BUS
RET
;
;
;
PPIDE_WAITRDY:
LD A,(PPIDE_TIMEOUT) ; GET TIMEOUT IN 0.1 SECS
LD B,A ; PUT IN OUTER LOOP VAR
PPIDE_WAITRDY1:
LD DE,(PPIDE_TOSCALER) ; CPU SPEED SCALER TO INNER LOOP VAR
PPIDE_WAITRDY2:
;IN A,(PPIDE_REG_STAT) ; READ STATUS
CALL PPIDE_IN
.DB PPIDE_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,PPIDE_WAITRDY2 ; INNER LOOP RETURN
DJNZ PPIDE_WAITRDY1 ; OUTER LOOP RETURN
JP PPIDE_RDYTO ; EXIT WITH RDYTO ERR
;
;
;
PPIDE_WAITDRQ:
LD A,(PPIDE_TIMEOUT) ; GET TIMEOUT IN 0.1 SECS
LD B,A ; PUT IN OUTER LOOP VAR
PPIDE_WAITDRQ1:
LD DE,(PPIDE_TOSCALER) ; CPU SPEED SCALER TO INNER LOOP VAR
PPIDE_WAITDRQ2:
;IN A,(PPIDE_REG_STAT) ; READ STATUS
CALL PPIDE_IN
.DB PPIDE_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,PPIDE_WAITDRQ2
DJNZ PPIDE_WAITDRQ1
JP PPIDE_DRQTO ; EXIT WITH BUFTO ERR
;
;
;
PPIDE_WAITBSY:
LD A,(PPIDE_TIMEOUT) ; GET TIMEOUT IN 0.1 SECS
LD B,A ; PUT IN OUTER LOOP VAR
PPIDE_WAITBSY1:
LD DE,(PPIDE_TOSCALER) ; CPU SPEED SCALER TO INNER LOOP VAR
PPIDE_WAITBSY2:
;IN A,(PPIDE_REG_STAT) ; READ STATUS
CALL PPIDE_IN ; 17TS + 204TS
.DB PPIDE_REG_STAT
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,PPIDE_WAITBSY2 ; 12TS
DJNZ PPIDE_WAITBSY1 ; -----
JP PPIDE_BSYTO ; EXIT WITH BSYTO ERR ; 263TS
;
; READ A VALUE FROM THE DEVICE POINTED TO BY IY AND RETURN IT IN A
;
PPIDE_IN:
EX (SP),HL ; GET PARM POINTER ; 19TS
PUSH BC ; SAVE INCOMING BC ; 11TS
LD A,PPIDE_DIR_READ ; SET DATA BUS DIRECTION TO READ ; 7TS
;OUT (PPIDE_REG_PPI),A ; DO IT
LD C,(IY+PPIDE_PPI) ; PPI CONTROL WORD ; 19TS
EZ80_IO
OUT (C),A ; WRITE IT ; 12TS
;
LD B,(HL) ; GET CTL PORT VALUE ; 7TS
;LD C,PPIDE_REG_CTL ; SETUP PORT TO WRITE
;LD C,(IY+PPIDE_CTL) ; SET IDE ADDRESS
DEC C ; SET IDE ADDRESS ; 4TS
EZ80_IO
OUT (C),B ; SET ADDRESS LINES ; 12TS
SET 6,B ; TURN ON READ BIT ; 8TS
EZ80_IO
OUT (C),B ; ASSERT READ LINE ; 12TS
;
;IN A,(PPIDE_REG_DATALO) ; GET DATA VALUE FROM DEVICE
DEC C ; 4TS
DEC C ; 4TS
EZ80_IO
IN A,(C) ; GET DATA VALUE FROM DEVICE ; 12
INC C ; 4TS
INC C ; 4TS
;
RES 6,B ; CLEAR READ BIT ; 8TS
EZ80_IO
OUT (C),B ; DEASSERT READ LINE ; 12TS
POP BC ; RECOVER INCOMING BC ; 10TS
INC HL ; POINT PAST PARM ; 6TS
EX (SP),HL ; RESTORE STACK ; 19TS
RET ; 10TS
; ; -----
; OUTPUT VALUE IN A TO THE DEVICE POINTED TO BY IY ; 204TS
;
PPIDE_OUT:
; *** TODO *** FIX ORDER OF SET/CLEAR WRITE LINE
EX (SP),HL ; GET PARM POINTER
PUSH BC ; SAVE INCOMING BC
PUSH AF ; PRESERVE INCOMING VALUE
LD A,PPIDE_DIR_WRITE ; SET DATA BUS DIRECTION TO WRITE
;OUT (PPIDE_REG_PPI),A ; DO IT
LD C,(IY+PPIDE_PPI) ; PPI CONTROL WORD
EZ80_IO
OUT (C),A ; WRITE IT
POP AF ; RECOVER VALUE TO WRITE
;
LD B,(HL) ; GET IDE ADDRESS VALUE
;LD C,PPIDE_REG_CTL ; SETUP PORT TO WRITE
;LD C,(IY+PPIDE_CTL) ; SET IDE ADDRESS
DEC C ; SET IDE ADDRESS
EZ80_IO
OUT (C),B ; SET ADDRESS LINES
SET 5,B ; TURN ON WRITE BIT
EZ80_IO
OUT (C),B ; ASSERT WRITE LINE
;
DEC C
DEC C
;OUT (PPIDE_REG_DATALO),A ; SEND DATA VALUE TO DEVICE
EZ80_IO
OUT (C),A ; SEND DATA VALUE TO DEVICE
INC C
INC C
;
RES 5,B ; CLEAR WRITE BIT
EZ80_IO
OUT (C),B ; DEASSERT WRITE LINE
POP BC ; RECOVER INCOMING BC
INC HL ; POINT PAST PARM
EX (SP),HL ; RESTORE STACK
RET
;
;=============================================================================
; ERROR HANDLING AND DIAGNOSTICS
;=============================================================================
;
; ERROR HANDLERS
;
PPIDE_INVUNIT:
LD A,PPIDE_STINVUNIT
JR PPIDE_ERR2 ; SPECIAL CASE FOR INVALID UNIT
;
PPIDE_NOMEDIA:
LD A,PPIDE_STNOMEDIA
JR PPIDE_ERR
;
PPIDE_CMDERR:
LD A,PPIDE_STCMDERR
JR PPIDE_ERR
;
PPIDE_IOERR:
LD A,PPIDE_STIOERR
JR PPIDE_ERR
;
PPIDE_RDYTO:
LD A,PPIDE_STRDYTO
JR PPIDE_ERR
;
PPIDE_DRQTO:
LD A,PPIDE_STDRQTO
JR PPIDE_ERR
;
PPIDE_BSYTO:
LD A,PPIDE_STBSYTO
JR PPIDE_ERR
;
PPIDE_NOTSUP:
LD A,PPIDE_STNOTSUP
JR PPIDE_ERR
;
PPIDE_NOTRDY:
LD A,PPIDE_STNOTRDY
JR PPIDE_ERR
;
PPIDE_ERR:
LD (IY+PPIDE_STAT),A ; SAVE NEW STATUS
;
PPIDE_ERR2:
#IF (PPIDETRACE >= 2)
CALL PPIDE_PRTSTAT
CALL PPIDE_REGDUMP
#ENDIF
OR A ; SET FLAGS
RET
;
;
;
PPIDE_PRTERR:
RET Z ; DONE IF NO ERRORS
; FALL THRU TO PPIDE_PRTSTAT
;
; PRINT FULL DEVICE STATUS LINE
;
PPIDE_PRTSTAT:
PUSH AF
PUSH DE
PUSH HL
LD A,(IY+PPIDE_STAT)
CP PPIDE_STINVUNIT
JR Z,PPIDE_PRTSTAT2 ; INVALID UNIT IS SPECIAL CASE
CALL PPIDE_PRTPREFIX ; PRINT UNIT PREFIX
JR PPIDE_PRTSTAT3
PPIDE_PRTSTAT2:
CALL NEWLINE
PRTS("PPIDE:$") ; NO UNIT NUM IN PREFIX FOR INVALID UNIT
PPIDE_PRTSTAT3:
CALL PC_SPACE ; FORMATTING
CALL PPIDE_PRTSTATSTR
POP HL
POP DE
POP AF
RET
;
; PRINT STATUS STRING
;
PPIDE_PRTSTATSTR:
PUSH AF
PUSH DE
LD A,(IY+PPIDE_STAT)
OR A
LD DE,PPIDE_STR_STOK
JR Z,PPIDE_PRTSTATSTR1
INC A
LD DE,PPIDE_STR_STINVUNIT
JR Z,PPIDE_PRTSTATSTR1
INC A
LD DE,PPIDE_STR_STNOMEDIA
JR Z,PPIDE_PRTSTATSTR1
INC A
LD DE,PPIDE_STR_STCMDERR
JR Z,PPIDE_PRTSTATSTR1
INC A
LD DE,PPIDE_STR_STIOERR
JR Z,PPIDE_PRTSTATSTR1
INC A
LD DE,PPIDE_STR_STRDYTO
JR Z,PPIDE_PRTSTATSTR1
INC A
LD DE,PPIDE_STR_STDRQTO
JR Z,PPIDE_PRTSTATSTR1
INC A
LD DE,PPIDE_STR_STBSYTO
JR Z,PPIDE_PRTSTATSTR1
INC A
LD DE,PPIDE_STR_STNOTSUP
JR Z,PPIDE_PRTSTATSTR1
INC A
LD DE,PPIDE_STR_STNOTRDY
JR Z,PPIDE_PRTSTATSTR1
LD DE,PPIDE_STR_STUNK
PPIDE_PRTSTATSTR1:
CALL WRITESTR
POP DE
POP AF
RET
;
; PRINT ALL REGISTERS DIRECTLY FROM DEVICE
; DEVICE MUST BE SELECTED PRIOR TO CALL
;
PPIDE_REGDUMP:
PUSH AF
PUSH BC
push DE
CALL PC_SPACE
CALL PC_LBKT
LD A,PPIDE_DIR_READ ; SET DATA BUS DIRECTION TO READ
;OUT (PPIDE_REG_PPI),A ; DO IT
LD C,(IY+PPIDE_PPI) ; PPI CONTROL WORD
EZ80_IO
OUT (C),A ; WRITE IT
LD C,(IY+PPIDE_CTL) ; SET IDE ADDRESS
LD E,PPIDE_REG_CMD
LD B,7
PPIDE_REGDUMP1:
LD A,E ; REGISTER ADDRESS
;OUT (PPIDE_REG_CTL),A ; SET IT
EZ80_IO
OUT (C),A ; REGISTER ADDRESS
XOR PPIDE_CTL_DIOR ; SET BIT TO ASSERT READ LINE
;OUT (PPIDE_REG_CTL),A ; ASSERT READ
EZ80_IO
OUT (C),A ; ASSERT READ
;IN A,(PPIDE_REG_DATALO) ; GET VALUE
DEC C ; CTL -> MSB
DEC C ; MSB -> LSB
EZ80_IO
IN A,(C) ; GET VALUE
INC C ; LSB -> MSB
INC C ; MSB -> CTL
CALL PRTHEXBYTE ; DISPLAY IT
;LD A,C ; RELOAD ADDRESS W/ READ UNASSERTED
;OUT (PPIDE_REG_CTL),A ; AND SET IT
EZ80_IO
OUT (C),E ; RELOAD ADDRESS W/ READ UNASSERTED
;DEC C ; NEXT LOWER REGISTER
DEC E ; NEXT LOWER REGISTER
DEC B ; DEC LOOP COUNTER
CALL NZ,PC_SPACE ; FORMATTING
JR NZ,PPIDE_REGDUMP1 ; LOOP AS NEEDED
CALL PC_RBKT ; FORMATTING
POP DE
POP BC
POP AF
RET
;
; PRINT DIAGNONSTIC PREFIX
;
PPIDE_PRTPREFIX:
PUSH AF
CALL NEWLINE
PRTS("PPIDE$")
LD A,(IY+PPIDE_DEV) ; GET CURRENT DEVICE NUM
CP $FE ; NOT YET ASSIGNED?
JR Z,PPIDE_PRTPREFIX1 ; SKIP DEV NUM IF SO
CALL PRTDECB
PPIDE_PRTPREFIX1:
CALL PC_COLON
POP AF
RET
;
;=============================================================================
; STRING DATA
;=============================================================================
;
PPIDE_STR_STOK .TEXT "OK$"
PPIDE_STR_STINVUNIT .TEXT "INVALID UNIT$"
PPIDE_STR_STNOMEDIA .TEXT "NO MEDIA$"
PPIDE_STR_STCMDERR .TEXT "COMMAND ERROR$"
PPIDE_STR_STIOERR .TEXT "IO ERROR$"
PPIDE_STR_STRDYTO .TEXT "READY TIMEOUT$"
PPIDE_STR_STDRQTO .TEXT "DRQ TIMEOUT$"
PPIDE_STR_STBSYTO .TEXT "BUSY TIMEOUT$"
PPIDE_STR_STNOTSUP .TEXT "NOT SUPPORTED$"
PPIDE_STR_STNOTRDY .TEXT "NOT READY$"
PPIDE_STR_STUNK .TEXT "UNKNOWN ERROR$"
;
PPIDE_STR_NO .TEXT "NO$"
PPIDE_STR_NOPPI .TEXT "PPI NOT PRESENT$"
PPIDE_STR_8BIT .TEXT " 8-BIT$"
;
PPIDE_STR_TYPEATA .TEXT " ATA$"
PPIDE_STR_TYPEATAPI .TEXT " ATAPI$"
;
;=============================================================================
; DATA STORAGE
;=============================================================================
;
PPIDE_TIMEOUT .DB PPIDE_TONORM ; WAIT FUNCS TIMEOUT IN TENTHS OF SEC
PPIDE_TOSCALER .DW CPUMHZ * 380 ; WAIT FUNCS SCALER FOR CPU SPEED
;
PPIDE_CMD .DB 0 ; PENDING COMMAND TO PROCESS
PPIDE_IOFNADR .DW 0 ; PENDING IO FUNCTION ADDRESS
PPIDE_DRVHD .DB 0 ; CURRENT DRIVE/HEAD MASK
;
PPIDE_DSKBUF .DW 0 ; ACTIVE DISK BUFFER
PPIDE_XFRDIR .DB 0 ; 0=READ, NON-0=WRITE
;
PPIDE_DEVNUM .DB 0 ; TEMP DEVICE NUM USED DURING INIT
;
; SCSI COMMAND TEMPLATES (ALWAYS 12 BYTES FOR ATAPI)
;
PPIDE_PKTCMD_RW .DB $00, $00, $00, $00, $01, $00, $00, $00, $00, $00, $00, $00 ; READ/WRITE SECTOR
PPIDE_PKTCMD_SENSE .DB $03, $00, $00, $00, $FF, $00, $00, $00, $00, $00, $00, $00 ; REQUEST SENSE DATA
PPIDE_PKTCMD_RDCAP .DB $25, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00 ; READ CAPACITY
PPIDE_PKTCMD_RW10 .DB $28, $00, $00, $00, $00, $00, $00, $00, $01, $00, $00, $00 ; READ/WRITE SECTOR
PPIDE_PKTCMD_TSTRDY .DB $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00 ; TEST UNIT READY