Getting the default MSX font pattern

In the last article, we learned how to modify a single character from the original MSX font type, and we also found out the differences between Screen 0 and Screen 1 character, but now what we want to do is to create our own personal font type as artsy as possible. Fancy!

Before we start designing our character pattern, I thought “wouldn’t be nice to have the original pattern so we could see what we are actually doing?”. Sure I’m no professional font designer, and the best I can do is to stretch some vowels and add some curves at the consonants, and for that, I definitely need to have the original character showing on the screen for reference.

Where do the character fonts come from?

Now there is something I’ve always taken for granted and never imagined that would be something noticeable, but every computer comes with a pre-defined font pattern stored somewhere, otherwise, it wouldn’t print anything readable on the screen.

On an MSX machine, as stated on the MSX.org wiki page, the font pattern is copied from the main ROM to the VRAM every time we invoke the Screen routine to set the screen mode, replacing any pattern currently stored at the VRAM. While on Screen 0 (40×24 text mode) the pattern occupies 2 KB of VRAM from 0800H to 0FFFH, and on Screen 1 (32×24 text mode) the pattern also uses 2 KB of VRAM from 0000H to 07FFH, and this information is important because we are about to copy the pattern from the address defined by the video mode to the RAM, so we can print the patterns in the screen and do some cool stuff with that.

It took me quite some time to figure out what I should do to move the pattern data between MSXPen and TinySprite since these are the two tools I rather use in my Chromebook when I do my research. There are several other tools out there that run on Windows, Linux, macOS, and even in real MSX machines, but I want to avoid anything that cannot be promptly used from the browser, and I even may create some online tools in the future to make things easier but that’s something for another day.

At first, I created this code that copies the data from the address 0x8*49 (Pattern for the character 0) to the RAM, then uses the bit command to compare each bit from the bytes of the pattern and print “0” or “1” based on the result from the command, and it’s important to notice that we aren’t storing the results in any other place than the actual screen. Using the MSXWeb emulator from the MSXPen site we can press the “alt+c” key combination to copy the screen content to the clipboard (yep, I’m that old, and yep, it’s the actual name of this function) so then we can paste it in a text file.

Alt+c copies the text from the screen on the MSX web emulator

The code with the usual comments is the following:

CHGMOD:		equ 0x005f		;BIOS call to change the screen mode
CHPUT:		equ 0x00a2		;Prints the contents points by A on the screen
CLS:		equ 0x00C3		;Clear the screen. call XOR A before to clean up the Zero flag 
ERAFNK:		equ 0x00CC		;Remove the function keys from the screen
CHGET:		equ 0x009F		;Wait for a key to be pressed 
LDIRMV:		equ 0x0059		;Copies A blocks from the address HL of the VRAM into address DE in RAM
            
		org 0xc000		; Storing the program at page 3
        
main:
		ld a,1			;We set the screen mode 1 loading the value into A
		call CHGMOD		;then we call CHGMOD to change the video mode
		call ERAFNK		;Removing the function keys so it's not copied through alt+c
		ld hl,0x8*49		;Loading into HL the position for the first pattern. Each pattern uses 8 bytes
					;so we multiply 8 by the inicial character pattern at position 49 = 0
		ld de,font		;Load into DE the position where the VRAM pattern will be copied
 	       ld bc,8*74		;We want 74 characters copied, from 0 through "z"
	        call LDIRMV		;Calls the routine to copy data from VRAM to RAM
	        ld hl,font		;We load the address defined for "font" into HL 
	        ld bc,74		;then we set the counter on BC for the main loop 
	        ld d,49			;and store in D the value for the first character (0) to print later
		call loop		;Calling the main loop
	        ret			;then returning to BASIC when BD decreases to 0
loop:   
		push BC			;Let's send BC to the stack
		push DE			;followed by DE
		XOR A			;This should reset the Zero flag
		CALL CLS		;so we can call CLS to clear the screen
		ld b,8			;Loading 8 into B to iterate on each bytes of the character pattern 
		pop DE			;Let's bring DE back from the stack
		ld a,";"		;Load the character ";"into A
		call CHPUT		;then print it before printing the current character being shown
		ld a,d			;Get the value from D and load into A
		call CHPUT		;and print it, which corresponds to the letter being iterated ahead
		inc d			;We decrease D
		ld a,"\r"		;Load the ASCII code for return into A
		call CHPUT		;Then print it to return to the start of the line
		ld a,"\n"		;next we load the ASCII code for new line into A
		call CHPUT		;then print it, moving the cursor to the new line below
		call iterate		;Calls the iterate routine that prints the pattern as binary
		call CHGET		;Waits for a key to be pressed after printing the pattern of each letter
		POP BC			;Brings back BC from the stack
		dec BC			;Decrements BC
		LD A,C			;Loads C into A
		OR B 			;And excutes A OR B
		JR NZ,loop		;While the zero flag is not raised repeats the loop
		ret			;Returns to the main routine

iterate:			;This routine probably can be improved using shift operations
				;but to keep things simple to understand I left it as it is
		bit 7,(hl)		;Reads the first bit from the byte pointed by HL
		call z,zero		;and calls the zero routine if the result is zero
		call nz,one		;otherwise calls the one routine
		bit 6,(hl)		;Same thing but with the next bit
		call z,zero		;so we repeat the whole process
		call nz,one      	;on every bit from the by pointed by HL
		bit 5,(hl)		;and call the proper routine to print
		call z,zero		;the ASCII character related to the value
		call nz,one		
		bit 4,(hl)
		call z,zero
		call nz,one	
		bit 3,(hl)
		call z,zero
		call nz,one
		bit 2,(hl)
		call z,zero
		call nz,one
		bit 1,(hl)
		call z,zero
		call nz,one
		bit 0,(hl)
		call z,zero
		call nz,one
		ld a,"\n"		;After the last bit is checked we add a new line
		call CHPUT		;and print it
		ld a,"\r"		;then we add a carriage return
		call CHPUT		;and aso print it
		inc hl			;Increase HL to get the next byte
		djnz iterate		;And do this until B reaches 0
		ld a,"\n"		;At the end of the iteration we add another new line
		call CHPUT		;and print it
		RET			;returning to the loop routine
zero:
		ld a,"0"		;We load the ASCII character "0" into A
		call CHPUT		;then print it
		RET			;and return to the caller from the iterate routine
one:
		ld a,"1"		;We load he ASCII character "1" into A
		call CHPUT		;then print it
		RET			;abd return to the caller from the iterate routine

font:
		DB 0			;Initial value of font
		end main		;This ends the program as required by the MSXPen code parser

In the end, this resulted in a pretty simple and functional program but very limited use, unless you are looking to use a text editor to create your font patterns in binary.

But, can we make something better?

Of course, we can! We need to transfer the original font patterns from the WebMSX emulator to the TinySprite tool, and the binary format is not useful for this requirement.

The TinySprite tool allows us to import pattern designs through two different methods:

  1. Using the “Load Backup” button and pasting the backup in the widget field

Notice that the tool uses a proprietary backup format that, although being in text mode, needs to follow the proper parameters otherwise it will result in garbage being loaded into the slots. This is how a TinySprite backup looks like:

TinySprite backup format

The header describes the sprite type (MSX1/MSX2), the name of the slot (0123 for this example), then we have the pattern where dots are empty/transparent spaces and the numbers are related to the color used by the pixel at the positions.

The Export Sprites and Load Backup are the options available to provide data persistence on the tool, since every time the site is closed or even reloaded all content is lost. Don’t say I didn’t warn you about that!

  1. Use the “Import DATA into Slot”

This option is available through the last icon from the right side of the Slots field, the one with the arrow pointing down to a bunch of pages that look like a continuous form paper from the days of yore:

The “Slots” field

This one is really useful since we can load patterns into a single slot, and it’s what we will use to transfer the data from the WebMSX output, but it has some limitations. I couldn’t load any data using binary format into the slots, and the only format that worked for me was in hexadecimal, so this is what I’m going to use here.

It took me quite some time to figure out what would be the best way to transform my requirements into a useful code. I tried to do some crazy stuff like storing the values in the RAM then changing the screen mode back to 40×24 text mode, then writing the data on a device, and then showing the information one character at a time, but in the end, I finally came with a solution that delivered what I needed quite well! The best thing is that I could find a complete assembly code that transforms decimal values into hexadecimal, and this saved me a lot of time, to be honest! Thank God for StackOverflow!

Here is the code that prints all patterns for the characters between the number 0 through the lower case letter “z”:

; bios call to print a character on screen
CHGMOD:		equ 0x005f		;Changes the screen mode
WRTVRM: 	equ 0x004d		;Grava na VRAM no endereco HL o conteudo de A
CHPUT:  	equ 0x00a2		;Imprime o conteudo de A na tela
LDIRMV:		equ 0x0059		;Copies A blocks from the address HL of the VRAM into address DE in RAM
ERAFNK: 	equ 0x00CC		;Removes the function key from the screen
LINL32:		equ 0xF3AF		;Width for SCREEN 1 (default 29)
CHGET: 		equ 0x009F		;Waits for a key to be pressed
CLS: 		equ 0x00C3		;Clear screen. Requires Zero flag to be set, so XOR A should do the trick

		org 0xD000		;Lets store the program at page 3

start:
		ld hl,LINL32		;We are changing the screen width in mode 1 
		ld (hl),32		;by setting the value 32 at the address opinterd 
		ld a,1			;then loading 1 into register A
		call CHGMOD		;and calling CHGMOD routine
       		call ERAFNK		;Lets remove the function keys from the screen so it's not copied along with the data
        	ld hl,0x8*48		;We will copy the data from the VRAM from the 48th character (0), so we multiply it by
					;8 which is the size of each pattern
		ld de,font		;Loading into DE the memory position for the font
        	ld bc,75*8		;We want to copy 8 bytes of 75 character patterns, so BC will be set as 75*8
        	call LDIRMV		;Call the routine to copy the data from VRAM to RAM
		ld hl,font		;Let's put the RAM position where the pattern were copied into HL
		ld b,5			;Then set 5 into B as the number of pages with the hexadecimal output
initial:            
		push BC			;Save BC in the stack
		ld b,16			;Load 16 into b, which will be the counter for character patterns per page
		ld c,1			;Load 1 into C, which will be used to add a break line after 4 lines of patterns
		call mainloop		;Calls the main loop
		call CHGET		;Wait for a key to be pressed to control the output pagination
		xor a			;Raising the Zero flag
		call CLS		;so we can clear the screen calling the routine CLS
		POP BC			;Bringing back BC from the stack
		djnz initial		;then looping through initial until B decreases to zero
		ret			;end program and returns to BASIC, hopefully
mainloop:
		PUSH BC			;Saving the values from BC into the stack
		ld b,8			;Loading 8 into B, which will be the counter for loop
		call loop		;Calling the loop routine
		ld a,"\r"		;We add ASCII code for carriage return into A
		call CHPUT		;then we print it
		ld a,"\n"		;next we load the next line into A
		call CHPUT		;and calls CHPUT again, jumping the cursor to the beginning of a new line
		pop BC			;Getting BC back from the stack
		inc hl			;Incrementing HL to proceed to the next character pattern
		ld a,c			;Now we will load the value from C into A
		cp 4			;And compare it with 4, which will take care of the line break for each block
		call z,skip4		;If CP 4 raizes the zero flag, we call the skip4 routine
		INC C			;Incrementing the counter at C
		djnz mainloop		;Then looping through mainloop until B decreases to zero
		ret			;which allows to return the program back to the initial routine
            
skip4:
		ld c,0			;Load 0 into C to reset the counter
		ld a,"\n"		;Then once again we print new line
		call CHPUT		;and
		ld a,"\r"		;carriage return
		call CHPUT		;on the screen, creating an empty line between blocks of 4 character patterns
		ret			;and return to the mainloop
loop:
		ld a,"$"		;each hexadecimal value needs to be preceeded by the dollar sign
		call CHPUT		;so we print it first during the loop
		ld a,(hl)		;now we load the value where HL is pointing at
		call NumToHex		;and call the NumToHex to transform the decimal value into hexadecimal
		ld a,d			;The NumToHex return the values on DE, do we first load D into A
		call CHPUT		;and print the first digit of the hexadecimal value
		ld a,e			;then we load E into A
		call CHPUT		;to print the second digit of the hexadecimal value
		djnz loop2		;and jump into loop2 until B decreases to 0, to avoid adding a comma at the
					;end of the line with the pattern data 
		ret			;finishing the loop and returning to the mainloop routine
loop2:            
		ld a,","		;the loop2 will add a comma between the hexadecimal values
		call CHPUT		;and print it
		inc hl			;then increase the position pointed by HL
		jr loop			;and repeat the loop routine

NumToHex:    				;Routine borrowed from
					;https://stackoverflow.com/questions/22838444/convert-an-8bit-number-to-hex-in-z80-assembler
		ld c, a			;a = number to convert
		call Num1		;calls the Num1 routine
		ld d, a			;then loads A into D
		ld a, c			;and restores the value of A from C
		call Num2		;calling the Num2 routine after that
		ld e, a			;and loading A into E
		ret			;return with hex number in DE

Num1:
		rra			;9-bit rotation to right - http://z80-heaven.wikidot.com/instructions-set:rr 
		rra			;rotates A to the right again
		rra			;and again
		rra			;and once more
Num2        
		or $F0			;execute an OR operation on A and $F0
		daa			;the A register is BCD corrected using the contents of the flags
					;http://z80-heaven.wikidot.com/instructions-set:daa
		add a, $A0		;load $40 into A
		adc a, $40		;Ascii hex at this point (0 to F)   
		ret			;and returns to the NumToHex routine
font:
		db 0
		; use the label "start" as the entry point
		end start

The program can be executed at MSXPen from this link, and after each page is printed you can use Alt+C to copy the content to the clipboard as shown here:

Copying the hexadecimal values from WebMSX

Next, we just need to use the “Import DATA into slot” option from TinySprite to load the patterns. Notice that we need to enter only 4 lines of patterns on each slot, and that’s why the code adds a space after four lines with data. See how nice a person I am?

Importing data into a slot

Wash, rinse, and repeat until all characters are loaded into 19 slots of the TinySprite tool. I also changed the names of each slot to make things easier.

All character patterns loaded in TinySprite

Can it be just a little easier?

Yes, it can! Just download the TinySprite backup file below, copy its content and paste at the tool’s “Load Backup” widget!

Now we have everything we need to create that amazing font type we always wanted, and load it back on our MSX machines to print amazing texts! But this is a subject for another article. Until then have fun modifying your character patterns but don’t forget to back up your work after finishing!

In the last article, we learned how to modify a single character from the original MSX font type, and we also found out the differences between Screen 0 and Screen 1 character, but now what we want to do is to create our own personal font type as artsy as possible. Fancy! Before we start…

Deixe um comentário

Your email address will not be published. Required fields are marked *

en_USEnglish