;; This example shows the normal position of the cpc's 300Hz interrupt.
;; (i.e. the interrupt hasn't been delay)
;;
;; We use a fast ticker so we can show the most accurate position.
;;
;;
;; In Winape:
;; Reset cpc
;; Open assembler
;; New file
;; Copy and paste this code into the window
;; Assemble
;; In CPC window type:
;; CALL &8000



;; firmware functions we use in this example
.kl_new_fast_ticker equ &bce0
.mc_wait_flyback    equ &bd19
.kl_del_fast_ticker equ &bce6
.km_test_key 		equ &bb1e
.mc_set_inks		equ &bd25
.scr_set_mode		equ &bc0e
.txt_output			equ &bb5a
.txt_set_cursor	equ &bb75

org &8000

.start
ld a,2
call scr_set_mode

;; prevent firmware setting colours
;; and stop flicker at the top of screen which is caused by this
ld a,&c9
ld (mc_set_inks),a

ld hl,message
call print_msg

call set_vsync_pos
call set_hsync_pos
call set_vdisp
call set_hdisp
call calc_ram_size
;; synchronise our ticker interrupt with the vsync       
call mc_wait_flyback
halt
halt
call mc_wait_flyback


ld a,6
ld (ticker_counter),a
ld hl,colours
ld (current_colour_pointer),hl

;; install interrupt
ld hl,ticker_event_block
ld b,%11000001				;; near address, express asynchronous event
ld c,&80					;; rom select 
ld de,ticker_function
call kl_new_fast_ticker


mainloop:
call mc_wait_flyback
call check_keys
jp c,quit_to_basic
halt
halt
jp mainloop

;; check if a key has been pressed and perform action if it has
check_keys:
ld a,0					;; cursor up
call km_test_key
jp nz,do_up
ld a,2					;; cursor down
call km_test_key
jp nz,do_down
ld a,8					;; cursor left
call km_test_key
jp nz,do_left
ld a,1					;; cursor right
call km_test_key
jp nz,do_right
ld a,47					;; space
call km_test_key
ret z
scf
ret

print_msg:
ld a,(hl)
inc hl
or a
ret z
call txt_output
jr print_msg



do_up:
bit 7,c
jr nz,make_shorter

ld a,(vsync_pos)
inc a
ld (vsync_pos),a


call set_vsync_pos

or a
ret

make_shorter:
ld a,(vdisp)
dec a
ld (vdisp),a

call set_vdisp

or a
ret

make_taller:
ld a,(vdisp)
inc a
ld (vdisp),a

call set_vdisp

or a
ret


.do_down
bit 7,c
jr nz,make_taller

ld a,(vsync_pos)
dec a
ld (vsync_pos),a

call set_vsync_pos

or a
ret

.do_left
bit 7,c
jr nz,make_thinner

ld a,(hsync_pos)
inc a
ld (hsync_pos),a

call set_hsync_pos
or a
ret

.make_thinner
ld a,(hdisp)
dec a
ld (hdisp),a

call set_hdisp
or a
ret


.do_right
bit 7,c
jr nz,make_fatter

ld a,(hsync_pos)
dec a
ld (hsync_pos),a

call set_hsync_pos
or a
ret

.make_fatter
ld a,(hdisp)
inc a
ld (hdisp),a

call set_hdisp
or a
ret


.set_vsync_pos
ld h,1
ld l,2
call txt_set_cursor
ld a,'&'
call txt_output
ld a,(vsync_pos)
call print_hex
ld bc,&bc07
out (c),c
ld a,(vsync_pos)
inc b
out (c),a
ret


.set_hsync_pos
ld h,1
ld l,4
call txt_set_cursor
ld a,'&'
call txt_output
ld a,(hsync_pos)
call print_hex
ld bc,&bc02
out (c),c
ld a,(hsync_pos)
inc b
out (c),a
ret


.set_vdisp
ld h,1
ld l,6
call txt_set_cursor
ld a,'&'
call txt_output
ld a,(vdisp)
call print_hex
ld bc,&bc06
out (c),c
ld a,(vdisp)
inc b
out (c),a

call calc_ram_size

ret


.set_hdisp
ld h,1
ld l,8
call txt_set_cursor
ld a,'&'
call txt_output
ld a,(hdisp)
call print_hex
ld bc,&bc01
out (c),c
ld a,(hdisp)
inc b
out (c),a

call calc_ram_size

ret


.vsync_pos defb 30
.hsync_pos defb 30
.vdisp defb 25
.hdisp defb 40

.quit_to_basic
ld hl,ticker_event_block
call kl_del_fast_ticker
ret


;; this is initialised by
;; the firmware; holds runtime state of ticker interrupt
.ticker_event_block
defs 10

;; this is the function called each 1/300th of a second
.ticker_function
push af
push hl
;;push bc
;; The 1/300th of a second interrupt effectively splits
;; the screen into 6 sections of equal height. Each section
;; spans the entire width of the screen.
;;
;; We want to ensure that the effect is stationary so we reset
;; every 6 calls of this function. We need to ensure we are synced with vsync in
;; order that this works correctly.
ld a,(ticker_counter)
dec a
ld (ticker_counter),a
or a
jr nz,ticker_function2
ld a,6
ld (ticker_counter),a
ld hl,colours
ld (current_colour_pointer),hl

.ticker_function2

;; get pointer to current mode
ld hl,(current_colour_pointer)
;; get the mode

;; Select border
ld bc,&7f10			;; 
out (c),c			;; 
;; Set colour for border
ld a,(hl)			;; read colour from table
out (c),a			;; set colour

;; update pointer
inc hl
;; store pointer
ld (current_colour_pointer),hl

;; ensure express asynchronous event is retriggered correctly
;; see SOFT968
ld hl,ticker_event_block+2
ld (hl),#00
;;pop bc
pop hl
pop af
ret
 

print_hex:
push af
rrca
rrca
rrca
rrca
call print_hex_digit
pop af
.print_hex_digit
and &f
cp 10
jr nc,print_hex_digit2
add a,'0'
jp txt_output
print_hex_digit2:
add a,'A'-10
jp txt_output

calc_ram_size:
ld h,1
ld l,13
call txt_set_cursor

ld a,(hdisp)
ld l,a
ld h,0
;; x2 to convert hdisp into bytes
add hl,hl
ld a,(vdisp)
call mul16

;; scanlines per char line
add hl,hl
add hl,hl
add hl,hl

push hl
ld a,'&'
call txt_output

ld a,h
call print_hex
pop hl
ld a,l
call print_hex
ret


;; HL = value				(e.g. 1
;; A = multiplier (not 0)
mul16:
ld e,l
ld d,h

mul16a:
dec a
ret z
add hl,de
jr mul16a

  
message:
defb 31,1,1,"Vsync Position (CRTC Register 7):"
defb 31,1,3,"Hsync Position (CRTC Register 2):"
defb 31,1,5,"Vertical Displayed (CRTC Register 6):"
defb 31,1,7,"Horizontal Displayed (CRTC Register 1):"
defb 31,1,12,"RAM used (approx):"
defb 31,1,20,"up/down cursor key (no shift): Change vsync pos",10,13
defb "left/right cursor key (no shift): Change hsync pos",10,13
defb "up/down cursor key (shift): Change height",10,13
defb "left/right cursor key (shift): Change width",10,13
defb 0
  

.ticker_counter defb 0

.current_colour_pointer defw colours

;; colours for each split

.colours
defb &43		;; pastel yellow
defb &40		;; white
defb &54		;; black
defb &4b		;; bright white
defb &45		;; purple
defb &51		;; yellow