		SUBTITLE	"< UART 0 - Driver. >"
		NEWPAGE
		SCOPE

	
U0DVR 	  	JR	U0BGN           	;Driver entry point. Branch around linkage
		DW 	U0END           	;Last memory location used
		DB      3,"$CL"
		DW      U0DCB$       		;DCB used.
		DW      0			;Reserved.
			
CLDATA$		EQU	$
MSMASK		EQU	$-CLDATA$
		DB	80h

;	UART Control Port image
;	Bit 7:	1 = Even parity, 0 = Odd parity
;	Bit 6 - 5 = Word length (00=5,10=6,01=7,11=8)
;	Bit 4:	1 = 2 stop bits, 0 = 1 stop bit
;	Bit 3:	1 = disable parity, 0 = enable parity
;	Bit 2:	1 = enable TX data, 0 = break
;	Bit 1:	0 = Data Terminal Ready
;	Bit 0:	0 = Request To Send

UCIMAGE		EQU	$-CLDATA$
		DB	0A4H			; 10100101 = 7E1
BAUDRT		DB	55H			; Init 300 baud
LOGBRK		EQU	$-CLDATA$
		DB	03H			; Default is Ctl-C
CLFLG		EQU	$-CLDATA$
		DB	00H			; Init no char in buf
CLBUF		EQU	$-CLDATA$
		DB	00H			; One-char buffer
esccount	db	2			; Start counter off at 2.			
U0BGN		ei
		ld	ix,CLDATA$		; Base address of driver data pool.
		JR	C,RXUART0		; Go if input req, GET.
		Jp	Z,TXUART0		; Go if output, PUT.

; CTL request.

CTLUART0	LD	A,C			; Get @CTL byte
		OR	A			; @CTL 00?
		JR	Z,CANISND		; Go if so
		DEC	A
		JR	Z,CTL1			; Go if CTL 01
		DEC	A
		JR	Z,CTL2			; CTL 02 "init uart"
		CP	4-2			; Wakeup feature?
		JR	Z,CTL4			; Go if wakeup
;		XOR	A
		RET

; CL initialization routine.  Set up DR interrupt
; vector and initialize the hardware

INIT		LD	A,($-$)			; Get WRINT
		;OUT	(@WRINT),A
		CALL	CTL2
LINK		RET
		DB	0,0

; Initialize the UART and BRG

CTL2		LD	BC,(CLDATA$+UCIMAGE)	; Vals from DCB.
		;OUT	(MASRES),A		; Reprime UART.
		LD	A,C
		;OUT	(UARTCTL),A
		LD	A,B
		;OUT	(BAUDSET),A
		RET

CTL4		PUSH	IY			; Xfer pointer to DE
		POP	DE
		LD	A,D			; Test if set or reset
		OR	E
		LD	A,0C9H			; Init disable reset
		LD	HL,(WAKEADR+1)		; Get old value.
		JR	Z,SETWAK		; Jump if disable
		LD	A,0C3H			; Make enable
SETWAK		LD	(WAKEADR),A		; Load the opcode.
		LD	(WAKEADR+1),DE		; Then the address.
		PUSH	HL			; Transfer pointer to IY
		POP	IY
		RET
		
;	Check if ready to send

CANISND		IN0	a,(UART0_MSR)		; Get CTS status & test if CTS is ready..
		BIT	4,A			; If other end sets CTS true, they are ready to receive.I just
		JR	Z,CANISND		; If not ready wait. Come on I am waiting in CANISND loop.
	
		IN0	A,(UART0_LSR)		; Find out if UART ready to transmit.
		cpl
		AND     UART_THRE		; Determine if our own UART is ready to send a character.
		push	AF			; Save results of this test.
			
; eZ80 modem status register format is as follows.

; Bit 7 - CD Carrier detect.
; Bit 6 - RI Ring indicator.
; Bit 5 - DSR Data Set Ready.
; Bit 4 - CTS Clear To Send.

; TRS-80 modem status register format is as follows.

; Bit 0 - Copy of serial input pin UART (Pin 20 of the DB-25).
; Bit 4 - RI Ring Indicator (Pin 22 of the DB-25).
; Bit 5 - CD Carrier Detect (Pin 8 of the DB-25).
; Bit 6 - DSR Data Set Ready (Pin 6 of the DB-25).
; Bit 7 - CTS Clear to Send (Pin 5 of the DB-25).
			
		in0	a,(UART0_MSR)		; Get modem status reg.
		ld	b,0F0h			; Set all upper 4 bits.

; Test CD pin on eZ80 & if not set, reset CD on TRS-80 modem status.
			
		bit	4,a			; Test eZ80 CTS pin and make TRS-80 CD pin follow it bc no CD on eZ80.
		jr	nz,b51			; Is it ON? If OFF then reset this bit in TRS-80 port image.
;        		res	5,b		; Turn TRS-80 CD OFF.

; Test RING on eZ80, if not on turn RING on TRS-80 modem status off.

b51		bit	6,a			; Test eZ80 RING indicator.
		jr	nz,b41			; Is it ON? If OFF then reset this bit in TRS-80 port image.
		res	4,b			; Turn TRS-80 RI OFF.

; Test data set ready and adjust TRS-80 status accordingly.

b41		bit	5,a			; Test eZ80 Data Set Ready.
		jr	nz,b61			; Is it ON? If OFF then reset this bit in TRS-80 port image.
		res	6,b			; Turn TRS-80 DSR OFF.
			
; Test eZ80 Clear To Send (CTS). Adjust TRS-80 to match.

b61		bit	4,a			; Test eZ80 Clear To Send.
		jr	nz,b71			; Is it ON? If OFF then reset this bit in TRS-80 port image.
		res	7,b			; Turn TRS-80 CTS OFF.

b71		ld	a,b
		cpl
		ld	b,a
		pop	AF			; Recover flag if UART empty. A has image of Modem Status Register.
		ld	a,b			; Get TRS-80 format modem status register in A.
		RET	NZ			; Return if can't send.
	
		XOR	(IX+MSMASK)		; Mask for which to flip.
		RRA				; Move into bits 0-3
		RRA
		RRA
		RRA
		AND	(IX+MSMASK)		; Mask for which to check
		AND	0FH			; Mask off garbage

;		xor	a			; PLUG IT...say handshake always ready.
		LD	A,B			; Get reg back
		RET				; Ret with Z or NZ.

; GET request. UART 0 I/O subroutine to receive byte into reg A.

RXUART0		CALL	CKINP			; Chk if avail from port
		RET	NZ			; Back if none
		SLA	(IX+CLFLG)		; Check if avail from buf
		JR	NC,RXUART0		; Go if none avail
		LD	A,(IX+CLBUF)		; Get the char
		CP	A			; Set Z flag & exit.
		RET

;		Break request

CTL1		ld	a,(IX+UCIMAGE)		; Get UART CTL image.
		res	2,a			; Show BREAK bit.
		;out	 (UARTCTL),a
		ret				; Return witn Z flag.
; Data received interrupt handler

RECVINT		LD	IX,CLDATA$		; Base of data area.
		CALL	CKINP			; See if available from port.
		LD	A,B
WAKEADR		RET					; Wakeup if enabled.
		DW	0			; Space for address.	

; Routine to check on a received character.

nochar		or	1			; Make NZ.
		ld	a,0			; A=0 No error.
		ret

CKINP		IN0     A,(UART0_LSR)		; Get status of data waiting?	IN A,(UARTST)	; Check if actually RX.
		AND     UART_DR     		; Char waiting?
		JR      Z,nochar		; Make NZ, NO char waiting.
			
		ld	a,10000000b
		LD	B,A			; Save status.
		;CPL				; Mask Data Received bit.
		;AND	80H
		;LD	A,00H			; Set "No error".
		;RET	NZ			; Return if none.
		;IN	A,(DATAREG)		; Get character.
		
		;ld	b,00000000b		; Set TRS-80 modem status register to char waiting.

		IN0    	A,(UART0_RBR)		; Get byte from UART0.
		LD	C,A			; Save it in C.
			
		cp	ESC.asc			; User hit escape? If so inc count by 1.
		ld	a,(esccount)
		jr	nz,resetesc
		dec	a
		jr	nz,CRCK			; Have not reached 0 yet.
		ld	a,2			; Reset counter to 2.
		ld	(esccount),a
		jp	zABORT			; Two counts....were out of here!
			
; Break, Pause and Enter handler routine.

resetesc	ld	a,2			; Reset counter back to 2.
CRCK		ld	(esccount),a
		ld	a,c
		LD	HL,zKFLAG$		; KFLAG$
		CP	CR.asc			; ENTER char received?
		JR	NZ,PAWSCK		; Go if not
		SET	2,(hl)			; Set ENTER bit
		JR	RECVEX
PAWSCK		CP	60H			; Pause char received?
		JR	NZ,BRKCHK		; Go if not
		SET	1,(HL)			; Set pause bit
		JR	RECVEX
BRKCHK		LD	A,(IX+LOGBRK)		; Break char received?
		OR	A			; Check if LOGBRK=0
		JR	Z,RECVEX		; No valid break if =0
		CP	C			; Check if a valid break
		JR	NZ,RECVEX		; Go if so.

; A break was received, check system's BREAK disable

BRKRECD		LD	A,(zSFLAG$)		; Check if break key.
		AND	10H			; is disabled
		LD	A,00H			; Ret NZ & A=0 if
		RET	NZ			; the BREAK is disabled
		LD	HL,zKFLAG$		; Hang onto flag
		SET	0,(HL)			; Else set break bit
		LD	C,80H			; & reset BREAK code
RECVEX		LD	(IX+CLBUF),C		; Put char in 1 char buf
		LD	(IX+CLFLG),80H		; Set char available
		ld	a,c
		cp	A			; Set Z flag.
		ret

; Character PUT request. Transmit byte in register C.

TXUART0:	call	CANISND
		JR     	nZ,TXUART0
		OUT0  	(UART0_THR),c
		ld	a,c
		RET

U0END:		EQU	$-1