;==============================================================================
;  CYGNUS KEMPSTON MOUSE TESTER
;==============================================================================
;
; This is very simple program for Kempston Mouse interface test. You can test
; any Kempston Mouse interface including Velesoft's interface with wheel support
; and with slave/master mode for two mouses connection.
;
; Velesoft's documentation
; http://velesoft.speccy.cz/kmturbo-cz.htm
; http://www.worldofspectrum.org/forums/showpost.php?p=265567&postcount=58

; DEBUGMODE

		cpu	Z80undoc
		org	32768

KMT_START	di				; disable interrupt
		push	ix			; and save all registers important for
		push	iy			; Basic interpretter
		exx
		push	ix
		push	iy
		push	hl
		exx

		ld	a,7			; paper 0, ink 7, bright 0
		ld	(CLS_COL),a
		ld	hl,FONT
		ld	(PRINT_FNA),hl

		call	HW_DETECT		; first detect KMouse interface and enable it if disabled

; 	ifdef		DEBUGMODE
; 		ld	a,1
; 		ld	(HW_DETECT_KMM),a
; 		ld	(HW_DETECT_KMS),a
; 		ld	(HW_DETECT_MBVER),a
; 		ld	a,01001110b
; 		ld	(HW_DETECT_MBVAL),a
; 	endif		; DEBUGMODE

		jp	KMT_MENU		; select tester mode

KMT_QUIT	call	PAUSENK			; RETURN TO ZX BASIC
		ld	a,(HW_DETECT_INH)	; restore KMouse inhibit when detected
		or	a
		jr	z,KMT_QUIT_1
		ld	a,128			; inhibit both KMouse interfaces
		ld	bc,65247
		out	(c),a


;KMT_QUIT_1
; 	ifdef		DEBUGMODE
; 		call	CLS
; 		ld	hl,TXT_TESTM_X
; 		call	TEXTOUT
; 		call	PRINT_NL
; 		ld	a,(HW_DETECT_KMM)
; 		ld	h,0
; 		ld	l,a
; 		call	NUMOUT8B
; 		call	PRINT_NL
; 		ld	a,(HW_DETECT_KMS)
; 		ld	h,0
; 		ld	l,a
; 		call	NUMOUT8B
; 		call	PRINT_NL
; 		ld	a,(HW_DETECT_INH)
; 		ld	h,0
; 		ld	l,a
; 		call	NUMOUT8B
; 	endif		; DEBUGMODE

KMT_QUIT_1		exx				; restore saved registers
		pop	hl
		pop	iy
		pop	ix
		exx
		pop	ix
		pop	iy
		ei				; enable interrupt
		ret				; return to Basic interpretter

;==============================================================================
; HARDWARE DETECT (Velesoft's KMouse interface 2008)
;==============================================================================

HW_DETECT	xor	a			; reset all KMouse detector variables
		ld	(HW_DETECT_KMM),a	; nothing is detected
		ld	(HW_DETECT_KMS),a
		ld	(HW_DETECT_MBVER),a
		ld	(HW_DETECT_INH),a
		call	HW_DETECT_PASS		; first pass
		ld	a,(HW_DETECT_KMM)	; is detected master or slave interface?
		or	a
		jr	nz,HW_DETECT_END	; one or more KMouses detected, not inhibited
		ld	a,(HW_DETECT_KMS)
		or	a
		jr	nz,HW_DETECT_END	; one or more KMouses detected, not inhibited

		ld	bc,65247		; nothing detected, try enable both KMouse interfaces
		xor	a
		out	(c),a

		call	HW_DETECT_PASS		; second pass

		ld	a,(HW_DETECT_KMM)	; is detected master or slave interface?
		or	a
		jr	nz,HW_DETECT_INHE	; master detected - inhibit was active
		ld	a,(HW_DETECT_KMS)
		or	a
		jr	z,HW_DETECT_END		; nothing detected in second pass, KMOUSE not inhibited

HW_DETECT_INHE	ld	a,1			; KMouse detected in second pass, but not in first, remeber inhibit
		ld	(HW_DETECT_INH),a
HW_DETECT_END	ret

HW_DETECT_PASS	ei				; wait for interrupt
		halt
		di
		ld	bc,32765		; write value to #7FFD
		ld	a,16			; and now write value 16, that will compared with readed values
		out	(c),a
		ld	bc,65247		; #FEDF (KMouse master #7FFD mirror)
		in	a,(c)			; read port #FEDF
		cp	16
		ld	a,1
		jr	z,HW_DETECT_KMM_F	; Z = master interface found
		xor	a
HW_DETECT_KMM_F	ld	(HW_DETECT_KMM),a
		ld	b,62			; B = #3E
		in	a,(c)			; read port #3EDF
		cp	16
		ld	a,1
		jr	z,HW_DETECT_KMS_F	; Z = slave interface found
		xor	a
HW_DETECT_KMS_F	ld	(HW_DETECT_KMS),a
		ld	bc,31
		in	a,(c)
		bit	7,a
		ld	a,1
		jr	z,HW_DETECT_KJ_F	; Z = Kempston joystick found
		xor	a
HW_DETECT_KJ_F	ld	(HW_DETECT_KJOY),a

		ei
		halt
		di
		in	a,(219)			; test readability of port #17 mirror (special slave KMouse for MB02)
		ld	b,a			; backup
		cp	255
		jr	z,HW_DETECT_MB_NF	; port #17 mirror is not readable
		and	11000000b
		cp	11000000b
		jr	z,HW_DETECT_MB_NF	; port is readable, but don't write this walue back
		ld	a,b
		ld	(HW_DETECT_MBVAL),a

		ld	a,63
		out	(23),a
		in	a,(31)
		ld	l,a
		in	a,(219)
		cp	63
		jr	nz,HW_DETECT_MB_NF	; NZ = not found
		cp	l
		jr	z,HW_DETECT_MB_NF	; Z = not found

		ld	a,39
		out	(23),a
		in	a,(31)
		ld	l,a
		in	a,(219)
		cp	39
		jr	nz,HW_DETECT_MB_NF	; NZ = not found
		cp	l
		jr	z,HW_DETECT_MB_NF	; Z = not found

		ld	a,b			; special slave for MB02 detected
		out	(23),a
		ld	a,1
		ld	(HW_DETECT_MBVER),a	; then set as detected slave KMouse too, because it is slave
		ret

HW_DETECT_MB_NF	xor	a
		ld	(HW_DETECT_MBVER),a
		ret

HW_DETECT_KMM	db	0			; 1 = KMouse master detected
HW_DETECT_KMS	db	0			; 1 = KMouse slave detected (and Fuller joystick port)
HW_DETECT_KJOY	db	0			; 1 = Kempston Joystick detected
HW_DETECT_MBVER	db	0			; 1 = special MB02 KMouse version detected
HW_DETECT_MBVAL	db	0			; value readed from MB02 paging port

HW_DETECT_INH	db	0			; 1 = KMouse was inhibited

;==============================================================================
; MAIN TESTER MENU
;==============================================================================
; Select test or quit. Main menu will reduce when only one interface detected.

KMT_MENU	call	CLS			; clear screen by default colors
		ld	hl,TXT_MAINMENU		; and print main part of menu
		call	TEXTOUT
		ld	hl,22528		; colors under main title
		ld	bc,256*1+32
		ld	a,64+8*1+7		; paper 1, ink 7, bright 1
		call	DRAW_COLORBOX
		ld	hl,22688		; colors under title of menu
		ld	bc,256*1+18
		ld	a,64+8*0+6		; paper 0, ink 6, bright 1
		call	DRAW_COLORBOX

		ld	a,(HW_DETECT_MBVER)	; test if special MB02 slave KMouse detected
		or	a
		jr	z,KMT_MENU_NOMB		; Z = no MB02 readable port
		ld	hl,TXT_DETECT_MBS	; NZ = print additional info
		call	TEXTOUT
		ld	hl,23104		; additional info colors
		ld	bc,256*1+32
		ld	a,64+8*0+4		; paper 0, ink 4, bright 1
		call	DRAW_COLORBOX
		ld	hl,23136		; additional info colors
		ld	bc,256*1+3
		ld	a,64+8*0+7		; paper 0, ink 7, bright 1
		call	DRAW_COLORBOX
		ld	hl,23136+10		; additional info colors
		ld	bc,256*1+22
		ld	a,64+8*0+7		; paper 0, ink 7, bright 1
		call	DRAW_COLORBOX
		ld	hl,TXT_DETECT_MBS2	; "Value "
		call	TEXTOUT
		ld	a,(HW_DETECT_MBVAL)
		ld	h,0
		ld	l,a
		call	NUMOUT8B
		ld	hl,TXT_DETECT_MBS3	; " (Page "
		call	TEXTOUT
		ld	a,(HW_DETECT_MBVAL)
		and	00011111b
		ld	h,0
		ld	l,a
		call	NUMOUT8B
		ld	a,(HW_DETECT_MBVAL)
		bit	5,a			; is write enabled?
		ld	hl,TXT_DETECT_MBS4	; " WE "
		jr	nz,KMT_MENU_MBP_1
		ld	hl,TXT_DETECT_MBS5	; " RO "
KMT_MENU_MBP_1	call	TEXTOUT
		ld	a,(HW_DETECT_MBVAL)
		and	11000000b
		cp	01000000b		; SRAM?
		jr	z,KMT_MENU_MBP_2	; Z = yes
		cp	10000000b		; ROM ?
		jr	z,KMT_MENU_MBP_3	; Z = yes
		or	a			; is MB02 memory disconnected?
		jr	z,KMT_MENU_MBP_4
		jr	KMT_MENU_MBP_5

KMT_MENU_MBP_2	ld	hl,TXT_DETECT_MBS6	; MB02 SRAM
		jr	KMT_MENU_MBP_0

KMT_MENU_MBP_3	ld	hl,TXT_DETECT_MBS7	; MB02 ROM
		jr	KMT_MENU_MBP_0

KMT_MENU_MBP_4	ld	hl,TXT_DETECT_MBS8	; no MB02 memory connected
		jr	KMT_MENU_MBP_0

KMT_MENU_MBP_5	ld	hl,TXT_DETECT_MBS9	; MB02 paging port reset
KMT_MENU_MBP_0	call	TEXTOUT

KMT_MENU_NOMB	ld	hl,TXT_DETECT_LN	; prepare print position for detection status
		call	TEXTOUT

		ld	a,(HW_DETECT_KMM)	; status - test if any KMouse detected
		ld	c,a
		ld	a,(HW_DETECT_KMS)
		or	c
		jr	z,KMT_MENU_0		; Z = nothing detected, display reduced menu

		ld	a,(HW_DETECT_KMS)
		or	a
		jr	z,KMT_MENU_1		; Z = master only

		ld	a,(HW_DETECT_KMM)
		or	a
		jr	z,KMT_MENU_2		; Z = slave only

		jr	KMT_MENU_3		; both interfaces present

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

KMT_MENU_0	ld	hl,TXT_DETECT_0		; nothing detected ... maybe only old KMouse?
		call	TEXTOUT
		ld	hl,23200		; status colors
		ld	bc,256*1+30
		ld	a,64+8*0+2		; paper 0, ink 2, bright 1
		call	DRAW_COLORBOX
		jr	KMT_MENU_LOOP

KMT_MENU_1	ld	hl,TXT_DETECT_M		; master only
		call	TEXTOUT
		ld	hl,23200		; status colors
		ld	bc,256*1+30
		ld	a,64+8*0+4		; paper 0, ink 4, bright 1
		call	DRAW_COLORBOX
		jr	KMT_MENU_LOOP

KMT_MENU_2	ld	hl,TXT_DETECT_S		; slave only
		call	TEXTOUT
		ld	hl,23200		; status colors
		ld	bc,256*1+30
		ld	a,64+8*0+4		; paper 0, ink 4, bright 1
		call	DRAW_COLORBOX
		jr	KMT_MENU_LOOP

KMT_MENU_3	ld	hl,TXT_DETECT_MS	; both, slave and master
		call	TEXTOUT
		ld	hl,23200		; status colors
		ld	bc,256*1+30
		ld	a,64+8*0+4		; paper 0, ink 4, bright 1
		call	DRAW_COLORBOX
;		jr	KMT_MENU_LOOP

KMT_MENU_LOOP	call	PAUSENK			; wait, any key mustn't pressed
		call	INKEY			; read keys, keykode will in reg. A
		cp	49
		jr	z,KMM_ONLYMASTER	; 1 = only master/single Kempston Mouse interface connected
		cp	50
		jr	z,KMM_SLAVEMASTER	; 2 = both interfaces are connected, slave and master
		cp	51
		jp	z,TEST_KJOY		; 3 = test Kempston joystick
		cp	52
		jp	z,TEST_FJOY		; 4 = test Fuller joystick
		cp	112
		jp	z,TEST_7FFD		; P = test port readability
		cp	114
		jr	z,KMT_HW_REDETECT	; R = restart HW detection
		cp	113
		jp	z,KMT_QUIT		; Q = return to ZX BASIC
		jr	KMT_MENU_LOOP

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

KMM_ONLYMASTER	xor	a
		jr	KMM_SELEND

KMM_SLAVEMASTER	ld	a,1

KMM_SELEND	ld	(KMT_MODE),a		; nastaví HID (human interface device)
		jr	KMT_MAIN

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

KMT_HW_REDETECT	call	HW_DETECT
		jp	KMT_MENU		; hw detection restart

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

KMT_MAIN	call	CLS			; clear screen
		ld	hl,TXT_TESTM_INIT	; text specific for master interface
		call	TEXTOUT
		ld	hl,TXT_32SP		; text separator
		call	TEXTOUT
		ld	hl,22535		; values highlighting
		ld	bc,256*4+8
		ld	a,64+8*0+7		; paper 0, ink 7, bright 1
		call	DRAW_COLORBOX
		ld	hl,22552		; values highlighting
		ld	bc,256*4+8
		ld	a,64+8*0+7		; paper 0, ink 7, bright 1
		call	DRAW_COLORBOX
		ld	hl,23040		; scrolling area
		ld	bc,256*8+32
		ld	a,8*1+7			; paper 1, ink 7, bright 0
		call	DRAW_COLORBOX
		ld	a,(KMT_MODE)		; what mode was selected?
		or	a
		jr	z,KMT_MAIN_ONLYM	; only master/single interface, jump over code for slave interface
; test menu for slave mouse interface
		ld	hl,TXT_TESTS_INIT	; both interfaces slave and master
		call	TEXTOUT			; print texts what are dedicated for slave interface
		ld	hl,TXT_32SP		; text separator
		call	TEXTOUT
		ld	hl,22791		; values highlighting
		ld	bc,256*4+8
		ld	a,64+8*0+7		; paper 0, ink 7, bright 1
		call	DRAW_COLORBOX
		ld	hl,22808		; values highlighting
		ld	bc,256*4+8
		ld	a,64+8*0+7		; paper 0, ink 7, bright 1
		call	DRAW_COLORBOX
		call	FILL_SAREA_MS
		jr	KMT_MAIN_CMN

KMT_MAIN_ONLYM	call	FILL_SAREA_M		; specific only for master or single

KMT_MAIN_CMN	ei				; wait for interrupt
		halt
		di
		ld	bc,64223		; #FADF - master interface buttons port
		in	a,(c)
		cpl
		ld	(ARROW_B_M),a	; in first pass will buttons change detected ...
		ld	bc,15071		; #3ADF - slave interface buttons port
		in	a,(c)
		cpl
		ld	(ARROW_B_S),a	; in first pass will buttons change detected ...

		ld	a,(KMT_MODE)
		or	a
		jr	z,KMT_LOOP_M
		jp	KMT_LOOP_MS

; read keyboard ports, and detect any EXIT key

KMT_MODE	db	0			; 0 = only one interface

;------------------------------------------------------------------------------
; MAIN TESTER LOOP - KMOUSE MASTER
;------------------------------------------------------------------------------

KMT_LOOP_M	ld	hl,SCROLL_UP		; initialize test
		ld	(KMT_WHEELM_UP_C+1),hl
		ld	hl,SCROLL_DOWN
		ld	(KMT_WHEELM_DW_C+1),hl
		ei				; get new values from ports before first pass
		halt				; wait for interrupt (50Hz)
		di
		ld	bc,64479		; axis X
		in	a,(c)
		inc	a			; value must be similar, but not exactly same, because in first
		ld	(ARROW_X_M),a		; pass is nice when all values are printed
		ld	bc,65503		; axis Y
		in	a,(c)
		inc	a
		ld	(ARROW_Y_M),a
		ld	bc,64223		; buttons & wheel
		in	a,(c)
		ld	(KMT_WHEELM_IN),a	; init wheel position
		ld	ix,KMT_WHEELM_LST
		push	af
		call	KM_WHEEL_IN
		pop	af
		and	11110000b		; init buttons last value, but change must be detected in first pass
		ld	(ARROW_B_M),a

; main loop
KMT_LOOP_M_1
; compute address and draw arrow
		ld	a,(ARROW_X_M)		; prepare address in VRAM from old/default ARROW coordinates
		ld	c,a
		ld	a,(ARROW_Y_M)
		call	KMT_COMPUTE_Y
		call	8880			; C = x, A = Y, result in HL
		ld	(ARROW_ADDR_M),hl	; save address in VRAM
		ld	(ARROW_SUB_M),a		; how much rotates subtract from 8
		ld	ix,ARROW_GRAPHICSM	; address of graphics to IX
		ld	hl,(ARROW_ADDR_M)	; address of place in VRAM where will arrow painted
		exx
		ld	hl,ARROW_BUFFER_M	; adress of buffer to HL'
		exx
		ld	a,(ARROW_SUB_M)		; number of horizontal rotates
		ld	(ARROW_DRW_2+1),a
		call	ARROW_DRAW

		ei				; wait for interrupt (50Hz)
		halt
		di
; read all ports immediatelly after interrupt and save it
		ld	bc,64479		; axis X
		in	a,(c)
		ld	(KMT_NEWVAL_MX),a
		ld	bc,65503		; axis Y
		in	a,(c)
		ld	(KMT_NEWVAL_MY),a
		ld	bc,64223		; buttons & wheel
		in	a,(c)
		ld	(KMT_NEWVAL_MB),a
; clear cursor
		ld	de,ARROW_BUFFER_M	; address of saved background for master cursor
		ld	hl,(ARROW_ADDR_M)	; get address where master cursor was painted
		call	ARROW_CLEAR
; master axis X
		ld	a,(ARROW_X_M)		; old value to B
		ld	b,a
		ld	a,(KMT_NEWVAL_MX)	; new value to A
		cp	b			; compare
		jr	z,KMT_LOOP_M_2		; Z = value not changed, jump over printing value
		ld	(ARROW_X_M),a		; save new value
		push	af
		ld	hl,TXT_TESTM_X		; set print position
		call	TEXTOUT
		pop	af
		ld	h,0			; copy 8 bit value to HL
		ld	l,a
		call	NUMOUT8B		; print value
; master axis Y
KMT_LOOP_M_2	ld	a,(ARROW_Y_M)		; old value to B
		ld	b,a
		ld	a,(KMT_NEWVAL_MY)	; new value to A
		cp	b			; compare
		jr	z,KMT_LOOP_M_3		; Z = value not changed, jump over printing value
		ld	(ARROW_Y_M),a		; save new value
		push	af
		ld	hl,TXT_TESTM_Y		; set print position
		call	TEXTOUT
		pop	af
		ld	h,0			; copy 8 bit value to HL
		ld	l,a
		call	NUMOUT8B		; print value
; master buttons & wheel
KMT_LOOP_M_3	ld	a,(ARROW_B_M)		; old value to B
		ld	b,a
		ld	a,(KMT_NEWVAL_MB)	; new value to A
		cp	b			; compare
		jr	z,KMT_LOOP_M_4		; Z = value not changed, jump over printing values
		ld	(ARROW_B_M),a		; save new value
		call	KMT_WHBUTT_M		; analyze and print values
; test keyboard and repeat
KMT_LOOP_M_4	xor	a
		in	a,(254)			; detect pressed key
		cpl
		and	00011111b
		jp	z,KMT_LOOP_M_1
		jp	KMT_MENU
;		jp	KMT_QUIT

; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
; master + slave

KMT_LOOP_MS	ld	hl,SCROLL_ULEFT		; initialize test
		ld	(KMT_WHEELM_UP_C+1),hl
		ld	hl,SCROLL_DLEFT
		ld	(KMT_WHEELM_DW_C+1),hl
		ld	hl,SCROLL_URIGHT
		ld	(KMT_WHEELS_UP_C+1),hl
		ld	hl,SCROLL_DRIGHT
		ld	(KMT_WHEELS_DW_C+1),hl
		ei				; get new values from ports before first pass
		halt				; wait for interrupt (50Hz)
		di
		ld	bc,64479		; axis X
		in	a,(c)
		inc	a			; value must be similar, but not exactly same, because in first
		ld	(ARROW_X_M),a		; pass is nice when all values are printed
		ld	bc,65503		; axis Y
		in	a,(c)
		inc	a
		ld	(ARROW_Y_M),a
		ld	bc,64223		; buttons & wheel
		in	a,(c)
		ld	(KMT_WHEELM_IN),a	; init wheel position
		ld	ix,KMT_WHEELM_LST
		push	af
		call	KM_WHEEL_IN
		pop	af
		and	11110000b		; init buttons last value, but change must be detected in first pass
		ld	(ARROW_B_M),a
		ld	bc,15327		; axis X
		in	a,(c)
		inc	a			; value must be similar, but not exactly same, because in first
		ld	(ARROW_X_S),a		; pass is nice when all values are printed
		ld	bc,16351		; axis Y
		in	a,(c)
		inc	a
		ld	(ARROW_Y_S),a
		ld	bc,15071		; buttons & wheel
		in	a,(c)
		ld	(KMT_WHEELS_IN),a	; init wheel position
		ld	ix,KMT_WHEELS_LST
		push	af
		call	KM_WHEEL_IN
		pop	af
		and	11110000b		; init buttons last value, but change must be detected in first pass
		ld	(ARROW_B_S),a

; main loop
KMT_LOOP_MS_1
; compute address and draw arrow - master
		ld	a,(ARROW_X_M)		; prepare address in VRAM from old/default ARROW coordinates
		ld	c,a
		ld	a,(ARROW_Y_M)
		call	KMT_COMPUTE_Y
		call	8880			; C = x, A = Y, result in HL
		ld	(ARROW_ADDR_M),hl	; save address in VRAM
		ld	(ARROW_SUB_M),a		; how much rotates subtract from 8
		ld	ix,ARROW_GRAPHICSM	; address of graphics to IX
		ld	hl,(ARROW_ADDR_M)	; address of place in VRAM where will arrow painted
		exx
		ld	hl,ARROW_BUFFER_M	; adress of buffer to HL'
		exx
		ld	a,(ARROW_SUB_M)		; number of horizontal rotates
		ld	(ARROW_DRW_2+1),a
		call	ARROW_DRAW

; compute address and draw arrow - slave
		ld	a,(ARROW_X_S)		; prepare address in VRAM from old/default ARROW coordinates
		ld	c,a
		ld	a,(ARROW_Y_S)
		call	KMT_COMPUTE_Y
		call	8880			; C = x, A = Y, result in HL
		ld	(ARROW_ADDR_S),hl	; save address in VRAM
		ld	(ARROW_SUB_S),a		; how much rotates subtract from 8
		ld	ix,ARROW_GRAPHICSS	; address of graphics to IX
		ld	hl,(ARROW_ADDR_S)	; address of place in VRAM where will arrow painted
		exx
		ld	hl,ARROW_BUFFER_S	; adress of buffer to HL'
		exx
		ld	a,(ARROW_SUB_S)		; number of horizontal rotates
		ld	(ARROW_DRW_2+1),a
		call	ARROW_DRAW

		ei				; wait for interrupt (50Hz)
		halt
		di
; read all ports immediatelly after interrupt and save it
		ld	bc,64479		; axis X
		in	a,(c)
		ld	(KMT_NEWVAL_MX),a
		ld	bc,65503		; axis Y
		in	a,(c)
		ld	(KMT_NEWVAL_MY),a
		ld	bc,64223		; buttons & wheel
		in	a,(c)
		ld	(KMT_NEWVAL_MB),a
		ld	bc,15327		; axis X
		in	a,(c)
		ld	(KMT_NEWVAL_SX),a
		ld	bc,16351		; axis Y
		in	a,(c)
		ld	(KMT_NEWVAL_SY),a
		ld	bc,15071		; buttons & wheel
		in	a,(c)
		ld	(KMT_NEWVAL_SB),a
; clear cursors (slave first - like push/pop)
		ld	de,ARROW_BUFFER_S	; address of saved background for master cursor
		ld	hl,(ARROW_ADDR_S)	; get address where master cursor was painted
		call	ARROW_CLEAR
		ld	de,ARROW_BUFFER_M	; address of saved background for master cursor
		ld	hl,(ARROW_ADDR_M)	; get address where master cursor was painted
		call	ARROW_CLEAR
; master axis X
		ld	a,(ARROW_X_M)		; old value to B
		ld	b,a
		ld	a,(KMT_NEWVAL_MX)	; new value to A
		cp	b			; compare
		jr	z,KMT_LOOP_MS_2		; Z = value not changed, jump over printing value
		ld	(ARROW_X_M),a		; save new value
		push	af
		ld	hl,TXT_TESTM_X		; set print position
		call	TEXTOUT
		pop	af
		ld	h,0			; copy 8 bit value to HL
		ld	l,a
		call	NUMOUT8B		; print value
; master axis Y
KMT_LOOP_MS_2	ld	a,(ARROW_Y_M)		; old value to B
		ld	b,a
		ld	a,(KMT_NEWVAL_MY)	; new value to A
		cp	b			; compare
		jr	z,KMT_LOOP_MS_3		; Z = value not changed, jump over printing value
		ld	(ARROW_Y_M),a		; save new value
		push	af
		ld	hl,TXT_TESTM_Y		; set print position
		call	TEXTOUT
		pop	af
		ld	h,0			; copy 8 bit value to HL
		ld	l,a
		call	NUMOUT8B		; print value
; master buttons & wheel
KMT_LOOP_MS_3	ld	a,(ARROW_B_M)		; old value to B
		ld	b,a
		ld	a,(KMT_NEWVAL_MB)	; new value to A
		cp	b			; compare
		jr	z,KMT_LOOP_MS_4		; Z = value not changed, jump over printing values
		ld	(ARROW_B_M),a		; save new value
		call	KMT_WHBUTT_M		; analyze and print values
; slave axis X
KMT_LOOP_MS_4	ld	a,(ARROW_X_S)		; old value to B
		ld	b,a
		ld	a,(KMT_NEWVAL_SX)	; new value to A
		cp	b			; compare
		jr	z,KMT_LOOP_MS_5		; Z = value not changed, jump over printing value
		ld	(ARROW_X_S),a		; save new value
		push	af
		ld	hl,TXT_TESTS_X		; set print position
		call	TEXTOUT
		pop	af
		ld	h,0			; copy 8 bit value to HL
		ld	l,a
		call	NUMOUT8B		; print value
; slave axis Y
KMT_LOOP_MS_5	ld	a,(ARROW_Y_S)		; old value to B
		ld	b,a
		ld	a,(KMT_NEWVAL_SY)	; new value to A
		cp	b			; compare
		jr	z,KMT_LOOP_MS_6		; Z = value not changed, jump over printing value
		ld	(ARROW_Y_S),a		; save new value
		push	af
		ld	hl,TXT_TESTS_Y		; set print position
		call	TEXTOUT
		pop	af
		ld	h,0			; copy 8 bit value to HL
		ld	l,a
		call	NUMOUT8B		; print value
; master buttons & wheel
KMT_LOOP_MS_6	ld	a,(ARROW_B_S)		; old value to B
		ld	b,a
		ld	a,(KMT_NEWVAL_SB)	; new value to A
		cp	b			; compare
		jr	z,KMT_LOOP_MS_7		; Z = value not changed, jump over printing values
		ld	(ARROW_B_S),a		; save new value
		call	KMT_WHBUTT_S		; analyze and print values
; test keyboard and repeat
KMT_LOOP_MS_7	xor	a
		in	a,(254)			; detect pressed key
		cpl
		and	00011111b
		jp	z,KMT_LOOP_MS_1
		jp	KMT_MENU
;		jp	KMT_QUIT

KMT_NEWVAL_MX	db	0			; new values readed from ports
KMT_NEWVAL_MY	db	0
KMT_NEWVAL_MB	db	0
KMT_NEWVAL_SX	db	0
KMT_NEWVAL_SY	db	0
KMT_NEWVAL_SB	db	0

;------------------------------------------------------------------------------
; KMouse returns value <0,255>, for arrow is needed <0,191> - compute it
; INPUT value in A
; OUTPUT value in A

KMT_COMPUTE_Y	push	hl
		push	bc
		cpl
		ld	b,0			; copy axis Y to BC
		ld	c,a
		ld	h,b			; and too HL too
		ld	l,c
		add	hl,bc			; HL = axis Y * 2
		add	hl,bc			; HL = axis Y * 3 (max 765)
		srl	h			; now divide HL by 4 (2* rotate all HL right and low bit from H
		rr	l			; carry to high bit in l)
		srl	h
		rr	l
		ld	a,l			; now new value ((axis X * 3)/4) copy to A and save to address in DE
		pop	bc
		pop	hl
		ret

; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
; Analyze and print changed values of buttons & wheel port for master KMouse interface.
; port value must be at right address in memory - (AXIS_B_M)

KMT_WHBUTT_M	ld	hl,TXT_TESTM_B		; letters FMLR
		call	TEXTOUT
		ld	a,(ARROW_B_M)		; save value readed from port, for wheel driver
		ld	(KMT_WHEELM_IN),a
		ld	h,0			; copy to HL
		ld	l,a
		push	af
		call	NUMOUT8B		; print decadic value
		pop	af
		push	af
		call	KMT_PRN_BS		; PRINT buttons state
		ld	hl,TXT_TESTM_BB		; buttons, set print position
		call	TEXTOUT
		pop	af
		call	NUMOUT_BIN		; print binary value, value must be in A register

		call	KM_WHEEL_MASTER		; read value of mouse wheel
		ld	hl,TXT_TESTM_W		; set print position
		call	TEXTOUT
		ld	a,(KMT_WHEELM_LST)	; get wheel position in interval <0,16>
		ld	h,0			; copy value to HL and print
		ld	l,a
		call	NUMOUT8B

		ld	a,' '			; print space character
		call	PRINT
		ld	a,(KMT_WHEELM_DIF)	; get a wheel difference
		or	a			; test it <-; 0; +>
		jr	z,KMT_WHEELM_0
		bit	7,a			; seventh bit is signum (plus, minus)
		jr	nz,KMT_WHEELM_UP	; minus is direction up!
		jr	KMT_WHEELM_DW

KMT_WHEELM_0	ld	a,'+'			; print space character at place of signum
		call	PRINT
		xor	a			; print decadic difference 0
		ld	h,a
		ld	l,a
		call	NUMOUT8B
		ld	hl,TXT_TESTM_WD		; set print position for direction info
		call	TEXTOUT
		ld	hl,TXT_NOTHING		; print '----'
		call	TEXTOUT
		ret

KMT_WHEELM_UP	ld	a,'-'
		call	PRINT
		ld	a,(KMT_WHEELM_DIF)
		neg
		push	af
		ld	h,0
		ld	l,a
		call	NUMOUT8B
		ld	hl,TXT_TESTM_WD		; set print position for direction info
		call	TEXTOUT
		ld	hl,TXT_UP
		call	TEXTOUT
		pop	af
KMT_WHEELM_UP_L	push	af			; loop - scroll same times as step of wheel was detected
KMT_WHEELM_UP_C	call	SCROLL_UP
		pop	af
		dec	a
		jr	nz,KMT_WHEELM_UP_L
		ret

KMT_WHEELM_DW	ld	a,'+'
		call	PRINT
		ld	a,(KMT_WHEELM_DIF)
		push	af
		ld	h,0
		ld	l,a
		call	NUMOUT8B
		ld	hl,TXT_TESTM_WD		; set print position for direction info
		call	TEXTOUT
		ld	hl,TXT_DOWN
		call	TEXTOUT
		pop	af
KMT_WHEELM_DW_L	push	af
KMT_WHEELM_DW_C	call	SCROLL_DOWN
		pop	af
		dec	a
		jr	nz,KMT_WHEELM_DW_L
		ret

; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
; Analyze and print changed values of buttons & wheel port for slave KMouse interface.
; port value must be at right address in memory - (AXIS_B_S)

KMT_WHBUTT_S	ld	hl,TXT_TESTS_B		; letters FMLR
		call	TEXTOUT
		ld	a,(ARROW_B_S)		; save value readed from port, for wheel driver
		ld	(KMT_WHEELS_IN),a
		ld	h,0			; copy to HL
		ld	l,a
		push	af
		call	NUMOUT8B		; print decadic value
		pop	af
		push	af
		call	KMT_PRN_BS		; PRINT buttons state
		ld	hl,TXT_TESTS_BB		; buttons, set print position
		call	TEXTOUT
		pop	af
		call	NUMOUT_BIN		; print binary value, value must be in A register

		call	KM_WHEEL_SLAVE		; read value of mouse wheel
		ld	hl,TXT_TESTS_W		; set print position
		call	TEXTOUT
		ld	a,(KMT_WHEELS_LST)	; get wheel position in interval <0,16>
		ld	h,0			; copy value to HL and print
		ld	l,a
		call	NUMOUT8B

		ld	a,' '			; print space character
		call	PRINT
		ld	a,(KMT_WHEELS_DIF)	; get a wheel difference
		or	a			; test it <-; 0; +>
		jr	z,KMT_WHEELS_0
		bit	7,a			; seventh bit is signum (plus, minus)
		jr	nz,KMT_WHEELS_UP	; minus is direction up!
		jr	KMT_WHEELS_DW

KMT_WHEELS_0	ld	a,'+'			; print space character at place of signum
		call	PRINT
		xor	a			; print decadic difference 0
		ld	h,a
		ld	l,a
		call	NUMOUT8B
		ld	hl,TXT_TESTS_WD		; set print position for direction info
		call	TEXTOUT
		ld	hl,TXT_NOTHING		; print '----'
		call	TEXTOUT
		ret

KMT_WHEELS_UP	ld	a,'-'
		call	PRINT
		ld	a,(KMT_WHEELS_DIF)
		neg
		push	af
		ld	h,0
		ld	l,a
		call	NUMOUT8B
		ld	hl,TXT_TESTS_WD		; set print position for direction info
		call	TEXTOUT
		ld	hl,TXT_UP
		call	TEXTOUT
		pop	af
KMT_WHEELS_UP_L	push	af			; loop - scroll same times as step of wheel was detected
KMT_WHEELS_UP_C	call	SCROLL_UP
		pop	af
		dec	a
		jr	nz,KMT_WHEELS_UP_L
		ret

KMT_WHEELS_DW	ld	a,'+'
		call	PRINT
		ld	a,(KMT_WHEELS_DIF)
		push	af
		ld	h,0
		ld	l,a
		call	NUMOUT8B
		ld	hl,TXT_TESTS_WD		; set print position for direction info
		call	TEXTOUT
		ld	hl,TXT_DOWN
		call	TEXTOUT
		pop	af
KMT_WHEELS_DW_L	push	af
KMT_WHEELS_DW_C	call	SCROLL_DOWN
		pop	af
		dec	a
		jr	nz,KMT_WHEELS_DW_L
		ret

;------------------------------------------------------------------------------
; part what print characters LRM for left, right and middle button when pressed

KMT_PRN_BS	push	af			; PRINT buttons state
		call	KMT_PRN_BSSP		; print SPACE
		pop	af
		push	af
		bit	3,a			; test fourth button
		call	KMT_PRN_BSF		; it is still tested, but newest interfaces returns 1
		pop	af
		push	af
		bit	2,a			; test middle button
		call	KMT_PRN_BSM
		pop	af
		push	af
		bit	1,a			; test left button
		call	KMT_PRN_BSL
		pop	af
		push	af
		bit	0,a			; test right button
		call	KMT_PRN_BSR
		pop	af
		ret

KMT_PRN_BSL	jr	nz,KMT_PRN_BSSP
		ld	a,'L'
		jr	KMT_PRN_CHAR

KMT_PRN_BSR	jr	nz,KMT_PRN_BSSP
		ld	a,'R'
		jr	KMT_PRN_CHAR

KMT_PRN_BSM	jr	nz,KMT_PRN_BSSP
		ld	a,'M'
		jr	KMT_PRN_CHAR

KMT_PRN_BSF	jr	nz,KMT_PRN_BSSP
		ld	a,'F'
		jr	KMT_PRN_CHAR

KMT_PRN_BSSP	ld	a,' '
KMT_PRN_CHAR	call	PRINT
		ret

;==============================================================================
; Compute values from mouse wheel (bits 7 - 4 on buttons port)
;==============================================================================
; CALL POINTS for both KMouse interfaces

KM_WHEEL_MASTER	ld	ix,KMT_WHEELM_LST
		jr	KM_WHEEL

KM_WHEEL_SLAVE	ld	ix,KMT_WHEELS_LST
		jr	KM_WHEEL

KMT_WHEELM_LST	db	0			; last wheel state
KMT_WHEELM_DIF	db	0			; difference from last state (signum plus is direction down)
KMT_WHEELM_IN	db	0			; value readed from buttons port before KM_WHEEL called

KMT_WHEELS_LST	db	0			; last wheel state
KMT_WHEELS_DIF	db	0			; difference from last state (signum plus is direction down)
KMT_WHEELS_IN	db	0			; value readed from buttons port before KM_WHEEL called

; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
; Main driver for KMouse WHEEL
; in IX register must be address of 3 variables (3 bytes for one KMouse interface)
;
; returns
;	LST	last port state <0; 16>
;	DIF	difference <-8; +8>
;	IN	new port state, readed directly from IO port without changes

KM_WHEEL	ld	a,(ix+0)		; read old wheel state
		ld	h,a
		call	KM_WHEEL_IN		; read new values, saved when buttons port was readed to reg. H
		sub	h			; subtract new value from old value
		ld	(ix+1),a		; save difference
		ret	z			; Z => values are same, wheel not moved, jump to ret
		jp	m,KM_WHEEL_0		; M => number is smaller than zero -> jump
		cp	15-6			; compare with 9
		jr	nc,KM_WHEEL_UPS		; NC =>  A>=9  up    A from interval <9, 255>
		jr	KM_WHEEL_DW		; C =>   A<9   down  A from interval <1, 8>

KM_WHEEL_0	neg				; change signum
		cp	15-6			; compare with 9
		jr	nc,KM_WHEEL_DWS		; NC =>  A>=9  down  A from interval <-255, -9>
		jr	KM_WHEEL_UP		; C =>   A<9   up    A from interval <-8, -1>

KM_WHEEL_DWS	neg				; change signum
KM_WHEEL_DW	and	00001111b		; keep only lower four bits
		ld	(ix+1),a		; save number of steps
		ret

KM_WHEEL_UPS	neg				; change signum
KM_WHEEL_UP	and	00001111b		; keep only lower four bits
		neg				; direction UP, value is smaller than 0
		ld	(ix+1),a		; save number of steps
		ret

KM_WHEEL_IN	ld	a,(ix+2)		; read value readed from buttons port without changes
		srl	a			; /16, only higher 4 bits are relevant for wheel
		srl	a
		srl	a
		srl	a
		ld	(ix+0),a		; and save value (value is in interval <0, 16>)
		ret

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

FILL_SAREA_M	ld	hl,TXT_SCRL_AREA_1	; for master or single KMouse
		call	TEXTOUT
		ld	bc,256*8+32
		ld	hl,20480
		call	DRAW_LINEBOX_I
		ret

FILL_SAREA_MS	ld	hl,TXT_SCRL_AREA_2	; for slave or both interfaces
		call	TEXTOUT
		ld	bc,256*8+16
		ld	hl,20480
		call	DRAW_LINEBOX_I
		ld	bc,256*8+16
		ld	hl,20480+16
		call	DRAW_LINEBOX_I
		ret

;==============================================================================
; KEMPSTON JOYSTICK TEST
;==============================================================================

TEST_KJOY	call	CLS
		ld	hl,TXT_JOY_KEMP
		call	TEXTOUT
		ld	hl,22528		; colors under main title
		ld	bc,256*1+32
		ld	a,64+8*1+5		; paper 1, ink 5, bright 1
		call	DRAW_COLORBOX
		ld	hl,22604		; values highlighting (port status)
		ld	bc,256*2+8
		ld	a,64+8*0+7		; paper 0, ink 7, bright 1
		call	DRAW_COLORBOX
		ld	hl,22656		; values highlighting (directions)
		ld	bc,256*8+5
		ld	a,64+8*0+6		; paper 0, ink 6, bright 1
		call	DRAW_COLORBOX
		ld	hl,TXT_JOY_PORT
		call	TEXTOUT
		ld	hl,TXT_PRESS_SPACE
		call	TEXTOUT
		call	PAUSENK

TEST_KJOY_LOOP	ld	bc,32766		; test SPACE
		in	a,(c)
		and	1
		jp	z,KMT_MENU		; Z = space pressed
		ld	hl,TXT_JOY_DEC		; initialize print position for binary value of joystick port
		call	TEXTOUT
		ei
		halt
		di
		ld	bc,31			; read Kempston joystick port
		in	a,(c)
		ld	h,0			; print binary value
		ld	l,a
		push	af
		push	hl
		call	NUMOUT8B
		ld	hl,TXT_JOY_BIN		; initialize print position for binary value of joystick port
		call	TEXTOUT
		pop	hl
		pop	af
		push	af
		call	NUMOUT_BIN
		ld	hl,TXT_JOY_DIRS		; initialize print position for list of "signals"
		call	TEXTOUT
		pop	af			; restore value
		ld	b,7			; max 7 lines
		bit	0,a			; right
		jr	z,TEST_KJOY_LEFT
		ld	hl,TXT_JOY_RIGHT
		push	af
		push	bc
		call	TEXTOUT
		dec	b
		pop	bc
		pop	af
TEST_KJOY_LEFT	bit	1,a			; left
		jr	z,TEST_KJOY_DOWN
		ld	hl,TXT_JOY_LEFT
		push	af
		push	bc
		call	TEXTOUT
		dec	b
		pop	bc
		pop	af
TEST_KJOY_DOWN	bit	2,a			; down
		jr	z,TEST_KJOY_UP
		ld	hl,TXT_JOY_DOWN
		push	af
		push	bc
		call	TEXTOUT
		dec	b
		pop	bc
		pop	af
TEST_KJOY_UP	bit	3,a			; up
		jr	z,TEST_KJOY_F1
		ld	hl,TXT_JOY_UP
		push	af
		push	bc
		call	TEXTOUT
		dec	b
		pop	bc
		pop	af
TEST_KJOY_F1	bit	4,a			; fire1
		jr	z,TEST_KJOY_F2
		ld	hl,TXT_JOY_FIRE1
		push	af
		push	bc
		call	TEXTOUT
		dec	b
		pop	bc
		pop	af
TEST_KJOY_F2	bit	5,a			; fire2
		jr	z,TEST_KJOY_F3
		ld	hl,TXT_JOY_FIRE2
		push	af
		push	bc
		call	TEXTOUT
		dec	b
		pop	bc
		pop	af
TEST_KJOY_F3	bit	6,a			; fire3
		jr	z,TEST_KJOY_SP
		ld	hl,TXT_JOY_FIRE3
		push	af
		push	bc
		call	TEXTOUT
		dec	b
		pop	bc
		pop	af
TEST_KJOY_SP	push	bc
		ld	hl,TXT_JOY_SPACE
		call	TEXTOUT
		pop	bc
		djnz	TEST_KJOY_SP
		jp	TEST_KJOY_LOOP

;==============================================================================
; FULLER JOYSTICK TEST
;==============================================================================

TEST_FJOY	call	CLS
		ld	hl,TXT_JOY_FULL
		call	TEXTOUT
		ld	hl,22528		; colors under main title
		ld	bc,256*1+32
		ld	a,64+8*1+5		; paper 1, ink 5, bright 1
		call	DRAW_COLORBOX
		ld	hl,22604		; values highlighting (port status)
		ld	bc,256*2+8
		ld	a,64+8*0+7		; paper 0, ink 7, bright 1
		call	DRAW_COLORBOX
		ld	hl,22656		; values highlighting (directions)
		ld	bc,256*8+5
		ld	a,64+8*0+6		; paper 0, ink 6, bright 1
		call	DRAW_COLORBOX
		ld	hl,TXT_JOY_PORT
		call	TEXTOUT
		ld	hl,TXT_PRESS_SPACE
		call	TEXTOUT
		call	PAUSENK

TEST_FJOY_LOOP	ld	bc,32766		; test SPACE
		in	a,(c)
		and	1
		jp	z,KMT_MENU		; Z = space pressed
		ld	hl,TXT_JOY_DEC		; initialize print position for binary value of joystick port
		call	TEXTOUT
		ei
		halt
		di
		ld	bc,127			; read Fuller joystick port
		in	a,(c)
		ld	h,0			; print binary value
		ld	l,a
		push	af
		push	hl
		call	NUMOUT8B
		ld	hl,TXT_JOY_BIN		; initialize print position for binary value of joystick port
		call	TEXTOUT
		pop	hl
		pop	af
		push	af
		call	NUMOUT_BIN
		ld	hl,TXT_JOY_DIRS		; initialize print position for list of "signals"
		call	TEXTOUT
		pop	af			; restore value
		ld	b,7			; max 7 lines
		bit	0,a			; right
		jr	nz,TEST_FJOY_LEFT
		ld	hl,TXT_JOY_RIGHT
		push	af
		push	bc
		call	TEXTOUT
		dec	b
		pop	bc
		pop	af
TEST_FJOY_LEFT	bit	1,a			; left
		jr	nz,TEST_FJOY_DOWN
		ld	hl,TXT_JOY_LEFT
		push	af
		push	bc
		call	TEXTOUT
		dec	b
		pop	bc
		pop	af
TEST_FJOY_DOWN	bit	2,a			; down
		jr	nz,TEST_FJOY_UP
		ld	hl,TXT_JOY_DOWN
		push	af
		push	bc
		call	TEXTOUT
		dec	b
		pop	bc
		pop	af
TEST_FJOY_UP	bit	3,a			; up
		jr	nz,TEST_FJOY_F1
		ld	hl,TXT_JOY_UP
		push	af
		push	bc
		call	TEXTOUT
		dec	b
		pop	bc
		pop	af
TEST_FJOY_F1	bit	7,a			; fire1
		jr	nz,TEST_FJOY_F2
		ld	hl,TXT_JOY_FIRE1
		push	af
		push	bc
		call	TEXTOUT
		dec	b
		pop	bc
		pop	af
TEST_FJOY_F2	bit	6,a			; fire2
		jr	nz,TEST_FJOY_F3
		ld	hl,TXT_JOY_FIRE2
		push	af
		push	bc
		call	TEXTOUT
		dec	b
		pop	bc
		pop	af
TEST_FJOY_F3	bit	5,a			; fire3
		jr	nz,TEST_FJOY_SP
		ld	hl,TXT_JOY_FIRE3
		push	af
		push	bc
		call	TEXTOUT
		dec	b
		pop	bc
		pop	af
TEST_FJOY_SP	push	bc
		ld	hl,TXT_JOY_SPACE
		call	TEXTOUT
		pop	bc
		djnz	TEST_FJOY_SP
		jp	TEST_FJOY_LOOP

;==============================================================================
; TEST PORT READABILITY
;==============================================================================

TEST_7FFD	call	CLS			; prepare screen
		ld	hl,TXT_PORT
		call	TEXTOUT
		ld	hl,22528		; colors under main title
		ld	bc,256*1+32
		ld	a,64+8*1+5		; paper 1, ink 5, bright 1
		call	DRAW_COLORBOX
		ld	hl,22816		; values highlighting
		ld	bc,256*14+30
		ld	a,64+8*0+7		; paper 0, ink 7, bright 1
		call	DRAW_COLORBOX

		ld	de,TEST_7FFD_VALS	; table of test values
TEST_7FFD_LOOP	ld	a,(de)
		or	a			; test value
		jr	z,TEST_7FFD_END
		ei				; all tested ports read immediatelly after interrupt
		halt
		di
		ld	bc,32765		; #7FFD
		out	(c),a
		ld	bc,65247		; #FEDF
		in	a,(c)
		ld	(TEST_FEDF_VALUE),a
		ld	bc,16095		; #3EDF
		in	a,(c)
		ld	(TEST_3EDF_VALUE),a

		push	de			; print readed values
		ld	a,' '
		call	PRINT
		pop	de
		push	de

		ld	a,(de)			; writed value
		ld	h,0
		ld	l,a
		call	NUMOUT8B

		ld	hl,TXT_PORT_SPACES	; value readed from #FEDF
		call	TEXTOUT
		ld	a,(TEST_FEDF_VALUE)
		ld	h,0
		ld	l,a
		call	NUMOUT8B

		ld	hl,TXT_PORT_SPACES	; value readed from #3EDF
		call	TEXTOUT
		ld	a,(TEST_3EDF_VALUE)
		ld	h,0
		ld	l,a
		call	NUMOUT8B

		call	PRINT_NL		; new line
		pop	de
		inc	de
		ld	bc,32765		; set back default RAM page (because ROM 128k)
		ld	a,16
		out	(c),a
		jr	TEST_7FFD_LOOP

TEST_7FFD_END	ld	bc,32765		; set back default RAM page
		ld	a,16
		out	(c),a
		ld	hl,TXT_PRESS_SPACE
		call	TEXTOUT
		call	PAUSENK
		call	PAUSE0
		jp	KMT_MENU
;		jp	KMT_QUIT

TEST_7FFD_VALS	db	1,2,3,4,5,6,16,17,18,19,20,21,22,23,0
TEST_FEDF_VALUE	db	0
TEST_3EDF_VALUE	db	0
; TEST_17_VALUE	db	0

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

SCROLL_UP	ld	hl,20480
		ld	de,SCROLL_LNBUFF
		ld	bc,32
		ldir
		ld	hl,20480
		ld	b,63
SCROLL_UP_0	push	hl
		call	DOWNHL
		pop	de
		ld	a,b
		ld	bc,32
		push	hl
		ldir
		pop	hl
		ld	b,a
		djnz	SCROLL_UP_0
		ld	hl,SCROLL_LNBUFF
		ld	de,22528-32
		ld	bc,32
		ldir
		ret

SCROLL_ULEFT	ld	hl,20480
		ld	de,SCROLL_LNBUFF
		ld	bc,16
		ldir
		ld	hl,20480
		ld	b,63
SCROLL_ULEFT_0	push	hl
		call	DOWNHL
		pop	de
		ld	a,b
		ld	bc,16
		push	hl
		ldir
		pop	hl
		ld	b,a
		djnz	SCROLL_ULEFT_0
		ld	hl,SCROLL_LNBUFF
		ld	de,22528-32
		ld	bc,16
		ldir
		ret

SCROLL_URIGHT	ld	hl,20480+16
		ld	de,SCROLL_LNBUFF
		ld	bc,16
		ldir
		ld	hl,20480+16
		ld	b,63
SCROLL_URIGHT_0	push	hl
		call	DOWNHL
		pop	de
		ld	a,b
		ld	bc,16
		push	hl
		ldir
		pop	hl
		ld	b,a
		djnz	SCROLL_URIGHT_0
		ld	hl,SCROLL_LNBUFF
		ld	de,22528-16
		ld	bc,16
		ldir
		ret

SCROLL_DOWN	ld	hl,16384+6144-32
		ld	de,SCROLL_LNBUFF
		ld	bc,32
		ldir
		ld	hl,22528-32
		ld	b,63
SCROLL_DOWN_0	push	hl
		call	UPHL
		pop	de
		ld	a,b
		ld	bc,32
		push	hl
		ldir
		pop	hl
		ld	b,a
		djnz	SCROLL_DOWN_0
		ld	hl,SCROLL_LNBUFF
		ld	de,16384+4096
		ld	bc,32
		ldir
		ret

SCROLL_DLEFT	ld	hl,16384+6144-32
		ld	de,SCROLL_LNBUFF
		ld	bc,16
		ldir
		ld	hl,22528-32
		ld	b,63
SCROLL_DLEFT_0	push	hl
		call	UPHL
		pop	de
		ld	a,b
		ld	bc,16
		push	hl
		ldir
		pop	hl
		ld	b,a
		djnz	SCROLL_DLEFT_0
		ld	hl,SCROLL_LNBUFF
		ld	de,16384+4096
		ld	bc,16
		ldir
		ret

SCROLL_DRIGHT	ld	hl,16384+6144-16
		ld	de,SCROLL_LNBUFF
		ld	bc,16
		ldir
		ld	hl,22528-16
		ld	b,63
SCROLL_DRIGHT_0	push	hl
		call	UPHL
		pop	de
		ld	a,b
		ld	bc,16
		push	hl
		ldir
		pop	hl
		ld	b,a
		djnz	SCROLL_DRIGHT_0
		ld	hl,SCROLL_LNBUFF
		ld	de,16384+4096+16
		ld	bc,16
		ldir
		ret

SCROLL_LNBUFF	ds	32

;==============================================================================
; ARROW
;==============================================================================

ARROW_HEIGHT	equ	11

ARROW_COMPUTE	ld	a,(ARROW_X_M)		; compute address from coordinates
		ld	c,a
		ld	a,(ARROW_Y_M)
		call	8880			; C = x, A = Y, result in HL
		ld	(ARROW_ADDR_M),hl	; save address in VRAM
		ld	(ARROW_SUB_M),a		; how much rotates subtract from 8
		ld	a,(KMT_MODE)		; only master or master+slave interface?
		or	a
		ret	z			; Z = only master
		ld	a,(ARROW_X_S)
		ld	c,a
		ld	a,(ARROW_Y_S)
		call	8880			; C = x, A = Y, result in HL
		ld	(ARROW_ADDR_S),hl	; save address in VRAM
		ld	(ARROW_SUB_S),a		; how much rotates subtract from 8
		ret

;------------------------------------------------------------------------------
; DRAW ARROW
;------------------------------------------------------------------------------
; draw both cursors, master first, then slave

ARROWS_DRAW	ld	ix,ARROW_GRAPHICSM	; address of graphics to IX
		ld	hl,(ARROW_ADDR_M)	; address of place in VRAM where will arrow painted
		exx
		ld	hl,ARROW_BUFFER_M	; adress of buffer to HL'
		exx
		ld	a,(ARROW_SUB_M)
		ld	(ARROW_DRW_2+1),a
		call	ARROW_DRAW
		ld	a,(KMT_MODE)		; only master or master+slave interface?
		or	a
		ret	z			; Z = only master
		ld	ix,ARROW_GRAPHICSS	; address of graphics to IX
		ld	hl,(ARROW_ADDR_S)	; address of place in VRAM where will arrow painted
		exx
		ld	hl,ARROW_BUFFER_S	; adress of buffer to HL'
		exx
		ld	a,(ARROW_SUB_S)
		ld	(ARROW_DRW_2+1),a

ARROW_DRAW	ld	b,ARROW_HEIGHT		; height in pixels to B
ARROW_DRW_1	push	bc			; save number of remaining microlines
		push	hl			; dvakrát ulož adresu šipky ve VRAM, na kterou se bude kreslit
		push	hl
		ld	h,0			; do H ulož 0, sem se bude rotovat sprite/maska, pokud to bude třeba
		ld	l,(ix+0)		; do L přečti byte spritu
		ld	d,h			; vynuluj D (to samé jako H)
		ld	e,(ix+ARROW_HEIGHT)	; do E přečti byte masky
		inc	ix			; posuň ukazatel na grafiku spritu
		ld	a,8			; rotovat můžu nejvýše 8x
ARROW_DRW_2	sub	0			; od počtu rotací odečtu počet rotací vlevo a získám počet rotací vpravo
		ld	b,a			; počet rotací vpravo si uložím do B
ARROW_DRW_3	add	hl,hl			; HL *= 2 (náhrada rr hl)
		ex	de,hl			; prohoď HL a DE (add de,de taky bohužel neexistuje)
		add	hl,hl			; HL *= 2 (náhrada rr de)
		ex	de,hl			; HL a DE prohoď zase zpátky
		djnz	ARROW_DRW_3		; jednobytový sprite a maska jsou uloženy v HL a DE posunuté jak je třeba

		ex	(sp),hl			; prohoď poslední hodnotu v zásobníku (adresa šipky ve VRAM) a obsahem HL
		pop	bc			; do BC tak ze zásobníku vyzvednu odrotovanou předlohu
		ld	a,(hl)			; do A načtu původní obsah obrazovky
		exx
		ld	(hl),a			; uložím na (HL') - adresa bufferu (levý byte, budou dva)
		inc	hl			; posunu ukazatel do bufferu
		exx
		ld	a,d			; vezmu do a pravou část masky
		cpl				; invertuju ji (kdybych ji uložil invertovanou, byl by problém s rotací)
		and	(hl)			; a z pozadí vymažu ty pixely, kde měla maska 0
		or	b			; a do vykousnutého pozadí zaoruju předlohu
		ld	(hl),a			; a nakonec uložím do VRAM
		call	RIGHTL			; spočítej adresu o byte vpravo
		ld	a,(hl)			; celé kreslení provedu ještě jednou pro 2. byte více vpravo
		exx
		ld	(hl),a
		inc	hl
		exx
		ld	a,e
		cpl
		and	(hl)
		or	c
		ld	(hl),a
		pop	hl			; obnov adresu levého bytu ve VRAM
		call	DOWNHL			; spočítej adresu o pixel níž
		pop	bc			; obnov počítadlo
		djnz	ARROW_DRW_1		; a opakuj, dokud nejsou vykresleny všechny mikrořádky šipky
		ret

;------------------------------------------------------------------------------
; CLEAR ARROW - replace sprite with saved background
;------------------------------------------------------------------------------
; clear both cursors, slave first, then master

ARROWS_CLEAR	ld	a,(KMT_MODE)		; only master or master+slave interface?
		or	a
		jr	z,ARROWS_CLEAR_M	; Z = only master
		ld	de,ARROW_BUFFER_S	; address of saved background for master cursor
		ld	hl,(ARROW_ADDR_S)	; get address where slave cursor was painted
		call	ARROW_CLEAR
ARROWS_CLEAR_M	ld	de,ARROW_BUFFER_M	; address of saved background for master cursor
		ld	hl,(ARROW_ADDR_M)	; get address where master cursor was painted


ARROW_CLEAR	ld	b,ARROW_HEIGHT		; height of sprite in pixels
ARROW_CLR_1	ld	a,(de)			; get byte from saved background
		ld	(hl),a			; write to VRAM
		inc	de			; increment DE, next byte of background
		push	hl			; remember HL
		call	RIGHTL			; compute address of right byte
		ld	a,(de)			; get next byte from saved background
		ld	(hl),a			; write to VRAM
		inc	de			; increment DE, next byte of background
		pop	hl			; restore address of left byte in HL
		call	DOWNHL			; compute address by 1 pixel down
		djnz	ARROW_CLR_1		; repeat
		ret

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

RIGHTL		ld	a,l			; RIGHTL zajištuje posun adresy spritu ve
		inc	l			; VRAM o byte vpravo a jeho spravné vykreslení,
		xor	l			; pokud je jeho levá půlka přímo u pravého
		bit	5,a			; okraje obrazovky. V takovém případě se
		ret	z			; pravá půlka kreslí do ROM, takže vlastně
		ld	h,0			; nekreslí / BACHA NA WRITEABLE ROMky!! (nahradit 0 číslem 60,
		ret				; poškodí font)

;==============================================================================
; ARROW graphics
;==============================================================================

ARROW_GRAPHICSM	db	00000000b		; sprite
		db	01000000b
		db	01100000b
		db	01110000b
		db	01111000b
		db	01111100b
		db	01111110b
		db	01111000b
		db	01001100b
		db	00000100b
		db	00000000b

		db	11100000b		; mask, must follow imediatelly after sprite
		db	11110000b
		db	11111000b
		db	11111100b
		db	11111110b
		db	11111111b
		db	11111111b
		db	11111111b
		db	11111110b
		db	11111110b
		db	00001110b

ARROW_GRAPHICSS	db	00000000b		; sprite
		db	01000000b
		db	01100000b
		db	01010000b
		db	01001000b
		db	01000100b
		db	01001110b
		db	01111000b
		db	01001100b
		db	00000100b
		db	00000000b

		db	11100000b		; mask, must follow imediatelly after sprite
		db	11110000b
		db	11111000b
		db	11111100b
		db	11111110b
		db	11111111b
		db	11111111b
		db	11111111b
		db	11111110b
		db	11111110b
		db	00001110b

ARROW_BUFFER_M	ds	ARROW_HEIGHT*2		; buffer for save background under arrow (slave interface)
ARROW_ADDR_M	dw	16384			; address in VRAM where arrow was painted last time
ARROW_SUB_M	db	0			; how much rotates subtract ...
ARROW_X_M	db	128			; coordinates of master cursor
ARROW_Y_M	db	96
ARROW_B_M	db	0			; last state of buttons port

ARROW_BUFFER_S	ds	ARROW_HEIGHT*2		; buffer for save background under arrow (master interface)
ARROW_ADDR_S	dw	16384			; address in VRAM where arrow was painted last time
ARROW_SUB_S	db	0			; how much rotates subtract ...
ARROW_X_S	db	128			; coordinates of slave cursor
ARROW_Y_S	db	96
ARROW_B_S	db	0			; last state of buttons port

;==============================================================================
;  IMPORTANT LIBRARIES
;==============================================================================

		include		"libs/inkey3.za"
CLS		include		"libs/cls_fast.za"
CLS_COL		equ		CLS_FAST_COL
		include		"libs/downhl.za"
		include		"libs/uphl.za"
		include		"libs/beep.za"
		include		"libs/print.za"
		include		"libs/numout.za"
		include		"libs/numout_binary.za"
		include		"libs/pausenk.za"			; pausenk, only for keyboard
		include		"libs/pause0.za"			; pausenk, only for keyboard
		include		"libs/draw_colorbox.za"
		include		"libs/draw_linebox.za"
FONT		binclude	"libs/font_iso8859-2_8x8.bin"		; my very nice font :-)

;==============================================================================
; All texts for potentialy localization are here.

TXT_MAINMENU	db	22,0,0
		db	"KEMPSTON WHEEL MOUSE TESTER 2.0",13
		db	13
		db	"Tester works with Velesoft\'s",13
		db	"KMouse Turbo interface 2008.",13
		db	13
		db	"Select tester mode",13
		db	13
		db	"1 KMouse master or single",13
		db	"2 both KMouse slave + master",13
		db	"3 Kempston joystick test",13
		db	"4 Fuller joystick test",13
		db	"P read test of port #7FFD",13
		db	"R restart HW detection",13
		db	"Q quit - return to ZX BASIC"
		db	22,23,9
		db	"http://cygnus.speccy.cz"
		db	0

TXT_DETECT_LN	db	22,21,0,0				; set print position to "status line"
TXT_DETECT_0	db	"No KMouse interface detected.",0
TXT_DETECT_M	db	"KMouse 2008, master only.",0
TXT_DETECT_S	db	"KMouse 2008, slave only.",0
TXT_DETECT_MS	db	"KMouse 2008, master + slave.",0

TXT_DETECT_MBS	db	22,18,0					; special slave KMouse version for MB02 (slave only)
		db	"MB02 paging port #17 is readable"
		db	0

TXT_DETECT_MBS2	db	22,19,0,0
TXT_DETECT_MBS3	db	" = page ",0
TXT_DETECT_MBS4	db	" writeable ",0				; write enabled
TXT_DETECT_MBS5	db	" read only ",0				; read only
TXT_DETECT_MBS6	db	"SRAM",0				; MB02 SRAM is connected
TXT_DETECT_MBS7	db	"ROM",0					; MB02 ROM is connected
TXT_DETECT_MBS8	db	"NOMEM",0				; MB02 RAM/ROM is not connected
TXT_DETECT_MBS9	db	"HWRESET",0				; MB02 paging port was reseted

TXT_TESTM_INIT	db	22, 0, 0,"AXIS X"
		db	22, 1, 0,"AXIS Y"
		db	22, 0,16,"BUTTONS"
		db	22, 3, 0,"WHEEL"
		db	22, 3,16,"DIRECT."
		db	22, 6, 0,0

TXT_TESTM_X	db	22, 0, 7,0				; axis X value
TXT_TESTM_Y	db	22, 1, 7,0				; axis Y value
TXT_TESTM_B	db	22, 0,24,0				; decadic value readed from buttons port
TXT_TESTM_BB	db	22, 1,24,0				; binary value readed from buttons port
TXT_TESTM_W	db	22, 3, 7,0				; decadic value of wheel
TXT_TESTM_WD	db	22, 3,24,0				; wheel direction when moving

TXT_TESTS_INIT	db	22, 8, 0,"AXIS X"
		db	22, 9, 0,"AXIS Y"
		db	22, 8,16,"BUTTONS"
		db	22,11, 0,"WHEEL"
		db	22,11,16,"DIRECT."
		db	22,14, 0,0

TXT_TESTS_X	db	22, 8, 7,0				; axis X value
TXT_TESTS_Y	db	22, 9, 7,0				; axis Y value
TXT_TESTS_B	db	22, 8,24,0				; decadic value readed from buttons port
TXT_TESTS_BB	db	22, 9,24,0				; binary value readed from buttons port
TXT_TESTS_W	db	22,11, 7,0				; decadic value of wheel
TXT_TESTS_WD	db	22,11,24,0				; wheel direction when moving

TXT_32SP	db	"--------------------------------",0	; text separator

TXT_NOTHING	db	"----",0
TXT_UP		db	"UP  ",0
TXT_DOWN	db	"DOWN",0

TXT_SCRL_AREA_1 db	22,18,0
		db	"        SCROLLABLE AREA",13,13
		db	"       ROTATE MOUSE WHEEL",0

TXT_SCRL_AREA_2 db	22,18,0
		db	"  SCROLL AREA     SCROLL AREA",13,13
		db	"   FOR MASTER      FOR SLAVE",13,13
		db	"     KMOUSE          KMOUSE",0

TXT_JOY_KEMP	db	22,0,0
		db	"Kempston joystick",0

TXT_JOY_FULL	db	22,0,0
		db	"Fuller joystick",0

TXT_JOY_PORT	db	22,2,0,"PORT STATUS ",0
TXT_JOY_DEC	db	22,2,12,0
TXT_JOY_BIN	db	22,3,12,0

TXT_JOY_DIRS	db	22,5,0,0
TXT_JOY_LEFT	db	"LEFT ",13,0
TXT_JOY_RIGHT	db	"RIGHT",13,0
TXT_JOY_UP	db	"UP   ",13,0
TXT_JOY_DOWN	db	"DOWN ",13,0
TXT_JOY_FIRE1	db	"FIRE1",13,0
TXT_JOY_FIRE2	db	"FIRE2",13,0
TXT_JOY_FIRE3	db	"FIRE3",13,0
TXT_JOY_SPACE	db	"     ",13,0

TXT_PORT	db	22,0,0
		db	"Test #7FFD readability",13
		db	13
		db	"This part testing KMouse ports ",13
		db	"#FEDF (master) and #3EDF (slave)"
		db	"where is stored value written to"
		db	"port #7FFD, which isn\'t readable"
		db	"on original ZX Spectrum 128k."
		db	22,8,0						; text when no KMouse detected
		db	"Value   #FEDF   #3EDF",13
		db	0

TXT_PORT_SPACES	db	"     ",0					; 5 spaces between port values

TXT_PRESS_SPACE	db	22,23,0,"Press space for return to menu.",0