;; This code shows how to patch the firmware so that you can use your own char drawing functions with it. ;; The font is a 6 pixel wide font and only works in mode 1. ;; ;; We patch: ;; - TXT SET PEN - so we can define pen colour of our font using "PEN" from BASIC ;; - TXT SET PAPER - so we can define background colour of our font using "PAPER" from BASIC ;; - TXT WRITE CHAR - so we can draw chars on the screen using "PRINT" and also they are drawn using the built in "line editor" ;; ;; We use TXT GET PEN, TXT GET PAPER to get current pen and paper so we can setup our colours for our drawing code. ;; ;; Bugs: ;; - Cursor position is wrong. ;; - Cursor colour is wrong. ;; - BASIC insists on a 40 char wide screen. Not sure how to fix yet. ;; ;; Limitations: ;; - Our font doesn't have lower case chars, we look for those and convert to upper case ;; ;; The pixel data is defined in mode 2 (2 colours, 1 bit per pixel) ;; This is converted at runtime to mode 1 format (4 colours, 2 bits per pixel) ;; And then drawn to the screen ;; ;; The code does some screen pixel manipulate to draw and mask the chars onto the screen. ;; ;; org &4000 nolist ;; nibbles swapped! pen0 equ %00000000 pen1 equ %00001000 pen2 equ %10000000 pen3 equ %10001000 ;; aaaa aabb bbbb cccc ccdd dddd eeee eeff ffff ;; 0 1 2 3 4 5 6 7 8 ;; 0->0 ;; 1->1 ;; 2->3 ;; 3->4 ;; 4->6 ;; 5->7 ;; 6->9 ;;txt_output equ &bb5a ;;txt_set_cursor equ &bb75 txt_set_pen equ &bb90 txt_set_paper equ &bb96 txt_write_char equ &bdd3 scr_char_position equ &bc1a scr_next_line equ &bc26 scr_char_limits equ &bc17 txt_get_pen equ &bb93 txt_get_paper equ &bb99 txt_draw_cursor equ &bdcd txt_undraw_cursor equ &bdd0 ;;txt_ask_state start: ;;ld a,&c3 ;;ld (txt_output),a ;;ld hl,display_char ;;ld (txt_output+1),hl ld a,&c3 ld hl,display_cursor ld (txt_draw_cursor),a ld (txt_draw_cursor+1),hl ld (txt_undraw_cursor),a ld (txt_undraw_cursor+1),hl ld hl,scr_char_position ld de,old_scr_char_position ld bc,3 ldir ld a,&c3 ld (scr_char_position),a ld hl,our_scr_char_position ld (scr_char_position+1),a ld a,&c3 ld (scr_char_limits),a ld hl,our_scr_char_limits ld (scr_char_limits+1),hl ;;ld hl,txt_set_cursor ;;ld de,old_txt_set_cursor ;;ld bc,3 ;;ldir ;;ld a,&c3 ;;ld (txt_set_cursor),a ;;ld hl,set_txt_coord ;;ld (txt_set_cursor+1),hl ld hl,txt_set_pen ld de,old_txt_set_pen ld bc,3 ldir ld a,&c3 ld (txt_set_pen),a ld hl,set_txt_pen ld (txt_set_pen+1),hl ld hl,txt_set_paper ld de,old_txt_set_paper ld bc,3 ldir ld a,&c3 ld (txt_set_paper),a ld hl,set_txt_paper ld (txt_set_paper+1),hl ld a,&c3 ld (txt_write_char),a ld hl,display_char_wr ld (txt_write_char+1),hl call txt_get_pen call txt_set_pen call txt_get_paper call txt_set_paper ret our_scr_char_limits: ld b,53 ;; 53 chars accross ld c,25 ;; 25 chars down ret old_scr_char_position: defs 3 working_coords: defw 0 our_scr_char_position: ld (working_coords),hl ld h,0 call old_scr_char_position ld a,(working_coords+1) srl a ld c,a add a,a ;; x2 add a,c ;; x3 ld c,a ld a,(working_coords+1) and &1 add a,c add a,l ld l,a ld a,h adc a,0 ld h,a ret ;; A = char ;; H = x ;; L = y display_char_wr: ld (txt_coords),hl jp display_char ;;ld h,0 ;;ld l,1 ;;call set_txt_coord ;;ld h,pen0 ;;ld l,pen1 ;;call set_txt_colours ld hl,message call display_message l1: jp l1 display_message: ld a,(hl) inc hl or a ret z call display_char jr display_message message: defb "THIS IS A TEST",0 ;; each char is 6 mode 1 pixels wide and 8 mode 1 pixels tall ;; in mode 1, each byte uses 4 pixels ;; so this means that each char uses 2 bytes, with the last 2 pixels of each line are unused. ;; this is done for simplicity. ;; ;; this means each char is 2 bytes wide and 8 bytes tall ;; to work out screen address to draw char to ;; ;; byte 0 byte 2 byte 3 byte 4 byte 5 ;; 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 ;; first char uses pixels 0,1,2,3,4,5 ;; second char uses pixels 6,7,8,9,10,11 ;; third char uses 12,13,14,15, 16, 17 ;; even/odd x coord display_char: push hl push de push bc ;; work out location of pixel data ;; 1 bit per pixel font used here cp 'a' jr c,display_char3 cp 'z'+1 jr nc,display_char3 and &df display_char3: sub ' ' ld l,a ld h,0 add hl,hl add hl,hl add hl,hl ld de,font add hl,de ;; convert from 1 bit per pixel to 2 bit per pixel call depack_char ;; x coord, remove bit 0, and multiply by 3 ;; 0->0 ;; 2->3 ;; 4->6 ld h,0 ld a,(txt_y) ld l,a call old_scr_char_position ld a,(txt_x) srl a ld c,a add a,a ;; x2 add a,c ;; x3 ld c,a ld a,(txt_x) and &1 add a,c add a,l ld l,a ld a,h adc a,0 ld h,a ;; now display char in appropiate location ld de,char_depack_buffer ex de,hl call display_char2 ;; increment text coord position ld hl,txt_x inc (hl) pop bc pop de pop hl ret display_cursor: call txt_ask_state and &3 ret nz push hl push de push bc ;; x coord, remove bit 0, and multiply by 3 ;; 0->0 ;; 2->3 ;; 4->6 ld h,0 ld a,(txt_y) ld l,a call old_scr_char_position ld a,(txt_x) srl a ld c,a add a,a ;; x2 add a,c ;; x3 ld c,a ld a,(txt_x) and &1 add a,c add a,l ld l,a ld a,h adc a,0 ld h,a ex de,hl call display_cursor2 pop bc pop de pop hl ret display_char2: ld a,(txt_x) and 1 jp nz,display_char_odd jp display_char_even display_cursor2: ld a,(txt_x) and 1 jp nz,display_cursor_odd jp display_cursor_even ;; H = x coord ;; L = y coord set_txt_coord: ld (txt_coords),hl old_txt_set_cursor: defs 3 lookup_pen: add a,pen_table AND 255 ld l,a ld a,pen_table/256 adc a,0 ld h,a ld a,(hl) ret pen_table: defb pen0 defb pen1 defb pen2 defb pen3 set_txt_pen: push af call lookup_pen ld (fg_color+1),a pop af old_txt_set_pen: defs 3 set_txt_paper: push af call lookup_pen ld (bk_color+1),a pop af old_txt_set_paper: defs 3 ;; convert 1-bit per pixel into 2 bit per pixel depack_char: ld b,8 ld de,char_depack_buffer depack_char2: push bc ld c,(hl) call depack_byte call depack_byte inc hl pop bc djnz depack_char2 ret ;; take 4x 1 bit per pixel from one byte and write out 4 2-bit per pixels to one byte depack_byte: xor a call depack_pixel call depack_pixel call depack_pixel call depack_pixel ld (de),a inc de ret depack_pixel: call depack_pix or b rlca ret depack_pix: ;; shift into carry rlc c bk_color: ld b,pen0 ret nc fg_color: ld b,pen1 ret txt_coords: txt_y: defb 0 txt_x: defb 0 ;; in this example B is the odd char ;; on screen: ;; ;; aaaa aabb bbbb ;; 0 1 2 ;; ;; pixels from char: ;; bbbb bb display_char_odd: ld b,8 dco1: push bc push de ;; read 4 pixels from screen ;; keep left 2 pixels ld a,(de) and %11001100 ld c,a ;; read font data ;; shift data two pixels to right ld a,(hl) rrca rrca and %00110011 ;; combine with screen or c ld (de),a inc de ld a,(hl) rlca rlca and %11001100 ld c,a inc hl ld a,(hl) rrca rrca and %00110011 or c ld (de),a inc hl pop de ex de,hl call scr_next_line ex de,hl pop bc djnz dco1 ret ;; in this example B is the odd char ;; on screen: ;; ;; aaaa aabb bbbb ;; 0 1 2 ;; ;; pixels from char: ;; bbbb bb display_cursor_odd: ld b,8 dcuo1: push bc ld a,(de) xor %00110011 ld (de),a inc de ld a,(de) cpl ld (de),a dec de ex de,hl call scr_next_line ex de,hl pop bc djnz dcuo1 ret ;; in this example A is the even char ;; on screen: ;; ;; aaaa aabb bbbb ;; 0 1 2 ;; ;; pixels from char: ;; aaaa aa display_char_even: ld b,8 dce1: push bc push de ;; read 4 pixels ld a,(hl) ;; store to screen ld (de),a inc de inc hl ;; read 4 pixels from screen ld a,(de) ;; isolate the pixels we don't want to change and %00110011 ld c,a ;; now read 4 pixels from font ld a,(hl) ;; isolate pixels we want and %11001100 ;; combine with screen data or c ;; write back to screen ld (de),a ;;inc de inc hl pop de ex de,hl call scr_next_line ex de,hl pop bc djnz dce1 ret display_cursor_even: ld b,8 dcue1: push bc ld a,(de) cpl ld (de),a inc de ld a,(de) xor %11001100 ld (de),a dec de ex de,hl call scr_next_line ex de,hl pop bc djnz dcue1 ret char_depack_buffer: defs 16 font: defb &00 defb &00,&00,&00,&00,&00,&00,&00,&00,&10,&10,&10,&10,&00,&10,&00,&00 defb &28,&28,&00,&00,&00,&00,&00,&00,&28,&7c,&28,&28,&7c,&28,&00,&00 defb &10,&7c,&50,&7c,&14,&7c,&10,&60,&64,&08,&10,&20,&4c,&0c,&00,&10 defb &28,&28,&30,&54,&48,&34,&00,&10,&10,&20,&00,&00,&00,&00,&00,&08 defb &10,&20,&20,&20,&10,&08,&00,&20,&10,&08,&08,&08,&10,&20,&00,&00 defb &00,&28,&10,&7c,&10,&28,&00,&00,&00,&10,&10,&7c,&10,&10,&00,&00 defb &00,&00,&00,&00,&20,&20,&40,&00,&00,&00,&00,&7c,&00,&00,&00,&00 defb &00,&00,&00,&00,&30,&30,&00,&00,&00,&04,&08,&10,&20,&40,&00,&00 defb &38,&4c,&54,&54,&64,&38,&00,&00,&30,&50,&10,&10,&10,&7c,&00,&00 defb &38,&44,&04,&38,&40,&7c,&00,&00,&38,&44,&18,&04,&44,&38,&00,&00 defb &08,&18,&28,&48,&7c,&08,&00,&00,&7c,&40,&78,&04,&44,&38,&00,&00 defb &38,&40,&78,&44,&44,&38,&00,&00,&7c,&04,&08,&10,&20,&20,&00,&00 defb &38,&44,&38,&44,&44,&38,&00,&00,&38,&44,&44,&3c,&04,&38,&00,&00 defb &00,&00,&20,&00,&00,&20,&00,&00,&00,&10,&00,&00,&10,&10,&20,&00 defb &00,&08,&10,&20,&10,&08,&00,&00,&00,&00,&7c,&00,&7c,&00,&00,&00 defb &00,&20,&10,&08,&10,&20,&00,&00,&38,&44,&08,&10,&00,&10,&00,&70 defb &00,&70,&48,&48,&48,&48,&00,&00,&38,&44,&44,&7c,&44,&44,&00,&00 defb &78,&44,&78,&44,&44,&78,&00,&00,&38,&44,&40,&40,&44,&38,&00,&00 defb &78,&24,&24,&24,&24,&78,&00,&00,&7c,&40,&78,&40,&40,&7c,&00,&00 defb &7c,&40,&78,&40,&40,&40,&00,&00,&38,&44,&40,&4c,&44,&38,&00,&00 defb &44,&44,&7c,&44,&44,&44,&00,&00,&38,&10,&10,&10,&10,&38,&00,&00 defb &04,&04,&04,&44,&44,&38,&00,&00,&48,&50,&60,&50,&48,&44,&00,&00 defb &40,&40,&40,&40,&40,&7c,&00,&00,&44,&6c,&54,&44,&44,&44,&00,&00 defb &44,&64,&54,&4c,&44,&44,&00,&00,&38,&44,&44,&44,&44,&38,&00,&00 defb &78,&44,&44,&78,&40,&40,&00,&00,&38,&44,&44,&54,&48,&34,&00,&00 defb &78,&44,&44,&78,&48,&44,&00,&00,&38,&40,&38,&04,&44,&38,&00,&00 defb &7c,&10,&10,&10,&10,&10,&00,&00,&44,&44,&44,&44,&44,&38,&00,&00 defb &44,&44,&44,&44,&28,&10,&00,&00,&44,&44,&44,&44,&54,&28,&00,&00 defb &44,&28,&10,&10,&28,&44,&00,&00,&44,&44,&28,&10,&10,&10,&00,&00 defb &7c,&08,&10,&20,&40,&7c,&00,&00 list