@ -20,6 +20,8 @@
;
UART_DEBUG .EQU FALSE
;
UART_BUFSZ .EQU 32 ; RECEIVE RING BUFFER SIZE
;
UART_NONE .EQU 0 ; UNKNOWN OR NOT PRESENT
UART_8250 .EQU 1
UART_16450 .EQU 2
@ -43,9 +45,13 @@ 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)
;;
;UART_FIFO .EQU 0 ; FIFO ENABLE BIT
;UART_AFC .EQU 1 ; AUTO FLOW CONTROL ENABLE BIT
;
; THESE BITS ARE SET IN THE UART TYPE BYTE TO FURTHER
; IDENTIFY THE FEATURES OF THE CHIP
;
UART_INTACT .EQU 7 ; INT RCV ACTIVE BIT
UART_FIFOACT .EQU 6 ; FIFO ACTIVE BIT
UART_AFCACT .EQU 5 ; AUTO FLOW CONTROL ACTIVE BIT
;
UARTSBASE .EQU $ 68
UARTCBASE .EQU $ 80
@ -86,7 +92,7 @@ UART_PREINIT0:
POP DE ; GET ENTRY ADDRESS BACK, BUT PUT IN DE
POP BC ; RESTORE LOOP CONTROL
;
LD A ,( IY + 1 ) ; GET THE UART TYPE DETECTED
LD A ,( IY + 1 ) ; GET THE UART TYPE DETECTED
OR A ; SET FLAGS
JR Z , UART_PREINIT2 ; SKIP IT IF NOTHING FOUND
;
@ -98,6 +104,29 @@ UART_PREINIT0:
UART_PREINIT2:
INC C ; NEXT PHYSICAL UNIT
DJNZ UART_PREINIT0 ; LOOP UNTIL DONE
;
# IF (( UARTINTS ) & ( INTMODE > 0 ))
; *** FIXME *** WE SHOULD CHECK TO SEE IF ANY UNITS ARE ACTUALLY
; USING INT RCV. IF NOT, WE SHOULD NOT HOOK IM1!!!
;
; SETUP INT VECTORS AS APPROPRIATE
LD A ,( UART_DEV ) ; GET DEVICE COUNT
OR A ; SET FLAGS
JR Z , UART_PREINIT3 ; IF ZERO, NO UART DEVICES, ABORT
;
# IF ( INTMODE = = 1 )
; ADD IM1 INT CALL LIST ENTRY
LD HL , UART_INT ; GET INT VECTOR
CALL HB_ADDIM1 ; ADD TO IM1 CALL LIST
# ENDIF
;
# IF (( INTMODE = = 2 ) | ( INTMODE = = 3 ))
; *** FIXME *** IMPLEMENT THIS!!!
# ENDIF
;
# ENDIF
;
UART_PREINIT3:
XOR A ; SIGNAL SUCCESS
RET ; AND RETURN
;
@ -106,19 +135,19 @@ UART_PREINIT2:
UART_INITUNIT:
; DETECT THE UART TYPE
CALL UART_DETECT ; DETERMINE UART TYPE
LD ( IY + 1 ), A ; ALSO SAVE IN CONFIG TABLE
LD ( IY + 1 ), A ; AND SAVE IN CONFIG TABLE
OR A ; SET FLAGS
RET Z ; ABORT IF NOTHING THERE
;
; UPDATE WORKING UART DEVICE NUM
LD HL , UART_DEV ; POINT TO CURRENT UART DEVICE NUM
LD A ,( HL ) ; PUT IN ACCUM
INC ( HL ) ; INCREMENT IT (FOR NEXT LOOP)
LD ( IY ), A ; UDPATE UNIT NUM
;
; SET DEFAULT CONFIG
LD DE , - 1 ; LEAVE CONFIG ALONE
JP UART_INITDEV ; IMPLEMENT IT AND RETURN
JP UART_INITDEVX ; IMPLEMENT IT AND RETURN
;
;
;
@ -137,7 +166,7 @@ UART_INIT1:
PUSH HL ; COPY CFG DATA PTR
POP IY ; ... TO IY
LD A ,( IY + 1 ) ; GET UART TYPE
LD A ,( IY + 1 ) ; GET UART TYPE
OR A ; SET FLAGS
CALL NZ , UART_PRTCFG ; PRINT IF NOT ZERO
@ -148,6 +177,116 @@ UART_INIT1:
XOR A ; SIGNAL SUCCESS
RET ; DONE
;
; RECEIVE INTERRUPT HANDLER
;
# IF (( UARTINTS ) & ( INTMODE > 0 ))
;
; IM1 ENTRY POINT
;
; POLL ALL DEVICES THAT MIGHT ENABLE INTERRUPT DRIVEN
; RECEIVE. HANDLE FIRST INTERRUPT ENCOUNTERED (IF ANY).
; MOST BOARDS REQUIRE UARTS THAT WILL HAVE AFC. THE
; ONLY BOARDS THAT MAY NOT ARE THE SBC AND THE CAS.
;
; THIS COULD BE IMPROVED BY DYNAMICALLY SETTING UP THE
; POLLING CHAIN WHEN DEVICES ARE INITIALIZED SUCH THAT
; ONLY DEVICES ACTUALLY USING INTS ARE POLLED HERE.
;
UART_INT:
;
# IF ( UARTSBC )
LD IY , UART_CFG_SBC
CALL UART_INTRCV
RET NZ
# ENDIF
;
# IF ( UARTCAS )
LD IY , UART_CFG_CAS
CALL UART_INTRCV
RET NZ
# ENDIF
;
XOR A ; CLEAR ACCUM (INT NOT HANDLED)
RET ; DONE
;
; HANDLE INT FOR A SPECIFIC CHANNEL
; BASED ON UNIT CFG POINTED TO BY IY
;
UART_INTRCV:
; ARE INTERRUPTS IN USE ON THIS DEVICE?
LD A ,( IY + 1 ) ; GET UART TYPE
AND % 10000000 ; ISOLATE INT RCV BIT
RET Z ; INTS NOT SUPPORTED
; CHECK TO SEE IF SOMETHING IS ACTUALLY THERE
LD C ,( IY + 3 ) ; STATUS PORT TO C
IN A ,( C ) ; GET LSR
AND $ 01 ; ISOLATE RECEIVE READY BIT
RET Z ; NOTHING AVAILABLE ON CURRENT CHANNEL
;
UART_INTRCV1:
; RECEIVE CHARACTER INTO BUFFER
LD C ,( IY + 2 ) ; DATA PORT TO C
IN A ,( C ) ; READ PORT
LD B , A ; SAVE BYTE READ
LD L ,( IY + 6 ) ; SET HL TO
LD H ,( IY + 7 ) ; ... START OF BUFFER STRUCT
LD A ,( HL ) ; GET COUNT
CP UART_BUFSZ ; COMPARE TO BUFFER SIZE
JR Z , UART_INTRCV4 ; BAIL OUT IF BUFFER FULL, RCV BYTE DISCARDED
INC A ; INCREMENT THE COUNT
LD ( HL ), A ; AND SAVE IT
; *** FIXME *** THE FOLLOWING SHOULD ONLY BE DONE IF RTS FLOW CONTROL IS ON!!!
; SOMETHING LIKE THIS MAY WORK...
;BIT 5,(IY+5)
;JR Z,UART_INTRCV2
CP UART_BUFSZ / 2 ; BUFFER GETTING FULL?
JR NZ , UART_INTRCV2 ; IF NOT, BYPASS CLEARING RTS
LD C ,( IY + 3 ) ; LSR PORT TO C
DEC C ; POINT TO MCR PORT
IN A ,( C ) ; GET MCR VALUE
AND ~% 00000010 ; CLEAR RTS
OUT ( C ), A ; AND SAVE IT
;
UART_INTRCV2:
INC HL ; HL NOW HAS ADR OF HEAD PTR
PUSH HL ; SAVE ADR OF HEAD PTR
LD A ,( HL ) ; DEREFERENCE HL
INC HL
LD H ,( HL )
LD L , A ; HL IS NOW ACTUAL HEAD PTR
LD ( HL ), B ; SAVE CHARACTER RECEIVED IN BUFFER AT HEAD
INC HL ; BUMP HEAD POINTER
POP DE ; RECOVER ADR OF HEAD PTR
LD A , L ; GET LOW BYTE OF HEAD PTR
SUB UART_BUFSZ + 4 ; SUBTRACT SIZE OF BUFFER AND POINTER
CP E ; IF EQUAL TO START, HEAD PTR IS PAST BUF END
JR NZ , UART_INTRCV3 ; IF NOT, BYPASS
LD H , D ; SET HL TO
LD L , E ; ... HEAD PTR ADR
INC HL ; BUMP PAST HEAD PTR
INC HL
INC HL
INC HL ; ... SO HL NOW HAS ADR OF ACTUAL BUFFER START
UART_INTRCV3:
EX DE , HL ; DE := HEAD PTR VAL, HL := ADR OF HEAD PTR
LD ( HL ), E ; SAVE UPDATED HEAD PTR
INC HL
LD ( HL ), D
; CHECK FOR MORE PENDING...
LD C ,( IY + 3 ) ; STATUS PORT TO C
IN A ,( C ) ; GET LSR
AND $ 01 ; ISOLATE RECEIVE READY BIT
JR NZ , UART_INTRCV1 ; IF SET, DO SOME MORE
UART_INTRCV4:
OR $ FF ; NZ SET TO INDICATE INT HANDLED
RET
;
# ENDIF
;
; DRIVER FUNCTION TABLE
;
UART_FNTBL:
@ -167,17 +306,81 @@ UART_FNTBL:
UART_IN:
CALL UART_IST ; RECEIVED CHAR READY?
JR Z , UART_IN ; LOOP IF NOT
LD C ,( IY + 2 ) ; C := BASE UART PORT (WHICH IS ALSO RBR REG)
# IF (( UARTINTS ) & ( INTMODE > 0 ))
BIT UART_INTACT ,( IY + 1 ) ; INT RCV BIT
JR Z , UART_IN1 ; NORMAL INPUT IF NOT SET
JR UART_INTIN ; INT RCV INPUT
# ENDIF
;
UART_IN1:
LD C ,( IY + 2 ) ; C := BASE UART PORT (WHICH IS ALSO RBR REG)
IN E ,( C ) ; CHAR READ TO E
XOR A ; SIGNAL SUCCESS
RET ; AND DONE
;
# IF (( UARTINTS ) & ( INTMODE > 0 ))
;
UART_INTIN:
HB_DI ; AVOID COLLISION WITH INT HANDLER
LD L ,( IY + 6 ) ; SET HL TO
LD H ,( IY + 7 ) ; ... START OF BUFFER STRUCT
LD A ,( HL ) ; GET COUNT
DEC A ; DECREMENT COUNT
LD ( HL ), A ; SAVE UPDATED COUNT
; *** FIXME *** THE FOLLOWING SHOULD ONLY BE DONE IF RTS FLOW CONTROL IS ON!!!
; SOMETHING LIKE THIS MAY WORK...
;BIT 5,(IY+5)
;JR Z,UART_INTIN1
CP UART_BUFSZ / 4 ; BUFFER LOW THRESHOLD
JR NZ , UART_INTIN1 ; IF NOT, BYPASS SETTING RTS
LD C ,( IY + 3 ) ; LSR PORT TO C
DEC C ; POINT TO MCR PORT
IN A ,( C ) ; GET MCR VALUE
OR % 00000010 ; SET RTS
OUT ( C ), A ; AND SAVE IT
;
UART_INTIN1:
INC HL
INC HL
INC HL ; HL NOW HAS ADR OF TAIL PTR
PUSH HL ; SAVE ADR OF TAIL PTR
LD A ,( HL ) ; DEREFERENCE HL
INC HL
LD H ,( HL )
LD L , A ; HL IS NOW ACTUAL TAIL PTR
LD C ,( HL ) ; C := CHAR TO BE RETURNED
INC HL ; BUMP TAIL PTR
POP DE ; RECOVER ADR OF TAIL PTR
LD A , L ; GET LOW BYTE OF TAIL PTR
SUB UART_BUFSZ + 2 ; SUBTRACT SIZE OF BUFFER AND POINTER
CP E ; IF EQUAL TO START, TAIL PTR IS PAST BUF END
JR NZ , UART_INTIN2 ; IF NOT, BYPASS
LD H , D ; SET HL TO
LD L , E ; ... TAIL PTR ADR
INC HL ; BUMP PAST TAIL PTR
INC HL ; ... SO HL NOW HAS ADR OF ACTUAL BUFFER START
UART_INTIN2:
EX DE , HL ; DE := TAIL PTR VAL, HL := ADR OF TAIL PTR
LD ( HL ), E ; SAVE UPDATED TAIL PTR
INC HL
LD ( HL ), D
LD E , C ; MOVE CHAR TO RETURN TO E
HB_EI ; INTERRUPTS OK AGAIN
XOR A ; SIGNAL SUCCESS
RET ; AND DONE
;
# ENDIF
;
;
;
UART_OUT:
CALL UART_OST ; READY FOR CHAR?
JR Z , UART_OUT ; LOOP IF NOT
LD C ,( IY + 2 ) ; C := BASE UART PORT (WHICH IS ALSO THR REG)
LD C ,( IY + 2 ) ; C := BASE UART PORT (WHICH IS ALSO THR REG)
OUT ( C ), E ; SEND CHAR FROM E
XOR A ; SIGNAL SUCCESS
RET
@ -185,7 +388,14 @@ UART_OUT:
;
;
UART_IST:
LD C ,( IY + 3 ) ; C := LINE STATUS REG (LSR)
# IF (( UARTINTS ) & ( INTMODE > 0 ))
BIT UART_INTACT ,( IY + 1 ) ; INT RCV BIT
JR Z , UART_IST1 ; NORMAL INPUT IF NOT SET
JR UART_INTIST ; ELSE INT RCV
# ENDIF
;
UART_IST1:
LD C ,( IY + 3 ) ; C := LINE STATUS REG (LSR)
IN A ,( C ) ; GET STATUS
AND $ 01 ; ISOLATE BIT 0 (RECEIVE DATA READY)
JP Z , CIO_IDLE ; NOT READY, RETURN VIA IDLE PROCESSING
@ -193,10 +403,22 @@ UART_IST:
INC A ; ACCUM := 1 TO SIGNAL 1 CHAR WAITING
RET ; DONE
;
# IF (( UARTINTS ) & ( INTMODE > 0 ))
;
UART_INTIST:
LD L ,( IY + 6 ) ; GET ADDRESS
LD H ,( IY + 7 ) ; ... OF RECEIVE BUFFER
LD A ,( HL ) ; BUFFER UTILIZATION COUNT
OR A ; SET FLAGS
JP Z , CIO_IDLE ; NOT READY, RETURN VIA IDLE PROCESSING
RET
;
# ENDIF
;
;
;
UART_OST:
LD C ,( IY + 3 ) ; C := LINE STATUS REG (LSR)
LD C ,( IY + 3 ) ; C := LINE STATUS REG (LSR)
IN A ,( C ) ; GET STATUS
AND $ 20 ; ISOLATE BIT 5 ()
JP Z , CIO_IDLE ; NOT READY, RETURN VIA IDLE PROCESSING
@ -206,7 +428,18 @@ UART_OST:
;
;
;
;
; NOTE THAT THERE ARE TWO ENTRY POINTS. INITDEV WILL DISABLE/ENABLE INTS
; AND INITDEVX WILL NOT. THIS IS DONE SO THAT THE PREINIT ROUTINE ABOVE
; CAN AVOID ENABLING/DISABLING INTS.
;
UART_INITDEV:
HB_DI ; DISABLE INTS
CALL UART_INITDEVX ; DO THE WORK
HB_EI ; INTS BACK ON
RET ; DONE
;
UART_INITDEVX:
; TEST FOR -1 WHICH MEANS USE CURRENT CONFIG (JUST REINIT)
LD A , D ; TEST DE FOR
AND E ; ... VALUE OF -1
@ -214,8 +447,8 @@ UART_INITDEV:
JR NZ , UART_INITDEV1 ; IF DE == -1, REINIT CURRENT CONFIG
;
; LOAD EXISTING CONFIG TO REINIT
LD E ,( IY + 4 ) ; LOW BYTE
LD D ,( IY + 5 ) ; HIGH BYTE
LD E ,( IY + 4 ) ; LOW BYTE
LD D ,( IY + 5 ) ; HIGH BYTE
;
UART_INITDEV1:
; DETERMINE DIVISOR
@ -225,8 +458,8 @@ UART_INITDEV1:
RET NZ ; ABORT IF COMPDIV FAILS!
;
; GOT A DIVISOR, COMMIT NEW CONFIG
LD ( IY + 4 ), E ; SAVE LOW WORD
LD ( IY + 5 ), D ; SAVE HI WORD
LD ( IY + 4 ), E ; SAVE LOW WORD
LD ( IY + 5 ), D ; SAVE HI WORD
;
; START OF ACTUAL UART CONFIGURATION
LD A , 80H ; DLAB IS BIT 7 OF LCR
@ -245,6 +478,20 @@ UART_INITDEV1:
;
XOR A ; DLAB OFF NOW
UART_OUTP ( UART_LCR ) ; DO IT
;
XOR A ; IER VALUE FOR NO INTS
;
# IF (( UARTINTS ) & ( INTMODE > 0 ))
;
BIT UART_INTACT ,( IY + 1 ) ; CHECK INT RCV BIT
JR Z , UART_INITDEV1A ; SKIP IF NOT SET
INC A ; DATA RCVD INT BIT OF IER
;
UART_INITDEV1A:
;
# ENDIF
;
UART_OUTP ( UART_IER ) ; SETUP IER REGISTER
;
; SETUP FCR, BIT 5 IS KEPT ON EVEN THOUGH IT IS PROBABLY
; IRRELEVANT BECAUSE IT ONLY APPLIES TO 750 AND DLAB IS
@ -253,18 +500,29 @@ UART_INITDEV1:
UART_OUTP ( UART_FCR ) ; DO IT
;
; SETUP LCR FROM SECOND CONFIG BYTE
LD A ,( IY + 4 ) ; GET CONFIG BYTE
LD A ,( IY + 4 ) ; GET CONFIG BYTE
AND ~ $ C0 ; ISOLATE PARITY, STOP/DATA BITS
UART_OUTP ( UART_LCR ) ; SAVE IT
;
; SETUP MCR FROM FIRST CONFIG BYTE
LD A ,( IY + 5 ) ; GET CONFIG BYTE
LD A ,( IY + 5 ) ; GET CONFIG BYTE
AND ~ $ 1 F ; REMOVE ENCODED BAUD RATE BITS
OR $ 03 ; FORCE RTS & DTR
UART_OUTP ( UART_MCR ) ; SAVE IT
;
; THE MCR REGISTER AFE BIT WILL NORMALLY BE SET/RESET BY THE
; VALUE OF THE CONFIG BYTE. HOWEVER, IF THE CHIP IS NOT AFC CAPABLE
; WE ARE PROBABLY USING INT RCV FOR FLOW CONTROL. ALTHOUGH THE
; CHIP PROBABLY IGNORES THE AFE BIT, WE FORCE CLEAR IT ANYWAY. IT WOULD
; BE BAD IF AFC AND INT RCV ARE ACTIVE AT THE SAME TIME.
BIT UART_AFCACT ,( IY + 1 ) ; IS AFC SUPPOSED TO BE ON?
JR NZ , UART_INITDEV1B ; IF SO, AFE BIT IS OK BASED ON CONFIG BYTE
RES 5 , A ; ELSE FORCE IT OFF
;
UART_INITDEV1B:
UART_OUTP ( UART_MCR ) ; SAVE MCR VALUE
;
; TEST FOR EFR CAPABLE CHIPS
LD A ,( IY + 1 ) ; GET UART TYPE
LD A ,( IY + 1 ) ; GET UART TYPE
CP UART_16650 ; 16650?
JR Z , UART_INITDEV2 ; USE EFR REGISTER
CP UART_16850 ; 16850?
@ -277,7 +535,7 @@ UART_INITDEV2:
PUSH AF ; SAVE IT
LD A , $ BF ; VALUE TO ACCESS EFR
UART_OUTP ( UART_LCR ) ; SET VALUE IN LCR
LD A ,( IY + 5 ) ; GET CONFIG BYTE
LD A ,( IY + 5 ) ; GET CONFIG BYTE
BIT 5 , A ; AFC REQUESTED?
LD A , $ C0 ; ASSUME AFC ON
JR NZ , UART_INITDEV3 ; YES, IMPLEMENT IT
@ -289,11 +547,42 @@ UART_INITDEV3:
UART_OUTP ( UART_LCR ) ; AND PUT IT BACK
;
UART_INITDEV4:
;
# IF (( UARTINTS ) & ( INTMODE > 0 ))
;
LD A ,( IY + 7 ) ; MSB OF BUFFER
OR A ; SET FLAGS
JR Z , UART_INITDEV5 ; BYPASS IF NO BUFFER
; RESET THE RECEIVE BUFFER
LD E ,( IY + 6 )
LD D ,( IY + 7 ) ; DE := _CNT
XOR A ; A := 0
LD ( DE ), A ; _CNT = 0
INC DE ; DE := ADR OF _HD
PUSH DE ; SAVE IT
INC DE
INC DE
INC DE
INC DE ; DE := ADR OF _BUF
POP HL ; HL := ADR OF _HD
LD ( HL ), E
INC HL
LD ( HL ), D ; _HD := _BUF
INC HL
LD ( HL ), E
INC HL
LD ( HL ), D ; _TL := _BUF
;
UART_INITDEV5:
;
# ENDIF
;
;
# IF ( UART_DEBUG )
PRTS ( " [$" )
; DEBUG: DUMP UART TYPE
LD A ,( IY + 1 )
LD A ,( IY + 1 )
CALL PRTHEXBYTE
; DEBUG: DUMP IIR
@ -334,25 +623,68 @@ UART_INITDEV4:
;
;
UART_QUERY:
LD E ,( IY + 4 ) ; FIRST CONFIG BYTE TO E
LD D ,( IY + 5 ) ; SECOND CONFIG BYTE TO D
LD E ,( IY + 4 ) ; FIRST CONFIG BYTE TO E
LD D ,( IY + 5 ) ; SECOND CONFIG BYTE TO D
XOR A ; SIGNAL SUCCESS
RET ; DONE
;
;
;
UART_DEVICE:
LD D , CIODEV_UART ; D := DEVICE TYPE
LD E ,( IY ) ; E := PHYSICAL UNIT
LD C , $ 00 ; C := DEVICE TYPE, 0x00 IS RS-232
LD H , 0 ; H := 0, DRIVER HAS NO MODES
LD L ,( IY + 2 ) ; L := BASE I/O ADDRESS
XOR A ; SIGNAL SUCCESS
LD D , CIODEV_UART ; D := DEVICE TYPE
LD E ,( IY ) ; E := PHYSICAL UNIT
LD C , $ 00 ; C := DEVICE TYPE, 0x00 IS RS-232
LD H ,( IY + 1 ) ; H := UART TYPE BYTE
LD L ,( IY + 2 ) ; L := BASE I/O ADDRESS
XOR A ; SIGNAL SUCCESS
RET
;
; UART DETECTION ROUTINE
;
UART_DETECT:
CALL UART_CHIP ; DETECT CHIP VARIANT
RET Z ; DONE IF NO CHIP
;LD A,UART_16550A ; *DEBUG*
LD C , A ; PUT CHIP VARIANT IN C
;
; *** FIXME *** THIS NEEDS TO CHANGE WHEN INTMODE 2/3 IS IMPLEMENTED. AT THIS
; POINT, WE ONLY SET THE INT RCV FEATURE BIT FOR IM1 BECAUSE THAT IS ALL
; THAT IS IMPLEMENTED.
;
;#IF ((UARTINTS) & (INTMODE > 0))
# IF (( UARTINTS ) & ( INTMODE = = 1 ))
;
; CHECK TO SEE IF INT RCV WANTED ON THIS DEVICE
PUSH AF ; SAVE CHIP ID
CP UART_16550C ; 16550C OR LATER?
JR NC , UART_DETECT1 ; NO INTS, USE AFC INSTEAD
LD A ,( IY + 7 ) ; MSB OF RING BUFFER
OR A ; SET FLAGS
JR Z , UART_DETECT1 ; NO BUFFER, NO INTS ALLOWED
SET UART_INTACT , C ; SET INT RCV BIT
;
UART_DETECT1:
POP AF ; RESTORE CHIP ID
;
# ENDIF
;
CP UART_16550 ; 16550 OR GREATER?
JR C , UART_DETECT2 ; NO MORE FEATURES
SET UART_FIFOACT , C ; RECORD FIFO FEATURE
CP UART_16550C ; 16550C OR GREATER?
JR C , UART_DETECT2 ; NO MORE FEATURES
SET UART_AFCACT , C ; RECORD AFC FEATURE
;
UART_DETECT2:
LD A , C ; RETURN RESULT IN A
CALL PRTHEXBYTE
RET
;
; DETERMINE TEH UART CHIP VARIANT AND RETURN IN A
;
UART_CHIP:
;
; SEE IF UART IS THERE BY CHECKING DLAB FUNCTIONALITY
XOR A ; ZERO ACCUM
@ -363,26 +695,26 @@ UART_DETECT:
UART_OUTP ( UART_DLM ) ; OUTPUT TO DLM
UART_INP ( UART_DLM ) ; READ IT BACK
CP $ 5 A ; CHECK FOR TEST VALUE
JP NZ , UART_DETECT _NONE ; NOPE, UNKNOWN UART OR NOT PRESENT
JP NZ , UART_CHIP _NONE ; NOPE, UNKNOWN UART OR NOT PRESENT
XOR A ; DLAB BIT OFF
UART_OUTP ( UART_LCR ) ; OUTPUT TO LCR (DLAB REGS NOW INACTIVE)
UART_INP ( UART_IER ) ; READ IER
CP $ 5 A ; CHECK FOR TEST VALUE
JP Z , UART_DETECT _NONE ; IF STILL $5A, UNKNOWN OR NOT PRESENT
JP Z , UART_CHIP _NONE ; IF STILL $5A, UNKNOWN OR NOT PRESENT
;
; TEST FOR FUNCTIONAL SCRATCH REG, IF NOT, WE HAVE AN 8250
LD A , $ 5 A ; LOAD TEST VALUE
UART_OUTP ( UART_SCR ) ; PUT IT IN SCRATCH REGISTER
UART_INP ( UART_SCR ) ; READ IT BACK
CP $ 5 A ; CHECK IT
JR NZ , UART_DETECT _8250 ; STUPID 8250
JR NZ , UART_CHIP _8250 ; STUPID 8250
;
; TEST FOR EFR REGISTER WHICH IMPLIES 16650/850
LD A , $ BF ; VALUE TO ENABLE EFR
UART_OUTP ( UART_LCR ) ; WRITE IT TO LCR
UART_INP ( UART_SCR ) ; READ SCRATCH REGISTER
CP $ 5 A ; SPR STILL THERE?
JR NZ , UART_DETECT 1 ; NOPE, HIDDEN, MUST BE 16650/850
JR NZ , UART_CHIP 1 ; NOPE, HIDDEN, MUST BE 16650/850
;
; RESET LCR TO DEFAULT (DLAB OFF)
;LD A,$80 ; DLAB BIT ON
@ -394,22 +726,21 @@ UART_DETECT:
UART_OUTP ( UART_FCR ) ; PUT IT IN FCR
UART_INP ( 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
JR Z , UART_CHIP _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
JR Z , UART_CHIP _16550 ; IF NOT SET, MUST BE 16550
BIT 5 , A ; BIT 5 IS 64 BYTE FIFO
JR Z , UART_DETECT 2 ; IF NOT SET, MUST BE 16550A/C
JR UART_DETECT _16750 ; ONLY THING LEFT IS 16750
JR Z , UART_CHIP 2 ; IF NOT SET, MUST BE 16550A/C
JR UART_CHIP _16750 ; ONLY THING LEFT IS 16750
;
UART_DETECT 1: ; PICK BETWEEN 16650/850
UART_CHIP 1: ; PICK BETWEEN 16650/850
; RESET LCR TO DEFAULT (DLAB OFF)
XOR A ; DLAB BIT OFF
UART_OUTP ( UART_LCR ) ; RESET LCR
; NOT SURE HOW TO DIFFERENTIATE 16650 FROM 16850 YET
JR UART_DETECT_16650 ; ASSUME 16650
RET
JR UART_CHIP_16650 ; ASSUME 16650
;
UART_DETECT 2: ; PICK BETWEEN 16550A/C
UART_CHIP 2: ; PICK BETWEEN 16550A/C
; SET AFC BIT IN FCR
LD A , $ 20 ; SET AFC BIT, MCR:5
UART_OUTP ( UART_MCR ) ; WRITE NEW FCR VALUE
@ -417,45 +748,45 @@ UART_DETECT2: ; PICK BETWEEN 16550A/C
; READ IT BACK, IF SET, WE HAVE 16550C
UART_INP ( 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
JR Z , UART_CHIP _16550A ; NOT SET, SO 16550A
JR UART_CHIP _16550C ; IS SET, SO 16550C
;
UART_DETECT _NONE:
LD A ,( IY + 2 ) ; BASE IO PORT
UART_CHIP _NONE:
LD A ,( IY + 2 ) ; BASE IO PORT
CP UARTSBASE ; IS THIS PRIMARY SBC PORT?
JR Z , UART_DETECT _8250 ; SPECIAL CASE FOR PRIMARY UART!
JR Z , UART_CHIP _8250 ; SPECIAL CASE FOR PRIMARY UART!
LD A , UART_NONE ; IF SO, TREAT AS 8250 NO MATTER WHAT
RET
;
UART_DETECT _8250:
UART_CHIP _8250:
LD A , UART_8250
RET
;
UART_DETECT _16450:
UART_CHIP _16450:
LD A , UART_16450
RET
;
UART_DETECT _16550:
UART_CHIP _16550:
LD A , UART_16550
RET
;
UART_DETECT _16550A:
UART_CHIP _16550A:
LD A , UART_16550A
RET
;
UART_DETECT _16550C:
UART_CHIP _16550C:
LD A , UART_16550C
RET
;
UART_DETECT _16650:
UART_CHIP _16650:
LD A , UART_16650
RET
;
UART_DETECT _16750:
UART_CHIP _16750:
LD A , UART_16750
RET
;
UART_DETECT _16850:
UART_CHIP _16850:
LD A , UART_16850
RET
;
@ -492,12 +823,13 @@ UART_PRTCFG:
LD A ,( IY ) ; DEVICE NUM
CALL PRTDECB ; PRINT DEVICE NUM
PRTS ( ": IO=0x$" ) ; FORMATTING
LD A ,( IY + 2 ) ; GET BASE PORT
LD A ,( IY + 2 ) ; GET BASE PORT
CALL PRTHEXBYTE ; PRINT BASE PORT
; PRINT THE UART TYPE
CALL PC_SPACE ; FORMATTING
LD A ,( IY + 1 ) ; GET UART TYPE BYTE
LD A ,( IY + 1 ) ; GET UART TYPE BYTE
AND $ 0 F ; LOW BITS ONLY
RLCA ; MAKE IT A WORD OFFSET
LD HL , UART_TYPE_MAP ; POINT HL TO TYPE MAP TABLE
CALL ADDHLA ; HL := ENTRY
@ -507,25 +839,31 @@ UART_PRTCFG:
CALL WRITESTR ; PRINT IT
;
; ALL DONE IF NO UART WAS DETECTED
LD A ,( IY + 1 ) ; GET UART TYPE BYTE
LD A ,( IY + 1 ) ; GET UART TYPE BYTE
OR A ; SET FLAGS
RET Z ; IF ZERO, NOT PRESENT
;
PRTS ( " MODE=$" ) ; FORMATTING
LD E ,( IY + 4 ) ; LOAD CONFIG
LD D ,( IY + 5 ) ; ... WORD TO DE
LD E ,( IY + 4 ) ; LOAD CONFIG
LD D ,( IY + 5 ) ; ... WORD TO DE
CALL PS_PRTSC0 ; PRINT CONFIG
;
; ; PRINT FEATURES ENABLED
; LD A,(UART_FEAT)
; BIT UART_FIFO,A
; JR Z,UART_INITUNIT2
; PRTS(" FIFO$")
;UART_INITUNIT2:
; BIT UART_AFC,A
; JR Z,UART_INITUNIT3
; PRTS(" AFC$")
;UART_INITUNIT3:
; PRINT FEATURES ENABLED
BIT UART_INTACT ,( IY + 1 ) ; GET INT RCV BIT
JR Z , UART_PRTCFG1
PRTS ( " INT$" )
;
UART_PRTCFG1:
BIT UART_FIFOACT ,( IY + 1 ) ; GET FIFO BIT
JR Z , UART_PRTCFG2
PRTS ( " FIFO$" )
;
UART_PRTCFG2:
BIT UART_AFCACT ,( IY + 1 ) ; GET AFC BIT
JR Z , UART_PRTCFG3
PRTS ( " AFC$" )
;
UART_PRTCFG3:
;
XOR A
RET
@ -537,7 +875,7 @@ UART_PRTCFG:
UART_INP_IMP:
EX ( SP ), HL ; SWAP HL AND TOS
PUSH BC ; PRESERVE BC
LD A ,( IY + 2 ) ; GET UART IO BASE PORT
LD A ,( IY + 2 ) ; GET UART IO BASE PORT
OR ( HL ) ; OR IN REGISTER ID BITS
LD C , A ; C := PORT
IN A ,( C ) ; READ PORT INTO A
@ -552,7 +890,7 @@ UART_OUTP_IMP:
EX ( SP ), HL ; SWAP HL AND TOS
PUSH BC ; PRESERVE BC
LD B , A ; PUT VALUE TO WRITE IN B
LD A ,( IY + 2 ) ; GET UART IO BASE PORT
LD A ,( IY + 2 ) ; GET UART IO BASE PORT
OR ( HL ) ; OR IN REGISTER ID BITS
LD C , A ; C := PORT
OUT ( C ), B ; WRITE VALUE TO PORT
@ -594,31 +932,34 @@ UART_DEV .DB 0 ; DEVICE NUM USED DURING INIT
;
UART_CFG:
# IF ( UARTSBC )
UART_CFG_SBC:
; SBC/ZETA ONBOARD SERIAL PORT
.DB 0 ; DEVICE NUMBER (UPDATED DURING INIT)
.DB 0 ; UART TYPE
.DB UARTSBASE ; IO PORT BASE (RBR, THR)
.DB UARTSBASE + UART_LSR ; LINE STATUS PORT (LSR)
.DW UARTCFG ; LINE CONFIGURATION
.FILL 2 , $ FF ; FILLER
.DW UARTSBC_RCVBUF ; POINTER TO RCV BUFFER STRUCT
# ENDIF
# IF ( UARTCAS )
UART_CFG_CAS:
; CASSETTE INTERFACE SERIAL PORT
.DB 0 ; DEVICE NUMBER (UPDATED DURING INIT)
.DB 0 ; UART TYPE
.DB UARTCBASE ; IO PORT BASE (RBR, THR)
.DB UARTCBASE + UART_LSR ; LINE STATUS PORT (LSR)
.DW UARTCASSPD ; LINE CONFIGURATION
.FILL 2 , $ FF ; FILLER
.DW UARTCAS_RCVBUF ; POINTER TO RCV BUFFER STRUCT
# ENDIF
# IF ( UARTMFP )
UART_CFG_MFP:
; MF/PIC SERIAL PORT
.DB 0 ; DEVICE NUMBER (UPDATED DURING INIT)
.DB 0 ; UART TYPE
.DB UARTMBASE ; IO PORT BASE (RBR, THR)
.DB UARTMBASE + UART_LSR ; LINE STATUS PORT (LSR)
.DW UARTCFG ; LINE CONFIGURATION
.FILL 2 , $ FF ; FIL LER
.DW 0 ; SHOULD NEVER NEED INT HAND LER
# ENDIF
# IF ( UART4 )
; 4UART SERIAL PORT A
@ -627,28 +968,28 @@ UART_CFG:
.DB UART4BASE + 0 ; IO PORT BASE (RBR, THR)
.DB UART4BASE + 0 + UART_LSR ; LINE STATUS PORT (LSR)
.DW UARTCFG ; LINE CONFIGURATION
.FILL 2 , $ FF ; FIL LER
.DW 0 ; SHOULD NEVER NEED INT HAND LER
; 4UART SERIAL PORT B
.DB 0 ; DEVICE NUMBER (UPDATED DURING INIT)
.DB 0 ; UART TYPE
.DB UART4BASE + 8 ; IO PORT BASE (RBR, THR)
.DB UART4BASE + 8 + UART_LSR ; LINE STATUS PORT (LSR)
.DW UARTCFG ; LINE CONFIGURATION
.FILL 2 , $ FF ; FIL LER
.DW 0 ; SHOULD NEVER NEED INT HAND LER
; 4UART SERIAL PORT C
.DB 0 ; DEVICE NUMBER (UPDATED DURING INIT)
.DB 0 ; UART TYPE
.DB UART4BASE + 16 ; IO PORT BASE (RBR, THR)
.DB UART4BASE + 16 + UART_LSR ; LINE STATUS PORT (LSR)
.DW UARTCFG ; LINE CONFIGURATION
.FILL 2 , $ FF ; FIL LER
.DW 0 ; SHOULD NEVER NEED INT HAND LER
; 4UART SERIAL PORT D
.DB 0 ; DEVICE NUMBER (UPDATED DURING INIT)
.DB 0 ; UART TYPE
.DB UART4BASE + 24 ; IO PORT BASE (RBR, THR)
.DB UART4BASE + 24 + UART_LSR ; LINE STATUS PORT (LSR)
.DW UARTCFG ; LINE CONFIGURATION
.FILL 2 , $ FF ; FIL LER
.DW 0 ; SHOULD NEVER NEED INT HAND LER
# ENDIF
# IF ( UARTRC )
; UARTRC SERIAL PORT A
@ -657,14 +998,47 @@ UART_CFG:
.DB UARTRBASE ; IO PORT BASE (RBR, THR)
.DB UARTRBASE + UART_LSR ; LINE STATUS PORT (LSR)
.DW UARTCFG ; LINE CONFIGURATION
.FILL 2 , $ FF ; FIL LER
.DW 0 ; SHOULD NEVER NEED INT HAND LER
; UARTRC SERIAL PORT B
.DB 0 ; DEVICE NUMBER (UPDATED DURING INIT)
.DB 0 ; UART TYPE
.DB UARTRBASE + 8 ; IO PORT BASE (RBR, THR)
.DB UARTRBASE + 8 + UART_LSR ; LINE STATUS PORT (LSR)
.DW UARTCFG ; LINE CONFIGURATION
.FILL 2 , $ FF ; FIL LER
.DW 0 ; SHOULD NEVER NEED INT HAND LER
# ENDIF
;
UART_CNT .EQU ( $ - UART_CFG ) / 8
;
# IF (( ! UARTINTS ) | ( INTMODE = = 0 ))
;
UARTSBC_RCVBUF .EQU 0
UARTCAS_RCVBUF .EQU 0
;
# ELSE
;
; UART SBC RECEIVE BUFFER
;
# IF ( UARTSBC )
;
UARTSBC_RCVBUF:
UARTSBC_CNT .DB 0 ; CHARACTERS IN RING BUFFER
UARTSBC_HD .DW UARTSBC_BUF ; BUFFER HEAD POINTER
UARTSBC_TL .DW UARTSBC_BUF ; BUFFER TAIL POINTER
UARTSBC_BUF .FILL UART_BUFSZ , 0 ; RECEIVE RING BUFFER
;
# ENDIF
;
; UART CASSETTE RECEIVE BUFFER
;
# IF ( UARTCAS )
;
UARTCAS_RCVBUF:
UARTCAS_CNT .DB 0 ; CHARACTERS IN RING BUFFER
UARTCAS_HD .DW UARTCAS_BUF ; BUFFER HEAD POINTER
UARTCAS_TL .DW UARTCAS_BUF ; BUFFER TAIL POINTER
UARTCAS_BUF .FILL UART_BUFSZ , 0 ; RECEIVE RING BUFFER
;
# ENDIF
;
# ENDIF