mirror of https://github.com/wwarthen/RomWBW.git
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.
767 lines
18 KiB
767 lines
18 KiB
;
|
|
;==================================================================================================
|
|
; UART DRIVER (SERIAL PORT)
|
|
;==================================================================================================
|
|
;
|
|
UART_DEBUG .EQU FALSE
|
|
;
|
|
UART_NONE .EQU 0 ; UNKNOWN OR NOT PRESENT
|
|
UART_8250 .EQU 1
|
|
UART_16450 .EQU 2
|
|
UART_16550 .EQU 3
|
|
UART_16550A .EQU 4
|
|
UART_16550C .EQU 5
|
|
UART_16650 .EQU 6
|
|
UART_16750 .EQU 7
|
|
UART_16850 .EQU 8
|
|
;
|
|
UART_RBR .EQU 0 ; DLAB=0: RCVR BUFFER REG (READ)
|
|
UART_THR .EQU 0 ; DLAB=0: XMIT HOLDING REG (WRITE)
|
|
UART_IER .EQU 1 ; DLAB=0: INT ENABLE REG (READ)
|
|
UART_IIR .EQU 2 ; INT IDENT REGISTER (READ)
|
|
UART_FCR .EQU 2 ; FIFO CONTROL REG (WRITE)
|
|
UART_LCR .EQU 3 ; LINE CONTROL REG (READ/WRITE)
|
|
UART_MCR .EQU 4 ; MODEM CONTROL REG (READ/WRITE)
|
|
UART_LSR .EQU 5 ; LINE STATUS REG (READ)
|
|
UART_MSR .EQU 6 ; MODEM STATUS REG (READ)
|
|
UART_SCR .EQU 7 ; SCRATCH REGISTER (READ/WRITE)
|
|
UART_DLL .EQU 0 ; DLAB=1: DIVISOR LATCH (LS) (READ/WRITE)
|
|
UART_DLM .EQU 1 ; DLAB=1: DIVISOR LATCH (MS) (READ/WRITE)
|
|
UART_EFR .EQU 2 ; LCR=$BF: ENHANCED FEATURE REG (READ/WRITE)
|
|
;
|
|
#DEFINE UART_IN(RID) CALL UART_INP \ .DB RID
|
|
#DEFINE UART_OUT(RID) CALL UART_OUTP \ .DB RID
|
|
;
|
|
#IF (UARTCNT >= 1)
|
|
UART0_RBR .EQU UART0IOB + 0 ; DLAB=0: RCVR BUFFER REG (READ ONLY)
|
|
UART0_THR .EQU UART0IOB + 0 ; DLAB=0: XMIT HOLDING REG (WRITE ONLY)
|
|
UART0_IER .EQU UART0IOB + 1 ; DLAB=0: INT ENABLE REG
|
|
UART0_IIR .EQU UART0IOB + 2 ; INT IDENT REGISTER (READ ONLY)
|
|
UART0_FCR .EQU UART0IOB + 2 ; FIFO CONTROL REG (WRITE ONLY)
|
|
UART0_LCR .EQU UART0IOB + 3 ; LINE CONTROL REG
|
|
UART0_MCR .EQU UART0IOB + 4 ; MODEM CONTROL REG
|
|
UART0_LSR .EQU UART0IOB + 5 ; LINE STATUS REG
|
|
UART0_MSR .EQU UART0IOB + 6 ; MODEM STATUS REG
|
|
UART0_SCR .EQU UART0IOB + 7 ; SCRATCH REGISTER
|
|
UART0_DLL .EQU UART0IOB + 0 ; DLAB=1: DIVISOR LATCH (LS)
|
|
UART0_DLM .EQU UART0IOB + 1 ; DLAB=1: DIVISOR LATCH (MS)
|
|
UART0_EFR .EQU UART0IOB + 2 ; ENHANCED FEATURE (WHEN LCR = $BF)
|
|
;
|
|
#ENDIF
|
|
;
|
|
#IF (UARTCNT >= 2)
|
|
UART1_RBR .EQU UART1IOB + 0 ; DLAB=0: RCVR BUFFER REG (READ ONLY)
|
|
UART1_THR .EQU UART1IOB + 0 ; DLAB=0: XMIT HOLDING REG (WRITE ONLY)
|
|
UART1_IER .EQU UART1IOB + 1 ; DLAB=0: INT ENABLE REG
|
|
UART1_IIR .EQU UART1IOB + 2 ; INT IDENT REGISTER (READ ONLY)
|
|
UART1_FCR .EQU UART1IOB + 2 ; FIFO CONTROL REG (WRITE ONLY)
|
|
UART1_LCR .EQU UART1IOB + 3 ; LINE CONTROL REG
|
|
UART1_MCR .EQU UART1IOB + 4 ; MODEM CONTROL REG
|
|
UART1_LSR .EQU UART1IOB + 5 ; LINE STATUS REG
|
|
UART1_MSR .EQU UART1IOB + 6 ; MODEM STATUS REG
|
|
UART1_SCR .EQU UART1IOB + 7 ; SCRATCH REGISTER
|
|
UART1_DLL .EQU UART1IOB + 0 ; DLAB=1: DIVISOR LATCH (LS)
|
|
UART1_DLM .EQU UART1IOB + 1 ; DLAB=1: DIVISOR LATCH (MS)
|
|
UART1_EFR .EQU UART1IOB + 2 ; ENHANCED FEATURE (WHEN LCR = $BF)
|
|
;
|
|
#ENDIF
|
|
;
|
|
#IF (UARTCNT >= 3)
|
|
UART2_RBR .EQU UART2IOB + 0 ; DLAB=0: RCVR BUFFER REG (READ ONLY)
|
|
UART2_THR .EQU UART2IOB + 0 ; DLAB=0: XMIT HOLDING REG (WRITE ONLY)
|
|
UART2_IER .EQU UART2IOB + 1 ; DLAB=0: INT ENABLE REG
|
|
UART2_IIR .EQU UART2IOB + 2 ; INT IDENT REGISTER (READ ONLY)
|
|
UART2_FCR .EQU UART2IOB + 2 ; FIFO CONTROL REG (WRITE ONLY)
|
|
UART2_LCR .EQU UART2IOB + 3 ; LINE CONTROL REG
|
|
UART2_MCR .EQU UART2IOB + 4 ; MODEM CONTROL REG
|
|
UART2_LSR .EQU UART2IOB + 5 ; LINE STATUS REG
|
|
UART2_MSR .EQU UART2IOB + 6 ; MODEM STATUS REG
|
|
UART2_SCR .EQU UART2IOB + 7 ; SCRATCH REGISTER
|
|
UART2_DLL .EQU UART2IOB + 0 ; DLAB=1: DIVISOR LATCH (LS)
|
|
UART2_DLM .EQU UART2IOB + 1 ; DLAB=1: DIVISOR LATCH (MS)
|
|
UART2_EFR .EQU UART2IOB + 2 ; ENHANCED FEATURE (WHEN LCR = $BF)
|
|
;
|
|
#ENDIF
|
|
;
|
|
#IF (UARTCNT >= 4)
|
|
UART3_RBR .EQU UART3IOB + 0 ; DLAB=0: RCVR BUFFER REG (READ ONLY)
|
|
UART3_THR .EQU UART3IOB + 0 ; DLAB=0: XMIT HOLDING REG (WRITE ONLY)
|
|
UART3_IER .EQU UART3IOB + 1 ; DLAB=0: INT ENABLE REG
|
|
UART3_IIR .EQU UART3IOB + 2 ; INT IDENT REGISTER (READ ONLY)
|
|
UART3_FCR .EQU UART3IOB + 2 ; FIFO CONTROL REG (WRITE ONLY)
|
|
UART3_LCR .EQU UART3IOB + 3 ; LINE CONTROL REG
|
|
UART3_MCR .EQU UART3IOB + 4 ; MODEM CONTROL REG
|
|
UART3_LSR .EQU UART3IOB + 5 ; LINE STATUS REG
|
|
UART3_MSR .EQU UART3IOB + 6 ; MODEM STATUS REG
|
|
UART3_SCR .EQU UART3IOB + 7 ; SCRATCH REGISTER
|
|
UART3_DLL .EQU UART3IOB + 0 ; DLAB=1: DIVISOR LATCH (LS)
|
|
UART3_DLM .EQU UART3IOB + 1 ; DLAB=1: DIVISOR LATCH (MS)
|
|
UART3_EFR .EQU UART3IOB + 2 ; ENHANCED FEATURE (WHEN LCR = $BF)
|
|
;
|
|
#ENDIF
|
|
;
|
|
; CHARACTER DEVICE DRIVER ENTRY
|
|
; A: RESULT (OUT), CF=ERR
|
|
; B: FUNCTION (IN)
|
|
; C: CHARACTER (IN/OUT)
|
|
; E: DEVICE/UNIT (IN)
|
|
;
|
|
UART_INIT:
|
|
;
|
|
; SETUP THE DISPATCH TABLE ENTRIES
|
|
;
|
|
LD B,UARTCNT ; LOOP CONTROL
|
|
LD C,0 ; PHYSICAL UNIT INDEX
|
|
UART_INIT0:
|
|
PUSH BC ; SAVE LOOP CONTROL
|
|
LD B,C ; PHYSICAL UNIT
|
|
LD C,CIODEV_UART ; DEVICE TYPE
|
|
LD DE,0 ; UNIT DATA BLOB ADDRESS
|
|
CALL CIO_ADDENT ; ADD ENTRY, BC IS NOT DESTROYED
|
|
POP BC ; RESTORE LOOP CONTROL
|
|
INC C ; NEXT PHYSICAL UNIT
|
|
DJNZ UART_INIT0 ; LOOP UNTIL DONE
|
|
;
|
|
#IF (UARTCNT >= 1)
|
|
CALL UART0_INIT
|
|
#ENDIF
|
|
#IF (UARTCNT >= 2)
|
|
CALL UART1_INIT
|
|
#ENDIF
|
|
#IF (UARTCNT >= 3)
|
|
CALL UART2_INIT
|
|
#ENDIF
|
|
#IF (UARTCNT >= 4)
|
|
CALL UART3_INIT
|
|
#ENDIF
|
|
RET
|
|
;
|
|
;
|
|
;
|
|
UART_DISPATCH:
|
|
LD A,C ; GET DEVICE/UNIT
|
|
AND $0F ; ISOLATE UNIT
|
|
#IF (UARTCNT >= 1)
|
|
JP Z,UART0_DISPATCH
|
|
#ENDIF
|
|
#IF (UARTCNT >= 2)
|
|
DEC A
|
|
JP Z,UART1_DISPATCH
|
|
#ENDIF
|
|
#IF (UARTCNT >= 3)
|
|
DEC A
|
|
JP Z,UART2_DISPATCH
|
|
#ENDIF
|
|
#IF (UARTCNT >= 4)
|
|
DEC A
|
|
JP Z,UART3_DISPATCH
|
|
#ENDIF
|
|
CALL PANIC
|
|
|
|
;
|
|
;
|
|
;
|
|
#IF (UARTCNT >= 1)
|
|
;
|
|
UART0_INIT:
|
|
PRTS("UART0: IO=0x$")
|
|
LD A,UART0IOB
|
|
CALL PRTHEXBYTE
|
|
;
|
|
; SETUP FOR GENERIC INIT ROUTINE
|
|
LD (UART_BASE),A ; IO BASE ADDRESS
|
|
LD DE,UART0OSC >> 16
|
|
LD (UART_OSCHI),DE
|
|
LD DE,UART0OSC & $FFFF
|
|
LD (UART_OSCLO),DE
|
|
LD DE,UART0BAUD >> 16
|
|
LD (UART_BAUDHI),DE
|
|
LD DE,UART0BAUD & $FFFF
|
|
LD (UART_BAUDLO),DE
|
|
;
|
|
; MAP REQUESTED FEATURES TO FLAGS IN UART_FUNC
|
|
XOR A ; START WITH NO FEATURES
|
|
#IF (UART0FIFO)
|
|
SET UART_FIFO,A ; TURN ON FIFO BIT IF REQUESTED
|
|
#ENDIF
|
|
#IF (UART0AFC)
|
|
SET UART_AFC,A ; TURN ON AFC BIT IF REQUESTED
|
|
#ENDIF
|
|
LD (UART_FUNC),A ; SAVE IT
|
|
;
|
|
JP UART_INITP ; HAND OFF TO GENERIC INIT CODE
|
|
;
|
|
;
|
|
;
|
|
UART0_DISPATCH:
|
|
LD A,B ; GET REQUESTED FUNCTION
|
|
AND $0F ; ISOLATE SUB-FUNCTION
|
|
JP Z,UART0_IN ; BF_CIOIN
|
|
DEC A
|
|
JP Z,UART0_OUT ; BF_CIOOUT
|
|
DEC A
|
|
JP Z,UART0_IST ; BF_CIOIST
|
|
DEC A
|
|
JP Z,UART0_OST ; BF_CIOOST
|
|
DEC A
|
|
JP Z,UART0_INITDEV ; BF_CIOINIT
|
|
DEC A
|
|
JP Z,UART0_QUERY ; BF_CIOQUERY
|
|
DEC A
|
|
JP Z,UART0_DEVICE ; BF_CIODEVICE
|
|
CALL PANIC
|
|
;
|
|
;
|
|
;
|
|
UART0_IN:
|
|
CALL UART0_IST
|
|
OR A
|
|
JR Z,UART0_IN
|
|
IN A,(UART0_RBR) ; READ THE CHAR FROM THE UART
|
|
LD E,A
|
|
RET
|
|
;
|
|
;
|
|
;
|
|
UART0_IST:
|
|
IN A,(UART0_LSR) ; READ LINE STATUS REGISTER
|
|
AND $01 ; TEST IF DATA IN RECEIVE BUFFER
|
|
JP Z,CIO_IDLE ; DO IDLE PROCESSING AND RETURN
|
|
XOR A
|
|
INC A ; SIGNAL CHAR READY, A = 1
|
|
RET
|
|
;
|
|
;
|
|
;
|
|
UART0_OUT:
|
|
CALL UART0_OST
|
|
OR A
|
|
JR Z,UART0_OUT
|
|
LD A,E
|
|
OUT (UART0_THR),A ; THEN WRITE THE CHAR TO UART
|
|
RET
|
|
;
|
|
UART0_OST:
|
|
IN A,(UART0_LSR) ; READ LINE STATUS REGISTER
|
|
AND $20
|
|
JP Z,CIO_IDLE ; DO IDLE PROCESSING AND RETURN
|
|
XOR A
|
|
INC A ; SIGNAL BUFFER EMPTY, A = 1
|
|
RET
|
|
;
|
|
UART0_INITDEV:
|
|
XOR A ; NOT IMPLEMENTED!!!
|
|
RET
|
|
;
|
|
;
|
|
;
|
|
UART0_QUERY:
|
|
LD DE,UART0BAUD >> 16
|
|
LD HL,UART0BAUD & $FFFF
|
|
XOR A
|
|
RET
|
|
;
|
|
;
|
|
;
|
|
UART0_DEVICE:
|
|
LD D,CIODEV_UART ; D := DEVICE TYPE
|
|
LD E,C ; E := PHYSICAL UNIT
|
|
XOR A ; SIGNAL SUCCESS
|
|
RET
|
|
;
|
|
#ENDIF
|
|
;
|
|
;
|
|
;
|
|
#IF (UARTCNT >= 2)
|
|
;
|
|
UART1_INIT:
|
|
CALL NEWLINE
|
|
PRTS("UART1: IO=0x$")
|
|
LD A,UART1IOB
|
|
CALL PRTHEXBYTE
|
|
;
|
|
; SETUP FOR GENERIC INIT ROUTINE
|
|
LD (UART_BASE),A ; IO BASE ADDRESS
|
|
LD DE,UART1OSC >> 16
|
|
LD (UART_OSCHI),DE
|
|
LD DE,UART1OSC & $FFFF
|
|
LD (UART_OSCLO),DE
|
|
LD DE,UART1BAUD >> 16
|
|
LD (UART_BAUDHI),DE
|
|
LD DE,UART1BAUD & $FFFF
|
|
LD (UART_BAUDLO),DE
|
|
;
|
|
; MAP REQUESTED FEATURES TO FLAGS IN UART_FUNC
|
|
XOR A ; START WITH NO FEATURES
|
|
#IF (UART1FIFO)
|
|
SET UART_FIFO,A ; TURN ON FIFO BIT IF REQUESTED
|
|
#ENDIF
|
|
#IF (UART1AFC)
|
|
SET UART_AFC,A ; TURN ON AFC BIT IF REQUESTED
|
|
#ENDIF
|
|
LD (UART_FUNC),A ; SAVE IT
|
|
;
|
|
JP UART_INITP ; HAND OFF TO GENERIC INIT CODE
|
|
;
|
|
;
|
|
;
|
|
UART1_DISPATCH:
|
|
LD A,B ; GET REQUESTED FUNCTION
|
|
AND $0F ; ISOLATE SUB-FUNCTION
|
|
JP Z,UART1_IN ; BF_CIOIN
|
|
DEC A
|
|
JP Z,UART1_OUT ; BF_CIOOUT
|
|
DEC A
|
|
JP Z,UART1_IST ; BF_CIOIST
|
|
DEC A
|
|
JP Z,UART1_OST ; BF_CIOOST
|
|
DEC A
|
|
JP Z,UART1_INITDEV ; BF_CIOINIT
|
|
DEC A
|
|
JP Z,UART1_QUERY ; BF_CIOQUERY
|
|
DEC A
|
|
JP Z,UART1_DEVICE ; BF_CIODEVICE
|
|
CALL PANIC
|
|
;
|
|
;
|
|
;
|
|
UART1_IN:
|
|
CALL UART1_IST
|
|
OR A
|
|
JR Z,UART1_IN
|
|
IN A,(UART1_RBR) ; READ THE CHAR FROM THE UART
|
|
LD E,A
|
|
RET
|
|
;
|
|
;
|
|
;
|
|
UART1_IST:
|
|
IN A,(UART1_LSR) ; READ LINE STATUS REGISTER
|
|
AND $01 ; TEST IF DATA IN RECEIVE BUFFER
|
|
JP Z,CIO_IDLE ; DO IDLE PROCESSING AND RETURN
|
|
XOR A
|
|
INC A ; SIGNAL CHAR READY, A = 1
|
|
RET
|
|
;
|
|
;
|
|
;
|
|
UART1_OUT:
|
|
CALL UART1_OST
|
|
OR A
|
|
JR Z,UART1_OUT
|
|
LD A,E
|
|
OUT (UART1_THR),A ; THEN WRITE THE CHAR TO UART
|
|
RET
|
|
;
|
|
UART1_OST:
|
|
IN A,(UART1_LSR) ; READ LINE STATUS REGISTER
|
|
AND $20
|
|
JP Z,CIO_IDLE ; DO IDLE PROCESSING AND RETURN
|
|
XOR A
|
|
INC A ; SIGNAL BUFFER EMPTY, A = 1
|
|
RET
|
|
;
|
|
UART1_INITDEV:
|
|
XOR A ; NOT IMPLEMENTED!!!
|
|
RET
|
|
;
|
|
;
|
|
;
|
|
UART1_QUERY:
|
|
LD DE,UART1BAUD >> 16
|
|
LD HL,UART1BAUD & $FFFF
|
|
XOR A
|
|
RET
|
|
;
|
|
;
|
|
;
|
|
UART1_DEVICE:
|
|
LD D,CIODEV_UART ; D := DEVICE TYPE
|
|
LD E,C ; E := PHYSICAL UNIT
|
|
XOR A ; SIGNAL SUCCESS
|
|
RET
|
|
;
|
|
#ENDIF
|
|
;
|
|
; UART INITIALIZATION ROUTINE
|
|
;
|
|
UART_INITP:
|
|
; WAIT FOR ANY IN-FLIGHT DATA TO BE SENT
|
|
LD B,0 ; LOOP TIMEOUT COUNTER
|
|
UART_INITP00:
|
|
UART_IN(UART_LSR) ; GET LINE STATUS REGISTER
|
|
BIT 6,A ; TEST BIT 6 (TRANSMITTER EMPTY)
|
|
JR NZ,UART_INITP0 ; EMPTY, CONTINUE
|
|
LD DE,100 ; DELAY 100 * 16US
|
|
CALL VDELAY ; NORMALIZE TIMEOUT TO CPU SPEED
|
|
DJNZ UART_INITP00 ; KEEP CHECKING UNTIL TIMEOUT
|
|
|
|
UART_INITP0:
|
|
; DETECT THE UART TYPE
|
|
CALL UART_DETECT ; DETERMINE UART TYPE
|
|
LD (UART_TYPE),A ; SAVE TYPE
|
|
|
|
; HL IS USED BELOW TO REFER TO FEATURE BITS ENABLED
|
|
LD HL,UART_FEAT ; HL POINTS TO FEATURE FLAGS BYTE
|
|
XOR A ; RESET ALL FEATURES
|
|
LD (HL),A ; SAVE IT
|
|
|
|
; START OF UART INITIALIZATION, SET BAUD RATE
|
|
LD A,80H
|
|
UART_OUT(UART_LCR) ; DLAB ON
|
|
CALL UART_COMPDIV ; COMPUTE DIVISOR TO BC
|
|
LD A,B
|
|
UART_OUT(UART_DLM) ; SET DIVISOR (MS)
|
|
LD A,C
|
|
UART_OUT(UART_DLL) ; SET DIVISOR (LS)
|
|
|
|
; SET LCR TO DEFAULT
|
|
LD A,$03 ; DLAB OFF, 8 DATA, 1 STOP, NO PARITY
|
|
UART_OUT(UART_LCR) ; SAVE IT
|
|
|
|
; SET MCR TO DEFAULT
|
|
LD A,$03 ; DTR + RTS
|
|
UART_OUT(UART_MCR) ; SAVE IT
|
|
|
|
LD A,(UART_TYPE) ; GET UART TYPE
|
|
CP UART_16550A ; 16550A OR BETTER?
|
|
JR C,UART_INITP1 ; NOPE, SKIP FIFO & AFC FEATURES
|
|
|
|
LD B,0 ; START BY ASSUMING NO FIFOS, FCR=0
|
|
LD A,(UART_FUNC) ; LOAD FIFO ENABLE REQUEST VALUE
|
|
BIT UART_FIFO,A ; TEST FOR FIFO REQUESTED
|
|
JR Z,UART_FIFO1 ; NOPE
|
|
LD B,$07 ; VALUE TO ENABLE AND RESET FIFOS
|
|
SET UART_FIFO,(HL) ; RECORD FEATURE ENABLED
|
|
UART_FIFO1:
|
|
LD A,B ; MOVE VALUE TO A
|
|
UART_OUT(UART_FCR) ; DO IT
|
|
|
|
LD A,(UART_TYPE) ; GET UART TYPE
|
|
CP UART_16550C ; 16550C OR BETTER?
|
|
JR C,UART_INITP1 ; NOPE, SKIP AFC FEATURES
|
|
|
|
; BRANCH BASED ON TYPE AFC CONFIGURATION (EFR OR MCR)
|
|
LD A,(UART_TYPE) ; GET UART TYPE
|
|
CP UART_16650 ; 16650?
|
|
JR Z,UART_AFC2 ; USE EFR REGISTER
|
|
CP UART_16850 ; 16750?
|
|
JR Z,UART_AFC2 ; USE EFR REGISTER
|
|
|
|
; SET AFC VIA MCR
|
|
LD B,$03 ; START WITH DEFAULT MCR
|
|
LD A,(UART_FUNC) ; LOAD AFC ENABLE REQUEST VALUE
|
|
BIT UART_AFC,A ; TEST FOR AFC REQUESTED
|
|
JR Z,UART_AFC1 ; NOPE
|
|
SET 5,B ; SET MCR BIT TO ENABLE AFC
|
|
SET UART_AFC,(HL) ; RECORD FEATURE ENABLED
|
|
UART_AFC1:
|
|
LD A,B ; MOVE VALUE TO Ar
|
|
UART_OUT(UART_MCR) ; SET AFC VALUE VIA MCR
|
|
JR UART_INITP1 ; AND CONTINUE
|
|
|
|
UART_AFC2: ; SET AFC VIA EFR
|
|
LD A,$BF ; VALUE TO ACCESS EFR
|
|
UART_OUT(UART_LCR) ; SET VALUE IN LCR
|
|
|
|
LD B,0 ; ASSUME AFC OFF, EFR=0
|
|
LD A,(UART_FUNC) ; LOAD AFC ENABLE REQUEST VALUE
|
|
BIT UART_AFC,A ; TEST FOR AFC REQUESTED
|
|
JR Z,UART_AFC3 ; NOPE
|
|
LD B,$C0 ; ENABLE CTS/RTS FLOW CONTROL
|
|
SET UART_AFC,(HL) ; RECORD FEATURE ENABLED
|
|
UART_AFC3:
|
|
LD A,B ; MOVE VALUE TO A
|
|
UART_OUT(UART_EFR) ; SAVE IT
|
|
LD A,$03 ; NORMAL LCR VALUE
|
|
UART_OUT(UART_LCR) ; SAVE IT
|
|
|
|
UART_INITP1:
|
|
#IF (UART_DEBUG)
|
|
PRTS(" [$")
|
|
|
|
; DEBUG: DUMP UART TYPE
|
|
LD A,(UART_TYPE)
|
|
CALL PRTHEXBYTE
|
|
|
|
; DEBUG: DUMP IIR
|
|
UART_IN(UART_IIR)
|
|
CALL PC_SPACE
|
|
CALL PRTHEXBYTE
|
|
|
|
; DEBUG: DUMP LCR
|
|
UART_IN(UART_LCR)
|
|
CALL PC_SPACE
|
|
CALL PRTHEXBYTE
|
|
|
|
; DEBUG: DUMP MCR
|
|
UART_IN(UART_MCR)
|
|
CALL PC_SPACE
|
|
CALL PRTHEXBYTE
|
|
|
|
; DEBUG: DUMP EFR
|
|
LD A,$BF
|
|
UART_OUT(UART_LCR)
|
|
UART_IN(UART_EFR)
|
|
PUSH AF
|
|
LD A,$03
|
|
UART_OUT(UART_LCR)
|
|
POP AF
|
|
CALL PC_SPACE
|
|
CALL PRTHEXBYTE
|
|
|
|
PRTC(']')
|
|
#ENDIF
|
|
|
|
; PRINT THE UART TYPE
|
|
LD A,(UART_TYPE)
|
|
RLCA
|
|
LD HL,UART_TYPE_MAP
|
|
LD D,0
|
|
LD E,A
|
|
ADD HL,DE ; HL NOW POINTS TO MAP ENTRY
|
|
LD A,(HL)
|
|
INC HL
|
|
LD D,(HL)
|
|
LD E,A ; HL NOW POINTS TO STRING
|
|
CALL PC_SPACE
|
|
CALL WRITESTR ; PRINT THE STRING
|
|
;
|
|
; ALL DONE IF NO UART WAS DETECTED
|
|
LD A,(UART_TYPE)
|
|
OR A
|
|
; JR Z,UART_INITP3
|
|
;
|
|
; PRINT BAUD RATE
|
|
PRTS(" BAUD=$")
|
|
LD HL,(UART_BAUDHI)
|
|
LD BC,(UART_BAUDLO)
|
|
LD DE,UART_INITBUF
|
|
CALL BIN2BCD
|
|
EX DE,HL
|
|
CALL PRTBCD
|
|
; CALL PRTDEC
|
|
;
|
|
; PRINT FEATURES ENABLED
|
|
LD A,(UART_FEAT)
|
|
BIT UART_FIFO,A
|
|
JR Z,UART_INITP2
|
|
PRTS(" FIFO$")
|
|
UART_INITP2:
|
|
BIT UART_AFC,A
|
|
JR Z,UART_INITP3
|
|
PRTS(" AFC$")
|
|
UART_INITP3:
|
|
;
|
|
RET
|
|
;
|
|
UART_INITBUF .FILL 5,0 ; WORKING BUFFER FOR BCD NUMBER
|
|
;
|
|
; UART DETECTION ROUTINE
|
|
;
|
|
UART_DETECT:
|
|
;
|
|
; SEE IF UART IS THERE BY CHECKING DLAB FUNCTIONALITY
|
|
XOR A ; ZERO ACCUM
|
|
UART_OUT(UART_IER) ; IER := 0
|
|
LD A,$80 ; DLAB BIT ON
|
|
UART_OUT(UART_LCR) ; OUTPUT TO LCR (DLAB REGS NOW ACTIVE)
|
|
LD A,$5A ; LOAD TEST VALUE
|
|
UART_OUT(UART_DLM) ; OUTPUT TO DLM
|
|
UART_IN(UART_DLM) ; READ IT BACK
|
|
CP $5A ; CHECK FOR TEST VALUE
|
|
JR NZ,UART_DETECT_NONE ; NOPE, UNKNOWN UART OR NOT PRESENT
|
|
XOR A ; DLAB BIT OFF
|
|
UART_OUT(UART_LCR) ; OUTPUT TO LCR (DLAB REGS NOW INACTIVE)
|
|
UART_IN(UART_IER) ; READ IER
|
|
CP $5A ; CHECK FOR TEST VALUE
|
|
JR Z,UART_DETECT_NONE ; IF STILL $5A, UNKNOWN OR NOT PRESENT
|
|
;
|
|
; TEST FOR FUNCTIONAL SCRATCH REG, IF NOT, WE HAVE AN 8250
|
|
LD A,$5A ; LOAD TEST VALUE
|
|
UART_OUT(UART_SCR) ; PUT IT IN SCRATCH REGISTER
|
|
UART_IN(UART_SCR) ; READ IT BACK
|
|
CP $5A ; CHECK IT
|
|
JR NZ,UART_DETECT_8250 ; STUPID 8250
|
|
;
|
|
; TEST FOR EFR REGISTER WHICH IMPLIES 16650/850
|
|
LD A,$BF ; VALUE TO ENABLE EFR
|
|
UART_OUT(UART_LCR) ; WRITE IT TO LCR
|
|
UART_IN(UART_SCR) ; READ SCRATCH REGISTER
|
|
CP $5A ; SPR STILL THERE?
|
|
JR NZ,UART_DETECT1 ; NOPE, HIDDEN, MUST BE 16650/850
|
|
;
|
|
; RESET LCR TO DEFAULT
|
|
LD A,$80 ; DLAB BIT ON
|
|
UART_OUT(UART_LCR) ; RESET LCR
|
|
;
|
|
; TEST FCR TO ISOLATE 16450/550/550A
|
|
LD A,$E7 ; TEST VALUE
|
|
UART_OUT(UART_FCR) ; PUT IT IN FCR
|
|
UART_IN(UART_IIR) ; READ BACK FROM IIR
|
|
BIT 6,A ; BIT 6 IS FIFO ENABLE, LO BIT
|
|
JR Z,UART_DETECT_16450 ; IF NOT SET, MUST BE 16450
|
|
BIT 7,A ; BIT 7 IS FIFO ENABLE, HI BIT
|
|
JR Z,UART_DETECT_16550 ; IF NOT SET, MUST BE 16550
|
|
BIT 5,A ; BIT 5 IS 64 BYTE FIFO
|
|
JR Z,UART_DETECT2 ; IF NOT SET, MUST BE 16550A/C
|
|
JR UART_DETECT_16750 ; ONLY THING LEFT IS 16750
|
|
;
|
|
UART_DETECT1: ; PICK BETWEEN 16650/850
|
|
; NOT SURE HOW TO DIFFERENTIATE 16650 FROM 16850 YET
|
|
JR UART_DETECT_16650 ; ASSUME 16650
|
|
RET
|
|
;
|
|
UART_DETECT2: ; PICK BETWEEN 16650A/C
|
|
; SET AFC BIT IN FCR
|
|
LD A,$20 ; SET AFC BIT, MCR:5
|
|
UART_OUT(UART_MCR) ; WRITE NEW FCR VALUE
|
|
;
|
|
; READ IT BACK, IF SET, WE HAVE 16550C
|
|
UART_IN(UART_MCR) ; READ BACK MCR
|
|
BIT 5,A ; CHECK AFC BIT
|
|
JR Z,UART_DETECT_16550A ; NOT SET, SO 16550A
|
|
JR UART_DETECT_16550C ; IS SET, SO 16550C
|
|
;
|
|
UART_DETECT_NONE:
|
|
LD A,UART_NONE
|
|
RET
|
|
;
|
|
UART_DETECT_8250:
|
|
LD A,UART_8250
|
|
RET
|
|
;
|
|
UART_DETECT_16450:
|
|
LD A,UART_16450
|
|
RET
|
|
;
|
|
UART_DETECT_16550:
|
|
LD A,UART_16550
|
|
RET
|
|
;
|
|
UART_DETECT_16550A:
|
|
LD A,UART_16550A
|
|
RET
|
|
;
|
|
UART_DETECT_16550C:
|
|
LD A,UART_16550C
|
|
RET
|
|
;
|
|
UART_DETECT_16650:
|
|
LD A,UART_16650
|
|
RET
|
|
;
|
|
UART_DETECT_16750:
|
|
LD A,UART_16750
|
|
RET
|
|
;
|
|
UART_DETECT_16850:
|
|
LD A,UART_16850
|
|
RET
|
|
;
|
|
; COMPUTE DIVISOR TO BC
|
|
; USES UART_BAUD AND UART_OSC VARIABLES BELOW
|
|
;
|
|
UART_COMPDIV:
|
|
; SETUP DE:HL WITH OSC FREQUENCY
|
|
LD DE,(UART_OSCHI)
|
|
LD HL,(UART_OSCLO)
|
|
; DIVIDE OSC FREQ BY PRESCALE FACTOR OF 16
|
|
LD B,4 ; 4 ITERATIONS
|
|
UART_COMPDIV1:
|
|
SRL D
|
|
RR E
|
|
RR H
|
|
RR L
|
|
DJNZ UART_COMPDIV1
|
|
; CONVERT FROM DE:HL -> A:HL (THROW AWAY HIGH BYTE)
|
|
LD A,E
|
|
; SETUP C:DE WITH TARGET BAUD RATE
|
|
LD BC,(UART_BAUDHI)
|
|
LD DE,(UART_BAUDLO)
|
|
; DIVIDE OSC FREQ AND BAUD BY 2 UNTIL FREQ FITS IN 16 BITS
|
|
UART_COMPDIV2:
|
|
SRL A
|
|
RR H
|
|
RR L
|
|
SRL C
|
|
RR D
|
|
RR E
|
|
OR A
|
|
JR NZ,UART_COMPDIV2
|
|
; DIVIDE ADJUSTED VALUES (OSC FREQ / BAUD RATE)
|
|
CALL DIV16
|
|
RET
|
|
;
|
|
; ROUTINES TO READ/WRITE PORTS INDIRECTLY
|
|
;
|
|
; READ VALUE OF UART PORT ON TOS INTO REGISTER A
|
|
;
|
|
UART_INP:
|
|
EX (SP),HL ; SWAP HL AND TOS
|
|
PUSH BC ; PRESERVE BC
|
|
LD A,(UART_BASE) ; GET UART IO BASE PORT
|
|
OR (HL) ; OR IN REGISTER ID BITS
|
|
LD C,A ; C := PORT
|
|
INC HL ; BUMP HL PAST REG ID PARM
|
|
IN A,(C) ; READ PORT INTO A
|
|
POP BC ; RESTORE BC
|
|
EX (SP),HL ; SWAP BACK HL AND TOS
|
|
RET
|
|
;
|
|
; WRITE VALUE IN REGISTER A TO UART PORT ON TOS
|
|
;
|
|
UART_OUTP:
|
|
EX (SP),HL ; SWAP HL AND TOS
|
|
PUSH BC ; PRESERVE BC
|
|
PUSH AF ; SAVE AF (VALUE TO WRITE)
|
|
LD A,(UART_BASE) ; GET UART IO BASE PORT
|
|
OR (HL) ; OR IN REGISTER ID BITS
|
|
LD C,A ; C := PORT
|
|
INC HL ; BUMP HL PAST REG ID PARM
|
|
POP AF ; RESTORE VALUE TO WRITE
|
|
OUT (C),A ; WRITE VALUE TO PORT
|
|
POP BC ; RESTORE BC
|
|
EX (SP),HL ; SWAP BACK HL AND TOS
|
|
RET
|
|
;
|
|
;
|
|
;
|
|
UART_TYPE_MAP:
|
|
.DW UART_STR_NONE
|
|
.DW UART_STR_8250
|
|
.DW UART_STR_16450
|
|
.DW UART_STR_16550
|
|
.DW UART_STR_16550A
|
|
.DW UART_STR_16550C
|
|
.DW UART_STR_16650
|
|
.DW UART_STR_16750
|
|
.DW UART_STR_16850
|
|
|
|
UART_STR_NONE .DB "<NOT PRESENT>$"
|
|
UART_STR_8250 .DB "8250$"
|
|
UART_STR_16450 .DB "16450$"
|
|
UART_STR_16550 .DB "16550$"
|
|
UART_STR_16550A .DB "16550A$"
|
|
UART_STR_16550C .DB "16550C$"
|
|
UART_STR_16650 .DB "16650$"
|
|
UART_STR_16750 .DB "16750$"
|
|
UART_STR_16850 .DB "16850$"
|
|
;
|
|
; WORKING VARIABLES
|
|
;
|
|
UART_BASE .DB 0 ; BASE IO ADDRESS FOR ACTIVE UART
|
|
UART_TYPE .DB 0 ; UART TYPE DISCOVERED
|
|
UART_FEAT .DB 0 ; UART FEATURES DISCOVERED
|
|
UART_BAUDLO .DW 0 ; BAUD RATE LO WORD
|
|
UART_BAUDHI .DW 0 ; BAUD RATE HI WORD
|
|
UART_OSCLO .DW 0 ; UART OSC FREQUENCY LO
|
|
UART_OSCHI .DW 0 ; UART OSC FREQUENCY HI
|
|
;UART_DIV .DW 0 ; BAUD DIVISOR
|
|
UART_FUNC .DB 0 ; UART FUNCTIONS REQUESTED
|
|
;
|
|
;
|
|
;
|
|
UART_FIFO .EQU 0 ; FIFO ENABLE BIT
|
|
UART_AFC .EQU 1 ; AUTO FLOW CONTROL ENABLE BIT
|
|
|