This is for a VZ200 (and similar machines) with the Australian hardware mod to enable the use of hi-res graphics. It would need to be patched to work with the German version of the mod.
This is not the current version and it does not use 8 bit increments for the pointers or the 8 bit high font yet.
The design is similar to the 6803 version so see it's notes.
I have looked at implementing a version that will work for the Coleco Adam or MSX machines, but since the CPU must access video RAM via the VDP, it will require maintaining a virtual screen, rendering to a buffer, and then dumping graphics data to the VDP. The single character printing can be dropped since the code must always generate the graphics from the virtual screen buffer 2 characters at a time. That code has been started, but it is nowhere near complete and it is not being worked on at this time.
This is not the current version and it does not use 8 bit increments for the pointers or the 8 bit high font yet.
The design is similar to the 6803 version so see it's notes.
I have looked at implementing a version that will work for the Coleco Adam or MSX machines, but since the CPU must access video RAM via the VDP, it will require maintaining a virtual screen, rendering to a buffer, and then dumping graphics data to the VDP. The single character printing can be dropped since the code must always generate the graphics from the virtual screen buffer 2 characters at a time. That code has been started, but it is nowhere near complete and it is not being worked on at this time.
;************************************************** ;* File: print64.z80 ;************************************************** ;* Copyright (c) 2008-2015 James Diffendaffer ;************************************************** ;* Description: ;* Emulates a 64 character by 24 line text display using ;* 4 bit wide characters on a 256 * 192 graphics display. ;* This version is for the VZ200 and Z80 CPU ;* ;* Contains functions to print a string at the current screen location, ;* print strings @ a specific screen location, line wrapping, scrolling, ;* clear screen, the character generator and a font. ;* Characters are stored with identical data in the left and right nibble ;* to make rendering faster and several loops have been unrolled for speed. ;* The print64 routine has been rewritten and now differs quite a bit from the ;* original spectrum code found on the worldofspectrum forum. ;* The font rendering sequence is smaller and faster. ;************************************************** ;* Version history ;* Version Date Description ;* 2.12 Oct 14, 2015 Updated 64180 code to reflect a change in register usage ;* 2.11 Oct 14, 2015 Added printing 2 characters at a tine and optional 64180/z80 instruction usage ;* 2.10 Sept 30, 2015 changed font rendering code to use XOR. Saves 3 instructions per character pixel height ;* 2.09 Sept 28, 2015 added .VZ file header so batch file can directly build VZ file ;* 2.08 Sept 28, 2015 documentation and code cleanup ;* 2.07 Sept 27, 2015 added background color for cls and scroll, code for inverting RAM/font ;* 2.06 Sept 27, 2015 preliminary changes to use inverse screen color. Font needs inverted for best speed. ;* 2.05 Sept 26, 2015 reintroduced optimization that removed subtracting 32 (space) from the character ;* 2.04 Sept 25, 2015 removed redundant code from print64 and fixed some comments ;* 2.03 Sept 24, 2015 Fixed missing descenders ;* 2.02 Sept 24, 2015 Rewrote print64 routine to use 4 less instructions per byte written to the screen ;* 2.01 Sept 9, 2015 Altered documentation ;* 2.00 Sept 6, 2015 Refactored code to unroll loops, use faster instruction sequences, ;* altered font format to eliminate bit shifting, eliminated some unnecesary code, and fixed a bug ;* 1.04 Feb 15, 2013 Initial running VZ demo ;* 1.00 ?, 2008 Initial port to VZ (exact date unknown)? ;************************************************** ;* definitions to make TASM use more common assembler directives #define EQU .EQU #define ORG .ORG #define RMB .BLOCK #define DEFB .BYTE #define FCC .TEXT #define FDB .WORD #define END .END #define equ .EQU #define org .ORG #define rmb .BLOCK #define defb .BYTE #define fcc .TEXT #define fdb .WORD #define end .END ;if we want to use HD64180/Z180 instructions. Requires using the -x3 command line option on TASM for additional instructions ;#define 64180 1 ;************************************************** ;VZ ROM entry vector addresses ;************************************************** POLCAT equ $FFDC ; Read the keyboard ;************************************************** ;VZ Graphics hardware definitions ;************************************************** ;* VTech VZ200/300/Laser/... constants #define screen 7000h ; address of VZ screen memory #define AUSMOD 1 ; for use with Australian VZ graphics mod ;#define GERMOD 1 ; for use with German VZ graphics mod ;********** ;* info for Australian hi res mod ;********** ;* video RAM $7000-$77FF ;* $6800 Bit 3 of cassette/Speaker/vdg control latch sets hi-res graphics when = 1 ;* Bit 4 = VDG background 128x64 ;* VDG Port is at 32 aka 20h ;* out 32,!00000000 ;text screen page zero ;* bits 0-1 = bank select ;* bits 2-4 = 6847 graphics mode 0-7 ;* bit 5 = internal/external font control, unused in most mods ;********** #ifdef AUSMOD #define vdgport 20h ; I/O port address to set the VDG mode #define vdgcmode 6800h ; address to set color palette and graphics/text select #define vdgcolor0 00000000b ;Color palette settings #define vdgcolor1 00010000b #define CG1 00000000b ; CG1 graphics mode bits #define RG1 00010000b ; RG1 graphics mode bits #define CG2 00001000b ; CG2 graphics mode bits #define RG2 00011000b ; RG2 graphics mode bits #define CG3 00000100b ; CG3 graphics mode bits #define RG3 00010100b ; RG3 graphics mode bits #define CG6 00001100b ; CG6 graphics mode bits #define RG6 00011100b ; RG6 graphics mode bits #define CSS 00010000b ; color set select bit #define GFX 00001000b ; graphics mode select #endif ;********** ;* info for German hi res mod ;********** ;* address 783B bit 1 set enables 256x192 ;* port 222 bit 0-1 = page ;* ;* This code is incomplete ;********** #ifdef GERMOD ;#define vpage 222 #endif ;************************************************** ;* screen parameters ;* ;* Define the graphics mode you are going to use as 1 ;* This is used to set up all the screen parameters used by ;* the graphics routines so they will work in your ;* chosen mode. ;************************************************** #define GFX_RG6 1 ; Set the mode we will use here ;************************************************** ;* sets up the screen parameters based on define above ;************************************************** #ifdef GFX_CG1 ; parameters for CG1 #define CGMODE 1 ScreenWidth equ 64 ScreenHeight equ 64 BytesPerLine equ (ScreenWidth)/4 #endif #ifdef GFX_CG2 ; parameters for CG2 #define CGMODE 1 ScreenWidth equ 128 ScreenHeight equ 64 BytesPerLine equ (ScreenWidth)/4 #endif #ifdef GFX_CG3 ; parameters for CG3 #define CGMODE 1 ScreenWidth equ 128 ScreenHeight equ 96 BytesPerLine equ (ScreenWidth)/4 #endif #ifdef GFX_CG6 ; parameters for CG6 #define CGMODE 1 ScreenWidth equ 128 ScreenHeight equ 192 BytesPerLine equ (ScreenWidth)/4 #endif #ifdef GFX_RG1 ; parameters for RG1 #define RGMODE 1 ScreenWidth equ 128 ScreenHeight equ 64 BytesPerLine equ ((ScreenWidth)/8) #endif #ifdef GFX_RG2 ; parameters for RG2 #define RGMODE 1 ScreenWidth equ 128 ScreenHeight equ 96 BytesPerLine equ ((ScreenWidth)/8) #endif #ifdef GFX_RG3 ; parameters for RG3 #define RGMODE 1 ScreenWidth equ 128 ScreenHeight equ 192 BytesPerLine equ ((ScreenWidth)/8) #endif #ifdef GFX_RG6 ; parameters for RG4 #define RGMODE 1 #define ScreenWidth 256 #define ScreenHeight 192 #define BytesPerLine ((ScreenWidth)/8) #endif #define VidRAMSize 2048 ; size of video RAM window ;BytesPerLine*ScreenHeight ;************************************************** ;* graphics text routine macros ;************************************************** #DEFINE PRINTAT(loc,str) ld bc,loc \ ld hl,str \ call print_at #DEFINE PRINT(str) ld hl,str \ call print #DEFINE SETVDG() out (vdgport),a #DEFINE SetBGColor(color) ld a,color \ ld (BACKGRND),a ;#DEFINE SETVDG(mode,page) ld a,mode+page \ out (vdgport),a #DEFINE InvertFont(font,length) ld hl,font \ ld bc,length \ call invert_mem ;#DEFINE DEMO2 1 ;************************************************** ;************************************************** org $B000-24 ; fcc VCF0 ; file type ID fcc VCF0PRINT64 defb 0,0,0,0,0,0,0,0,0 ; zero padded file name defb 0,$f1 ; checksum? ; fdb endofprog-START, fdb START ; start address START: ; org $B000 ;where to store out program ;************************************************** ;* test code ;************************************************** di ; SetBGColor($ff) ; set the background color SetBGColor($00) ; set the background color call CLS ; clear the screen ; InvertFont(font,fontend-font) ; inverting the bits in our font so we can print black on green ld a,GFX+vdgcolor0 ; set to graphics with color set 0 ld (vdgcmode),a ; set the hardware ld a,RG6 SETVDG() ; set the graphics mode to 256x192 B&W #ifdef DEMO1 PRINTAT(24,string1) ;demo the print routines PRINTAT(8*64+24,string2) PRINTAT(2*8*64+24,string3) neverquit: jr neverquit #endif #ifdef DEMO2 ld hl,sstring neverquit: xor a ;clear a ld (hl),a ; loopy: ld (hl),a call print ld hl,sstring ld a,(hl) inc a cp 96 jr nz,loopy jr neverquit #endif ld a,' ' ; the first character in our font ld hl,TextString ; the address where we will put our text string lll: ld (hl),a ; write the character to the string inc hl ; point to next string address inc a ; increment the character value cp '~'+1 ; last character in the character set? jr nz,lll ; branch if not xor a ; clear a ld (hl),a ; zero terminate the string ; print the string we just built endlessly neverquit: ld hl,TextString call print ; ld hl,version ; string with the current version number ; call print ; print it scan: ; call 2EF4H ;scan the keyboard ; or a ;check to see if a key was pressed ; jr nz,scan ;keep looping as long as it is jr neverquit ret ;version: ; defb " Version 2.07 ",0 #ifdef DEMO1 ;* characters are stored in first byte for demo2 sstring: defb " ",0 #endif #ifdef DEMO2 ;* strings for demo1 string1: defb "Graphics Page 0",0 string2: defb "Graphics Page 1",0 string3: defb "Graphics Page 2",0 #endif ;************************************************** ;************************************************** ;* CLS ;************************************************** ;* clear the graphics screen ;************************************************** CLS: ;set graphics page to 0 ld a,RG6+0 ;RG6 page 0 SETVDG() call zero_fill_screen ;clear page ;set graphics page to 1 ld a,RG6+1 ;RG6 page 1 SETVDG() call zero_fill_screen ;clear page ;set graphics page to 2 ld a,RG6+2 ;RG6 page 2 SETVDG() ;fall through to fill_screen and return directly from there ;************************************************** zero_fill_screen: ld hl,screen ;source ld de,screen+1 ;destination ld bc,VidRAMSize-1 ;number of bytes to clear ; xor a ;clear a ld a,(BACKGRND) ;clear a ld (hl),a ;clear first byte ldir ;clear the rest ret ;************************************************** ;************************************************** ; invert_mem ;************************************************** ; hl contains pointer to RAM to invert ; bc contains number of bytes to invert ;************************************************** invert_mem: nxtaddr: ld a,(hl) ; get original byte cpl ; invert it ld (hl),a ; write it back inc hl ; point to next memory address dec bc ; decrement count ; we have to do this because the Z80 doesn't update cpu flags with the DEC instruction ld a,b ; if b or c has any bits set, the or will set them and the flags will show non-zero or c jr nz,nxtaddr ; go until the counter is zero ret ;************************************************** ;************************************************** ; print_at ;************************************************** ; works like Microsoft BASIC PRINT@ command ; 64 characters by 24 lines in RG6 mode ; print_at locations 0-1535 (64*24-1) ; HL contains string pointer ; BC contains print@ location ; ; Since screen width is 64 (0-63), lowest 6 bits of bc is column ; The next 5 bits are the row ;************************************************** print_at: ld a,c ;get the print at low byte and (BytesPerLine*2)-1 ;111111 ;mask off row bits ld (AT_COL),a ;set the column ld a,b ;get the print at upper byte and %00000111 ;mask off top bits so carry isn't impacted rl c ;rotate top 2 bits into a through the carry rl a rl c rl a ld (AT_ROW),a ;save row ;fall through to print ;************************************************** ; print ;************************************************** ; hl contains the string pointer ;************************************************** print: ld a,(AT_ROW) ld b,0 ; determin what screen memory page we are going to print on and set the hardware ; there are 8 lines of text per page cp 8 jr c,_cnext ; less than? sbc a,8 ; adjust for next page inc b ; for graphics page setting cp 8 jr c,_cnext ; less than? sbc a,8 ; adjust for next page inc b ; for graphics page setting cp 8 jr c,_cnext ; less than? sbc a,8 ; adjust for next page inc b ; for graphics page setting _cnext: ld (AT_IROW),a ; set page row ld a,b ; setup bits for changing graphics page add a,RG6 SETVDG() ; set the hardware _nextchar: ld a,(hl) ; get character cp 0 ; string terminator? jr z,_printexit ; exit if zero (string terminator) ; cp ; carriage return? ; jr z,_creturn ; handle it if so ; cp ; linefeed? ; jr z,_lfeed ; handle it if so ; tab? ; bell? ; home? ; inverse text? ; now calculate screen address and check for 2 character print ld c,a ; save first character ex de,hl ; save string pointer to DE ; IROW is corrected for the screen page by subtracting 8 for each page above 0 by the caller ld a,(AT_IROW) ; get the screen page row adc a,70h ; add screen MSB (from $7000) ld h,a ; save it ld a,(AT_COL) ; get the column rra ; least significant bit only indicates which half of byte character is on ld l,a ; screen address LSB is 0 so just put a in l ld (SCREENPTR),hl ; save the screen pointer ex de,hl ; restore string pointer jr c,onechar0 ; First character is in the right nibble so we only print one character ; 1st character is in the left nibble, now check for two characters inc hl ; point to next character ld a,(hl) ; get next character into A cp 0 ; string terminator? jr z,onechar ; we can only print one character if it's zero ; we can print two characters at once push hl ; save string pointer call print642 ; output 2 characters pop hl ; restore string pointer inc hl ; next char ld a,(AT_COL) ; and 2 to column add a,2 ld (AT_COL),a jr testeol onechar0: inc hl ; point to next character onechar: ; character is in c push hl ; save string pointer call print_64 ; output a character pop hl ; restore string pointer ;update the column ld a,(AT_COL) ; get column inc a ; next colum ld (AT_COL),a ; save it testeol: cp BytesPerLine*2 ; 64 chsrs / line (0-63) jr c,_nextchar ; is column past the end of a line? Keep printing if not. ;wrap the line, update column, row, scroll xor a ; clear a ld (AT_COL),a ; set column to zero _lfeed: ld a,(AT_ROW) ; increment the row inc a ld (AT_ROW),a cp 24 ; (ScreenHeight/8) ;24 lines (0-23) jr c,print ; if row isn't past the end of the screen, we are still worrying about possible page flips dec a ; reduce row back to last line ld (AT_ROW),a ; save it push hl call scroll ; scroll the screen pop hl jr _nextchar ; Once we get here we don't worry about switching pages so skip that code _creturn: xor a ; clear a ld (AT_COL),a ; set column to zero jp print ; keep printing _printexit: ret ;************************************************** ;************************************************** ;* scroll ;************************************************** ;* scroll the paged graphics screen ;************************************************** #define Scrol1() ldi \ ldi \ ldi \ ldi \ ldi \ ldi \ ldi \ ldi \ ldi \ ldi \ ldi \ ldi \ ldi \ ldi \ ldi \ ldi \ ldi \ ldi \ ldi \ ldi \ ldi \ ldi \ ldi \ ldi \ ldi \ ldi \ ldi \ ldi \ ldi \ ldi \ ldi \ ldi scroll: ;*********************** ;scroll page 0 ;*********************** ld a,RG6+0 ;RG6 page 0 SETVDG() call scroll_page ;*********************** ;copy line of characters from page 1 to page 0 ;*********************** ld a,RG6+1 ;RG6 page 1 (source page) SETVDG() ld hl,screen ;copy from source page to buffer ld de,Scroll_Buffer ld bc,BytesPerLine*8 ;1 row of characters 8 bits high ; ldir ;copy one row of text Scrol1() Scrol1() Scrol1() Scrol1() Scrol1() Scrol1() Scrol1() Scrol1() ld a,RG6+0 ;RG6 page 0 (destination page) SETVDG() ld hl,Scroll_Buffer ;copy from buffer to destination page ld de,BytesPerLine*8*7+screen ld bc,BytesPerLine*8 ;1 row of characters 8 bits high ; ldir ;copy one row of text Scrol1() Scrol1() Scrol1() Scrol1() Scrol1() Scrol1() Scrol1() Scrol1() ;*********************** ;scroll page 1 ;*********************** ld a,RG6+1 ;RG6 page 1 (source page) SETVDG() call scroll_page ;*********************** ;copy line of characters from page 2 to page 1 ;*********************** ld a,RG6+2 ;RG6 page 2 (source page) SETVDG() ld hl,screen ;copy from source page to buffer ld de,Scroll_Buffer ld bc,BytesPerLine*8 ;1 row of characters 8 bits high ; ldir ;copy one row of text Scrol1() Scrol1() Scrol1() Scrol1() Scrol1() Scrol1() Scrol1() Scrol1() ld a,RG6+1 ;RG6 page 1 (destination page) SETVDG() ld hl,Scroll_Buffer ;copy from buffer to destination page ld de,BytesPerLine*8*7+screen ;56=8*7 ld bc,BytesPerLine*8 ;1 row of characters 8 bits high ; ldir ;copy one row of text Scrol1() Scrol1() Scrol1() Scrol1() Scrol1() Scrol1() Scrol1() Scrol1() ;*********************** ;scroll page 2 ;*********************** ld a,RG6+2 ;RG6 page 2 SETVDG() call scroll_page ;*********************** ;clear last line ;*********************** ld hl,BytesPerLine*8*7+screen ;BytesPerLine * # of lines per character * 7 lines + screen address ; ld (hl),0 ;store 0 at fist address ld a,(BACKGRND) ; get background color ld (hl),a ;store background color at fist address ld de,BytesPerLine*8*7+1+screen ;ld de,hl+1 ld bc,BytesPerLine*8-1 ;one line minus first byte. ; ldir ;clrloop1 ;copy one row of text Scrol1() Scrol1() Scrol1() Scrol1() Scrol1() Scrol1() Scrol1() Scrol1() ret ;************************************************** scroll_page: ld hl,BytesPerLine*8+screen ;source ;address of 2nd line on page ld de,screen ;destination ;address of 1st line on page ; ld bc,ScreenHeight/3*BytesPerLine - BytesPerLine*8 ;number of rows for 1/3 of the screen -1 (lines on page to be scrolled) ld bc,2048 - 256 ;number of rows for 1/3 of the screen -1 (lines on page to be scrolled) ; ldir scrloop1: ;scroll one row of text Scrol1() Scrol1() Scrol1() Scrol1() Scrol1() Scrol1() Scrol1() Scrol1() jp pe, scrloop1 ret ;************************************************** ;************************************************** ;* 64#4 - 4x8 FONT DRIVER FOR 64 COLUMNS (c) 2007, 2011, 2013 ;************************************************** ;* Original by Andrew Owen (657 bytes) ;* Optimized by Crisis (602 bytes) ;* Reimplemented by Einar Saukas (496 bytes) ;* VZ implementation by James Diffendaffer (424 bytes) ;************************************************** print_64: ; c contains character #ifndef 64180 ld h,0 ld l,c ; now HL = INT(char) ; now do the multiply ld b,h ; ld c,l ; now BC = char add hl,hl ; now HL = 2 * INT(char) add hl,hl ; now HL = 4 * INT(char) add hl,hl ; now HL = 8 * INT(char) sbc hl,bc ; now HL = 7 * INT(char) ex de,hl ; now DE contains 7 * char. #else ld d,7 ; for the multiply by 7 ld e,c ; now DE = INT(char) ; now do the multiply mlt de ; now DE contains 7 * char #endif ld hl,(SCREENPTR) ; get the screen pointer ld a,(AT_COL) ; get the column rra ; least significant bit only indicates which half of byte character is on ex de,hl ; now HL = INT(char) and DE contains screen address. 64180 HL contains 7 * char jr c,RIGHTnibble ; carry is still set or clear from rra above ; Calculate location of the character font data in FONT_ADDR ; Formula: FONT_ADDR + 7 * INT ((char-32)/2) - 1 ;left side ld bc,FONT_ADDRl-224 ;add font address - correct for missing sbc a,' ' add hl,bc ; now hl = FONT_ADDR + 7 * INT(char) ex de,hl ; I have to use de for the font so we can add hl,bc for screen address ld bc,32 ; 32 bytes per line, used to update hl below ; Main loop to copy 8 font bytes into screen (1 blank + 7 from font data) ld a,(BACKGRND) ; first font byte is always background color ld (hl),a ; write background color to screen add hl,bc ; next line ld a,(de) ; store next font byte in A xor (hl) ; combine half screen and half font and 11110000b ; mask half of the font byte xor (hl) ; combine half screen and half font ld (hl),a ; write result back to screen inc de ; next font data location add hl,bc ; next line ld a,(de) ; store next font byte in A xor (hl) ; combine half screen and half font and 11110000b ; mask half of the font byte xor (hl) ; combine half screen and half font ld (hl),a ; write result back to screen inc de ; next font data location add hl,bc ; next line ld a,(de) ; store next font byte in A xor (hl) ; combine half screen and half font and 11110000b ; mask half of the font byte xor (hl) ; combine half screen and half font ld (hl),a ; write result back to screen inc de ; next font data location add hl,bc ; next line ld a,(de) ; store next font byte in A xor (hl) ; combine half screen and half font and 11110000b ; mask half of the font byte xor (hl) ; combine half screen and half font ld (hl),a ; write result back to screen inc de ; next font data location add hl,bc ; next line ld a,(de) ; store next font byte in A xor (hl) ; combine half screen and half font and 11110000b ; mask half of the font byte xor (hl) ; combine half screen and half font ld (hl),a ; write result back to screen inc de ; next font data location add hl,bc ; next line ld a,(de) ; store next font byte in A xor (hl) ; combine half screen and half font and 11110000b ; mask half of the font byte xor (hl) ; combine half screen and half font ld (hl),a ; write result back to screen inc de ; next font data location add hl,bc ; next line ld a,(de) ; store next font byte in A xor (hl) ; combine half screen and half font and 11110000b ; mask half of the font byte xor (hl) ; combine half screen and half font ld (hl),a ; write result back to screen ; inc de ; next font data location ; add hl,bc ; next line ret ;************************************************** RIGHTnibble: ;right side ld bc,FONT_ADDRr-224 ;add font address - correct for missing sbc a,' ' add hl,bc ; now hl = FONT_ADDR + 7 * INT(char) ex de,hl ; I have to use de for the font so we can add hl,bc for screen address ld bc,32 ; 32 bytes per line, used to update hl below ; Main loop to copy 8 font bytes into screen (1 blank + 7 from font data) ld a,(BACKGRND) ; first font byte is always background color ld (hl),a ; write background color to screen add hl,bc ; next line ld a,(de) ; store next font byte in A xor (hl) ; combine half screen and half font and 00001111b ; mask half of the font byte xor (hl) ; combine half screen and half font ld (hl),a ; write result back to screen inc de ; next font data location add hl,bc ; next line ld a,(de) ; store next font byte in A xor (hl) ; combine half screen and half font and 00001111b ; mask half of the font byte xor (hl) ; combine half screen and half font ld (hl),a ; write result back to screen inc de ; next font data location add hl,bc ; next line ld a,(de) ; store next font byte in A xor (hl) ; combine half screen and half font and 00001111b ; mask half of the font byte xor (hl) ; combine half screen and half font ld (hl),a ; write result back to screen inc de ; next font data location add hl,bc ; next line ld a,(de) ; store next font byte in A xor (hl) ; combine half screen and half font and 00001111b ; mask half of the font byte xor (hl) ; combine half screen and half font ld (hl),a ; write result back to screen inc de ; next font data location add hl,bc ; next line ld a,(de) ; store next font byte in A xor (hl) ; combine half screen and half font and 00001111b ; mask half of the font byte xor (hl) ; combine half screen and half font ld (hl),a ; write result back to screen inc de ; next font data location add hl,bc ; next line ld a,(de) ; store next font byte in A xor (hl) ; combine half screen and half font and 00001111b ; mask half of the font byte xor (hl) ; combine half screen and half font ld (hl),a ; write result back to screen inc de ; next font data location add hl,bc ; next line ld a,(de) ; store next font byte in A xor (hl) ; combine half screen and half font and 00001111b ; mask half of the font byte xor (hl) ; combine half screen and half font ld (hl),a ; write result back to screen ; inc de ; next font data location ; add hl,bc ; next line ret ;************************************************** ; write two characters at once ;************************************************** print642: #ifndef 64180 ; C contains left character, A contains right character ld b,0 ; ld c,a ; now BC = INT(char) ; inc hl ; ld a,(hl) ; get 2nd character before HL gets changed ; Calculate location of the first character font data in FONT_ADDR ; Formula: FONT_ADDR + 7 * INT ((char-32)/2) - 1 ld h,b ld l,c ; now HL = char add hl,hl ; now HL = 2 * INT(char) add hl,hl ; now HL = 4 * INT(char) add hl,hl ; now HL = 8 * INT(char) sbc hl,bc ; now HL = 7 * INT(char) ld bc,FONT_ADDRl-224 ;add font address - correct for missing sbc a,' ' add hl,bc ; now hl = FONT_ADDR + 7 * INT(char) ex de,hl ; use DE for first character data pointer ; Calculate location of the second character font data in FONT_ADDR ; Formula: FONT_ADDR + 7 * INT ((char-32)/2) - 1 ld h,0 ld l,a ; now HL = INT(char) ld b,h ld c,l ; now BC = char add hl,hl ; now HL = 2 * INT(char) add hl,hl ; now HL = 4 * INT(char) add hl,hl ; now HL = 8 * INT(char) sbc hl,bc ; now HL = 7 * INT(char) ld bc,FONT_ADDRr-224 ;add font address - correct for missing sbc a,' ' add hl,bc ; now hl = FONT_ADDR + 7 * INT(char) HL is now 2nd character data pointer #else ; C contains left character, A contains right character ld d,7 ; for the multiply by 7 ld e,c ; left character ; inc hl ; point to next character ; ld a,(hl) ; get right character before we change HL ld h,d ; for the multiply by 7 ld l,a ; right character mlt DE ; multiply the left character by 7 mlt HL ; multiply the right character by 7 ld bc,FONT_ADDRr-224 ; get the right nibble adjusted font address add hl,bc ; add it to HL ex de,hl ; put it in DE so we can us HL again ld bc,FONT_ADDRl-224 ; get the left nibble adjusted font address add hl,bc ; add it to HL ; ex de,hl ; Code works without this, just remember DE and HL have been reversed from Z80 code #endif ;set up the screen pointers ld ix,(SCREENPTR) ld iy,(SCREENPTR) ld bc,128 ; Index offsets only go to 127(?) so IY must be 128 greater than IX. add iy,bc ;start printing ld a,(BACKGRND) ; first font byte is always background color ;; ld a,(de) ; get byte of 1st char ;; add a,(hl) ; get byte of 2nd char ld (IX+0),a ; write result back to screen ;; inc de ; next font1 data location ;; inc hl ; next font2 data location ld a,(de) ; get byte of 1st char add a,(hl) ; get byte of 2nd char ld (IX+32),a ; write result back to screen inc de ; next font1 data location inc hl ; next font2 data location ld a,(de) ; get byte of 1st char add a,(hl) ; get byte of 2nd char ld (IX+64),a ; write result back to screen inc de ; next font1 data location inc hl ; next font2 data location ld a,(de) ; get byte of 1st char add a,(hl) ; get byte of 2nd char ld (IX+96),a ; write result back to screen inc de ; next font1 data location inc hl ; next font2 data location ld a,(de) ; get byte of 1st char add a,(hl) ; get byte of 2nd char ld (IY+0),a ; write result back to screen inc de ; next font1 data location inc hl ; next font2 data location ld a,(de) ; get byte of 1st char add a,(hl) ; get byte of 2nd char ld (IY+32),a ; write result back to screen inc de ; next font1 data location inc hl ; next font2 data location ld a,(de) ; get byte of 1st char add a,(hl) ; get byte of 2nd char ld (IY+64),a ; write result back to screen inc de ; next font1 data location inc hl ; next font2 data location ld a,(de) ; get byte of 1st char add a,(hl) ; get byte of 2nd char ld (IY+96),a ; write result back to screen ret ;************************************************** ; LOCAL VARIABLES ;************************************************** AT_COL: defb 0 ; current column position (0-31) AT_ROW: defb 0 ; current row position (0-23) AT_IROW: defb 0 ; row on graphics page ;,70h ;70h is upper byte of screen address BACKGRND: defb 0 ; background color (set to $00 or $FF) SCREENPTR: fdb 0 ;************************************************** ; HALF WIDTH 4x8 FONT designed by Andrew Owen ; Top row is always zero and not stored (96 chars x 7 / 2 = 336 bytes) ;************************************************** ;************************************************** ; HALF WIDTH 4x8 FONT ; Top row is always zero and not stored (336 bytes) ; characters are 4 bits wide and 7 bits high ; (the top row is always blank) ;************************************************** .MODULE Font font: FONT_ADDRl: defb $00, $00, $00, $00, $00, $00, $00 ; defb $20, $20, $20, $20, $00, $20, $00 ;! defb $50, $50, $00, $00, $00, $00, $00 ;" defb $20, $70, $20, $20, $70, $20, $00 ;# defb $20, $70, $60, $30, $70, $20, $00 ;$ defb $50, $10, $20, $20, $40, $50, $00 ;% defb $20, $40, $30, $50, $50, $30, $00 ;& defb $20, $20, $00, $00, $00, $00, $00 ;' defb $10, $20, $40, $40, $40, $20, $10 ;( defb $40, $20, $10, $10, $10, $20, $40 ;) defb $20, $70, $20, $50, $00, $00, $00 ;* defb $00, $00, $20, $70, $20, $00, $00 ;+ defb $00, $00, $00, $00, $00, $20, $20 ;, defb $00, $00, $00, $70, $00, $00, $00 ;- defb $00, $00, $00, $00, $00, $10, $00 ;. defb $10, $10, $20, $20, $40, $40, $00 ;/ defb $20, $50, $50, $50, $50, $20, $00 ;0 defb $20, $60, $20, $20, $20, $70, $00 ;1 defb $20, $50, $10, $20, $40, $70, $00 ;2 defb $70, $10, $20, $10, $50, $20, $00 ;3 defb $50, $50, $50, $70, $10, $10, $00 ;4 defb $70, $40, $60, $10, $50, $20, $00 ;5 defb $10, $20, $60, $50, $50, $20, $00 ;6 defb $70, $10, $10, $20, $20, $20, $00 ;7 defb $20, $50, $20, $50, $50, $20, $00 ;8 defb $20, $50, $50, $30, $20, $40, $00 ;9 defb $00, $00, $20, $00, $00, $20, $00 ;: defb $00, $00, $20, $00, $00, $20, $20 ;; defb $00, $10, $20, $40, $20, $10, $00 ;< defb $00, $00, $70, $00, $70, $00, $00 ;= defb $00, $40, $20, $10, $20, $40, $00 ;> defb $20, $50, $10, $20, $00, $20, $00 ;? defb $20, $50, $70, $70, $40, $30, $00 ;@ defb $30, $50, $50, $70, $50, $50, $00 ;A defb $60, $50, $60, $50, $50, $60, $00 ;B defb $30, $40, $40, $40, $40, $30, $00 ;C defb $60, $50, $50, $50, $50, $60, $00 ;D defb $70, $40, $60, $40, $40, $70, $00 ;E defb $70, $40, $60, $40, $40, $40, $00 ;F defb $30, $40, $40, $50, $50, $30, $00 ;G defb $50, $50, $70, $50, $50, $50, $00 ;H defb $70, $20, $20, $20, $20, $70, $00 ;I defb $30, $10, $10, $50, $50, $20, $00 ;J defb $50, $50, $60, $50, $50, $50, $00 ;K defb $40, $40, $40, $40, $40, $70, $00 ;L defb $50, $70, $50, $50, $50, $50, $00 ;M defb $60, $50, $50, $50, $50, $50, $00 ;N defb $20, $50, $50, $50, $50, $20, $00 ;O defb $60, $50, $50, $60, $40, $40, $00 ;P defb $20, $50, $50, $50, $50, $30, $00 ;Q defb $60, $50, $50, $60, $50, $50, $00 ;R defb $30, $40, $20, $10, $50, $20, $00 ;S defb $70, $20, $20, $20, $20, $20, $00 ;T defb $50, $50, $50, $50, $50, $20, $00 ;U defb $50, $50, $50, $50, $20, $20, $00 ;V defb $50, $50, $50, $50, $70, $50, $00 ;W defb $50, $50, $20, $20, $50, $50, $00 ;X defb $50, $50, $50, $20, $20, $20, $00 ;Y defb $70, $10, $20, $20, $40, $70, $00 ;Z defb $30, $20, $20, $20, $20, $20, $30 ;[ defb $40, $40, $20, $20, $10, $10, $00 ;\ defb $60, $20, $20, $20, $20, $20, $60 ;] defb $20, $50, $00, $00, $00, $00, $00 ;^ defb $00, $00, $00, $00, $00, $00, $F0 ;_ defb $20, $10, $00, $00, $00, $00, $00 ;£ defb $00, $00, $30, $50, $50, $30, $00 ;a defb $40, $40, $60, $50, $50, $60, $00 ;b defb $00, $00, $30, $40, $40, $30, $00 ;c defb $10, $10, $30, $50, $50, $30, $00 ;d defb $00, $00, $20, $50, $60, $30, $00 ;e defb $10, $20, $70, $20, $20, $40, $00 ;f defb $00, $00, $30, $50, $50, $30, $60 ;g defb $40, $40, $60, $50, $50, $50, $00 ;h defb $20, $00, $60, $20, $20, $70, $00 ;i defb $10, $00, $30, $10, $10, $50, $20 ;j defb $40, $40, $50, $60, $50, $50, $00 ;k defb $60, $20, $20, $20, $20, $70, $00 ;l defb $00, $00, $50, $70, $50, $50, $00 ;m defb $00, $00, $60, $50, $50, $50, $00 ;n defb $00, $00, $20, $50, $50, $20, $00 ;o defb $00, $00, $60, $50, $50, $60, $40 ;p defb $00, $00, $30, $50, $50, $30, $10 ;q defb $00, $00, $50, $60, $40, $40, $00 ;r defb $00, $00, $30, $60, $30, $60, $00 ;s defb $00, $20, $70, $20, $20, $10, $00 ;t defb $00, $00, $50, $50, $50, $20, $00 ;u defb $00, $00, $50, $50, $20, $20, $00 ;v defb $00, $00, $50, $50, $70, $50, $00 ;w defb $00, $00, $50, $20, $20, $50, $00 ;x defb $00, $00, $50, $50, $50, $30, $60 ;y defb $00, $00, $70, $30, $60, $70, $00 ;z defb $10, $20, $20, $40, $20, $20, $10 ;{ defb $20, $20, $20, $20, $20, $20, $00 ;| defb $40, $20, $20, $10, $20, $20, $40 ;} defb $50, $a0, $00, $00, $00, $00, $00 ;~ defb $60, $90, $60, $40, $60, $90, $60 ;© FONT_ADDRr: defb $00, $00, $00, $00, $00, $00, $00 ; defb $02, $02, $02, $02, $00, $02, $00 ;! defb $05, $05, $00, $00, $00, $00, $00 ;" defb $02, $07, $02, $02, $07, $02, $00 ;# defb $02, $07, $06, $03, $07, $02, $00 ;$ defb $05, $01, $02, $02, $04, $05, $00 ;% defb $02, $04, $03, $05, $05, $03, $00 ;& defb $02, $02, $00, $00, $00, $00, $00 ;' defb $01, $02, $04, $04, $04, $02, $01 ;( defb $04, $02, $01, $01, $01, $02, $04 ;) defb $02, $07, $02, $05, $00, $00, $00 ;* defb $00, $00, $02, $07, $02, $00, $00 ;+ defb $00, $00, $00, $00, $00, $02, $02 ;, defb $00, $00, $00, $07, $00, $00, $00 ;- defb $00, $00, $00, $00, $00, $01, $00 ;. defb $01, $01, $02, $02, $04, $04, $00 ;/ defb $02, $05, $05, $05, $05, $02, $00 ;0 defb $02, $06, $02, $02, $02, $07, $00 ;1 defb $02, $05, $01, $02, $04, $07, $00 ;2 defb $07, $01, $02, $01, $05, $02, $00 ;3 defb $05, $05, $05, $07, $01, $01, $00 ;4 defb $07, $04, $06, $01, $05, $02, $00 ;5 defb $01, $02, $06, $05, $05, $02, $00 ;6 defb $07, $01, $01, $02, $02, $02, $00 ;7 defb $02, $05, $02, $05, $05, $02, $00 ;8 defb $02, $05, $05, $03, $02, $04, $00 ;9 defb $00, $00, $02, $00, $00, $02, $00 ;: defb $00, $00, $02, $00, $00, $02, $02 ;; defb $00, $01, $02, $04, $02, $01, $00 ;< defb $00, $00, $07, $00, $07, $00, $00 ;= defb $00, $04, $02, $01, $02, $04, $00 ;> defb $02, $05, $01, $02, $00, $02, $00 ;? defb $02, $05, $07, $07, $04, $03, $00 ;@ defb $03, $05, $05, $07, $05, $05, $00 ;A defb $06, $05, $06, $05, $05, $06, $00 ;B defb $03, $04, $04, $04, $04, $03, $00 ;C defb $06, $05, $05, $05, $05, $06, $00 ;D defb $07, $04, $06, $04, $04, $07, $00 ;E defb $07, $04, $06, $04, $04, $04, $00 ;F defb $03, $04, $04, $05, $05, $03, $00 ;G defb $05, $05, $07, $05, $05, $05, $00 ;H defb $07, $02, $02, $02, $02, $07, $00 ;I defb $03, $01, $01, $05, $05, $02, $00 ;J defb $05, $05, $06, $05, $05, $05, $00 ;K defb $04, $04, $04, $04, $04, $07, $00 ;L defb $05, $07, $05, $05, $05, $05, $00 ;M defb $06, $05, $05, $05, $05, $05, $00 ;N defb $02, $05, $05, $05, $05, $02, $00 ;O defb $06, $05, $05, $06, $04, $04, $00 ;P defb $02, $05, $05, $05, $05, $03, $00 ;Q defb $06, $05, $05, $06, $05, $05, $00 ;R defb $03, $04, $02, $01, $05, $02, $00 ;S defb $07, $02, $02, $02, $02, $02, $00 ;T defb $05, $05, $05, $05, $05, $02, $00 ;U defb $05, $05, $05, $05, $02, $02, $00 ;V defb $05, $05, $05, $05, $07, $05, $00 ;W defb $05, $05, $02, $02, $05, $05, $00 ;X defb $05, $05, $05, $02, $02, $02, $00 ;Y defb $07, $01, $02, $02, $04, $07, $00 ;Z defb $03, $02, $02, $02, $02, $02, $03 ;[ defb $04, $04, $02, $02, $01, $01, $00 ;\ defb $06, $02, $02, $02, $02, $02, $06 ;] defb $02, $05, $00, $00, $00, $00, $00 ;^ defb $00, $00, $00, $00, $00, $00, $0f ;_ defb $02, $01, $00, $00, $00, $00, $00 ;£ defb $00, $00, $03, $05, $05, $03, $00 ;a defb $04, $04, $06, $05, $05, $06, $00 ;b defb $00, $00, $03, $04, $04, $03, $00 ;c defb $01, $01, $03, $05, $05, $03, $00 ;d defb $00, $00, $02, $05, $06, $03, $00 ;e defb $01, $02, $07, $02, $02, $04, $00 ;f defb $00, $00, $03, $05, $05, $03, $06 ;g defb $04, $04, $06, $05, $05, $05, $00 ;h defb $02, $00, $06, $02, $02, $07, $00 ;i defb $01, $00, $03, $01, $01, $05, $02 ;j defb $04, $04, $05, $06, $05, $05, $00 ;k defb $06, $02, $02, $02, $02, $07, $00 ;l defb $00, $00, $05, $07, $05, $05, $00 ;m defb $00, $00, $06, $05, $05, $05, $00 ;n defb $00, $00, $02, $05, $05, $02, $00 ;o defb $00, $00, $06, $05, $05, $06, $04 ;p defb $00, $00, $03, $05, $05, $03, $01 ;q defb $00, $00, $05, $06, $04, $04, $00 ;r defb $00, $00, $03, $06, $03, $06, $00 ;s defb $00, $02, $07, $02, $02, $01, $00 ;t defb $00, $00, $05, $05, $05, $02, $00 ;u defb $00, $00, $05, $05, $02, $02, $00 ;v defb $00, $00, $05, $05, $07, $05, $00 ;w defb $00, $00, $05, $02, $02, $05, $00 ;x defb $00, $00, $05, $05, $05, $03, $06 ;y defb $00, $00, $07, $03, $06, $07, $00 ;z defb $01, $02, $02, $04, $02, $02, $01 ;{ defb $02, $02, $02, $02, $02, $02, $00 ;| defb $04, $02, $02, $01, $02, $02, $04 ;} defb $05, $0a, $00, $00, $00, $00, $00 ;~ defb $06, $09, $06, $04, $06, $09, $06 ;© fontend: curchar: defb 0 endofprog: TextString: rmb 256 ;************************************************** ; Determine where temporary buffer for the screen scroll will lie ;************************************************** Scroll_Buffer: rmb BytesPerLine*8 ; temporary buffer for copying across page boundary ;************************************************** end ;************************************************** ;**************************************************
No comments:
Post a Comment