;;---------------------------------------------
;;
;; 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