;;---------------------------------------------
;;
;; screen is split into 2 sections
;; 
;;
;; screen is 39 char lines tall, 25 for main area, rest for "border".
;; we need 1 char line effectively for the scroll, (and we take this away from the border area).
;; this is split into 2 areas, one added at the end of the "border" region, and one added at the end
;; of the main region, setup so they always both add to 8 scanlines so that the vsync in the bottom 
;; section is always at the same position.
;; these 2 areas are defined using CRTC register R5.
;; 

;; top and bottom are the same section wrapped around.
;; bottom section wraps to the top, and has a vsync triggered in the middle of it.

;; 8 lines per char
;; 
;; top section is: 6 char lines tall (6*8 = 48 scan lines)
;; R5!=0 here
;;
;; - interrupt occurs at 2nd line within this block. 
;; Next one happens 52 lines later at scanline 54. Potential that 7 additional lines are added.

;; main section is 25 char lines tall (25 * 8 = 200 scanlines)
;; R5!=0 here

;; bottom section is: 7 char lines tall (7*8 = 56 scan lines)
;; R5 = 0 here

org &4000
nolist

scr_set_mode equ &bc0e
txt_output equ &bb5a
start:

ld a,2
call scr_set_mode

ld bc,24*80
ld d,' '
l2:
inc d
ld a,d
cp &7f
jr nz,no_char_reset
ld d,' '
no_char_reset:
ld a,d
call txt_output
dec bc
ld a,b
or c
jr nz,l2

di
im 1
ld a,&c3
ld hl,int_handler1
ld (&0038),a
ld (&0039),hl
ld bc,&bc07
out (c),c
ld bc,&bd00+7
out (c),c
call vsync_sync
ld bc,&bc04
out (c),c
ld bc,&bd00+14-1-1
out (c),c
ei

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

loop1:
ld b,&f5
l1:
in a,(c)
rra
jr nc,l1
call check_keys

ld a,(scroll_adjustment)
add a,&f5
ld (hsync2),a

ld a,1
ld (fetch_values),a




loop5:
loop2:
halt
halt
halt
jp loop1


;; check if a key has been pressed and perform action if it has
check_keys:
;; we scan the keyboard using the hardware directly
;;
;; we do this because we have turned off firmware interrupts (so firmware
;; can't scan it for us)
;; 
;; we turned off the firmware interrupts because our effect is updated every frame

;; update keyboard state
call scan_keyboard

;; f8
ld a,(matrix_buffer+1)
bit 3,a
jp nz,scroll_up
;; f2
ld a,(matrix_buffer+1)
bit 6,a
jp nz,scroll_down
;; f4
ld a,(matrix_buffer+2)
bit 4,a
jp nz,scroll_left
;; f6
ld a,(matrix_buffer+0)
bit 4,a
jp nz,scroll_right
;; f7
ld a,(matrix_buffer+1)
bit 2,a
jp nz,scroll_up_left
;; f9
ld a,(matrix_buffer+0)
bit 3,a
jp nz,scroll_up_right
;; f1
ld a,(matrix_buffer+1)
bit 5,a
jp nz,scroll_down_left
;; f3
ld a,(matrix_buffer+0)
bit 5,a
jp nz,scroll_down_right
ret

scroll_down_right:
ld c,1
call scroll_down
call scroll_right
ret


scroll_down_left:
ld c,1
call scroll_down
call scroll_left
ret


scroll_up_left:
ld c,1
call scroll_up
call scroll_left
ret

scroll_up_right:
ld c,1
call scroll_up
call scroll_right
ret


scroll_adjustment:
defb 0

scroll_right:
ld a,(scroll_adjustment)
xor 1					
ld (scroll_adjustment),a
cp 1
ret z

ld hl,(scrl2)
inc hl
ld a,h
and &3
or &30
ld h,a
ld (scrl2),hl
ret


scroll_left:
ld a,(scroll_adjustment)
xor 1					
ld (scroll_adjustment),a
or a
ret z

ld hl,(scrl2)
dec hl
ld a,h
and &3
or &30
ld h,a
ld (scrl2),hl
ret
;;---------------------------------------------

;; update these seperate of display
scroll_down:
ld a,(vscrl_line2)
inc a
and &7
ld (vscrl_line2),a
cp 7
ret nz
ld hl,(scrl2)
ld bc,40
add hl,bc
ld a,h
and &3
or &30
ld h,a
ld (scrl2),hl
ret
scroll_down2:
and &7
ld (vscrl_line2),a
ret


;; update these seperate of display
scroll_up:
ld a,(vscrl_line2)
dec a
and &7
ld (vscrl_line2),a
or a
ret nz
ld hl,(scrl2)
or a
ld bc,40
sbc hl,bc
ld a,h
and &3
or &30
ld h,a
ld (scrl2),hl
ret

vsync_sync:
ld b,&f5
vs1:
in a,(c)
rra
jr nc,vs1
vs2:
in a,(c)
rra
jr c,vs2
ret

;;-----------------------------------------------------------------------------
;; this is called 2 lines after the vsync starts.
;; vsync occurs on char line 7
;;
;; +2
;; +52
;; +52 -> 106

;; 7 lines until end of end of block = 56 lines
;; + 8 max. = 64

;; 106-64 = 42 lines/8 = 5 lines
;; next int is 10 lines before end
;; next after that is 

int_handler1:
push bc
push hl
push af


;; make vsync position no longer reachable
ld bc,&bc07
out (c),c
ld bc,&bdff
out (c),c

ld bc,&bc03
out (c),c
inc b
ld a,(hsync)
out (c),a

;; add some lines after to do vertical scroll
ld bc,&bc05
out (c),c
inc b
ld a,(vscrl_line)
neg
add a,8
out (c),a

ld hl,int_handler2
ld (&0039),hl
pop af
pop hl
pop bc
ei
ret

;; not used, still in top part
int_handler2:
push hl
ld bc,&bc0c
out (c),c
ld hl,(scrl)
inc b
out (c),h
ld bc,&bc0d
out (c),c
inc b
out (c),l
ld bc,&bc01
out (c),c
ld bc,&bd00+40
out (c),c
ld hl,int_handler3
ld (&0039),hl
pop hl
ei
ret

;; this is
int_handler3:
push bc
push hl
push af
;; set height of this area
ld bc,&bc04
out (c),c
ld bc,&bd00+25-1
out (c),c

;; set scroll after
ld bc,&bc05
out (c),c
inc b
ld a,(vscrl_line)
out (c),a

ld hl,int_handler4
ld (&0039),hl
pop af
pop hl
pop bc
ei
ret


int_handler4:
push hl
ld hl,int_handler5
ld (&0039),hl
pop hl
ei
ret


int_handler5:
push hl

ld hl,int_handler6
ld (&0039),hl
pop hl
ei
ret

int_handler6:
push bc
push hl
push af

;; turn off border for bottom bit...
ld bc,&bc01
out (c),c
ld bc,&bd00
out (c),c

;; 39-25 = 14

;; set height of this area
ld bc,&bc04
out (c),c
ld bc,&bd00+14-1-1
out (c),c

;; this can't be on first char line
ld bc,&bc07
out (c),c
ld bc,&bd00+7
out (c),c
ld hl,int_handler1
ld (&0039),hl

ld a,(fetch_values)
or a
jr z,int_handler1a
;; refresh display versions
ld a,(vscrl_line2)
ld (vscrl_line),a
ld hl,(scrl2)
ld (scrl),hl
ld a,(hsync2)
ld (hsync),a
xor a
ld (fetch_values),a

int_handler1a:

pop af
pop hl
pop bc
ei
ret

fetch_values:
defb 0

hsync:
defb &85

hsync2:
defb &85

scrl2:
defw &3000

vscrl_line2:
defb 0

vscrl_line:
defb 0

scrl:
defw &3000


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

scan_keyboard:
;; store old keyboard state
ld hl,matrix_buffer
ld de,old_matrix_buffer
ld bc,10
ldir

;; get new keyboard state
ld hl,matrix_buffer        ; buffer to store matrix data

ld bc,&f40e                ; write PSG register index (14) to PPI port A (databus to PSG)
out (c),c

ld b,&f6
in a,(c)
and &30
ld c,a

or &C0                     ; bit 7=bit 6=1 (PSG operation: write register index)
out (c),a                  ; set PSG operation -> select PSG register 14

;; at this point PSG will have register 14 selected.
;; any read/write operation to the PSG will act on this register.
out (c),c                  ; bit 7=bit 6=0 (PSG operation: inactive)

inc b
ld a,&92
out (c),a                  ; write PPI control: port A: input, port B: input, port C upper: output
                           ; port C lower: output
push bc
set 6,c                    ; bit 7=0, bit 6=1 (PSG operation: read register data)

scan_key:
ld b,&f6 
out (c),c                 ;set matrix line & set PSG operation

ld b,&f4                  ;PPI port A (databus to/from PSG)
in a,(c)                  ;get matrix line data from PSG register 14

cpl                       ;invert data: 1->0, 0->1
                          ;if a key/joystick button is pressed bit will be "1"
                          ;keys that are not pressed will be "0"

ld (hl),a                 ;write line data to buffer
inc hl                    ;update position in buffer
inc c                     ;update line

ld a,c
and &0f
cp &0a                    ;scanned all rows?
jr nz,scan_key            ;no loop and get next row

;; scanned all rows
pop bc

ld a,&82                  ;write PPI Control: Port A: Output, Port B: Input, Port C upper: output, Port C lower: output.
out (c),a

dec b
out (c),c                 ;set PSG operation: bit7=0, bit 6=0 (PSG operation: inactive)
ret

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

;; This buffer has one byte per keyboard line. 
;; Each byte defines a single keyboard line, which defines 
;; the state for up to 8 keys.
;;
;; A bit in a byte will be '1' if the corresponding key 
;; is pressed, '0' if the key is not pressed.
matrix_buffer:
defs 10

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

old_matrix_buffer:
defs 10


end