;; This example shows how to draw chars to the screen in mode 2
;; using the OS/firmware pixel data from the ROM.
;; 
;; this example is for mode 2
;;
;; This code can't be in the range &0000-&3fff because it
;; activates the lower rom in this range.


scr_base equ &c000
scr_height equ 200
chars_width equ 8
chars_height equ 25
scr_set_mode equ &bc0e

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

org &4000

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

start:

;; disable interrupts so firmware doesn't take control
;; also shows we don't use firmware for our functions
di

;; set mode 2
;; lower and upper rom disabled
ld bc,&7f00+%10001110
out (c),c

;; initialise screen address table used for calculating position to draw chars
call make_scr_table

;; set char coordinates
ld h,10
ld l,10
call set_char_coords

ld hl,message
call print_msg

;; and loop forever
end_loop:
jp end_loop


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

message: 
defb "This is a text drawing test using mode 2 and OS rom char data",0

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

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

;;--------------------------------------------------------------------------------------------
;; H = X char coord (0-79)
;; L = Y char coord (0-24)
;; origin is top-left 0,0

set_char_coords:
ld a,h
ld (x_coord),a
ld a,l
ld (y_coord),a
scc2:
ld a,l
;; X = byte/char coordinate
;; multiply Y by 8 to get line
add a,a				;; x2
add a,a				;; x4
add a,a				;; x8
ld l,a				;;
call calc_scr_addr
ld (char_scr_addr),hl
ret

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

char_scr_addr:
defw 0

x_coord:
defb 0
y_coord:
defb 0

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

;; update x and y coordinate to move to right
;; if we get to end of the line, go to start of next line
;; if we go past last char, wrap back to start
go_right:
ld a,(x_coord)
inc a
ld (x_coord),a
cp chars_width
ret nz
xor a
ld (x_coord),a
ld a,(y_coord)
inc a
ld (y_coord),a
cp chars_height
ret nz
xor a
ld (y_coord),a
ret

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

;; update char coords and recalc screen address
go_char_right:
call go_right
ld a,(x_coord)
ld h,a
ld a,(y_coord)
ld l,a
call scc2
ret


;;--------------------------------------------------------------------------------------------
;; IN:
;; h = x byte coord
;; l = y line coord
;; OUT: 
;; HL = screen coordinate

calc_scr_addr:
push bc
push de
ld c,h
ld h,0
add hl,hl
ld de,scr_table
add hl,de
ld a,(hl)
inc hl
ld h,(hl)
ld l,a
ld b,0
add hl,bc
pop de
pop bc
ret

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

scr_table:
defs 400

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

make_scr_table:
ld ix,scr_table
ld hl,scr_base			;; screen base
ld b,scr_height			;; height in lines
.st1 ld (ix+0),l
ld (ix+1),h
inc ix
inc ix
call scr_next_line
djnz st1
ret

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

scr_next_line:
ld a,h
add a,8
ld h,a
ld a,h
and &38
ret nz
ld a,l
add a,&50
ld l,a
ld a,h
adc a,&c0
ld h,a
ret

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

;; A = char to display
print_char:
push hl
push de
push bc

;; page in lower rom
;; bit 1,0: mode (mode 2)
;; bit 2: lower rom enable
;; bit 3: upper rom disable
;;


;; get addr for char pixel data
;;
;; each char is 8 bytes. One byte per line.
;; each bit is a single pixel and we can
;; plot this directly to the screen for mode 2.
;;
;; The OS converts the pixel data at runtime for mode 1 and mode 0.
;;
;; The OS stores char 0 to char 255.
;;
;; a = char
ld l,a
ld h,0
add hl,hl					;; x2
add hl,hl					;; x4
add hl,hl					;; x8
ld de,&3800					;; address of font in OS rom
							;; char 0
							
add hl,de
ex de,hl
;; DE = char pixel data

ld hl,(char_scr_addr)
;; HL = screen address


;; lower rom readable between &0000-&3fff
ld bc,&7f00+%10001010
out (c),c


;; print entire char 
ld b,8
print_char_line:
;; do one line
ld a,(de)
ld (hl),a
;; update pixel pointer
inc de
;; update screen pointer
call scr_next_line
djnz print_char_line

;; disable lower rom
;; mode 2, upper rom disabled
ld bc,&7f00+%10001110
out (c),c


;; now update coords for next char
call go_char_right


pop bc
pop de
pop hl
ret

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

;;end start