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.
 
 
 
 
 
 

1034 lines
25 KiB

;
;=============================================================================
; S100 ESP32 SD DISK DRIVER
;=============================================================================
;
; DISK DEVICE DRIVER FOR THE S100 ESP32-BASED SD INTERFACE FOUND
; ON THE S100 2CF+1CF BOARD AND THE DUAL SD BOARD AS DESIGNED BY
; JOHN MONAHAN.
;
; http://www.s100computers.com/My%20System%20Pages/IDE%202CF+SD%20Board/IDE%202CF+1SD%20Board.htm
; http://www.s100computers.com/My%20System%20Pages/Dual%20SD%20card%20Board/Dual%20SD%20card%20Board.htm
;
;
; TODO:
; - AVOID RESELECTING PRI/SEC ON EVERY I/O CALL
; - REDUCE PUSH/POP CALLS IN GET/PUTBYTE, BLKREAD/WRITE
;
; NOTES:
;
; THE ESP32 IMPLEMENTS AN INTELLIGENT SD CARD CONTROLLER THAT HANDLES
; ALL OF THE SD CARD INTIALIZATION AND LOW-LEVEL I/O. IT EXPOSES A
; COMMAND/RESPONSE PROTOCOL. THE DUAL SD BOARD SUPPORTS TWO SD CARD
; DEVICES. SEPARATE INIT AND SELECT COMMANDS ARE PROVIDED TO HANDLE
; THIS AS NEEDED. THE 2CF+1SD SUPPORTS ONLY A SINGLE SD CARD DEVICE.
;
; TWO SEQUENTIAL I/O ADDRESSES ARE IMPLEMENTED. THE FIRST IS
; FOR STATUS AND THE SECOND IS FOR COMMAND & DATA EXCHANGE.
;
; === STATUS REGISTER (READ) ===
; BIT 2SD 2CF+1SD
; ------ --------- ---------
; BIT-0 SENDACT SENDACT
; BIT-1 SD0_CD SD1_CD
; BIT-2 SD1_CD RCV
; BIT-3 /SD0_CS GPIO3
; BIT-4 /SD1_CS /ERROR
; BIT-5 DIAG /SD1_CS
; BIT-6 /ERROR GPIO47
; BIT-7 RCVRDY RCVRDY
;
; SENDACT: DATA OUTPUT TO ESP32 PENDING, XMIT REGISTER FULL
; RCVRDY: DATA FROM ESP32 READY TO READ
; SD0_CD: SD0 CARD DETECT
; SD1_CD: SD1 CARD DETECT
; SD0_CS: SD0 CHIP SELECT
; SD1_CS: SD1 CHIP SELECT
; ERROR: ERROR INDICATOR
; DIAG: DIAGNOSTIC SWITCH
; GPIOX: GPIO BIT LEVEL
;
; COMMAND/DATA EXCHANGES
; ----------------------
;
; ->CMD_INIT1, <-STATUS
; ->CMD_INIT2, <-STATUS
; ->CMD_SEL1, <-STATUS
; ->CMD_SEL2, <-STATUS
; ->CMD_SETTRKSEC, ->[Track (byte), Sector (byte)], <-STATUS
; ->CMD_READ, <-[Sector Data (512 bytes)], <-STATUS
; ->CMD_WRITE, ->[Sector Data (512 bytes)], <-STATUS
; ->CMD_FORMAT, <-STATUS
; ->CMD_RESET
;
; ADDED IN V1.4:
; ->CMD_FWVER, <-[BoardID (byte), Ver-Major (byte), Ver-Minor (byte)], <-STATUS
; ->CMD_SETLBA, ->[LBA value (4 bytes, MS first)], <-STATUS
; ->CMD_TYPE, <-[SD Card Type (1 byte)], <-STATUS
; ->CMD_CAP, <-[Sector Count (4 bytes, MS first)], <-STATUS
; ->CMD_CID, <-[CID Data (16 bytes), <-STATUS
; ->CMD_CSD, <-[CSD Data (16 bytes), <-STATUS
; ->CMD_DISP, ->[null terminated string], <-STATUS
; ->CMD_ECHO, ->[null terminated string], <-[null terminated string], <-STATUS
;
; IF AN ERROR OCCURS IN ANY COMMAND THAT RETURNS DATA BEFORE THE
; STATUS BYTE, THEN DUMMY PADDING DATA IS SENT BEFORE THE
; ERROR STATUS.
;
ESPSD_IO_STATUS .EQU 0 ; OFFSET OF STATUS PORT FROM BASE I/O ADDRESS
ESPSD_IO_DATA .EQU 1 ; OFFSET OF DATA PORT FROM BASE I/O ADDRESS
;
ESPSD_CMD_INIT0 .EQU $80 ; INITIALIZE PRIMARY SD CARD
ESPSD_CMD_INIT1 .EQU $81 ; INITIALIZE SECONDARY SD CARD
ESPSD_CMD_SEL0 .EQU $82 ; (RE)SELECT PRIMARY SD CARD
ESPSD_CMD_SEL1 .EQU $83 ; (RE)SELECT SECONDARY SD CARD
ESPSD_CMD_SETTRKSEC .EQU $84 ; SET TRACK/SECTOR FOR SUBSEQUENT I/O
ESPSD_CMD_READ .EQU $85 ; READ SECTOR FROM SELECTED SD CARD AT CURRENT LBA
ESPSD_CMD_WRITE .EQU $86 ; WRITE SECTOR TO SELECTED SD CARD AT CURRENT LBA
ESPSD_CMD_FORMAT .EQU $87 ; FORMAT SECTOR ON SELECTED SD CARD AT CURRENT LBA
ESPSD_CMD_RESET .EQU $88 ; RESET ESP32 MODULE
ESPSD_CMD_FWVER .EQU $90 ; REPORT ESP32 FIRMWARE VERSION
ESPSD_CMD_SETLBA .EQU $91 ; SET NEW CURRENT LBA (32-BIT)
ESPSD_CMD_TYPE .EQU $92 ; REPORT CARD TYPE OF SELECTED SD CARD
ESPSD_CMD_CAP .EQU $93 ; REPORT CAPACITY (SECTORS) OF SELECTED SD CARD
ESPSD_CMD_CID .EQU $94 ; REPORT CID DATA OF SELECTED SD CARD
ESPSD_CMD_CSD .EQU $95 ; REPORT CSD DATA OF SELECTED SD CARD
ESPSD_CMD_DISP .EQU $96 ; REPORT CSD DATA OF SELECTED SD CARD
ESPSD_CMD_ECHO .EQU $97 ; REPORT CSD DATA OF SELECTED SD CARD
;
ESPSD_STAT_OK .EQU $00 ; OPERATION COMPLETED OK
ESPSD_STAT_ERR .EQU $1A ; OPERATION FAILED
;
; BOARD IDS
;
ESPSD_BOARD_2CF1SD .EQU 1 ; 2CF+1SD
ESPSD_BOARD_2SD .EQU 2 ; 2SD
;
; ESPSD DEVICE STATUS CODES
;
ESPSD_STOK .EQU 0
ESPSD_STNOMEDIA .EQU -1
ESPSD_STIOERR .EQU -2
ESPSD_STTO .EQU -3
ESPSD_STNOTRDY .EQU -4
;
; IDE DEVICE CONFIGURATION
;
; PER DEVICE DATA OFFSETS IN CFG BLOCK
;
ESPSD_DEV .EQU 0 ; OFFSET OF DEVICE NUMBER (BYTE)
ESPSD_ROLE .EQU 1 ; 0=PRIMARY, 1=SECONDARY
ESPSD_IOBASE .EQU 2 ; IO BASE ADDRESS (BYTE)
ESPSD_STAT .EQU 3 ; LAST STATUS (BYTE)
ESPSD_MEDCAP .EQU 4 ; MEDIA CAPACITY (DWORD)
ESPSD_LBA .EQU 8 ; OFFSET OF LBA (DWORD)
;
ESPSD_CFGSIZ .EQU 12 ; SIZE OF CFG TBL ENTRIES
;
ESPSD_CFGTBL:
;
#IF (ESPSDCNT >= 1)
;
ESPSD_DEV0P: ; DEVICE 0, PRIMARY
.DB $FE ; DRIVER DEVICE NUMBER (FILLED DYNAMICALLY)
.DB 0 ; PRIMARY
.DB ESPSD0BASE ; IO BASE ADDRESS
.DB ESPSD_STNOTRDY ; DEVICE STATUS
.DW $0000,$0001 ; DEVICE CAPACITY
.DW 0,0 ; CURRENT LBA
;
DEVECHO "ESPSD: IO="
DEVECHO ESPSD0BASE
DEVECHO ", PRIMARY"
DEVECHO "\n"
;
#IF (ESPSD0DUAL)
;
ESPSD_DEV0S: ; DEVICE 0, SECONDARY
.DB $FE ; DRIVER DEVICE NUMBER (FILLED DYNAMICALLY)
.DB 1 ; SECONDARY
.DB ESPSD0BASE ; IO BASE ADDRESS
.DB ESPSD_STNOTRDY ; DEVICE STATUS
.DW $0000,$0001 ; DEVICE CAPACITY
.DW 0,0 ; CURRENT LBA
;
DEVECHO "ESPSD: IO="
DEVECHO ESPSD0BASE
DEVECHO ", SECONDARY"
DEVECHO "\n"
;
#ENDIF
;
#ENDIF
;
#IF (ESPSDCNT >= 2)
;
ESPSD_DEV1P: ; DEVICE 1, PRIMARY
.DB $FE ; DRIVER DEVICE NUMBER (FILLED DYNAMICALLY)
.DB 0 ; PRIMARY
.DB ESPSD1BASE ; IO BASE ADDRESS
.DB ESPSD_STNOTRDY ; DEVICE STATUS
.DW $0000,$0001 ; DEVICE CAPACITY
.DW 0,0 ; CURRENT LBA
;
DEVECHO "ESPSD: IO="
DEVECHO ESPSD1BASE
DEVECHO ", PRIMARY"
DEVECHO "\n"
;
#IF (ESPSD1DUAL)
;
ESPSD_DEV1S: ; DEVICE 1, SECONDARY
.DB $FE ; DRIVER DEVICE NUMBER (FILLED DYNAMICALLY)
.DB 1 ; SECONDARY
.DB ESPSD1BASE ; IO BASE ADDRESS
.DB ESPSD_STNOTRDY ; DEVICE STATUS
.DW $0000,$0001 ; DEVICE CAPACITY
.DW 0,0 ; CURRENT LBA
;
DEVECHO "ESPSD: IO="
DEVECHO ESPSD1BASE
DEVECHO ", SECONDARY"
DEVECHO "\n"
;
#ENDIF
;
#ENDIF
;
#IF ($ - ESPSD_CFGTBL) != (ESPSDCNT * 2 * ESPSD_CFGSIZ)
.ECHO "*** INVALID ESPSD CONFIG TABLE ***\n"
#ENDIF
;
.DB $FF ; END OF TABLE MARKER
;
;=============================================================================
; INITIALIZATION ENTRY POINT
;=============================================================================
;
ESPSD_INIT:
;
XOR A ; ZERO ACCUM
LD (ESPSD_DEVNUM),A ; INIT DEV UNIT NUM FOR DYNAMIC ASSIGNMENT
LD IY,ESPSD_CFGTBL ; POINT TO START OF CONFIG TABLE
;
ESPSD_INIT1:
LD A,(IY) ; LOAD FIRST BYTE TO CHECK FOR END
CP $FF ; CHECK FOR END OF TABLE VALUE
JR NZ,ESPSD_INIT2 ; IF NOT END OF TABLE, CONTINUE
XOR A ; SIGNAL SUCCESS
RET ; AND RETURN
;
ESPSD_INIT2:
CALL NEWLINE ; FORMATTING
PRTS("ESPSD:$") ; TAG
;
PRTS(" IO=0x$") ; LABEL FOR IO ADDRESS
LD A,(IY+ESPSD_IOBASE) ; GET IO BASE ADDRES
CALL PRTHEXBYTE ; DISPLAY IT
;
BIT 0,(IY+ESPSD_ROLE) ; GET ROLE BIT
JR NZ,ESPSD_INIT2A ; JUMP IF SECONDARY
PRTS(" PRIMARY$") ; SHOW PRIMATY
JR ESPSD_INIT2B ; JUMP AHEAD
ESPSD_INIT2A:
PRTS(" SECONDARY$") ; SHOW SECONDARY
ESPSD_INIT2B:
CALL ESPSD_DETECT ; PROBE FOR INTERFACE
JR Z,ESPSD_INIT3 ; GOT IT, MOVE ON TO INIT UNITS
PRTS(" NOT PRESENT$") ; SHOW NOT PRESENT
JR ESPSD_INIT4 ; SKIP CFG ENTRY
;
ESPSD_INIT3:
CALL PC_SPACE ; FORMATTING
CALL ESPSD_FWVER ; GET BOARD ID AND F/W VER
JR NZ,ESPSD_INIT3D ; HANDLE ERROR (IGNORE IT)
LD A,E ; BOARD ID
CP ESPSD_BOARD_2CF1SD ; 2CF+1SD?
JR NZ,ESPSD_INIT3A ; IF NOT, CHECK MORE
LD DE,ESPSD_STR_2CF1SD ; LOAD STRING
JR ESPSD_INIT3C ; SKIP TO PRINT
ESPSD_INIT3A:
CP ESPSD_BOARD_2SD ; 2SD?
JR NZ,ESPSD_INIT3B ; NOPE
LD DE,ESPSD_STR_2SD ; LOAD STRING
JR ESPSD_INIT3C ; SKIP TO PRINT
ESPSD_INIT3B:
LD DE,ESPSD_STR_UNKNOWN ; UNKNOWN BOARD
ESPSD_INIT3C:
CALL WRITESTR ; PRINT BOARD NAME
PRTS(" F/W V$")
LD A,H ; GET MAJOR VER
CALL PRTDEC8 ; PRINT IT
CALL PC_PERIOD ; SEPARATOR
LD A,L ; GET MINOR VER
CALL PRTDEC8 ; PRINT IT
;
ESPSD_INIT3D:
CALL ESPSD_INIT5 ; REGISTER & INIT DEVICE
;
ESPSD_INIT4:
LD DE,ESPSD_CFGSIZ ; SIZE OF CFG TABLE ENTRY
ADD IY,DE ; BUMP POINTER
JP ESPSD_INIT1 ; AND LOOP
;
ESPSD_INIT5:
; UPDATE DRIVER RELATIVE UNIT NUMBER IN CONFIG TABLE
LD A,(ESPSD_DEVNUM) ; GET NEXT UNIT NUM TO ASSIGN
LD (IY+ESPSD_DEV),A ; UPDATE IT
INC A ; BUMP TO NEXT UNIT NUM TO ASSIGN
LD (ESPSD_DEVNUM),A ; SAVE IT
;
; ADD UNIT TO GLOBAL DISK UNIT TABLE
LD BC,ESPSD_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
;
CALL ESPSD_INITDEV ; INITIALIZE DEVICE
#IF (ESPSDTRACE < 2)
JP NZ,ESPSD_PRTSTAT
#ENDIF
RET NZ
;
CALL ESPSD_PRTPREFIX ; TAG FOR ACTIVE DEVICE
;
; PRINT STORAGE CAPACITY (BLOCK COUNT)
PRTS(" BLOCKS=0x$") ; PRINT FIELD LABEL
LD A,ESPSD_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 PRTDEC32 ; PRINT DWORD IN DECIMAL
PRTS("MB$") ; PRINT SUFFIX
;
XOR A ; SUCCESS
RET
;
;=============================================================================
; DRIVER FUNCTION TABLE
;=============================================================================
;
ESPSD_FNTBL:
.DW ESPSD_STATUS
.DW ESPSD_RESET
.DW ESPSD_SEEK
.DW ESPSD_READ
.DW ESPSD_WRITE
.DW ESPSD_VERIFY
.DW ESPSD_FORMAT
.DW ESPSD_DEVICE
.DW ESPSD_MEDIA
.DW ESPSD_DEFMED
.DW ESPSD_CAP
.DW ESPSD_GEOM
#IF (($ - ESPSD_FNTBL) != (DIO_FNCNT * 2))
.ECHO "*** INVALID IDE FUNCTION TABLE ***\n"
#ENDIF
;
ESPSD_VERIFY:
ESPSD_FORMAT:
ESPSD_DEFMED:
SYSCHKERR(ERR_NOTIMPL) ; NOT IMPLEMENTED
RET
;
;
;
ESPSD_READ:
CALL HB_DSKREAD ; HOOK HBIOS DISK READ SUPERVISOR
;;;CALL NEWLINE
;;;LD A,'R'
;;;CALL COUT
;;;CALL PRTHEXWORDHL
LD A,ESPSD_CMD_READ ; SETUP FOR BLOCK READ CMD
JP ESPSD_IO ; CONTINUE TO GENERIC IO ROUTINE
;
;
;
ESPSD_WRITE:
CALL HB_DSKWRITE ; HOOK HBIOS DISK WRITE SUPERVISOR
;;;CALL NEWLINE
;;;LD A,'W'
;;;CALL COUT
;;;CALL PRTHEXWORDHL
LD A,ESPSD_CMD_WRITE ; SETUP FOR BLOCK WRITE CMD
JP ESPSD_IO ; CONTINUE TO GENERIC IO ROUTINE
;
;
;
ESPSD_STATUS:
;;;LD A,'S'
;;;CALL COUT
; RETURN UNIT STATUS
LD A,(IY+ESPSD_STAT) ; GET STATUS OF SELECTED DEVICE
OR A ; SET FLAGS
RET ; AND RETURN
;
;
;
ESPSD_RESET:
;;;LD A,'R'
;;;CALL COUT
CALL ESPSD_INITDEV ; REINITIALIZE UNIT
OR A ; SET RESULT FLAGS
RET
;
;
;
ESPSD_DEVICE:
;;;LD A,'D'
;;;CALL COUT
LD D,DIODEV_ESPSD ; D := DEVICE TYPE
LD E,(IY+ESPSD_DEV) ; E := PHYSICAL DEVICE NUMBER
LD C,%00110010 ; C := ATTRIBUTES, REMOVABLE, SD CARD
LD H,0 ; H := MODE
LD L,(ESPSD_IOBASE) ; L := BASE I/O ADDRESS
XOR A ; SIGNAL SUCCESS
RET
;
; ESPSD_GETMED
;
ESPSD_MEDIA:
;;;LD A,'M'
;;;CALL COUT
LD A,E ; GET FLAGS
OR A ; SET FLAGS
JR Z,ESPSD_MEDIA1 ; JUST REPORT CURRENT STATUS AND MEDIA
;
CALL ESPSD_INITDEV ; REINITIALIZE DEVICE
;
ESPSD_MEDIA1:
LD A,(IY+ESPSD_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
;
;
;
ESPSD_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+ESPSD_LBA+0),L ; SAVE NEW LBA
LD (IY+ESPSD_LBA+1),H ; ...
LD (IY+ESPSD_LBA+2),E ; ...
LD (IY+ESPSD_LBA+3),D ; ...
XOR A ; SIGNAL SUCCESS
RET ; AND RETURN
;
;
;
ESPSD_CAP:
;;;LD A,'C'
;;;CALL COUT
LD A,(IY+ESPSD_STAT) ; GET STATUS
PUSH AF ; SAVE IT
LD A,ESPSD_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
;
;
;
ESPSD_GEOM:
;;;LD A,'G'
;;;CALL COUT
; 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 ESPSD_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 ESPSD_CAP STATUS
;
;=============================================================================
; FUNCTION SUPPORT ROUTINES
;=============================================================================
;
; ON RETURN, ZF SET INDICATES HARDWARE FOUND
;
ESPSD_DETECT:
; DO A BLIND READ TO RESET INPUT CHANNEL
LD C,(IY+ESPSD_IOBASE)
INC C
IN A,(C)
; WE USE A DUMMY SELECT COMMAND TO TEST FOR PRESENCE
LD A,ESPSD_CMD_SEL0
ADD A,(IY+ESPSD_ROLE)
JP ESPSD_RUNCMD
;
; INITIALIZE DEVICE
;
ESPSD_INITDEV:
; CHECK CARD DETECT
LD A,(IY+ESPSD_ROLE) ; GET ROLE
LD B,%00000010 ; MASK FOR PRIMARY
OR A ; TEST ROLE
JR Z,ESPSD_INITDEV1 ; IF PRIMARY, JUMP AHEAD
LD B,%00000100 ; MASK FOR SECONDARY
ESPSD_INITDEV1:
LD C,(IY+ESPSD_IOBASE) ; STATUS PORT
IN A,(C) ; GET STATUS
AND B ; APPLY MASK
JP Z,ESPSD_NOMEDIA ; IF NO CARD, HANDLE AS NO MEDIA
;
CALL ESPSD_INITCARD ; PERFORM DEVICE INIT
JP NZ,ESPSD_NOMEDIA ; CONVERT TO NO MEDIA ERROR
;
; RESET STATUS
LD A,ESPSD_STOK
LD (IY+ESPSD_STAT),A
XOR A
RET
;
; COMMON SECTOR I/O
;
ESPSD_IO:
LD (ESPSD_CMDVAL),A ; SAVE THE COMMAND
LD (ESPSD_DSKBUF),HL ; SAVE DISK BUFFER ADDRESS
;
; CHECK FOR ERROR STATUS AND REINIT?
;
#IF (ESPSDTRACE == 1)
LD HL,ESPSD_PRTERR ; SET UP SD_PRTERR
PUSH HL ; ... TO FILTER ALL EXITS
#ENDIF
;
; SELECT PRI/SEC DEVICE
CALL ESPSD_SELECT ; SELECT DEVICE
JP NZ,ESPSD_ERR ; ON ERROR, RECORD AND BAIL OUT
;
; SET LBA
LD A,ESPSD_LBA ; OFFSET OF LBA VALUE
CALL LDHLIYA ; HL := IY + A, REG A TRASHED
CALL HB_DSKACT ; SHOW ACTIVITY
CALL ESPSD_SETLBA ; SEND LBA TO DEVICE
JP NZ,ESPSD_ERR ; ON ERROR, RECORD AND BAIL OUT
;
; PERFORM BLOCK READ/WRITE
LD HL,(ESPSD_DSKBUF) ; RECOVER THE DISK BUFFER ADR
LD A,(ESPSD_CMDVAL) ; GET ORIGINAL CMD
CP ESPSD_CMD_READ ; READ?
JR NZ,ESPSD_IO2 ; IF NOT, SKIP AHEAD
CALL ESPSD_BLKREAD ; DO THE READ
JR ESPSD_IO3 ; CONTINUE
ESPSD_IO2:
CALL ESPSD_BLKWRITE ; DO THE WRITE
ESPSD_IO3:
JP NZ,ESPSD_ERR ; ON ERROR, RECORD AND BAIL OUT
;
; INCREMENT LBA
LD A,ESPSD_LBA ; LBA OFFSET
CALL LDHLIYA ; HL := IY + A, REG A TRASHED
CALL INC32HL ; INCREMENT THE VALUE
;
; INCREMENT DMA
LD HL,ESPSD_DSKBUF+1 ; POINT TO MSB OF BUFFER ADR
INC (HL) ; BUMP DMA BY
INC (HL) ; ... 512 BYTES
;
; CLEAN UP
LD HL,(ESPSD_DSKBUF) ; CURRENT DMA TO HL
XOR A ; SIGNAL SUCCESS
RET ; AND DONE
;
;=============================================================================
; COMMAND PROCESSING
;=============================================================================
;
; INITIALIZE DEVICE
;
ESPSD_INITCARD:
; DO A BLIND READ TO RESET INPUT CHANNEL
LD C,(IY+ESPSD_IOBASE)
INC C
IN A,(C)
;
LD A,ESPSD_CMD_INIT0 ; INIT PRIMARY DEVICE
ADD A,(IY+ESPSD_ROLE) ; ADJUST FOR PRI/SEC
CALL ESPSD_RUNCMD ; USE COMMON CMD ROUTINE
RET NZ ; HANDLE ERROR
;
; GET CAPACITY
LD E,ESPSD_CMD_CAP ; GET CAPACITY COMMAND
CALL ESPSD_CMD_SLOW ; SEND IT
RET NZ ; HANDLE ERROR
;
LD A,ESPSD_MEDCAP ; OFFSET TO CAPACITY FIELD
CALL LDHLIYA ; HL := IY + A, REG A TRASHED
LD A,4 ; START AT END FOR LITTLE ENDIAN
CALL ADDHLA ; BUMP PTR TO END OF DWORD
LD B,4 ; LOOP FOR 4 BYTES
;
ESPSD_INITCARD1:
DEC HL ; DEC POINTER
PUSH BC ; SAVE LOOP CONTROL
CALL ESPSD_GETBYTE_SLOW ; FIRST BYTE (MSB)
POP BC ; RESTORE LOOP CONTROL
RET NZ ; HANDLE ERROR
LD (HL),E ; SAVE IT
DJNZ ESPSD_INITCARD1 ; LOOP AS NEEDED
;
JR ESPSD_GETRESULT ; EXIT VIA CMD RESULT HANDLER
;
; GET BOARD ID AND FIRMWARE VERSION
;
ESPSD_FWVER:
LD E,ESPSD_CMD_FWVER ; FWVER COMMAND
CALL ESPSD_CMD_SLOW ; SEND IT
RET NZ ; HANDLE ERROR
CALL ESPSD_GETBYTE_SLOW ; GET BOARD ID
RET NZ ; HANDLE ERROR
LD D,E ; SAVE IN D
CALL ESPSD_GETBYTE_SLOW ; GET VER MAJOR
RET NZ ; HANDLE ERROR
LD H,E ; PUT IN H
CALL ESPSD_GETBYTE_SLOW ; GET VER MINOR
RET NZ ; HANDLE ERROR
LD L,E ; PUT IN H
CALL ESPSD_GETBYTE_SLOW ; GET RESULT
RET NZ ; HANDLE ERROR
LD A,E ; RESULT TO ACCUM
LD E,D ; BOARD ID BACK TO E
OR A ; SET FLAGS
RET Z ; RETURN SUCCESS
LD A,ESPSD_STIOERR ; CALL THIS AN I/O ERR
OR A ; SET FLAGS
RET ; DONE
;
; (RE)SELECT DEVICE
;
ESPSD_SELECT:
LD A,ESPSD_CMD_SEL0 ; INIT PRIMARY DEVICE
ADD A,(IY+ESPSD_ROLE) ; ADJUST FOR PRI/SEC
JR ESPSD_RUNCMD ; USE COMMON CMD ROUTINE
;
; SIMPLE COMMAND COMMON CODE
;
ESPSD_RUNCMD:
LD E,A ; PUT IN E
CALL ESPSD_CMD_SLOW ; SEND COMMAND
RET NZ ; HANDLE ERROR
ESPSD_GETRESULT:
CALL ESPSD_GETBYTE_SLOW ; GET RESULT
RET NZ ; HANDLE ERROR
LD A,E ; RESULT TO ACCUM
OR A ; SET FLAGS
RET Z ; RETURN SUCCESS
LD A,ESPSD_STNOTRDY ; CALL THIS A NOT READY ERR
OR A ; SET FLAGS
RET ; DONE
;
; SET CURRENT LBA TO VALUE IN DE:HL
; HIGH WORD (DE) IS CURRENTLY IGNORED BECAUSE API ONLY SUPPORTS
; A 16-BIT LBA.
;
ESPSD_SETLBA:
LD E,ESPSD_CMD_SETLBA ; SETLBA COMMAND
CALL ESPSD_CMD_SLOW ; SEND IT
RET NZ ; HANDLE ERROR
LD A,4 ; LITTLE ENDIAN
CALL ADDHLA ; BUMP TO END OF LBA BYTES
LD B,4 ; LOOP TO SEND 4 BYTES
;
ESPSD_SETLBA1:
DEC HL ; DEC POINTER
LD E,(HL) ; GET NEXT BYTE TO SEND
PUSH BC ; SAVE LOOP CONTROL
CALL ESPSD_PUTBYTE_SLOW ; SEND BYTE
POP BC ; RESTORE LOOP CONTROL
RET NZ ; HANDLE ERROR
DJNZ ESPSD_SETLBA1 ; LOOP AS NEEDED
;
CALL ESPSD_GETBYTE_SLOW ; GET RESULT
RET NZ ; HANDLE ERROR
LD A,E ; RESULT TO ACCUM
OR A ; SET FLAGS
RET Z ; GOOD RETURN
LD A,ESPSD_STIOERR ; CALL THIS AN IO ERROR
OR A
RET
;
; BLOCK READ 512 BYTES TO ADDRESS IN HL
;
ESPSD_BLKREAD:
LD E,ESPSD_CMD_READ
CALL ESPSD_CMD_SLOW
RET NZ
;
LD B,0 ; LOOP COUNTER
#IF FALSE
ESPSD_BLKREAD1:
PUSH BC
CALL ESPSD_GETBYTE_SLOW
POP BC
RET NZ
LD (HL),E
INC HL
PUSH BC
CALL ESPSD_GETBYTE_SLOW
POP BC
RET NZ
LD (HL),E
INC HL
DJNZ ESPSD_BLKREAD1
#ELSE
LD C,(IY+ESPSD_IOBASE) ; SET IO PORT
INC C ; START W/ DATA PORT
CALL ESPSD_BLKREAD2 ; DO FIRST 256 BYTES
CALL ESPSD_BLKREAD2 ; DO SECOND 256 BYTES
#ENDIF
;
CALL ESPSD_GETBYTE_SLOW ; GET RESULT
RET NZ ; HANDLE ERROR
LD A,E ; RESULT TO ACCUM
OR A ; SET FLAGS
RET Z ; GOOD RETURN
LD A,ESPSD_STIOERR ; CALL THIS AN IO ERROR
OR A ; SET FLAGS
RET ; DONE
;
ESPSD_BLKREAD2:
; READ BYTES FAST (NO TIMEOUT CHECK)
DEC C ; BACK TO STATUS PORT
ESPSD_BLKREAD2A:
#IF (PLATFORM == PLT_S100)
IN A,(C) ; EXTRA READ FOR S100 STABILITY
#ENDIF
IN A,(C) ; GET STATUS
JP P,ESPSD_BLKREAD2A ; LOOP TILL DATA READY
INC C ; DATA PORT
INI ; GET BYTE, BUMP PTR
JR NZ,ESPSD_BLKREAD2 ; 256 TIMES
RET
;
; BLOCK WRITE
;
ESPSD_BLKWRITE:
LD E,ESPSD_CMD_WRITE
CALL ESPSD_CMD_SLOW
RET NZ
;
LD B,0 ; LOOP COUNTER
#IF FALSE
ESPSD_BLKWRITE1:
LD E,(HL)
INC HL
PUSH BC
CALL ESPSD_PUTBYTE_SLOW
POP BC
RET NZ
LD E,(HL)
INC HL
PUSH BC
CALL ESPSD_PUTBYTE_SLOW
POP BC
RET NZ
DJNZ ESPSD_BLKWRITE1
#ELSE
LD C,(IY+ESPSD_IOBASE) ; SET IO PORT
INC C ; START W/ DATA PORT
CALL ESPSD_BLKWRITE2 ; DO FIRST 256 BYTES
CALL ESPSD_BLKWRITE2 ; DO SECOND 256 BYTES
#ENDIF
;
CALL ESPSD_GETBYTE_SLOW ; GET RESULT
RET NZ ; HANDLE ERROR
LD A,E ; RESULT TO ACCUM
OR A ; SET FLAGS
RET Z ; GOOD RETURN
LD A,ESPSD_STIOERR ; CALL THIS AN IO ERROR
OR A ; SET FLAGS
RET ; DONE
;
ESPSD_BLKWRITE2:
; WRITE BYTES FAST (NO TIMEOUT CHECK)
DEC C ; BACK TO STATUS PORT
ESPSD_BLKWRITE2A:
#IF (PLATFORM == PLT_S100)
IN A,(C) ; EXTRA READ FOR S100 STABILITY
#ENDIF
IN A,(C) ; GET STATUS
RRA ; SEND RDY BIT TO CF
JR C,ESPSD_BLKWRITE2A ; LOOP WHILE XMIT FULL
INC C ; DATA PORT
OUTI ; SEND BYTE, BUMP PTR
JR NZ,ESPSD_BLKWRITE2 ; 256 TIMES
RET
;
;=============================================================================
; HARDWARE INTERFACE ROUTINES
;=============================================================================
;
; SEND COMMAND BYTE IN E TO ESP32
;
ESPSD_CMD:
PUSH DE
LD E,$33 ; COMMAND PREFIX BYTE
CALL ESPSD_PUTBYTE
POP DE
RET NZ
JR ESPSD_PUTBYTE
;
; SEND COMMAND BYTE IN E TO ESP32
;
ESPSD_CMD_SLOW:
PUSH DE
LD E,$33 ; COMMAND PREFIX BYTE
CALL ESPSD_PUTBYTE_SLOW
POP DE
RET NZ
JR ESPSD_PUTBYTE_SLOW
;
; WRITE BYTE IN E TO ESP32
; RETURN STATUS IN A (0=SUCCESS)
;
ESPSD_PUTBYTE:
#IF (ESPSDTRACE >= 3)
CALL PC_GT
#ENDIF
LD B,0
LD C,(IY+ESPSD_IOBASE)
ESPSD_PUTBYTE1:
#IF (PLATFORM == PLT_S100)
IN A,(C) ; EXTRA READ FOR S100 STABILITY
#ENDIF
IN A,(C)
BIT 0,A
JR Z,ESPSD_PUTBYTE2
DJNZ ESPSD_PUTBYTE1
LD A,ESPSD_STTO
OR A
RET
ESPSD_PUTBYTE2:
; NOPS NEEDED FOR RELIABILITY
;NOP \ NOP \ NOP \ NOP \ NOP \ NOP
INC C
OUT (C),E
;
#IF (ESPSDTRACE >= 3)
LD A,E
CALL PRTHEXBYTE
#ENDIF
;
XOR A
RET
;
; WRITE BYTE TO ESP32 FROM E WITH EXTRA LONG TIMEOUT
;
ESPSD_PUTBYTE_SLOW:
PUSH HL
LD HL,100 * CPUMHZ ; CPU SPEED SCALED TIMEOUT
ESPSD_PUTBYTE_SLOW1:
PUSH HL
CALL ESPSD_PUTBYTE
POP HL
JR Z,ESPSD_PUTBYTE_SLOW_Z
DEC HL
LD A,H
OR L
JR NZ,ESPSD_PUTBYTE_SLOW1
LD A,ESPSD_STTO
ESPSD_PUTBYTE_SLOW_Z:
;CALL PC_SPACE ; *DEBUG*
;CALL PRTHEXWORDHL ; *DEBUG*
POP HL
OR A ; SET FLAGS
RET
;
; READ BYTE FROM ESP32 INTO E
; RETURN STATUS IN A (0=SUCCESS)
;
ESPSD_GETBYTE:
#IF (ESPSDTRACE >= 3)
CALL PC_LT
#ENDIF
LD B,0
LD C,(IY+ESPSD_IOBASE)
ESPSD_GETBYTE1:
#IF (PLATFORM == PLT_S100)
IN A,(C) ; EXTRA READ FOR S100 STABILITY
#ENDIF
IN A,(C)
JP M,ESPSD_GETBYTE2
DJNZ ESPSD_GETBYTE1
LD A,ESPSD_STTO
OR A
RET
ESPSD_GETBYTE2:
; NOPS NEEDED FOR RELIABILITY
;NOP \ NOP \ NOP \ NOP \ NOP \ NOP
INC C
IN E,(C)
;
#IF (ESPSDTRACE >= 3)
LD A,E
CALL PRTHEXBYTE
#ENDIF
;
XOR A
RET
;
; READ BYTE FROM ESP32 INTO E WITH EXTRA LONG TIMEOUT
;
ESPSD_GETBYTE_SLOW:
PUSH HL
LD HL,100 * CPUMHZ ; CPU SPEED SCALED TIMEOUT
ESPSD_GETBYTE_SLOW1:
PUSH HL
CALL ESPSD_GETBYTE
POP HL
JR Z,ESPSD_GETBYTE_SLOW_Z
DEC HL
LD A,H
OR L
JR NZ,ESPSD_GETBYTE_SLOW1
LD A,ESPSD_STTO
ESPSD_GETBYTE_SLOW_Z:
;CALL PC_SPACE ; *DEBUG*
;CALL PRTHEXWORDHL ; *DEBUG*
POP HL
OR A ; SET FLAGS
RET
;
;=============================================================================
; ERROR HANDLING AND DIAGNOSTICS
;=============================================================================
;
; ERROR HANDLERS
;
ESPSD_NOMEDIA:
LD A,ESPSD_STNOMEDIA
JR ESPSD_ERR
;
ESPSD_IOERR:
LD A,ESPSD_STIOERR
JR ESPSD_ERR
;
ESPSD_TO:
LD A,ESPSD_STTO
JR ESPSD_ERR
;
ESPSD_NOTRDY:
LD A,ESPSD_STNOTRDY
JR ESPSD_ERR
;
ESPSD_ERR:
LD (IY+ESPSD_STAT),A ; SAVE NEW STATUS
;
#IF (ESPSDTRACE >= 2)
CALL ESPSD_PRTSTAT
#ENDIF
OR A ; SET FLAGS
RET
;
;
;
ESPSD_PRTERR:
RET Z ; DONE IF NO ERRORS
; FALL THRU TO ESPSD_PRTSTAT
;
; PRINT FULL DEVICE STATUS LINE
;
ESPSD_PRTSTAT:
PUSH AF
PUSH DE
PUSH HL
LD A,(IY+ESPSD_STAT)
CALL ESPSD_PRTPREFIX ; PRINT UNIT PREFIX
JR ESPSD_PRTSTAT3
ESPSD_PRTSTAT2:
CALL NEWLINE
PRTS("ESPSD:$") ; NO UNIT NUM IN PREFIX FOR INVALID UNIT
ESPSD_PRTSTAT3:
CALL PC_SPACE ; FORMATTING
CALL ESPSD_PRTSTATSTR
POP HL
POP DE
POP AF
RET
;
; PRINT STATUS STRING
;
ESPSD_PRTSTATSTR:
PUSH AF
PUSH DE
LD A,(IY+ESPSD_STAT)
OR A
LD DE,ESPSD_STR_STOK
JR Z,ESPSD_PRTSTATSTR1
INC A
LD DE,ESPSD_STR_STNOMEDIA
JR Z,ESPSD_PRTSTATSTR1
INC A
LD DE,ESPSD_STR_STIOERR
JR Z,ESPSD_PRTSTATSTR1
INC A
LD DE,ESPSD_STR_STTO
JR Z,ESPSD_PRTSTATSTR1
INC A
LD DE,ESPSD_STR_STNOTRDY
JR Z,ESPSD_PRTSTATSTR1
LD DE,ESPSD_STR_STUNK
ESPSD_PRTSTATSTR1:
CALL WRITESTR
POP DE
POP AF
RET
;
; PRINT DIAGNONSTIC PREFIX
;
ESPSD_PRTPREFIX:
PUSH AF
CALL NEWLINE
PRTS("ESPSD$")
LD A,(IY+ESPSD_DEV) ; GET CURRENT DEVICE NUM
CP $FE ; NOT YET ASSIGNED?
JR Z,ESPSD_PRTPREFIX1 ; SKIP DEV NUM IF SO
CALL PRTDECB
ESPSD_PRTPREFIX1:
CALL PC_COLON
POP AF
RET
;
;=============================================================================
; STRING DATA
;=============================================================================
;
ESPSD_STR_STOK .TEXT "OK$"
ESPSD_STR_STNOMEDIA .TEXT "NO MEDIA$"
ESPSD_STR_STIOERR .TEXT "IO ERROR$"
ESPSD_STR_STTO .TEXT "TIMEOUT$"
ESPSD_STR_STNOTRDY .TEXT "NOT READY$"
ESPSD_STR_STUNK .TEXT "UNKNOWN ERROR$"
;
ESPSD_STR_2CF1SD .TEXT "2CF+1SD$"
ESPSD_STR_2SD .TEXT "2SD$"
ESPSD_STR_UNKNOWN .TEXT "BOARD?$"
;
;=============================================================================
; DATA STORAGE
;=============================================================================
;
ESPSD_CMDVAL .DB 0 ; PENDING COMMAND FOR IO FUCNTIONS
ESPSD_DSKBUF .DW 0 ; ACTIVE DISK BUFFER
;
ESPSD_DEVNUM .DB 0 ; TEMP DEVICE NUM USED DURING INIT