; ;============================================================================= ; 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) ; ;-------------------------------------------------------------------------------------------------- ; HBIOS MODULE HEADER ;-------------------------------------------------------------------------------------------------- ; ORG_ESPSD .EQU $ ; .DW SIZ_ESPSD ; MODULE SIZE .DW ESPSD_INITPHASE ; ADR OF INIT PHASE HANDLER ; ESPSD_INITPHASE: ; INIT PHASE HANDLER, A=PHASE ;CP HB_PHASE_PREINIT ; PREINIT PHASE? ;JP Z,ESPSD_PREINIT ; DO PREINIT CP HB_PHASE_INIT ; INIT PHASE? JP Z,ESPSD_INIT ; DO INIT RET ; DONE ; 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 #ELSE RET NZ #ENDIF ; 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 E,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 E,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: ; #IF (ESPSD_USECD) ; 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 #ENDIF ; 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: ; #IF (ESPSDTRACE == 1) PUSH HL LD HL,ESPSD_PRTERR ; SET UP ESPSD_PRTERR EX (SP),HL ; ... TO FILTER ALL EXITS #ENDIF ; PUSH DE PUSH HL CALL ESPSD_CHKERR ; CHECK FOR ERR STATUS AND RESET IF SO POP HL POP DE RET NZ ; BAIL OUT ON ERROR ; LD A,E ; COMMAND TO ACCUM LD (ESPSD_CMDVAL),A ; SAVE THE COMMAND LD (ESPSD_DSKBUF),HL ; SAVE DISK BUFFER ADDRESS ; ; 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: JR NZ,ESPSD_IO4 ; IF ERROR, SKIP INCREMENT ; ; 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 ; XOR A ; SIGNAL SUCCESS ESPSD_IO4: LD HL,(ESPSD_DSKBUF) ; CURRENT DMA TO HL OR A ; SET FLAGS RET Z ; DONE IF NO ERROR LD A,ERR_IO ; SIGNAL IO ERROR OR A ; SET FLAGS RET ; AND DONE ; ; CHECK CURRENT DEVICE FOR ERROR STATUS AND ATTEMPT TO RECOVER ; VIA RESET IF DEVICE IS IN ERROR. ; ESPSD_CHKERR: LD A,(IY+ESPSD_STAT) ; GET STATUS OR A ; SET FLAGS CALL NZ,ESPSD_RESET ; IF ERROR STATUS, RESET BUS RET ; ;============================================================================= ; 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 ; 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 ; 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 ; SEND IT RET NZ ; HANDLE ERROR CALL ESPSD_GETBYTE ; GET BOARD ID RET NZ ; HANDLE ERROR LD D,E ; SAVE IN D CALL ESPSD_GETBYTE ; GET VER MAJOR RET NZ ; HANDLE ERROR LD H,E ; PUT IN H CALL ESPSD_GETBYTE ; GET VER MINOR RET NZ ; HANDLE ERROR LD L,E ; PUT IN H CALL ESPSD_GETBYTE ; 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 ; SEND COMMAND RET NZ ; HANDLE ERROR ESPSD_GETRESULT: CALL ESPSD_GETBYTE ; 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 ; 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 ; SEND BYTE POP BC ; RESTORE LOOP CONTROL RET NZ ; HANDLE ERROR DJNZ ESPSD_SETLBA1 ; LOOP AS NEEDED ; CALL ESPSD_GETBYTE ; 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 RET NZ ; LD B,0 ; LOOP COUNTER #IF FALSE ESPSD_BLKREAD1: PUSH BC CALL ESPSD_GETBYTE POP BC RET NZ LD (HL),E INC HL PUSH BC CALL ESPSD_GETBYTE 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 ; GET RESULT RET NZ ; HANDLE ERROR LD A,E ; RESULT TO ACCUM OR A ; SET FLAGS JP NZ,ESPSD_IOERR ; HANDLE AS IO ERROR XOR A ; SIGNAL SUCCESS RET ; AND DONE ; ESPSD_BLKREAD2: ; READ BYTES FAST (NO TIMEOUT CHECK) DEC C ; BACK TO STATUS PORT ESPSD_BLKREAD2A: #IF (PLATFORM == PLT_SZ180) IN A,(C) ; EXTRA READ FOR Z180 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 RET NZ ; LD B,0 ; LOOP COUNTER #IF FALSE ESPSD_BLKWRITE1: LD E,(HL) INC HL PUSH BC CALL ESPSD_PUTBYTE POP BC RET NZ LD E,(HL) INC HL PUSH BC CALL ESPSD_PUTBYTE 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 ; GET RESULT RET NZ ; HANDLE ERROR LD A,E ; RESULT TO ACCUM OR A ; SET FLAGS JP NZ,ESPSD_IOERR ; HANDLE AS IO ERROR XOR A ; SIGNAL SUCCESS RET ; AND DONE ; ESPSD_BLKWRITE2: ; WRITE BYTES FAST (NO TIMEOUT CHECK) DEC C ; BACK TO STATUS PORT ESPSD_BLKWRITE2A: #IF (PLATFORM == PLT_SZ180) IN A,(C) ; EXTRA READ FOR Z180 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 ; ; WRITE BYTE IN E TO ESP32 ; RETURN STATUS IN A (0=SUCCESS) ; BC IS DESTROYED ; ESPSD_PUTBYTE: #IF (ESPSDTRACE >= 3) CALL PC_GT #ENDIF PUSH HL ; PRESERVE HL LD C,(IY+ESPSD_IOBASE) LD HL,100 * CPUMHZ ; SETUP OUTER LOOP COUNTER ; ESPSD_PUTBYTE1: ; OUTER LOOP LD B,0 ; SETUP INNER LOOP COUNTER ; ESPSD_PUTBYTE2: ; INNER LOOP #IF (PLATFORM == PLT_SZ180) IN A,(C) ; EXTRA READ FOR Z180 STABILITY #ENDIF IN A,(C) ; READ STATUS BIT 0,A ; ISOLATE SENDACT (TXF) JR Z,ESPSD_PUTBYTE3 ; IF NOT ACTIVE, GO TO SEND BYTE DJNZ ESPSD_PUTBYTE2 ; LOOP SOME MORE ; DEC HL ; DEC OUTER LOOP COUNTER LD A,H ; TEST COUNTER OR L ; ... FOR ZERO JR NZ,ESPSD_PUTBYTE1 ; IF NOT ZERO, LOOP MORE ; ; HANDLE TIMEOUT POP HL ; RECOVER HL JP ESPSD_TO ; RETURN VIA ERROR HANDLER ; ESPSD_PUTBYTE3: POP HL ; RECOVER HL ; SEND THE DATA BYTE ; NOPS NEEDED FOR RELIABILITY??? ;NOP \ NOP \ NOP \ NOP \ NOP \ NOP INC C ; BUMP TO DATA PORT OUT (C),E ; SEND IT ; #IF (ESPSDTRACE >= 3) LD A,E CALL PRTHEXBYTE #ENDIF ; XOR A ; SIGNAL SUCCESS RET ; DONE ; ; READ BYTE FROM ESP32 INTO E ; RETURN STATUS IN A (0=SUCCESS) ; BC IS DESTROYED ; ESPSD_GETBYTE: #IF (ESPSDTRACE >= 3) CALL PC_LT #ENDIF PUSH HL ; PRESERVE HL LD C,(IY+ESPSD_IOBASE) LD HL,100 * CPUMHZ ; SETUP OUTER LOOP COUNTER ; ESPSD_GETBYTE1: ; OUTER LOOP LD B,0 ; SETUP INNER LOOP COUNTER ; ESPSD_GETBYTE2: ; INNER LOOP #IF (PLATFORM == PLT_SZ180) IN A,(C) ; EXTRA READ FOR Z180 STABILITY #ENDIF IN A,(C) ; READ STATUS JP M,ESPSD_GETBYTE3 ; IF RCV READY, GO TO GET BYTE DJNZ ESPSD_GETBYTE2 ; LOOP SOME MORE ; DEC HL ; DEC OUTER LOOP COUNTER LD A,H ; TEST COUNTER OR L ; ... FOR ZERO JR NZ,ESPSD_GETBYTE1 ; IF NOT ZERO, LOOP MORE ; ; HANDLE TIMEOUT POP HL ; RECOVER HL JP ESPSD_TO ; RETURN VIA ERROR HANDLER ; ESPSD_GETBYTE3: POP HL ; RECOVER HL ; NOPS NEEDED FOR RELIABILITY??? ;NOP \ NOP \ NOP \ NOP \ NOP \ NOP INC C ; BUMP TO DATA PORT IN E,(C) ; GET DATA BYTE ; #IF (ESPSDTRACE >= 3) LD A,E CALL PRTHEXBYTE #ENDIF ; XOR A ; SIGNAL SUCCESS RET ; DONE ; ;============================================================================= ; 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 ; ;-------------------------------------------------------------------------------------------------- ; HBIOS MODULE TRAILER ;-------------------------------------------------------------------------------------------------- ; END_ESPSD .EQU $ SIZ_ESPSD .EQU END_ESPSD - ORG_ESPSD ; MEMECHO "ESPSD occupies " MEMECHO SIZ_ESPSD MEMECHO " bytes.\n"