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.
 
 
 
 
 
 

681 lines
14 KiB

;
;==================================================================================================
; PPIDE DISK DRIVER
;==================================================================================================
;
; 11/29/2011 dwg - DOUGDEBUG controls the embedded NOPs which adjust for
; recovery time while using the parallel port to talk to the PPIDE and IDE
; device. Using this stabilized by Zeta (8MHz) with a CF chip.
;
; 12/02/2011 wbw - renamed DOUGDEBUG to PPIDESLOW and exposed in config
; PPIDESLOW now controls the RECOVERY macro definition.
;
#IF (PPIDESLOW)
#DEFINE RECOVERY NOP\ NOP\ NOP\ NOP
#ELSE
#DEFINE RECOVERY ;
#ENDIF
;
; MAP PPI PORTS TO PPIDE PORTS
;
#IF (PPIDEMODE == PPIDEMODE_DIO3)
IDELSB .EQU 20H ; LSB
IDEMSB .EQU 21H ; MSB
IDECTL .EQU 22H ; CONTROL SIGNALS
PPI1CONT .EQU 23H ; CONTROL BYTE PPI 82C55
#ELSE
IDELSB .EQU PPIA ; LSB
IDEMSB .EQU PPIB ; MSB
IDECTL .EQU PPIC ; CONTROL SIGNALS
PPI1CONT .EQU PPIX ; CONTROL BYTE PPI 82C55
#ENDIF
;
; PPI control bytes for read and write to IDE drive
;
RD_IDE_8255 .EQU 10010010B ; IDE_8255_CTL OUT, IDE_8255_LSB/MSB INPUT
WR_IDE_8255 .EQU 10000000B ; ALL THREE PORTS OUTPUT
;
; IDE CONTROL LINES FOR USE WITH IDE_8255_CTL. CHANGE THESE 8
; CONSTANTS TO REFLECT WHERE EACH SIGNAL OF THE 8255 EACH OF THE
; IDE CONTROL SIGNALS IS CONNECTED. ALL THE CONTROL SIGNALS MUST
; BE ON THE SAME PORT, BUT THESE 8 LINES LET YOU CONNECT THEM TO
; WHICHEVER PINS ON THAT PORT.
;
PPIDE_A0_LINE .EQU 01H ; DIRECT FROM 8255 TO IDE INTERFACE
PPIDE_A1_LINE .EQU 02H ; DIRECT FROM 8255 TO IDE INTERFACE
PPIDE_A2_LINE .EQU 04H ; DIRECT FROM 8255 TO IDE INTERFACE
PPIDE_CS0_LINE .EQU 08H ; INVERTER BETWEEN 8255 AND IDE INTERFACE
PPIDE_CS1_LINE .EQU 10H ; INVERTER BETWEEN 8255 AND IDE INTERFACE
PPIDE_WR_LINE .EQU 20H ; INVERTER BETWEEN 8255 AND IDE INTERFACE
PPIDE_RD_LINE .EQU 40H ; INVERTER BETWEEN 8255 AND IDE INTERFACE
PPIDE_RST_LINE .EQU 80H ; INVERTER BETWEEN 8255 AND IDE INTERFACE
;
;------------------------------------------------------------------
; MORE SYMBOLIC CONSTANTS... THESE SHOULD NOT BE CHANGED, UNLESS OF
; COURSE THE IDE DRIVE INTERFACE CHANGES, PERHAPS WHEN DRIVES GET
; TO 128G AND THE PC INDUSTRY WILL DO YET ANOTHER KLUDGE.
;
; SOME SYMBOLIC CONSTANTS FOR THE IDE REGISTERS, WHICH MAKES THE
; CODE MORE READABLE THAN ALWAYS SPECIFYING THE ADDRESS PINS
;
PPIDE_DATA .EQU PPIDE_CS0_LINE
PPIDE_ERROR .EQU PPIDE_CS0_LINE + PPIDE_A0_LINE
PPIDE_SEC_CNT .EQU PPIDE_CS0_LINE + PPIDE_A1_LINE
PPIDE_SECTOR .EQU PPIDE_CS0_LINE + PPIDE_A1_LINE + PPIDE_A0_LINE
PPIDE_CYL_LSB .EQU PPIDE_CS0_LINE + PPIDE_A2_LINE
PPIDE_CYL_MSB .EQU PPIDE_CS0_LINE + PPIDE_A2_LINE + PPIDE_A0_LINE
PPIDE_HEAD .EQU PPIDE_CS0_LINE + PPIDE_A2_LINE + PPIDE_A1_LINE
PPIDE_COMMAND .EQU PPIDE_CS0_LINE + PPIDE_A2_LINE + PPIDE_A1_LINE + PPIDE_A0_LINE
PPIDE_STTS .EQU PPIDE_CS0_LINE + PPIDE_A2_LINE + PPIDE_A1_LINE + PPIDE_A0_LINE
PPIDE_CONTROL .EQU PPIDE_CS1_LINE + PPIDE_A2_LINE + PPIDE_A1_LINE
PPIDE_ASTTS .EQU PPIDE_CS1_LINE + PPIDE_A2_LINE + PPIDE_A1_LINE + PPIDE_A0_LINE
;
; IDE COMMAND CONSTANTS. THESE SHOULD NEVER CHANGE.
;
PPIDECMD_RECAL .EQU 010H
PPIDECMD_READ .EQU 020H
PPIDECMD_WRITE .EQU 030H
PPIDECMD_INIT .EQU 091H
PPIDECMD_ID .EQU 0ECH
PPIDECMD_SPINDOWN .EQU 0E0H
PPIDECMD_SPINUP .EQU 0E1H
PPIDECMD_SETFEAT .EQU 0EFH
;
PPIDERC_OK .EQU 0
PPIDERC_CMDERR .EQU 1
PPIDERC_RDYTO .EQU 2
PPIDERC_BUFTO .EQU 3
;
; UNIT CONFIGURATION
;
PPIDE0_DEVICE .DB 11100000B ; LBA, MASTER DEVICE
PPIDE1_DEVICE .DB 11110000B ; LBA, SLAVE DEVICE
;
;
;
PPIDE_DISPATCH:
LD A,B ; GET REQUESTED FUNCTION
AND $0F
JR Z,PPIDE_RD
DEC A
JR Z,PPIDE_WR
DEC A
JR Z,PPIDE_ST
DEC A
JR Z,PPIDE_MED
CALL PANIC
;
PPIDE_RD:
JP PPIDE_XREAD
PPIDE_WR:
JP PPIDE_XWRITE
PPIDE_ST:
JP PPIDE_STATUS
PPIDE_MED:
JP PPIDE_MEDIA
;
; PPIDE_MEDIA
;
PPIDE_MEDIA:
LD A,MID_HD
RET
;
;
;
PPIDE_INIT:
PRTS("PPIDE: IO=0x$")
LD A,IDELSB
CALL PRTHEXBYTE
PRTS(" UNITS=2$")
#IF (PPIDESLOW)
PRTS(" SLOW$")
#ENDIF
CALL PPIDE_RESET
XOR A
DEC A ; INITIAL STATUS IS NOT READY $FF
LD (PPIDE_STAT),A ; SAVE IT
RET
;
;
;
PPIDE_STATUS:
LD A,(PPIDE_STAT) ; LOAD STATUS
OR A ; SET FLAGS
RET
;
;
;
PPIDE_XREAD:
LD A,PPIDECMD_READ
LD (PPIDEP_CMD),A
JP PPIDE_RW
;
;
;
PPIDE_XWRITE:
LD A,PPIDECMD_WRITE
LD (PPIDEP_CMD),A
JP PPIDE_RW
;
;
;
PPIDE_RW:
; CLEAR RESULTS
XOR A ; A = 0
LD (PPIDE_RC),A ; CLEAR RETURN CODE
LD (PPIDEP_STTS),A ; CLEAR SAVED STTS
LD (PPIDEP_ERR),A ; CLEAR SAVED ERR
; INIT REQUIRED?
LD A,(PPIDE_STAT)
OR A ; SET FLAGS
JR Z,PPIDE_RW0 ; IF STATUS OK, BYPASS RESET
CALL PPIDE_RESET ; DO THE RESET
#IF (PPIDE8BIT)
CALL PPIDE_WAITRDY
LD C,01H
LD A,PPIDE_ERROR
CALL PPIDE_WRITE
LD C,PPIDECMD_SETFEAT
LD A,PPIDE_COMMAND
CALL PPIDE_WRITE
CALL PPIDE_WAITRDY
JP NC,PPIDE_ERR
CALL PPIDE_CHKERR ; CHECK FOR ERRORS
JP NC,PPIDE_ERR
#IF (PPIDETRACE >= 2)
CALL IDE_PRT
#ENDIF
#ENDIF
PPIDE_RW0:
CALL PPIDE_WAITRDY ; WAIT FOR DRIVE READY
JP NC,PPIDE_ERR
CALL PPIDE_SETUP ; SETUP CYL, TRK, HEAD
LD A,(PPIDEP_CMD)
LD C,A
LD A,PPIDE_COMMAND
CALL PPIDE_WRITE
CALL PPIDE_WAITRDY ; WAIT FOR DRIVE READY
JP NC,PPIDE_ERR
CALL PPIDE_CHKERR ; CHECK FOR ERRORS
JP NC,PPIDE_ERR
CALL PPIDE_WAITBUF ; WAIT FOR BUFFER READY
JP NC,PPIDE_ERR
LD A,(PPIDEP_CMD) ; DISPATCH TO READ OR WRITE SPECIFIC LOGIC
CP PPIDECMD_WRITE
JP Z,PPIDE_RW1
CALL PPIDE_BUFRD ; READ BUFFER
CALL PPIDE_WAITRDY ; WAIT FOR DRIVE READY
JP NC,PPIDE_ERR
CALL PPIDE_CHKERR ; CHECK FOR ERRORS
JP NC,PPIDE_ERR
JP PPIDE_OK
PPIDE_RW1:
CALL PPIDE_BUFWR ; WRITE BUFFER
CALL PPIDE_WAITRDY ; WAIT FOR DRIVE READY
JP NC,PPIDE_ERR
CALL PPIDE_CHKERR ; CHECK FOR ERRORS
JP NC,PPIDE_ERR
JP PPIDE_OK
PPIDE_ERR:
XOR A
DEC A ; A = $FF TO SIGNAL ERROR
LD (PPIDE_STAT),A ; SAVE IT
#IF (PPIDETRACE >= 1)
PUSH AF
CALL PPIDE_PRT
POP AF
#ENDIF
RET
PPIDE_OK:
#IF (PPIDETRACE >= 2)
CALL PPIDE_PRT
#ENDIF
XOR A
RET
;
;
;
PPIDE_RESET:
LD C,000001110B ; NO INTERRUPTS, ASSERT RESET BOTH DRIVES
LD A,PPIDE_CONTROL
CALL PPIDE_WRITE
LD DE,8 ; DELAY ABOUT 200ms
CALL VDELAY
LD C,000000010B ; NO INTERRUPTS, DEASSERT RESET
LD A,PPIDE_CONTROL
CALL PPIDE_WRITE
XOR A ; STATUS OK
LD (PPIDE_STAT),A ; SAVE IT
RET
;
;
;
PPIDE_WAITRDY:
LD DE,0 ; TIMEOUT IS 250us * 65536 = 15 SECONDS
PPIDE_WBSY:
PUSH DE
LD DE,10 ; INNER LOOP DELAY IS 250us (25us * 10)
CALL VDELAY
POP DE
DEC DE
LD A,D
OR E
JP Z,PPIDE_TO
LD A,PPIDE_STTS
CALL PPIDE_READ
LD A,C
LD (PPIDEP_STTS),A ; SAVE IT
AND 011000000B ; ISOLATE BUSY AND RDY BITS
XOR 001000000B ; WE WANT BUSY(7) TO BE 0 AND RDY(6) TO BE 1
JP NZ,PPIDE_WBSY
SCF ; CARRY 1 = OK
RET
PPIDE_TO:
LD A,PPIDERC_RDYTO
LD (PPIDE_RC),A
XOR A ; CARRY 0 = TIMEOUT
RET
;
;
;
PPIDE_CHKERR:
LD A,PPIDE_STTS
CALL PPIDE_READ
LD A,C
LD (PPIDEP_STTS),A ; SAVE IT
AND 000000001B ; ERROR BIT SET?
SCF ; ASSUME NO ERR
RET Z ; NO ERR, RETURN WITH CF SET
LD A,PPIDE_ERROR
CALL PPIDE_READ
LD A,C
LD (PPIDEP_ERR),A ; SAVE IT
LD A,PPIDERC_CMDERR ; COMMAND ERROR
LD (PPIDE_RC),A ; SAVE IT
OR A ; CLEAR CF TO SIGNAL ERROR
RET
;
;
;
PPIDE_WAITBUF:
LD DE,0
PPIDE_WDRQ:
CALL DELAY
INC DE
LD A,D
OR E
JP Z,PPIDE_TO2
LD A,PPIDE_STTS
CALL PPIDE_READ
LD A,C
LD (PPIDEP_STTS),A ; SAVE IT
AND 010001000B ; TO FILL (OR READY TO FILL)
XOR 000001000B
JP NZ,PPIDE_WDRQ
SCF ; CARRY 1 = OK
RET
PPIDE_TO2:
LD A,PPIDERC_BUFTO
LD (PPIDE_RC),A
XOR A ; CARRY 0 = TIMED OUT
RET
;
;
;
#IF (PPIDE8BIT)
PPIDE_BUFRD:
LD HL,(DIOBUF)
LD DE,200H
PPIDE_BUFRD1:
LD A,PPIDE_DATA
CALL PPIDE_READ
LD (HL),C
INC HL
DEC DE
LD A,D
OR E
JP NZ,PPIDE_BUFRD1
RET
#ELSE
PPIDE_BUFRD:
LD HL,(DIOBUF)
LD D,0
PPIDE_BUFRD1:
LD A,PPIDE_DATA
CALL PPIDE_READ
LD (HL),C
INC HL
LD (HL),B
INC HL
DEC D
JP NZ,PPIDE_BUFRD1
RET
#ENDIF
;
;
;
#IF (PPIDE8BIT)
PPIDE_BUFWR:
LD HL,(DIOBUF)
LD DE,200H
PPIDE_BUFWR1:
LD C,(HL)
LD A,PPIDE_DATA
CALL PPIDE_WRITE
INC HL
DEC DE
LD A,D
OR E
JP NZ,PPIDE_BUFWR1
#ELSE
PPIDE_BUFWR:
LD HL,(DIOBUF)
LD D,0
PPIDE_BUFWR1:
LD C,(HL)
INC HL
LD B,(HL)
INC HL
LD A,PPIDE_DATA
CALL PPIDE_WRITE
DEC D
JP NZ,PPIDE_BUFWR1
RET
#ENDIF
;
;
;
PPIDE_SETUP:
LD C,1
LD A,PPIDE_SEC_CNT
CALL PPIDE_WRITE
LD A,(HSTDSK) ; HSTDSK -> HEAD BIT 4 TO SELECT UNIT
AND 0FH
CP 0
JP Z,PPIDE_SETUP_UNIT0
CP 1
JP Z,PPIDE_SETUP_UNIT1
CALL PANIC
PPIDE_SETUP_UNIT0:
LD A,(PPIDE0_DEVICE)
; LD DE,(PPIDE0_OFFSET)
JP PPIDE_SETUP1
PPIDE_SETUP_UNIT1:
LD A,(PPIDE1_DEVICE)
; LD DE,(PPIDE1_OFFSET)
JP PPIDE_SETUP1
PPIDE_SETUP1:
LD (PPIDEP_HEAD),A
LD C,A
LD A,PPIDE_HEAD
CALL PPIDE_WRITE
LD HL,(HSTTRK) ; HSTTRK -> IDECYLHI/LO
LD A,H
LD (PPIDEP_CYLHI),A
LD C,A
LD A,PPIDE_CYL_MSB
CALL PPIDE_WRITE
LD A,L
LD (PPIDEP_CYLLO),A
LD C,A
LD A,PPIDE_CYL_LSB
CALL PPIDE_WRITE
LD BC,(HSTSEC) ; HSTSEC -> IDESECTN
LD A,C
LD (PPIDEP_SEC),A
LD C,A
LD A,PPIDE_SECTOR
CALL PPIDE_WRITE
#IF (DSKYENABLE)
CALL PPIDE_DSKY
#ENDIF
RET
;
;
;
PPIDE_READ:
PUSH AF ; save register value
LD A,RD_IDE_8255
OUT (PPI1CONT),A ; Config 8255 chip, read mode
RECOVERY
POP AF ; restore register value
OUT (IDECTL),A ; Drive address onto control lines
RECOVERY
OR PPIDE_RD_LINE ; assert RD pin
OUT (IDECTL),A
RECOVERY
PUSH AF ; save register value
IN A,(IDELSB) ; read lower byte
RECOVERY
LD C,A ; save in reg C
IN A,(IDEMSB) ; read upper byte
RECOVERY
LD B,A ; save in reg C
POP AF ; restore register value
XOR PPIDE_RD_LINE ; de-assert RD signal
OUT (IDECTL),A
RECOVERY
XOR A
OUT (IDECTL),A ; Deassert all control pins
RECOVERY
RET
;
;
;
PPIDE_WRITE:
PUSH AF ; save IDE register value
LD A,WR_IDE_8255
OUT (PPI1CONT),A ; Config 8255 chip, write mode
RECOVERY
LD A,C ; get value to be written
OUT (IDELSB),A
RECOVERY
LD A,B ; get value to be written
OUT (IDEMSB),A
RECOVERY
POP AF ; get saved IDE register
OUT (IDECTL),A ; Drive address onto control lines
RECOVERY
OR PPIDE_WR_LINE ; assert write pin
OUT (IDECTL),A
RECOVERY
XOR PPIDE_WR_LINE ; de assert WR pin
OUT (IDECTL),A ; Drive address onto control lines
RECOVERY
XOR A
OUT (IDECTL),A ; release bus signals
RECOVERY
RET
;
;
;
#IF (DSKYENABLE)
PPIDE_DSKY:
LD HL,DSKY_HEXBUF
LD A,(PPIDEP_HEAD)
LD (HL),A
INC HL
LD A,(PPIDEP_CYLHI)
LD (HL),A
INC HL
LD A,(PPIDEP_CYLLO)
LD (HL),A
INC HL
LD A,(PPIDEP_SEC)
LD (HL),A
CALL DSKY_HEXOUT
RET
#ENDIF
;
;
;
PPIDE_PRT:
CALL NEWLINE
LD DE,PPIDESTR_PREFIX
CALL WRITESTR
CALL PC_SPACE
LD DE,PPIDESTR_CMD
CALL WRITESTR
LD A,(PPIDEP_CMD)
CALL PRTHEXBYTE
CALL PC_SPACE
CALL PC_LBKT
LD A,(PPIDEP_CMD)
LD DE,PPIDESTR_READ
CP PPIDECMD_READ
JP Z,PPIDE_PRTCMD
LD DE,PPIDESTR_WRITE
CP PPIDECMD_READ
JP Z,PPIDE_PRTCMD
LD DE,PPIDESTR_UNKCMD
PPIDE_PRTCMD:
CALL WRITESTR
CALL PC_RBKT
CALL PC_SPACE
LD A,(PPIDEP_HEAD)
CALL PRTHEXBYTE
LD A,(PPIDEP_CYLHI)
CALL PRTHEXBYTE
LD A,(PPIDEP_CYLLO)
CALL PRTHEXBYTE
LD A,(PPIDEP_SEC)
CALL PRTHEXBYTE
CALL PC_SPACE
LD DE,PPIDESTR_ARROW
CALL WRITESTR
CALL PC_SPACE
LD A,PPIDE_STTS
CALL PPIDE_READ
LD A,C
CALL PRTHEXBYTE
CALL PC_SPACE
LD A,PPIDE_ERROR
CALL PPIDE_READ
LD A,C
CALL PRTHEXBYTE
CALL PC_SPACE
LD DE,PPIDESTR_RC
CALL WRITESTR
LD A,(PPIDE_RC)
CALL PRTHEXBYTE
CALL PC_SPACE
CALL PC_LBKT
LD A,(PPIDE_RC)
LD DE,PPIDESTR_RCOK
CP PPIDERC_OK
JP Z,PPIDE_PRTRC
LD DE,PPIDESTR_RCCMDERR
CP PPIDERC_CMDERR
JP Z,PPIDE_PRTRC
LD DE,PPIDESTR_RCRDYTO
CP PPIDERC_RDYTO
JP Z,PPIDE_PRTRC
LD DE,PPIDESTR_RCBUFTO
CP PPIDERC_BUFTO
JP Z,PPIDE_PRTRC
LD DE,PPIDESTR_RCUNK
PPIDE_PRTRC:
CALL WRITESTR
CALL PC_RBKT
RET
;
;
;
PPIDESTR_PREFIX .TEXT "PPIDE:$"
PPIDESTR_CMD .TEXT "CMD=$"
PPIDESTR_RC .TEXT "RC=$"
PPIDESTR_ARROW .TEXT "-->$"
PPIDESTR_READ .TEXT "READ$"
PPIDESTR_WRITE .TEXT "WRITE$"
PPIDESTR_UNKCMD .TEXT "UNKCMD"
PPIDESTR_RCOK .TEXT "OK$"
PPIDESTR_RCCMDERR .TEXT "COMMAND ERROR$"
PPIDESTR_RCRDYTO .TEXT "READY TIMEOUT$"
PPIDESTR_RCBUFTO .TEXT "BUFFER TIMEOUT$"
PPIDESTR_RCUNK .TEXT "UNKNOWN ERROR$"
;
;==================================================================================================
; PPIDE DISK DRIVER - DATA
;==================================================================================================
;
PPIDE_STAT .DB 0
PPIDE_RC .DB 0
;
; PPIDE PARAMETERS
;
PPIDEP_CMD .DB 0
PPIDEP_HEAD .DB 0
PPIDEP_CYLHI .DB 0
PPIDEP_CYLLO .DB 0
PPIDEP_SEC .DB 0
PPIDEP_STTS .DB 0
PPIDEP_ERR .DB 0
;
;
;
;
;
;
;
; Error Register (ERR bit being set in the Status Register)
;
; Bit 7: BBK (Bad Block Detected) Set when a Bad Block is detected.
; Bit 6: UNC (Uncorrectable Data Error) Set when Uncorrectable Error is encountered.
; Bit 5: MC (Media Changed) Set to 0.
; Bit 4: IDNF (ID Not Found) Set when Sector ID not found.
; Bit 3: MCR (Media Change Request) Set to 0.
; Bit 2: ABRT (Aborted Command) Set when Command Aborted due to drive error.
; Bit 1: TKONF (Track 0 Not Found) Set when Executive Drive Diagnostic Command.
; Bit 0: AMNF (Address mark Not Found) Set in case of a general error.
;
; Status Register (When the contents of this register are read by the host, the IREQ# bit is cleared)
;
; Bit 7: BSY (Busy) Set when the drive is busy and unable to process any new ATA commands.
; Bit 6: DRDY (Data Ready) Set when the device is ready to accept ATA commands from the host.
; Bit 5: DWF (Drive Write Fault) Always set to 0.
; Bit 4: DSC (Drive Seek Complete) Set when the drive heads have been positioned over a specific track.
; Bit 3: DRQ (Data Request) Set when device is ready to transfer a word or byte of data to or from the host and the device.
; Bit 2: CORR (Corrected Data) Always set to 0.
; Bit 1: IDX (Index) Always set to 0.
; Bit 0: ERR (Error) Set when an error occurred during the previous ATA command.