;==================================================================================================
; Serial InterFace TEST - receive screen
;==================================================================================================
; uses 115200bps, two stop bits, no parity, HW data flow control
; (uncomment parts of code for IR mode or SW flow control)

		cpu	z80undoc

; baseports	131	100xxx11b	- port 131 is default
;		99	011xxx11b
;		195	110xxx11b
;		227	111xxx11b

SIF_PORT	equ	131

		org	32768

START		di				; store registers needed for return to BASIC
		push	iy
		exx
		push	hl
		exx

		ld	a,56			; default colors
		call	CLS_COLOR		; clear screen

		call	SIF_INIT		; set up 16C650
		jp	SIF_RECEIVE		; receive data and wait for key SPACE

; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
; return to BASIC

RETURN_TO_BASIC	ld	a,7			; white BORDER
		out	(254),a

		exx
		pop	hl
		exx
		pop	iy
		ei
		ret

;==================================================================================================

SIF_RECEIVE	ld	hl,16384		; buffer address
		ld	de,6912			; length = byte counter

		ld	a,7
		call	SIMPLEBEEP

SIF_REC_LOOP

; key SPACE = exit?
		ld	a,127			; read keyboard port 32766 (b, n, m, symbol shift, space)
		in	a,(254)
		rra				; bit 0 in carry (test key space)
		jr	nc,RETURN_TO_BASIC	; NC = space is pressed

; key R = RESET address to the start of screen
		ld	a,251			; read keyboard port 64510 (t, r, e, w, q)
		in	a,(254)
		and	00000100b		; bit 3 is key R
		jr	z,SIF_RECEIVE		; Z = R is pressed

; key P = user induced delay for data flow testing
SIF_DELAY	ld	a,223			; read keyboard port 57342 (y, u, i, o, p)
		in	a,(254)
		and	00000001b
		jr	nz,SIF_READ_FIFO	; NZ = P is not pressed

		ld	a,2			; red BORDER = delayed
		out	(254),a
		jp	SIF_DELAY		; repeat until key is pressed

; data ready?
SIF_READ_FIFO	xor	a
		in	a,(SIF_PORT+20)		; read LSR
		ld	b,a
		and	10000000b		; bit 7 = "FIFO data error"
		jr	nz,SIF_READ_FIFO_2	; NZ = no error
		ld	a,3			; "FIFO data error" = purple BORDER (wrong parity?)
		out	(254),a

SIF_READ_FIFO_2	ld	a,b
		and	00000001b		; bit 0 = "Receive data ready", 0 = no data, 1 = data in FIFO
		jp	z,SIF_REC_LOOP		; nz = no data

		ld	a,4			; green BORDER = reading data
		out	(254),a

		xor	a
		in	a,(SIF_PORT)		; read byte from UART

		ld	(hl),a			; write byte in buffer
		inc	hl			; increment pointer
		dec	de			; decrement byte counter
		ld	a,e
		or	d
		jp	nz,SIF_REC_LOOP		; NZ = repeat if byte counter > 0
		jp	SIF_RECEIVE		; reset address and byte counter

;==================================================================================================
; SIF init = set registers of 16C650
;==================================================================================================

SIF_INIT	ld	a,0			; select UART 16C650 on SIF - 0 = first, 2 = second
		out	(SIF_PORT+28),a

		xor	a			; reset temporary LCR
; set parity in LCR
; 00000000b		; no parity
; 00001000b		; odd parity
; 00011000b		; even parity
; 00111000b		; force parity 0
; 00101000b		; force parity 1
		or	00000000b		; no parity

; set stop bits in LCR
; 00000000b		; 0 = 1 stop bit
; 00000100b		; 1 = 2 stop bits
		or	00000100b		; 2 stop bits

; set word length
; 00000000b		; 00 = 5 bits - if (S_BITS=6) lcr+=1; else { if (S_BITS=7) lcr+=2; else lcr+=3; }
; 00000001b		; 01 = 6 bits - if (S_BITS=6) lcr+=1; else { if (S_BITS=7) lcr+=2; else lcr+=3; }
; 00000010b		; 10 = 7 bits
; 00000011b		; 11 = 8 bits (default)
		or	00000011b		; 8 bits
		ld	(SIF_LCR),a		; store value for latter use
		out	(SIF_PORT+12),a		; LCR

		ld	a,00000001b		; FIFO enable, no interrupts, no DMA, FCR[0] = 1 polled mode operation
		out	(SIF_PORT+8),a 		; FCR

; set baudrate, citation from datasheet - Baud rate registers set are accessible when LCR[7] = 1
; 460800/115200 = 4	 0, 4
; 460800/57600 = 8	 0, 8
; 460800/38400 = 12	 0, 12
; 460800/19200 = 24	 0, 24
; 460800/9600 = 48	 0, 48
; ...
		ld	a,128			; LCR[7] = 1 - enable access to the registers DLL and DLM
		out	(SIF_PORT+12),a		; LCR
		ld	a,4			; lower byte, "LSB of Divisor Latch"
		out	(SIF_PORT),a		; DLL register
		ld	a,0			; higher byte, "MSB of Divisor Latch"
		out	(SIF_PORT+4),a		; DLM register

; set automatic data flow control - specific for 16C650 - already set?
; from datasheet - EFR, Xon1, Xon2, Xoff1, Xoff2 are accessible only when the LCR is set to 0xBF
		ld	a,10111111b		; 191 (0xBF) - enable access to  Enhanced Registers (EFR, XON1, XON2, XOFF1, XOFF2)
		out	(SIF_PORT+12),a		; LCR

; hardware flow control with signals CTS RTS
		ld	a,11010000b		; EFR[7] = 1 enable auto CTS, EFR[6] = 1 enable auto RTS, EFR[4] must be active
		out	(SIF_PORT+8),a		; EFR

; switch back to general register set
SIF_INIT_FLOW_2	ld	a,(SIF_LCR)		; restore value in LCR register (switch back to compatible registers)
		out	(SIF_PORT+12),a		; LCR

; channel 1 (default) or channel 2 (IR) - channel is specific for SIF, IR mode for all 16C650 interfaces
; 		ld	a,01001000b		; MCR[7] = 1 enable IR mode, MCR[3] = 1 will set signal OUT2 in log 0 (output from UART)
		ld	a,00000010b		; MCR[1] is inverted RTS output
		out	(SIF_PORT+16),a		; MCR

; finally - disable all interrupts, SIFTERM is not using it (maybe it is not best decision)
SIF_INIT_IERVAL	ld	a,00000000b		; no interrupts, we are using polled mode operation
		out	(SIF_PORT+4),a		; IER
; 		in	a,(SIF_PORT+20)		; clear interrupts = read LSR
		ret

SIF_LCR		db	0			; here will be assembled Line Control Register

;--------------------------------------------------------------------------------------------------
; clear screen

CLS_COLOR	ld	(CLS_2+1),a		; 13T	store colors for future use

CLS		ld 	(CLS_SP_CMN+1),sp	; 20T - store stack pointer
		ld	sp,23296		; 10T - addr. of VRAM end, clearing backwards
CLS_2		ld	a,56			; 7T  - default color combination
		ld	b,24			; 7T  - 24 lines (color attributes)
		ld	h,a			; 4T  - copy color from A to H and L
		ld	l,a			; 4T
CLS_0		push	hl			; 11T - repeat 16x push = it stores 32 bytes
		push	hl			; all attr. will take (16*10T)*24 = 3840T
		push	hl
		push	hl
		push	hl
		push	hl
		push	hl
		push	hl
		push	hl
		push	hl
		push	hl
		push	hl
		push	hl
		push	hl
		push	hl
		push	hl
		djnz	CLS_0			; 307T - 23*13T, per line, 8T last one
		ld	h,b			; 4T  - now B==0, let H=0, L=0 too
		ld	l,b			; 4T
		ld	b,192			; 7T  - number of pixel lines
CLS_1		push	hl			; 11T - repeat 16x push = it stores 32 bytes
		push	hl			; all will take (16*11)*192 = 33792T
		push	hl
		push	hl
		push	hl
		push	hl
		push	hl
		push	hl
		push	hl
		push	hl
		push	hl
		push	hl
		push	hl
		push	hl
		push	hl
		push	hl
		djnz	CLS_1			; 191*13+8 = 2491T
CLS_SP_CMN	ld	sp,0			; 10T restore stack pointer
		ret

;--------------------------------------------------------------------------------------------------
; wait for key

; PAUSE0		xor	a
; 		in	a,(254)			; read all keys
; 		cpl				; invert it, pressed key is 0
; 		and	00011111b		; leave only bits relevant for keys
; 		jr	z,PAUSE0		; Z = no key is pressed => repeat
; 		ret				; something pressed, return

; wait if any key is pressed
PAUSENK		xor	a
		in	a,(254)			; read all keys
		cpl				; invert it, pressed key is 0
		and	00011111b		; leave only bits relevant for keys
		jr	nz,PAUSENK		; NZ = something is pressed => repeat
		ret				; nothing pressed, return

;--------------------------------------------------------------------------------------------------

SIMPLEBEEP	push	bc		; store BC
		ld	b,128		; counter, number of pulses
SIMPLEBEEP_2	out	(254),a
		xor	0011000b	; toggle only speaker bits
		push	bc		; store BC for inner loop
		ld	b,60		; 60 times repeat = little delay
SIMPLEBEEP_1	djnz	SIMPLEBEEP_1
	        pop	bc		; restore BC - inner loop
		djnz	SIMPLEBEEP_2
		pop	bc		; restore BC
		ret