;==================================================================================================
; RS232 - transmitting through AY-3-8912 with waiting for CTS from receiving side
;
; 57600bps (17,3611μs)	61.57813T na ZX128k, 61T bude trvat 17.19811μs, chyba -0.9% (58146bps)
;			60.76389T na ZX48k,  61T bude trvat 17.42857μs, chyba +0,4% (57377bps)
;==================================================================================================
;
;	AY I/O	ZX name	dir.	better name
;
;	A2	CTS	out	RTS
;	A3	RxD	out	TxD	->
;	A6	DTR	in	CTS	<-
;	A7	TxD	in	RxD

		cpu	z80undoc
		org	32768			; musí běžet v rychlé RAM

START		di				; 4T	nesmí být zpomalováno a přerušováno
;  		ld	a,7			; DEBUG
;  		out	(254),a			; DEBUG
		ld	hl,DATA			; 10T	adresa dat
		ld	de,DATA_LENGTH		; 10T	počet bytů k přenesení

TRANS_SET_AY_IN	exx				; 4T	přepni na sekundární sadu

		ld	bc,65533		; 10T	BC = 65533 (11111111 11111101)
		ld	a,7			; 7T	zvol registr 7 v AY
		out	(c),a			; 12T	65533,7

		ld	a,b			; 4T	A = 255, vypni zvuk a nastav I/O port jako výstup (bit 6 v log. 1)
		ld	b,191		; 	; 7T	BC = 49149 (10111111 11111101)
		out	(c),a			; 12T	49149,255

		ld	b,a			; 4T	BC = 65533
		ld	a,14			; 7T	zvol registr 14 v AY
		out	(c),a			; 12T	65533,14

		ld	a,b			; 4T	A = 255
		ld	b,191			; 7T	BC = 45149
		out	(c),a			; 12T	49149,255 = zapiš 255 a nastav pullupy na H, teď je možné port i číst

		exx				; 4T	přepni na primární sadu

; nastavení portu AY trvá 4+10+7+12+4+7+12+4+7+12+4+7+12+4+4 = 110T

WAIT_FOR_CTS	exx				; 4T	přepni na sekundární sadu
		ld	hl,64			; 10T	H = 0 počítadlo, L = 01000000, maska pro bit 6, vstup CTS
		ld	b,255			; 7T	BC = 65533, to je port, který lze číst, ne 49149

; připraven číst I/O port

WAIT_FOR_CTS_L	in	a,(c)			; 12T	čti AY I/O port 14 z 65533, čekáme na CTS
		and	l			; 4T	ponech jen bit 6
		jp	z,TRANSIEVE57600	; 10T

; když je CTS v 0 4+10+7 + 12+4+10 = 47T a skok

		dec	h			; 4T	sniž počítadlo do 256
		jp	nz, WAIT_FOR_CTS_L	; 10T

; čtení portu probíhá 256x 12+4+10+4+10 = 40T, pak se testuje mezerník

		ld	a,127			; 7T	port 32766 (klávesy B, N, M, SSHIFT, SPACE)
		in	a,(254)			; 11T	+ zpomalení, protože pomalý port?
		rra				; 4T	rotuj bit mezerníku vpravo skrz carry
		jp	nc,END			; 10T	NC = mezerník stisknutý (0 v bitu 0)
		jp	WAIT_FOR_CTS_L		; 10T

; každý 256. cyklus 12+4+10+4+10+7+11+4+10+10 = 82T při občasném testu mezerníku

TRANSIEVE57600	ld	b,191			; 7T	BC = 49149, bude se zapisovat do I/O portu
		ld	h,8			; 7T	H poslouží jako počítadlo 8 bitů
		exx				; 4T	přepni na primární sadu
		ld	a,(hl)			; 7T	data k odeslání do A
		exx				; 4T	přepni na sekundární sadu
		ld	l,a			; 4T	zkopíruj data z A do L
		rrc	l			; 8T	4x rotuj data vpravo (LSB na pozici bitu 3)
		rrc	l			; 8T	dvě rotace před outem, aby vyšly takty
		ld	a, 11110111b		; 7T	maska

; příprava	7+7+4+7+4+4+8+8+7 = 56T

; start bit
		out	(c),a			; 12T	zapiš na port, začíná start bit
		rrc	l			; 8T	a dvě rotace ze 4 po outu
		rrc	l			; 8T
; datové bity
TRANSIEV_LOOP	ld	a,0			; 7T	zpoždění
		ld	a,0			; 7T	zpoždění
		rrc	l			; 8T	další bit na pozici bitu 3
		ld	a,11110111b		; 7T	připrav masku
		or	l			; 4T	přidej masku

; od začátku start bitu	12+8+8+7+7+8+7+4 = 61T
; od minulého bitu	12+4+12+7+7+8+7+4 = 61T

		out	(c),a			; 12T	zapiš na port
		dec	h			; 4T	počítadlo bitů
		jr	nz,TRANSIEV_LOOP	; 12/7T	opakuj
		ld	a,(ix+0)		; 19T	zpoždění
		nop				; 4T	zpoždění
		nop				; 4T	zpoždění
		ld	a,11111111b		; 7T	log. 1 do bitu 3 pro stop bit
		exx				; 4T	přepni na primární sadu (BC, DE, HL)

; od posledního outu v cyklu 12+4+7+19+4+4+7+4 = 61T, trvání MSB

; stop bit
		out	(c),a			; 12T	zapiš na port
		inc	hl			; 6T	další adresa
		dec	de			; 6T	o byte míň
		ld	a,d			; 4T 	testuj, jestli je počet na nule
		or	e			; 4T
		jp	nz,WAIT_FOR_CTS		; 10T	opakuj, dokud nejsou přeneseny všechny byty

; od outu do skoku 12+6+6+4+4+10=42

; 		ld	a,6			; 7T	DEBUG
; 		out	(254),a			; 11T	DEBUG
		ei				; 4T	povol přerušení
		ret				; 10T	běžné ukončení přenosu

; od outu 12+6+6+4+4+10 = 42
; při opakování bytu se prodlouží o trvání detekce stavu CTS a další režii na začátku kódu
; celkem při opakování s CTS trvale aktivním 42+47+56=145T víc než dva stop bity, ale ne o mnoho (145-122 = 23T)

END		exx				; 4T	přepni na primární sadu
		ei				; 4T	povol přerušení
; 		ld	a,2			; 7T	DEBUG
; 		out	(254),a			; 11T	DEBUG
		ret				; 10T	ukončení přenosu při stisku mezerníku nenastane-li CTS

DATA		db	"Hello RS232 world! ZX Spectrum 128 is sending data."
		db	13,10			; CR, LF
; 		db	"abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ 0123456789"
; 		db	13,10			; CR, LF

DATA_LENGTH	equ	$ - DATA

;			naměřeno	má být	 	(bez DEBUG barvy okraje)
; bit log. 0		16.40μs		17.361μs	(ideální čas)
; bit log. 1		18.04μs		17.361μs	(ideální čas)
; stop bit mezi byty	41.71μs		40.880μs	(výpočtem ze 145T)
;
; šedá +2 má tendenci generovat log. 1 delší