; ;============================================================================= ; 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 ; ; 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) === ; ; 7 6 5 4 3 2 1 0 ; +-------+-------+-------+-------+-------+-------+-------+-------+ ; | XIN | ERR | DSW | CS1 | CS0 | CD1 | CD0 | XOUT | ; +-------+-------+-------+-------+-------+-------+-------+-------+ ; ; XIN: DATA READ FROM ESP32 PENDING ; ERR: ERROR ACTIVE ; DSW: OLED DISPLAY ACTIVATION ; CS1: SD CARD 1 CHIP SELECT ; CS0: SD CARD 0 CHIP SELECT ; CD1: SD CARD 1 MEDIA PRESENT (CARD DETECT) ; CD0: SD CARD 0 MEDIA PRESENT (CARD DETECT) ; XOUT: DATA WRITE TO ESP32 PENDING ; ; === STATUS REGISTER (WRITE) === ; ; 7 6 5 4 3 2 1 0 ; +-------+-------+-------+-------+-------+-------+-------+-------+ ; | XIN | | | | | | | XOUT | ; +-------+-------+-------+-------+-------+-------+-------+-------+ ; ; XIN: UNUSED??? ; XOUT: ACTIVATE WRITE TO ESP32 ; 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_SETLBA .EQU $84 ; SET LBA 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 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 ; ESPSD_CFGSIZ .EQU 12 ; SIZE OF CFG TBL ENTRIES ; ; PER DEVICE DATA OFFSETS ; 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_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 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: ; WE USE A DUMMY SETLBA COMMAND TO TEST FOR PRESENCE LD HL,0 ; IRRELEVANT JP ESPSD_SETLBA ; PASS OFF TO SETLBA ; ; 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 ; ; GET CAPACITY ; NOT CURRENTLY AVAILABLE IN ESP32 API ; CAPACITY IS HARD-CODED ABOVE AT API MAX OF $10000 BLOCKS ; ; 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 ;CALL LDELAY ; *DEBUG* ; ; SET LBA LD A,ESPSD_LBA ; OFFSET OF LBA VALUE CALL LDHLIYA ; HL := IY + A, REG A TRASHED CALL HB_DSKACT ; SHOW ACTIVITY CALL LD32 ; LOAD IT TO DE:HL, AF IS TRASHED CALL ESPSD_SETLBA ; SEND LBA TO DEVICE ;JP ESPSD_IOERR ; *DEBUG* JP NZ,ESPSD_ERR ; ON ERROR, RECORD AND BAIL OUT ;CALL LDELAY ; *DEBUG* ; ; 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 ;CALL LDELAY ; *DEBUG* ; ; 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: LD A,ESPSD_CMD_INIT0 ; INIT PRIMARY DEVICE ADD A,(IY+ESPSD_ROLE) ; ADJUST FOR PRI/SEC JR ESPSD_RUNCMD ; USE COMMON CMD ROUTINE ; ; (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 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 CALL ESPSD_CMD_SLOW RET NZ LD E,H CALL ESPSD_PUTBYTE_SLOW RET NZ LD E,L CALL ESPSD_PUTBYTE_SLOW RET NZ CALL ESPSD_GETBYTE_SLOW RET NZ 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 ESPSD_BLKREAD1: PUSH BC CALL ESPSD_GETBYTE_SLOW RET NZ LD (HL),E INC HL CALL ESPSD_GETBYTE_SLOW RET NZ LD (HL),E INC HL POP BC DJNZ ESPSD_BLKREAD1 ; 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 ; ; BLOCK WRITE ; ESPSD_BLKWRITE: LD E,ESPSD_CMD_WRITE CALL ESPSD_CMD_SLOW RET NZ ; LD B,0 ; LOOP COUNTER ESPSD_BLKWRITE1: PUSH BC LD E,(HL) INC HL CALL ESPSD_PUTBYTE_SLOW RET NZ LD E,(HL) INC HL CALL ESPSD_PUTBYTE_SLOW RET NZ POP BC DJNZ ESPSD_BLKWRITE1 ; 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 ; ;============================================================================= ; HARDWARE INTERFACE ROUTINES ;============================================================================= ; ; SEND COMMAND BYTE IN E TO ESP32 ; ESPSD_CMD: PUSH DE LD E,$33 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 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: IN A,(C) BIT 0,A JR Z,ESPSD_PUTBYTE2 ;JR ESPSD_PUTBYTE1 ; *DEBUG* DJNZ ESPSD_PUTBYTE1 LD A,ESPSD_STTO OR A RET ESPSD_PUTBYTE2: 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,50 * 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: IN A,(C) BIT 7,A JR NZ,ESPSD_GETBYTE2 DJNZ ESPSD_GETBYTE1 LD A,ESPSD_STTO OR A RET ESPSD_GETBYTE2: 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,50 * 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$" ; ;============================================================================= ; 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