;
;==================================================================================================
; Z280 UART DRIVER (Z280 BUILT-IN UART)
;==================================================================================================
;
;  SETUP PARAMETER WORD:
;  +-------+---+-------------------+ +---+---+-----------+---+-------+
;  |	   |RTS| ENCODED BAUD RATE | |DTR|XON|	PARITY	 |STP| 8/7/6 |
;  +-------+---+---+---------------+ ----+---+-----------+---+-------+
;    F	 E   D	 C   B	 A   9	 8     7   6   5   4   3   2   1   0
;	-- MSB (D REGISTER) --		 -- LSB (E REGISTER) --
;
; CONFIG ($FE__10):
; 7 6 5 4 3 2 1 0
; 1 1 0 0 0 0 1 0   DEFAULT VALUES
; | | | | | | | |
; | | | | | | | |
; | | | | | | | +-- LB:		LOOP BACK ENABLE
; | | | | | + +---- CR:		CLOCK RATE
; | | | | +-------- CS:		CLOCK SELECT
; | | | +---------- E/O:	EVEN/ODD
; | | +------------ P:		PARITY
; + +-------------- B/C:	BITS PER CHARACTER
;
; TRANSMITTER CONTROL/STATUS REGISTER ($FE__12)
; 7 6 5 4 3 2 1 0
; 1 0 0 0 0 0 0 0   DEFAULT VALUES
; | | | | | | | |
; | | | | | | | +-- BE:		BUFFER EMPTY
; | | | | | | +---- VAL:	VALUE
; | | | | | +------ FRC:	FORCE CHARACTER
; | | | | +-------- BRK:	SEND BREAK
; | | | +---------- SB:		STOP BITS
; | | +------------ 0:		RESERVED (SET TO 0)
; | +-------------- IE:		XMIT INT ENBABLE
; +---------------- EN:		TRANSMITTER ENABLE
;
; RECEIVER CONTROL/STATUS REGISTER ($FE__14)
; 7 6 5 4 3 2 1 0
; 1 0 0 0 0 0 0 0   DEFAULT VALUES
; | | | | | | | |
; | | | | | | | +-- ERR:	LOGICAL OR OF (OVE, PE, FE)
; | | | | | | +---- OVE:	OVERRUN ERROR
; | | | | | +------ PE:		PARITY ERROR
; | | | | +-------- FE:		FRAMING ERROR
; | | | +---------- CA:		RECEIVE CHAR AVAILABLE
; | | +------------ 0:		RESERVED (SET TO 0)
; | +-------------- IE:		RECEIVER INT ENBABLE
; +---------------- EN:		RECEIVER ENABLE
;
; INTERRUPT DRIVEN PROCESSING IS ONLY USED WHEN THE SYSTEM IS IN
; INTERRUPT MODE 3.  THIS IS BECAUSE THE BUILT-IN UART *ALWAYS* USES
; MODE 3 PROCESSING.  SINCE MODE 3 PROCESSING REQUIRES THE MODE 3
; INTERRUPT VECTOR TABLE WHICH IS LARGE AND WON'T FIT WELL IN HIGH
; RAM, IT IS IMPRACTICAL TO IMPLEMENT ANY INTERRUPT DRIVEN PROCESSING
; UNLESS FULL BLOWN INTERRUPT MODE 3 W/ NATIVE MEMORY MANAGEMENT
; IS BEING USED.
;
;
;
#IF (Z2U0HFC)
Z2U_BUFSZ	.EQU	32		; RECEIVE RING BUFFER SIZE
#ELSE
Z2U_BUFSZ	.EQU	144		; RECEIVE RING BUFFER SIZE
#ENDIF
;
Z2U_NONE	.EQU	0		; NOT PRESENT
Z2U_PRESENT	.EQU	1		; PRESENT
;
;
;
Z2U_PREINIT:
;
; SETUP THE DISPATCH TABLE ENTRIES
; NOTE: INTS WILL BE DISABLED WHEN PREINIT IS CALLED AND THEY MUST REMAIN
; DISABLED.
;
	LD	B,Z2U_CFGCNT		; LOOP CONTROL
	XOR	A			; ZERO TO ACCUM
	LD	(Z2U_DEV),A		; CURRENT DEVICE NUMBER
	LD	IY,Z2U_CFG		; POINT TO START OF CFG TABLE
Z2U_PREINIT0:
	PUSH	BC			; SAVE LOOP CONTROL
	CALL	Z2U_INITUNIT		; HAND OFF TO GENERIC INIT CODE
	POP	BC			; RESTORE LOOP CONTROL
;
	LD	A,(IY+1)		; GET THE Z280 UART TYPE DETECTED
	OR	A			; SET FLAGS
	JR	Z,Z2U_PREINIT2		; SKIP IT IF NOTHING FOUND
;
	PUSH	BC			; SAVE LOOP CONTROL
	PUSH	IY			; CFG ENTRY ADDRESS
	POP	DE			; ... TO DE
	LD	BC,Z2U_FNTBL		; BC := FUNCTION TABLE ADDRESS
	CALL	NZ,CIO_ADDENT		; ADD ENTRY IF Z2U FOUND, BC:DE
	POP	BC			; RESTORE LOOP CONTROL
;
Z2U_PREINIT2:
	LD	DE,Z2U_CFGSIZ		; SIZE OF CFG ENTRY
	ADD	IY,DE			; BUMP IY TO NEXT ENTRY
	DJNZ	Z2U_PREINIT0		; LOOP UNTIL DONE
;
#IF (INTMODE == 3)
	; SETUP INT VECTORS AS APPROPRIATE
	LD	A,(Z2U_DEV)		; GET DEVICE COUNT
	OR	A			; SET FLAGS
	JR	Z,Z2U_PREINIT3		; IF ZERO, NO Z2U DEVICES, ABORT
;
	LD	HL,Z2U_INT		; GET INT VECTOR
	LD	(Z280_IVT+$36),HL	; SET IT
#ENDIF
;
Z2U_PREINIT3:
	XOR	A			; SIGNAL SUCCESS
	RET				; AND RETURN
;
; Z280 UART INITIALIZATION ROUTINE
;
Z2U_INITUNIT:
	CALL	Z2U_DETECT		; DETERMINE Z280 UART TYPE
	LD	(IY+1),A		; SAVE IN CONFIG TABLE
	OR	A			; SET FLAGS
	RET	Z			; ABORT IF NOTHING THERE

	; UPDATE WORKING Z280 UART DEVICE NUM
	LD	HL,Z2U_DEV		; POINT TO CURRENT UART DEVICE NUM
	LD	A,(HL)			; PUT IN ACCUM
	INC	(HL)			; INCREMENT IT (FOR NEXT LOOP)
	LD	(IY),A			; UPDATE UNIT NUM
;
	; IT IS EASY TO SPECIFY A SERIAL CONFIG THAT CANNOT BE IMPLEMENTED
	; DUE TO THE CONSTRAINTS OF THE Z280 UART.  HERE WE FORCE A GENERIC
	; FAILSAFE CONFIG ONTO THE CHANNEL.  IF THE SUBSEQUENT "REAL"
	; CONFIG FAILS, AT LEAST THE CHIP WILL BE ABLE TO SPIT DATA OUT
	; AT A RATIONAL BAUD/DATA/PARITY/STOP CONFIG.
	CALL	Z2U_INITSAFE
;
	; SET DEFAULT CONFIG
	LD	DE,-1			; LEAVE CONFIG ALONE
	; CALL INITDEV TO IMPLEMENT CONFIG, BUT NOTE THAT WE CALL
	; THE INITDEVX ENTRY POINT THAT DOES NOT ENABLE/DISABLE INTS!
	JP	Z2U_INITDEVX		; IMPLEMENT IT AND RETURN
;
;
;
Z2U_INIT:
	LD	B,Z2U_CFGCNT		; COUNT OF POSSIBLE Z2U UNITS
	LD	IY,Z2U_CFG		; POINT TO START OF CFG TABLE
Z2U_INIT1:
	PUSH	BC			; SAVE LOOP CONTROL
	LD	A,(IY+1)		; GET Z2U TYPE
	OR	A			; SET FLAGS
	CALL	NZ,Z2U_PRTCFG		; PRINT IF NOT ZERO
	POP	BC			; RESTORE LOOP CONTROL
	LD	DE,Z2U_CFGSIZ		; SIZE OF CFG ENTRY
	ADD	IY,DE			; BUMP IY TO NEXT ENTRY
	DJNZ	Z2U_INIT1		; LOOP TILL DONE
;
	XOR	A			; SIGNAL SUCCESS
	RET				; DONE
;
; RECEIVE INTERRUPT HANDLER
;
#IF (INTMODE == 3)
;
; INT ENTRY POINT
;
Z2U_INT:
	; DISCARD REASON CODE
	INC	SP
	INC	SP
;
	; SAVE REGISTERS
	PUSH	AF
	PUSH	BC
	PUSH	DE
	PUSH	HL
;
	; START BY SELECTING I/O PAGE $FE (SAVING PREVIOUS VALUE)
	LD	C,Z280_IOPR		; REG C POINTS TO I/O PAGE REGISTER
	LDCTL	HL,(C)			; GET CURRENT I/O PAGE
	PUSH	HL			; SAVE IT
	LD	L,$FE			; NEW COUNTER/TIMER I/O PAGE
	LDCTL	(C),HL
;
	; CHECK TO SEE IF SOMETHING IS ACTUALLY THERE
	IN	A,(Z280_UARTRCTL)	; GET STATUS
	AND	$10			; ISOLATE CHAR AVAILABLE BIT
	JR	Z,Z2U_INTRCV4		; IF NOT, BAIL OUT
;
Z2U_INTRCV1:
	; RECEIVE CHARACTER INTO BUFFER
	IN	A,(Z280_UARTRECV)	; GET A BYTE
	LD	B,A			; SAVE BYTE READ
	LD	HL,Z2U0_RCVBUF		; SET HL TO START OF BUFFER STRUCT
	LD	A,(HL)			; GET COUNT
	CP	Z2U_BUFSZ		; COMPARE TO BUFFER SIZE
	JR	Z,Z2U_INTRCV4		; BAIL OUT IF BUFFER FULL, RCV BYTE DISCARDED
	INC	A			; INCREMENT THE COUNT
	LD	(HL),A			; AND SAVE IT
#IF (Z2U0HFC)
	CP	Z2U_BUFSZ / 2		; BUFFER GETTING FULL?
	JR	NZ,Z2U_INTRCV2		; IF NOT, BYPASS CLEARING RTS
	PUSH	HL			; SAVE HL
	LD	HL,0			; TC VALUE 0 CAUSES HIGH OUTPUT (RTS DEASSERTED)
	LD	C,Z280_CT2_TC		; SET C/T 2
	OUTW	(C),HL
	POP	HL			; RESTORE HL
#ENDIF
Z2U_INTRCV2:
	INC	HL			; HL NOW HAS ADR OF HEAD PTR
	PUSH	HL			; SAVE ADR OF HEAD PTR
	LD	HL,(HL)			; DEREFERENCE HL, 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	Z2U_BUFSZ+4		; SUBTRACT SIZE OF BUFFER AND POINTER
	CP	E			; IF EQUAL TO START, HEAD PTR IS PAST BUF END
	JR	NZ,Z2U_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
Z2U_INTRCV3:
	EX	DE,HL			; DE := HEAD PTR VAL, HL := ADR OF HEAD PTR
	LD	(HL),DE			; SAVE UPDATED HEAD PTR

	; CHECK FOR MORE PENDING...
	IN	A,(Z280_UARTRCTL)	; GET STATUS
	AND	$10			; ISOLATE CHAR AVAILABLE BIT
	JR	NZ,Z2U_INTRCV1
;
Z2U_INTRCV4:
	; RESTORE I/O PAGE
	LD	C,Z280_IOPR		; REG C POINTS TO I/O PAGE REGISTER
	POP	HL			; RECOVER ORIGINAL I/O PAGE
	LDCTL	(C),HL
;
	; RESTORE REGISTERS
	POP	HL
	POP	DE
	POP	BC
	POP	AF
;
	RETIL
#ENDIF
;
; DRIVER FUNCTION TABLE
;
Z2U_FNTBL:
	.DW	Z2U_IN
	.DW	Z2U_OUT
	.DW	Z2U_IST
	.DW	Z2U_OST
	.DW	Z2U_INITDEV
	.DW	Z2U_QUERY
	.DW	Z2U_DEVICE
#IF (($ - Z2U_FNTBL) != (CIO_FNCNT * 2))
	.ECHO	"*** INVALID Z2U FUNCTION TABLE ***\n"
#ENDIF
;
#IF (INTMODE < 3)
;
Z2U_IN:
	CALL	Z2U_IST			; CHECK FOR CHAR READY
	JR	Z,Z2U_IN		; IF NOT, LOOP
;
	; START BY SELECTING I/O PAGE $FE
	LD	L,$FE			; Z280 UART REGISTERS AT I/O PAGE $FE
	LD	C,Z280_IOPR		; REG C POINTS TO I/O PAGE REGISTER
	LDCTL	(C),HL
;
	; GET CHAR
	IN	A,(Z280_UARTRECV)	; GET A BYTE
	LD	E,A			; PUT IN E FOR RETURN
;	
	; RESTORE I/O PAGE TO $00
	LD	L,$00			; NORMAL I/O REG IS $00
	LD	C,Z280_IOPR		; REG C POINTS TO I/O PAGE REGISTER
	LDCTL	(C),HL
;
	XOR	A			; SIGNAL SUCCESS
	RET				; DONE
;
#ELSE
;
Z2U_IN:
	CALL	Z2U_IST			; SEE IF CHAR AVAILABLE
	JR	Z,Z2U_IN		; LOOP UNTIL SO
	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
;
#IF (Z2U0HFC)
	CP	Z2U_BUFSZ / 4		; BUFFER LOW THRESHOLD
	JR	NZ,Z2U_IN1		; IF NOT, BYPASS SETTING RTS
;
	; ASSERT RTS
	PUSH	HL
	LD	C,Z280_IOPR		; REG C POINTS TO I/O PAGE REGISTER
	LDCTL	HL,(C)			; GET CURRENT I/O PAGE
	PUSH	HL			; SAVE IT
	LD	L,$FE			; NEW COUNTER/TIMER I/O PAGE
	LDCTL	(C),HL
	LD	HL,1			; TC VALUE ~0 CAUSES LOW OUTPUT (RTS ASSERTED)
	LD	C,Z280_CT2_TC		; SET C/T 2
	OUTW	(C),HL
	LD	C,Z280_IOPR		; REG C POINTS TO I/O PAGE REGISTER
	POP	HL			; RECOVER ORIGINAL I/O PAGE
	LDCTL	(C),HL
	POP	HL
#ENDIF
;
Z2U_IN1:
	INC	HL			; HL := ADR OF TAIL PTR
	INC	HL			; "
	INC	HL			; "
	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	Z2U_BUFSZ+2		; SUBTRACT SIZE OF BUFFER AND POINTER
	CP	E			; IF EQUAL TO START, TAIL PTR IS PAST BUF END
	JR	NZ,Z2U_IN2		; 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
Z2U_IN2:
	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
;
;
;
Z2U_OUT:
	CALL	Z2U_OST			; CHECK IF OUTPUT REGISTER READY
	JR	Z,Z2U_OUT		; LOOP UNTIL SO
;
	; START BY SELECTING I/O PAGE $FE
	LD	L,$FE			; Z280 UART REGISTERS AT I/O PAGE $FE
	LD	C,Z280_IOPR		; REG C POINTS TO I/O PAGE REGISTER
	LDCTL	(C),HL
;
	; WRITE CHAR
	LD	A,E			; BYTE TO A
	OUT	(Z280_UARTXMIT),A	; SEND IT
;	
	; RESTORE I/O PAGE TO $00
	LD	L,$00			; NORMAL I/O REG IS $00
	LD	C,Z280_IOPR		; REG C POINTS TO I/O PAGE REGISTER
	LDCTL	(C),HL
;	
	XOR	A			; SIGNAL SUCCESS
	RET				; DONE
;
;
;
#IF (INTMODE < 3)
;
Z2U_IST:
	; START BY SELECTING I/O PAGE $FE
	LD	L,$FE			; Z280 UART REGISTERS AT I/O PAGE $FE
	LD	C,Z280_IOPR		; REG C POINTS TO I/O PAGE REGISTER
	LDCTL	(C),HL
;
	; GET RECEIVE STATUS
	IN	A,(Z280_UARTRCTL)	; GET STATUS
	AND	$10			; ISOLATE CHAR AVAILABLE BIT
;	
	; RESTORE I/O PAGE TO $00
	LD	L,$00			; NORMAL I/O REG IS $00
	LD	C,Z280_IOPR		; REG C POINTS TO I/O PAGE REGISTER
	LDCTL	(C),HL
;
	OR	A			; SET FLAGS
	JP	Z,CIO_IDLE		; NOT READY, RETURN VIA IDLE PROCESSING
;	
	RET
;
#ELSE
;
Z2U_IST:
	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				; DONE
;
#ENDIF
;
;
;
Z2U_OST:
;
	; START BY SELECTING I/O PAGE $FE
	LD	L,$FE			; Z280 UART REGISTERS AT I/O PAGE $FE
	LD	C,Z280_IOPR		; REG C POINTS TO I/O PAGE REGISTER
	LDCTL	(C),HL
;
	; GET TRANSMIT STATUS
	IN	A,(Z280_UARTXCTL)	; GET STATUS
;
	; RESTORE I/O PAGE TO $00
	LD	L,$00			; NORMAL I/O REG IS $00
	LD	C,Z280_IOPR		; REG C POINTS TO I/O PAGE REGISTER
	LDCTL	(C),HL
;
	; CHECK FOR CHAR AVAILABLE
	AND	$01			; ISOLATE CHAR AVAILABLE BIT
	JP	Z,CIO_IDLE		; NOT READY, RETURN VIA IDLE PROCESSING
	RET				; DONE
;
; AT INITIALIZATION THE SETUP PARAMETER WORD IS TRANSLATED TO THE FORMAT
; REQUIRED BY THE Z2U AND STORED IN A PORT/REGISTER INITIALIZATION TABLE,
; WHICH IS THEN LOADED INTO THE Z2U.
;
; 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.
;
Z2U_INITDEV:
	HB_DI				; DISABLE INTS
	CALL	Z2U_INITDEVX		; DO THE WORK
	HB_EI				; INTS BACK ON
	RET				; DONE
;
Z2U_INITSAFE:
	LD	A,%11000010		; 8N0, DIV 16, NO C/T
	LD	(Z2U_CFGREG),A		; SAVE IT
	LD	HL,1			; C/T DIV 1
	JR	Z2U_INITDEV8		; DO IT
;
Z2U_INITDEVX:
	; TEST FOR -1 WHICH MEANS USE CURRENT CONFIG (JUST REINIT)
	LD	A,D			; TEST DE FOR
	AND	E			; ... VALUE OF -1
	INC	A			; ... SO Z SET IF -1
	JR	NZ,Z2U_INITDEV1		; IF DE == -1, REINIT CURRENT CONFIG
;
	; LOAD EXISTING CONFIG TO REINIT
	LD	E,(IY+4)		; LOW BYTE
	LD	D,(IY+5)		; HIGH BYTE	
;
Z2U_INITDEV1:
	LD	(Z2U_NEWCFG),DE		; SAVE NEW CONFIG
;
; HACK FOR TESTING!!!
;
#IF FALSE
	;LD	A,%11000000		; 8N0, DIV 1, NO C/T
	LD	A,%11000010		; 8N0, DIV 16, NO C/T
	;LD	A,%11000100		; 8N0, DIV 32, NO C/T
	;LD	A,%11000110		; 8N0, DIV 64, NO C/T
	LD	(Z2U_CFGREG),A		; SAVE UART CONFIG VALUE
	;LD	HL,1			; 24MHZ / 8 / 1
	LD	HL,2			; 24MHZ / 8 / 2
	;LD	HL,3			; 24MHZ / 8 / 5
	;LD	HL,15			; 24MHZ / 8 / 15
	;LD	HL,26			; 24MHZ / 8 / 26 = 115384 BAUD (~115200)
	;LD	HL,52			; 24MHZ / 8 / 52 = 57692 BAUD (~57600)
	JP	Z2U_INITDEV8		; SKIP AHEAD TO IMPLMENT IT
#ENDIF
;
	LD	A,D			; HIWORD OF CONFIG
	AND	$1F			; ISOLATE BAUD RATE
	PUSH	AF
;
	LD	DE,Z2UOSC >> 16		; BAUD OSC HI WORD
	LD	HL,Z2UOSC & $FFFF	; BAUD OSC LO WORD
	LD	C,75			; BAUD RATE ENCODE CONSTANT
	CALL	ENCODE			; C = ENCODED OSC
	POP	DE			; D = UART OSC
	JP	NZ,Z2U_INITFAIL		; HANDLE ENCODE FAILURE
	LD	A,C			; TO A
	SUB	D			; DIV W/ SUB OF SQUARES
	; REG A NOW HAS ENCODED BAUD RATE DIVISOR
;
	PUSH	AF			; SAVE IT
	AND	$0F			; ISOLATE 2'S POWER
;
	; Z280 UART CAN USE 16, 32, OR 64 AS BAUD RATE DIVISOR
	; SET E TO IMPLEMENT WHAT WE CAN
	LD	E,%11000000		; 8N0, DIV 1, NO C/T
	CP	4			; DIV 16 POSSIBLE?
	JR	C,Z2U_INITDEV2		; IF NOT, SKIP AHEAD
	LD	E,%11000010		; 8N0, DIV 16, NO C/T
	SUB	4			; REFLECT IN TGT DIVISOR
	CP	1			; DIV 32 POSSIBLE?
	JR	C,Z2U_INITDEV2		; IF NOT, SKIP AHEAD
	LD	E,%11000100		; 8N0, DIV 32, NO C/T
	DEC	A			; REFLECT IN TGT DIVISOR
	CP	1			; DIV 64 POSSIBLE?
	JR	C,Z2U_INITDEV2		; IF NOT, SKIP AHEAD
	LD	E,%11000110		; 8N0, DIV 64, NO C/T
	DEC	A
;
Z2U_INITDEV2:
	LD	D,A			; 2'S POWER TO D
	POP	AF			; RECOVER ORIGINAL VALUE
	AND	$F0			; MASK OFF ORIG 2'S POWER
	OR	D			; COMBINE
	;CALL	PRTHEXBYTE		; *DEBUG*
	PUSH	AF			; RESAVE IT
	LD	A,E			; GET Z280 UART CONFIG REG VAL
	LD	(Z2U_CFGREG),A		; SAVE CONFIG REG VALUE FOR LATER
	POP	AF			; RECOVER REMAINING ENCODED DIVISOR
	LD	L,A			; INTO L
	LD	H,0			; H MUST BE ZERO
	LD	DE,1			; RATIO, SO NO CONSTANT
	CALL	DECODE			; DECODE INTO DE:HL
	JP	NZ,Z2U_INITFAIL		; HANDLE FAILURE
;
	; SAVE CONFIG PERMANENTLY NOW
	LD	DE,(Z2U_NEWCFG)		; GET NEW CONFIG BACK
	LD	(IY+4),E		; SAVE LOW WORD
	LD	(IY+5),D		; SAVE HI WORD
;
Z2U_INITDEV8:
	; START BY SELECTING I/O PAGE $FE
	PUSH	HL			; SAVE HL
	LD	L,$FE			; Z280 UART REGISTERS AT I/O PAGE $FE
	LD	C,Z280_IOPR		; REG C POINTS TO I/O PAGE REGISTER
	LDCTL	(C),HL
	POP	HL			; RESTORE HL
;
	DEC	HL			; ADJUST FOR T/C
	LD	A,H			; TEST FOR
	OR	L			; ... ZERO
	JR	Z,Z2U_INITDEV9		; IF ZERO, SKIP C/T
;
	; PROGRAM C/T 1
#IF	Z2UOSCEXT
	LD	A,%10001100		; CONFIG: C, RE, COUNTER
#ELSE
	LD	A,%10001000		; CONFIG: C, RE, COUNTER
#ENDIF
	OUT	(Z280_CT1_CFG),A	; SET C/T 1
	LD	C,Z280_CT1_TC		; SET C/T 1 FROM HL
	OUTW	(C),HL
	LD	C,Z280_CT1_CT		; SET C/T 1 FROM HL
	OUTW	(C),HL
	LD	A,%11100000		; CMD: EN, GT, TG
	OUT	(Z280_CT1_CMDST),A	; SET C/T 1
;
	; MODIFY CFG REG VALUE TO USE C/T
	LD	A,(Z2U_CFGREG)		; CONFIG VALUE
	SET	3,A			; SET C/T USAGE BIT
	LD	(Z2U_CFGREG),A		; SAVE IT
;
Z2U_INITDEV9:
	; PROGRAM THE UART
	LD	A,(Z2U_CFGREG)		; CONFIG VALUE
	OUT	(Z280_UARTCFG),A	; SET CONFIG REGISTER
	LD	A,%10000000		; ENABLE, NO INTS, 1 STOP BITS
	OUT	(Z280_UARTXCTL),A	; SET XMIT CTL REGISTER
#IF (INTMODE == 3)
	LD	A,%11000000		; ENABLE W/ RCV INTS
#ELSE
	LD	A,%10000000		; ENABLE, NO RCV INTS
#ENDIF
	OUT	(Z280_UARTRCTL),A	; SET RCV CTL REGISTER
;
#IF (Z2U0HFC)
	; SETUP C/T 2 FOR FLOW CONTROL
	LD	A,%00001000		; CONFIG: TIMER
	OUT	(Z280_CT2_CFG),A	; SET C/T 2 CONFIG
	LD	HL,1			; TC VALUE ~0 CAUSES LOW OUTPUT (RTS ASSERTED)
	LD	C,Z280_CT2_TC		; SET C/T 2
	OUTW	(C),HL
	LD	A,%00000000		; CMD: EN, GT
	OUT	(Z280_CT2_CMDST),A	; SET C/T 2
#ENDIF
;
	LD	L,$00			; NORMAL I/O REG IS $00
	LD	C,Z280_IOPR		; REG C POINTS TO I/O PAGE REGISTER
	LDCTL	(C),HL
;
#IF (INTMODE == 3)
;
	; 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
;
#ENDIF
;
	; RETURN SUCCESS
	XOR	A			; SIGNAL SUCCESS
	RET				; DONE
;
Z2U_INITFAIL:
	OR	$FF			; SIGNAL ERROR
	RET				; AND DONE
;
;
;
Z2U_QUERY:
	LD	E,(IY+4)		; FIRST CONFIG BYTE TO E
	LD	D,(IY+5)		; SECOND CONFIG BYTE TO D
	XOR	A			; SIGNAL SUCCESS
	RET				; DONE
;
;
;
Z2U_DEVICE:
	LD	D,CIODEV_Z2U		; 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+3)		; L := BASE I/O ADDRESS
	XOR	A			; SIGNAL SUCCESS
	RET
;
; Z280 UART DETECTION ROUTINE
; ALWAYS PRESENT, JUST SAY SO.
;
Z2U_DETECT:
	LD	A,Z2U_PRESENT		; PRESENT
	RET
;
;
;
Z2U_PRTCFG:
	; ANNOUNCE PORT
	CALL	NEWLINE			; FORMATTING
	PRTS("Z2U$")			; FORMATTING
	LD	A,(IY)			; DEVICE NUM
	CALL	PRTDECB			; PRINT DEVICE NUM
	PRTS(": IO=0x$")		; FORMATTING
	LD	A,(IY+3)		; GET BASE PORT
	CALL	PRTHEXBYTE		; PRINT BASE PORT
;
	; ALL DONE IF NO Z2U WAS DETECTED
	LD	A,(IY+1)		; GET Z2U 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
	CALL	PS_PRTSC0		; PRINT CONFIG
;
	XOR	A
	RET
;
; WORKING VARIABLES
;
Z2U_DEV		.DB	0		; DEVICE NUM USED DURING INIT
Z2U_CFGREG	.DB	0		; VALUE TO PROGRAM CFG REG
Z2U_NEWCFG	.DW	0		; TEMP STORE FOR NEW CFG
;
#IF (INTMODE < 3)
;
Z2U0_RCVBUF	.EQU	0
;
#ELSE
;
; RECEIVE BUFFERS
;
Z2U0_RCVBUF:
Z2U0_BUFCNT	.DB	0		; CHARACTERS IN RING BUFFER
Z2U0_HD		.DW	Z2U0_BUF	; BUFFER HEAD POINTER
Z2U0_TL		.DW	Z2U0_BUF	; BUFFER TAIL POINTER
Z2U0_BUF	.FILL	Z2U_BUFSZ,0	; RECEIVE RING BUFFER
Z2U0_BUFEND	.EQU	$		; END OF BUFFER
Z2U0_BUFSZ	.EQU	$ - Z2U0_BUF	; SIZE OF RING BUFFER
;
#ENDIF
;
; Z2U PORT TABLE
;
Z2U_CFG:
;
Z2U0_CFG:
	; Z2U CONFIG
	.DB	0			; DEVICE NUMBER (SET DURING INIT)
	.DB	0			; Z280 UART TYPE (SET DURING INIT)
	.DB	0			; MODULE ID
	.DB	Z2U0BASE		; BASE PORT
	.DW	Z2U0CFG			; LINE CONFIGURATION
	.DW	Z2U0_RCVBUF		; POINTER TO RCV BUFFER STRUCT
;
;
	DEVECHO	"Z2U: IO="
	DEVECHO	Z2U0BASE
#IF (INTMODE == 3)
	DEVECHO	", INTERRUPTS ENABLED"
#ENDIF
	DEVECHO	"\n"

;
Z2U_CFGSIZ	.EQU	$ - Z2U_CFG	; SIZE OF ONE CFG TABLE ENTRY
;
Z2U_CFGCNT	.EQU	($ - Z2U_CFG) / Z2U_CFGSIZ
