;; This example will show how you can distort the screen horizontally
;; using register 2 of the CRTC (Horizontal Sync Position).
;;
;; This example re-programs the Horizontal Sync Position on every scan-line
;; for a part of the display.

;;---------------------------------------------
;; NOTE: code position is not important.
org &8000
nolist

.set_scr_mode equ &bc0e
.scr_initialise equ &bbff
.txt_output equ &bb5a
.scr_set_border equ &bc38
.mc_wait_flyback equ &bd19

;;----------------------------------------------
;; setup a screen display so the effect is obvious

;; reset colours to their default values
call set_scr_mode

;; set screen mode
ld a,1
call scr_set_mode

;; set border to black
ld bc,0
call scr_set_border

;; wait for colours to be set by firmware
call mc_wait_flyback
call mc_wait_flyback

;; display the character set on the screen
ld a,'A'				;; initial character to display
ld bc,40*24				;; number of characters to write
.dcs1
push af
call txt_output			;; write character to screen and update
						;; text coordinates
pop af
inc a					;; increment character value
cp 'Z'+1				;; end of character range?
jr nz,dcs2
ld a,'A'				;; reset to start of range
.dcs2
dec bc					;; update character counter
ld a,b
or c
jr nz,dcs1				;; loop to display more characters


;; from here we can't use the firmware functions because this will effect
;; timing. Now we must use direct hardware access.

;;---------------------------------------------
;; initialisation

;; setup interrupt handler
;;
;; The interrupts are used to synchronise with the CRTC and the display.
;; This simple interrupt handler will always execute in the same time.
;;

di					;; disable interrupts
ld hl,&c9fb			;; install interrupt handler (EI:RET)
ld (&0038),hl		;; (&0038 is IM1 interrupt vector)
ei					;; enable interrupts

;; setup initial Horizontal Sync Position.
;;
;; This will define the Horizontal Sync Position for the first
;; frame of this example. The Horizontal Sync Position for subsequent
;; frames is defined within the program loop itself.
ld bc,&bc02
out (c),c
ld bc,&bd00+46
out (c),c

;;---------------------------------------------
;; program loop

.main_loop

;; wait for start of vsync. This test assumes the vsync
;; is not already active.
ld b,&f5
.ml1
in a,(c)
rra
jr nc,ml1

;; wait for a position within visible part of display
halt

halt

halt

;; these define a delay which is used to synchronise the program with 
;; the CRTC and the display.
defs 64-46
defs 64-3-4-3-2-1

;;
;; select CRTC register 2 (Horizontal Sync Position)
;; 
;; all register writes to the CRTC will not effect this
;; register.
ld bc,&bc02					
out (c),c
inc b						;; B = &BD (I/O address for CRTC register write)

ld hl,table					;; start of table of horizontal sync values
ld e,end_table-table		;; number of horizontal sync values
.l1
ld a,(hl)					;; get byte from table (horizontal sync position)
out (c),a					;; write to CRTC
inc hl						;; increment position in table

defs 64-2-4-2-1-3			;; This defines a delay so that the
							;; next CRTC register write occurs
							;; at the same horizontal position on the next
							;; scan-line

dec e						;; decrement loop counter
jp nz,l1					;; loop if there are more bytes to write


;; restore horizontal sync position
;; to default value (default is value assigned by firmware)
ld bc,&bc02
out (c),c
ld bc,&bd00+46
out (c),c

jp main_loop

;; the table of horizontal sync positions
.table
defb 46
defb 47
defb 48
defb 49
defb 50
defb 51
defb 52
defb 53
defb 54
defb 55
defb 56
defb 55
defb 54
defb 53
defb 52
defb 51
defb 50
defb 49
defb 48
defb 47
defb 46
.end_table

;; end of example