; ;================================================================================================== ; ESP32 DRIVER ; ; SUPPORTS DAN WERNER'S NHYODYNE (MBC) ESP32 MODULE ; https://github.com/danwerner21/nhyodyne/tree/main/Z80ESP ;================================================================================================== ; ; TODO: ; ESP_IOBASE .EQU $9C ESP_0_IO .EQU ESP_IOBASE + 0 ESP_1_IO .EQU ESP_IOBASE + 1 ESP_STAT .EQU ESP_IOBASE + 2 ; ; ESP STATUS PORT ; MSB XX S S S S S S ; | | | | | +- ESP0 READY OUTPUT ; | | | | +--- ESP0 BUSY ; | | | +----- ESP0 SPARE ; | | +------- ESP1 READY OUTPUT ; | +--------- ESP1 BUSY ; +----------- ESP1 SPARE ; ESP_0_RDY .EQU %00000001 ESP_0_BUSY .EQU %00000010 ESP_0_SPARE .EQU %00000100 ESP_1_RDY .EQU %00001000 ESP_1_BUSY .EQU %00010000 ESP_1_SPARE .EQU %00100000 ; ; COMMAND OPCODES ; ESP_CMD_NOP .EQU 0 ; NO OP ESP_CMD_COUT .EQU 1 ; CHAR OUT ESP_CMD_SOUT .EQU 2 ; STRING OUT ESP_CMD_KIN .EQU 3 ; KEY IN ESP_CMD_KST .EQU 4 ; KBD BUF STATUS ESP_CMD_DISC .EQU $FF ; DISCOVER ; ; GLOBAL ESP INITIALIZATION ; ESP_INIT: ; CALL NEWLINE ; FORMATTING PRTS("ESP: IO=0x$") LD A,ESP_IOBASE CALL PRTHEXBYTE ; CALL ESP_DETECT LD DE,ESP_STR_NOHW JP NZ,WRITESTR ; ; PRINT FIRMWARE VERSION PRTS(" F/W=$") CALL ESP_PRTVER ; CALL ESPCON_INIT ; CONSOLE INITIALIZATION ; RET ; ;================================================================================================== ; ESP32 INTERFACE FUNCTIONS ;================================================================================================== ; ESP_DETECT: CALL ESP_CLR ; CLEAR ANY PENDING DATA RET NZ ; IF FAILS, ASSUME NOT PRESENT LD A,ESP_CMD_DISC ; DISCOVER COMMAND CALL ESP_OUT ; SEND IT LD DE,10 ; DELAY 160US CALL VDELAY ; ... TO ENSURE OUTPUT RDY SET IN A,(ESP_STAT) ; GET STATUS AND ESP_0_RDY ; ISOLATE OUTPUT READY BIT XOR ESP_0_RDY ; INVERT SO 0=FOUND RET ; DONE ; ; CLEAR ESP INPUT QUEUE ; ESP_CLR: LD B,0 ; MAX CHARS TO READ ESP_CLR0: CALL ESP_WTNBSY ; WAIT TILL NOT BUSY IN A,(ESP_STAT) ; GET STATUS AND ESP_0_RDY ; IS THERE MORE DATA? RET Z ; IF NOT, DONE IN A,(ESP_0_IO) ; GET CHAR DJNZ ESP_CLR0 ; LOOP TILL DONE OR $FF ; SIGNAL FAILURE RET ; ; PRINT ESP VERSION STRING TO CONSOLE ; ESP_PRTVER: CALL ESP_CLR ; CLEAR ANY PENDING DATA LD A,ESP_CMD_DISC ; DISCOVER COMMAND CALL ESP_OUT ; SEND IT CALL ESP_WTRDY ; WAIT FOR READY TO OUTPUT ESP_PRTVER1: CALL ESP_WTNBSY ; WAIT TILL NOT BUSY IN A,(ESP_STAT) ; GET STATUS AND ESP_0_RDY ; ISOLATE OUTPUT READY BIT RET Z ; DONE IF NOTHING READY CALL ESP_IN ; GET NEXT CHAR CALL COUT ; PRINT CHAR JR ESP_PRTVER1 ; LOOP ; ; SEND BYTE TO ESP ; ESP_OUT: PUSH AF ; SAVE VALUE CALL ESP_WTNBSY ; WAIT TILL NOT BUSY POP AF ; POP VALUE OUT (ESP_0_IO),A ; SEND CHARACTER JR ESP_WTBSY ; RETURN VIA WTBSY ; ; GET BYTE FROM ESP (BLOCKING) ; ESP_INWAIT: CALL ESP_WTNBSY ; WAIT TILL NOT BUSY CALL ESP_WTRDY ; WAIT FOR READY TO OUTPUT ; FALL THRU (GET CHAR VIA ESP_IN) ; ; GET BYTE FROM ESP (NON BLOCKING) ; ESP_IN: CALL ESP_WTNBSY ; WAIT TILL NOT BUSY ESP_IN1: IN A,(ESP_0_IO) ; GET BYTE PUSH AF ; SAVE VALUE CALL ESP_WTBSY ; WAIT TILL BUSY POP AF ; RESTORE VALUE RET ; AND RETURN ; ; WAIT FOR ESP TO BE NOT BUSY ; ESP_WTNBSY: LD B,0 ; MAX TRIES ESP_WTNBSY1: IN A,(ESP_STAT) ; GET STATUS AND ESP_0_BUSY ; IS ESP BUSY? RET Z ; RETURN IF NOT BUSY DJNZ ESP_WTNBSY1 ; ELSE LOOP OR $FF ; SIGNAL TIMEOUT RET ; AND RETURN ; ; WAIT FOR ESP TO BE BUSY ; ESP_WTBSY: LD B,20 ; MAX TRIES ESP_WTBSY1: IN A,(ESP_STAT) ; GET STATUS AND ESP_0_BUSY ; IS ESP BUSY? XOR ESP_0_BUSY ; INVERT RET Z ; RETURN IF BUSY DJNZ ESP_WTBSY1 ; ELSE LOOP OR $FF ; SIGNAL TIMEOUT RET ; AND RETURN ; ; WAIT FOR ESP TO BE READY TO OUTPUT ; ESP_WTRDY: LD B,0 ; MAX TRIES ESP_WTRDY1: IN A,(ESP_STAT) ; GET STATUS AND ESP_0_RDY ; IS ESP READY TO OUTPUT XOR ESP_0_RDY ; INVERT, 0=READY RET Z ; RETURN IF READY DJNZ ESP_WTRDY1 ; ELSE LOOP OR $FF ; SIGNAL TIMEOUT RET ; AND RETURN ; ; ; ESP_STR_NOHW .TEXT " NOT PRESENT$" ESP_STR_UPGRADE .TEXT " !!!UPGRADE REQUIRED!!!$" ; ;================================================================================================== ; ESP32 CONSOLE DRIVER ;================================================================================================== ; ; ESPCON_ROWS .EQU 25 ; VGA DISPLAY ROWS ESPCON_COLS .EQU 80 ; VGA DISPLAY COLS ; ; ; ESPCON_INIT: ; CALL NEWLINE PRTS("ESPCON:$") ; ; DISPLAY CONSOLE DIMENSIONS CALL PC_SPACE LD A,ESPCON_COLS CALL PRTDECB LD A,'X' CALL COUT LD A,ESPCON_ROWS CALL PRTDECB CALL PRTSTRD .TEXT " TEXT (ANSI)$" ; ; ADD OURSELVES TO CIO DISPATCH TABLE ; LD D,0 ; PHYSICAL UNIT IS ZERO LD E,CIODEV_ESPCON ; DEVICE TYPE LD BC,ESPCON_FNTBL ; BC := FUNCTION TABLE ADDRESS CALL CIO_ADDENT ; ADD ENTRY, A := UNIT ASSIGNED LD (HCB + HCB_CRTDEV),A ; SET OURSELVES AS THE CRT DEVICE ; XOR A ; SIGNAL SUCCESS RET ; ; DRIVER FUNCTION TABLE ; ESPCON_FNTBL: .DW ESPCON_IN .DW ESPCON_OUT .DW ESPCON_IST .DW ESPCON_OST .DW ESPCON_INITDEV .DW ESPCON_QUERY .DW ESPCON_DEVICE #IF (($ - ESPCON_FNTBL) != (CIO_FNCNT * 2)) .ECHO "*** INVALID ESPCON FUNCTION TABLE ***\n" #ENDIF ; ; ; ESPCON_IN: CALL ESPCON_IST JR Z,ESPCON_IN LD A,ESP_CMD_KIN ; KBD INPUT CALL ESP_OUT ; SEND CMD OPCODE CALL ESP_INWAIT ; GET KEY LD E,A ; PUT IN E XOR A ; SIGNAL SUCCES RET ; AND DONE ; ; ; ESPCON_IST: LD A,ESP_CMD_KST ; KBD BUF STATUS CALL ESP_OUT ; SEND CMD OPCODE CALL ESP_INWAIT ; GET BUF SIZE OR A ; SET FLAGS RET Z ; AND DONE OR A RET ; ; ; ESPCON_OUT: PUSH DE LD A,ESP_CMD_COUT ; CHAR OUT OPCODE CALL ESP_OUT POP DE LD A,E CALL ESP_OUT ; SEND CHAR VALUE XOR A ; SIGNAL SUCCESS RET ; ; ; ESPCON_OST: OR $FF ; SIGNAL OUTPUT QUEUE READY RET ; RETURN ; ; ; ESPCON_INITDEV: SYSCHKERR(ERR_NOTIMPL) RET ; ; ; ESPCON_QUERY: LD DE,0 LD HL,0 XOR A RET ; ; ; ESPCON_DEVICE: LD D,CIODEV_ESPCON ; D := DEVICE TYPE LD E,0 ; E := DEVICE NUM, ALWAYS 0 LD C,$BF ; C := DEVICE TYPE, 0xBF IS PROP TERM LD H,0 ; H := 0, DRIVER HAS NO MODES LD L,ESP_IOBASE ; L := BASE I/O ADDRESS XOR A ; SIGNAL SUCCESS RET ; ;============================================================================= ; DATA STORAGE ;============================================================================= ;