Writing a Chip 8 Emulator – Built In Font Set (Part 4)

By Craig Thomas, Sun 15 October 2017, in category Emulation

chip8, emulation

Last time I wrote about how to draw pixels on the Chip 8 screen. We went over how the DRAW command uses an XOR method to turn pixels on and off, as well as how to draw an n-byte sprite to the screen. To quickly recap, here are the steps that you need in order to draw a sprite:

In the previous post, we examined some code that wrote the capital letter E to the screen.

Drawing Text

As you can already see, writing text to the screen would get very annoying very quickly. Not only would you need to define sprites for each character, you would need to keep track of where in memory the sprites were located. Doing some simple math, if you wanted to store the 26 alphabet characters plus the digits of 0 to 9, using 5 byte sprites, a total of 36 x 5 = 180 bytes of storage.

Luckily the designers of the Chip 8 specification thought about this headache, and provided a partial solution.

Chip 8 Font Set

The Chip 8 specification states that the first 512 ($200 hex) bytes of memory are reserved for the interpreter and should not be used as general storage. Within that 512 byte reserved space, the first 80 ($50 hex) bytes contain sprite information for the characters 0 through 9 and A through F. This font set can be used to display any hexadecimal number.

Each of the characters defined in the font set are 5 bytes long. The characters are mapped to the following memory locations:

Location    | Character
$00 to $04  |    0
$05 to $09  |    1
$0A to $0E  |    2
$0F to $13  |    3
$14 to $18  |    4
$19 to $1D  |    5
$1E to $22  |    6
$23 to $27  |    7
$28 to $2C  |    8
$2D to $31  |    9
$32 to $36  |    A
$37 to $3B  |    B
$3C to $40  |    C
$41 to $45  |    D
$46 to $4A  |    E
$4B to $4F  |    F

Using the Font Set (the Hard Way)

One way of using the built-in font set is to use the procedure we developed above, along with knowledge of where the fonts begin in memory. For example, if we wanted to display the character 9 at location 10, 5, then we would do the following:

If we were to do this using my Chip 8 Assembler, the raw program would look as follows:

start   LOADI   $2D       The location of the 9 character
        LOAD    r2,$10    The X position
        LOAD    r3,$5     The Y position
        DRAW    r2,r3,$5  Draw the sprite
end     JUMP    end

The statements, when assembled will be as follows:

-- Assembled Statements --
0x0200 A02D      start LOADI             $2D  # The location of the 9 character         
0x0202 6210             LOAD          r2,$10  # The X position                          
0x0204 6305             LOAD           r3,$5  # The Y position                          
0x0206 D235             DRAW        r2,r3,$5  # Draw the sprite                         
0x0208 1208        end  JUMP             end  #                         

The second column shows the compiled statements (loading the index register will be $A02D, loading the X position will be $6210, and so on). The result, when run will be:

Program Output

The reason why this I call this the hard way is that it requires looking up the starting address of the character that you want to draw. There is however, an easier way.

Using the Font Set (the Easy Way)

There is a built in command that loads the index register in a more natural way. The Fs29 command uses the source register as an index into the font set. It assumes the font set is loaded at location $00, and that each character is 5 bytes long. It multiplies the value in the source register by $5 to arrive at the proper memory location, which it then loads into the index register.

This whole process sounds complicated, but is easily demonstrated with an example. If we want to draw the character 9, then all we have to do is load the the value $9 into a register, and use that register as the source for the command. In this case, it will take the value $9 and multiply it by $5, loading the index register with the value of $2D.

From a coding standpoint, we do nearly the exact same thing as we did above, but this time we use the Fs29 command:

Again, using my Chip 8 Assembler, the raw program would look as follows:

start   LOAD    r1,$9     The single digit hex value to print
        LDSPR   r1        The sprite we want to load
        LOAD    r2,$10    The X position
        LOAD    r3,$5     The Y position
        DRAW    r2,r3,$5  Draw the sprite
end     JUMP    end

The assembled statements would be as follows:

-- Assembled Statements --
0x0200 6109      start  LOAD           r1,$9  # The single digit hex value to print     
0x0202 F129            LDSPR              r1  # The sprite we want to load              
0x0204 6210             LOAD          r2,$10  # The X position                          
0x0206 6305             LOAD           r3,$5  # The Y position                          
0x0208 D235             DRAW        r2,r3,$5  # Draw the sprite                         
0x020A 120A        end  JUMP             end  #                              

The output would be exactly the same as what we saw before:

Program Output

The reason why I call this method the easy way is that you can take a single digit hex value and display it directly without having to know where in memory the character is stored. Using this method, you can quickly print out the value of a user's score - which is something that many Chip 8 games actually do. Or, if you convert a hex value into decimal, you can quickly print out a multi-digit score.

Conclusion

The Chip 8 defines a simple 16 character font set that can be used to print out hexadecmial characters. Instead of having to know where in memory the values are stored, a command exists to more naturally load the memory values into the index register. While the process of printing out characters using this method takes an additional step, it makes printing out register values or other hex values very easy.

Tune in next time when I will go over the Super Chip 8 instruction set and how those changes would impact a basic Chip 8 emulator.