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.
 
 
 
 
 
 

608 lines
13 KiB

;
;==================================================================================================
; 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_0_CMD_COUT .EQU 1 ; CHAR OUT
ESP_0_CMD_SOUT .EQU 2 ; STRING OUT
ESP_0_CMD_KIN .EQU 3 ; KEY IN
ESP_0_CMD_KST .EQU 4 ; KBD BUF STATUS
ESP_CMD_SBAUD .EQU 6 ; SET SERIAL BAUD RATE
ESP_CMD_SMODE .EQU 7 ; SET SERIAL LINE MODE
ESP_CMD_SOUT .EQU 8 ; SERIAL BYTE OUT
ESP_CMD_SIN .EQU 10 ; SERIAL BYTE IN
ESP_CMD_SST .EQU 11 ; SERIAL INPUT STATUS
ESP_CMD_DISC .EQU $FF ; DISCOVER
;
; ESP CONFIG TABLE ENTRY OFFSETS
;
ESP_CFG_DEV .EQU 0 ; DEVICE NUMBER
ESP_CFG_IO .EQU 1 ; ESP I/O PORT
ESP_CFG_ST .EQU 2 ; ESP STATUS PORT
ESP_CFG_RDYMSK .EQU 3 ; ESP READY MASK
ESP_CFG_BSYMSK .EQU 4 ; ESP BUSY MASK
;
; GLOBAL ESP INITIALIZATION
;
ESP_INIT:
;
CALL NEWLINE ; FORMATTING
PRTS("ESP: IO=0x$")
LD A,ESP_IOBASE
CALL PRTHEXBYTE
;
XOR A ; ZERO ACCUM
LD (ESP_PRES),A ; CLEAR MODULE PRESENCE BITS
;
; DETECT FIRST ESP32 MODULE
PRTS(" A=$")
LD IY,ESPSER0_CFG
CALL ESP_DETECT
JR Z,ESP_INIT1 ; FOUND
LD DE,ESP_STR_NOHW
CALL WRITESTR
JR ESP_INIT2
;
ESP_INIT1:
CALL ESP_PRTVER
LD A,(ESP_PRES)
SET 0,A
LD (ESP_PRES),A
;
ESP_INIT2:
; DETECT SECOND ESP32 MODULE
PRTS(" B=$")
LD IY,ESPSER1_CFG
CALL ESP_DETECT
JR Z,ESP_INIT3 ; FOUND
LD DE,ESP_STR_NOHW
CALL WRITESTR
JR ESP_INIT4
;
ESP_INIT3:
CALL ESP_PRTVER
LD A,(ESP_PRES)
SET 1,A
LD (ESP_PRES),A
;
ESP_INIT4:
; INITIALIZE FIRST MODULE CHILD DRIVERS
LD A,(ESP_PRES)
BIT 0,A
JR Z,ESP_INIT5
LD IY,ESPSER0_CFG
CALL ESPSER_INIT ; SERIAL INITIALIZATION
LD IY,ESPCON0_CFG
CALL ESPCON_INIT ; CONSOLE INITIALIZATION
;
ESP_INIT5:
; INITIALIZE SECOND MODULE CHILD DRIVERS
LD A,(ESP_PRES)
BIT 1,A
JR Z,ESP_INIT6
LD IY,ESPSER1_CFG
CALL ESPSER_INIT ; SERIAL INITIALIZATION
;
ESP_INIT6:
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
;
; LOOK FOR SIGNATURE STARTING WITH "ESP"
CALL ESP_INWAIT ; ATTEMPT TO GET CHAR
CP 'E'
RET NZ
CALL ESP_INWAIT ; ATTEMPT TO GET CHAR
CP 'S'
RET NZ
CALL ESP_INWAIT ; ATTEMPT TO GET CHAR
CP 'P'
RET
;
; CLEAR ESP INPUT QUEUE
;
ESP_CLR:
LD B,0 ; MAX CHARS TO READ
ESP_CLR0:
CALL ESP_WTNBSY ; WAIT TILL NOT BUSY
RET NZ ; BAIL OUT IF TIMEOUT
IN A,(ESP_STAT) ; GET STATUS
AND (IY+ESP_CFG_RDYMSK) ; IS THERE MORE DATA?
RET Z ; IF NOT, DONE
LD C,(IY+ESP_CFG_IO) ; ESP I/O PORT
IN A,(C) ; GET BYTE
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
AND (IY+ESP_CFG_RDYMSK) ; 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
LD C,(IY+ESP_CFG_IO) ; ESP I/O PORT
OUT (C),A ; SEND BYTE
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:
LD C,(IY+ESP_CFG_IO) ; ESP I/O PORT
IN A,(C) ; 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:
LD C,(IY+ESP_CFG_ST) ; ESP STATUS PORT
IN A,(C) ; GET STATUS
AND (IY+ESP_CFG_BSYMSK) ; 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:
LD C,(IY+ESP_CFG_ST) ; ESP STATUS PORT
IN A,(C) ; GET STATUS
XOR $FF ; INVERT SO 0=BUSY
AND (IY+ESP_CFG_BSYMSK) ; IS ESP BUSY?
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:
LD C,(IY+ESP_CFG_ST) ; ESP STATUS PORT
IN A,(C) ; GET STATUS
XOR $FF ; INVERT SO 0=READY
AND (IY+ESP_CFG_RDYMSK) ; IS ESP READY TO OUTPUT
RET Z ; RETURN IF READY
DJNZ ESP_WTRDY1 ; ELSE LOOP
OR $FF ; SIGNAL TIMEOUT
RET ; AND RETURN
;
;
;
ESP_PRES .DB 0 ; MODULE PRESENCE BITS
;
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:
LD A,(ESPCON_DEVCNT) ; GET ESPCON PHYSICAL DEVICE COUNT
LD (IY+ESP_CFG_DEV),A ; SAVE PHYSICAL UNIT NUMBER
INC A ; UPDATE COUNT
LD (ESPCON_DEVCNT),A ; SAVE COUNT
;
; ADD OURSELVES TO CIO DISPATCH TABLE
;
LD BC,ESPCON_FNTBL ; BC := FUNCTION TABLE ADDRESS
PUSH IY ; COPY CONFIG ENTRY PTR
POP DE ; ... TO DE
CALL CIO_ADDENT ; ADD ENTRY, A := UNIT ASSIGNED
LD (HCB + HCB_CRTDEV),A ; SET OURSELVES AS THE CRT DEVICE
;
; ANNOUNCE OURSLEVES
;
CALL NEWLINE ; FORMATTING
PRTS("ESPCON$") ; NAME
LD A,(IY+ESP_CFG_DEV) ; GET PHYSICAL UNIT NUMBER
CALL PRTDECB ; UNIT STILL IN A FROM ABOVE
CALL PC_COLON ; FORMATTING
;
; 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)$"
;
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_0_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_0_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_0_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:
XOR A ; ZERO ACCUM
INC A ; ACCUM := 1 TO SIGNAL 1 BUFFER POSITION
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,(IY+ESP_CFG_DEV) ; E := DEVICE NUM
LD C,$BF ; C := DEVICE TYPE, 0xBF IS PROP TERM
LD H,0 ; H := 0, DRIVER HAS NO MODES
LD L,(IY+ESP_CFG_IO) ; L := BASE I/O ADDRESS
XOR A ; SIGNAL SUCCESS
RET
;
; ESPCON CONFIGURATION
;
ESPCON_CFG:
ESPCON0_CFG:
.DB 0 ; DEVICE NUMBER (UPDATED DURING INIT)
.DB ESP_0_IO ; ESP DATA PORT
.DB ESP_STAT ; ESP STATUS PORT
.DB ESP_0_RDY ; ESP READY BIT MASK
.DB ESP_0_BUSY ; ESP BUSY BIT MASK
;
;
;
ESPCON_DEVCNT .DB 0 ; ESPCON DEVICES COUNT
;
;==================================================================================================
; ESP32 SERIAL DRIVER
;==================================================================================================
;
ESPSER_LINECFG .EQU SER_115200_8N1
;
ESPSER_CFG_LINE .EQU 5
;
;
;
ESPSER_INIT:
LD A,(ESPSER_DEVCNT) ; GET ESPSER PHYSICAL DEVICE COUNT
LD (IY+ESP_CFG_DEV),A ; SAVE PHYSICAL UNIT NUMBER
INC A ; UPDATE COUNT
LD (ESPSER_DEVCNT),A ; SAVE COUNT
;
; ADD OURSELVES TO CIO DISPATCH TABLE
;
LD BC,ESPSER_FNTBL ; BC := FUNCTION TABLE ADDRESS
PUSH IY ; COPY CONFIG ENTRY PTR
POP DE ; ... TO DE
CALL CIO_ADDENT ; ADD ENTRY, A := UNIT ASSIGNED
;
; ANNOUNCE OURSLEVES
;
CALL NEWLINE ; FORMATTING
PRTS("ESPSER$") ; NAME
LD A,(IY+ESP_CFG_DEV) ; GET PHYSICAL UNIT NUMBER
CALL PRTDECB ; UNIT STILL IN A FROM ABOVE
CALL PC_COLON ; FORMATTING
;
PRTS(" MODE=$") ; FORMATTING
LD E,(IY+ESPSER_CFG_LINE+0) ; FIRST CONFIG BYTE TO E
LD D,(IY+ESPSER_CFG_LINE+1) ; SECOND CONFIG BYTE TO D
CALL PS_PRTSC0 ; PRINT CONFIG
;
; TODO: PRINT SERIAL CONFIG
;
XOR A ; SIGNAL SUCCESS
RET
;
; DRIVER FUNCTION TABLE
;
ESPSER_FNTBL:
.DW ESPSER_IN
.DW ESPSER_OUT
.DW ESPSER_IST
.DW ESPSER_OST
.DW ESPSER_INITDEV
.DW ESPSER_QUERY
.DW ESPSER_DEVICE
#IF (($ - ESPSER_FNTBL) != (CIO_FNCNT * 2))
.ECHO "*** INVALID ESPSER FUNCTION TABLE ***\n"
#ENDIF
;
;
;
ESPSER_IN:
CALL ESPSER_IST
JR Z,ESPSER_IN
LD A,ESP_CMD_SIN ; SERIAL 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
;
;
;
ESPSER_IST:
LD A,ESP_CMD_SST ; SERIAL STATUS
CALL ESP_OUT ; SEND CMD OPCODE
CALL ESP_INWAIT ; GET BUF SIZE
OR A ; SET FLAGS
RET Z ; AND DONE
OR A
RET
;
;
;
ESPSER_OUT:
PUSH DE
LD A,ESP_CMD_SOUT ; CHAR OUT OPCODE
CALL ESP_OUT
POP DE
LD A,E
CALL ESP_OUT ; SEND CHAR VALUE
XOR A ; SIGNAL SUCCESS
RET
;
;
;
ESPSER_OST:
XOR A ; ZERO ACCUM
INC A ; ACCUM := 1 TO SIGNAL 1 BUFFER POSITION
RET ; RETURN
;
;
;
ESPSER_INITDEV:
PUSH DE ; SAVE INCOMING CONFIG WORD
;
; XLATE NEW LINE MODE INTO C
LD A,E
AND %00111111 ; ISOLATE MODE BITS
LD C,0 ; 8N1 = 0
CP SER_DATA8 | SER_PARNONE | SER_STOP1
JR Z,ESPSER_INITDEV1 ; IF MATCH, DO IT
INC C ; 8E1 = 1
CP SER_DATA8 | SER_PAREVEN | SER_STOP1
JR Z,ESPSER_INITDEV1 ; IF MATCH, DO IT
INC C ; 8O1 = 2
CP SER_DATA8 | SER_PARODD | SER_STOP1
JR Z,ESPSER_INITDEV1 ; IF MATCH, DO IT
INC C ; 7N1 = 3
CP SER_DATA7 | SER_PARNONE | SER_STOP1
JR Z,ESPSER_INITDEV1 ; IF MATCH, DO IT
INC C ; 7E1 = 4
CP SER_DATA7 | SER_PAREVEN | SER_STOP1
JR Z,ESPSER_INITDEV1 ; IF MATCH, DO IT
INC C ; 7O1 = 5
CP SER_DATA7 | SER_PARODD | SER_STOP1
JR Z,ESPSER_INITDEV1 ; IF MATCH, DO IT
JR NZ,ESPSER_INITDEV_ERR ; ELSE FAIL
;
ESPSER_INITDEV1:
; DECODE NEW BAUD RATE INTO DE:HL
LD H,0
LD A,D
AND %00011111
LD L,A
LD DE,75
PUSH BC ; SAVE NEW LINE MODE
CALL DECODE ; DE:HL IS DECODED BAUD RATE
POP BC ; RESTORE NEW LINE MODE
JR NZ,ESPSER_INITDEV_ERR ; IF ERROR, FAIL
;
; PROGRAM NEW LINE MODE
PUSH BC
LD A,ESP_CMD_SMODE
CALL ESP_OUT
POP BC
LD A,C
;CALL PRTHEXBYTE
;CALL LDELAY
CALL ESP_OUT
;
; PROGRAM NEW BAUD RATE
LD A,ESP_CMD_SBAUD
CALL ESP_OUT
LD A,L
CALL ESP_OUT
LD A,H
CALL ESP_OUT
LD A,E
CALL ESP_OUT
LD A,D
CALL ESP_OUT
;
; SAVE NEW LINE CONFIG WORD
POP DE ; RESTORE CONFIG WORD
LD (IY+ESPSER_CFG_LINE+0),E ; FIRST CONFIG BYTE
LD (IY+ESPSER_CFG_LINE+1),D ; SECOND CONFIG BYTE
;
XOR A
RET
;
ESPSER_INITDEV_ERR:
POP DE ; THROW AWAY CONFIG WORD ON STACK
OR $FF
RET
;
;
;
ESPSER_QUERY:
LD E,(IY+ESPSER_CFG_LINE+0) ; FIRST CONFIG BYTE TO E
LD D,(IY+ESPSER_CFG_LINE+1) ; SECOND CONFIG BYTE TO D
LD HL,0
XOR A
RET
;
;
;
ESPSER_DEVICE:
LD D,CIODEV_ESPSER ; D := DEVICE TYPE
LD E,(IY+ESP_CFG_DEV) ; E := DEVICE NUM
LD C,$00 ; C := DEVICE TYPE, 0x00 IS RS-232
LD H,0 ; H := 0, DRIVER HAS NO MODES
LD L,(IY+ESP_CFG_IO) ; L := BASE I/O ADDRESS
XOR A ; SIGNAL SUCCESS
RET
;
; ESPSER CONFIGURATION
;
ESPSER_CFG:
ESPSER0_CFG:
.DB 0 ; DEVICE NUMBER (UPDATED DURING INIT)
.DB ESP_0_IO ; ESP DATA PORT
.DB ESP_STAT ; ESP STATUS PORT
.DB ESP_0_RDY ; ESP READY BIT MASK
.DB ESP_0_BUSY ; ESP BUSY BIT MASK
.DW ESPSER_LINECFG ; LINE CONFIGURATION
;
ESPSER1_CFG:
.DB 0 ; DEVICE NUMBER (UPDATED DURING INIT)
.DB ESP_1_IO ; ESP DATA PORT
.DB ESP_STAT ; ESP STATUS PORT
.DB ESP_1_RDY ; ESP READY BIT MASK
.DB ESP_1_BUSY ; ESP BUSY BIT MASK
.DW ESPSER_LINECFG ; LINE CONFIGURATION
;
;
;
ESPSER_DEVCNT .DB 0 ; ESPSER DEVICES COUNT