Writing a Chip 8 Emulator – DRAW command (Part 3)

By Craig Thomas, Thu 19 February 2015, in category Emulation

chip8, emulation

Previously, I wrote about the Chip 8’s basic execution structure, as well as how to decode and understand its instructions. While many of the commands are used to perform logical operations or fetch data from memory, I think that commands that perform input or output routines are equally important. After all, how can you interact with the emulator if you have no way of seeing what it is doing? In this post, I wanted to talk about one of the most important instructions in the Chip 8 arsenal: the DRAW command.

The Chip 8 Screen

First, a little background. The Chip 8 defines a single screen that is 64 pixels wide by 32 pixels tall. It’s a small screen, but it is a nice size to work with if you are writing an emulator for the first time.

Continuing on with simplicity, the Chip 8 is only capable of drawing pixels in a single color: white. Limited, yes, but easy to work with. If you like, you can have your Chip 8 emulator print the pixel out in any color at all. You just need to know that you can’t write a Chip 8 program that controls the color of the pixels written to the screen.

Writing Pixels with XOR

The Chip 8 has a really simple method of drawing a pixel to the screen. You can only control whether you want to turn a pixel on 1 or turn it off 0. When you turn on a pixel, it appears in the single glorious color that the Chip 8 has.

But writing to the Chip 8 screen isn’t just a simple matter of turning a pixel on and off. All write operations are governed by an XOR (exclusive OR) routine. The reason why the Chip 8 uses an XOR routine is because it makes certain graphics operations easier. However, it is a somewhat tricky concept if you are new to it. Bear with me while I draw out the truth table for an XOR:

0 xor 0 = 0
0 xor 1 = 1
1 xor 0 = 1
1 xor 1 = 0

To break this down, there are four different operations you can perform on the pixels. The first two work as you would expect them to:

With me so far? Here’s where things get a little trickier:

If the draw operation turns off a pixel that was already on, it will store the value 1 in register VF. This is a really important detail to remember, since it allows you to perform sprite hit detection. Which brings us to the next item of business.

Sprites

Yes, the Chip 8 actually had a concept of a sprite. To those who don’t know, a sprite is a distinct graphical object. Usually, in the realm of computer games, a sprite would be something like a player’s character on the screen.

Everything is a sprite to the Chip 8. This means that you don’t have to turn a pixel off or on individually; instead you control groups of pixels as specified by the sprite. Each sprite can be between 1 and 15 bytes long. The bit patterns within the bytes that you specify correspond to the pixels you want turned on or off. As you would expect, 1 turns on a pixel, and 0 turns off the pixel (subject of course to the above XOR rules). Here’s a simple example of a 7 byte sprite:

         bit 7 6 5 4 3 2 1 0
-------+--------------------
byte 1 |     0 1 1 1 1 1 0 0 
byte 2 |     0 1 0 0 0 0 0 0 
byte 3 |     0 1 0 0 0 0 0 0  
byte 4 |     0 1 1 1 1 1 0 0   
byte 5 |     0 1 0 0 0 0 0 0 
byte 6 |     0 1 0 0 0 0 0 0 
byte 7 |     0 1 1 1 1 1 0 0

Do you see the pattern? The sprite represents a capital E character. In hex, these bytes would be the following values:

         hex
-------+----
byte 1 |  7C
byte 2 |  40
byte 3 |  40
byte 4 |  7C
byte 5 |  40
byte 6 |  40
byte 7 |  7C

These 7 bytes would have to be placed somewhere in the Chip 8’s memory in order to write this sprite pattern to the screen. They also have to be placed in the order that you see them.

Using the Index Register

The index register is used to specify where in memory the sprite resides. This means that before you issue the DRAW command using the Chip 8 instruction set, you must first load the memory location of the sprite into the index register. Continuing our example above, say you stored the 7 byte sprite starting at location $300. You would need to first load the index register with that location. In machine code this is $A300. The DRAW command would then read byte 1 from $300, byte 2 from $301, and so on.

The DRAW Command

Okay, with all the background out of the way, we can finally examine the core DRAW instruction. The instruction takes on the form Dxyn. If you recall my earlier post, the D remains the same for all draw commands. The other options are:

Let’s go through a simple program that draws out the capital E at the location 10, 5 (X, Y). Here are the steps you would need to take:

The complete assembly listing for this program would be the following (note that I am using my Chip 8 Assembler to write and compile the assembly code for this example):

# Writes the letter E to the location (10, 5)
start   LOADI  sprite   Load the sprite location into index
        LOAD   r0,$A    Load 10 into register 0
        LOAD   r1,$5    Load 5 into register 1
        DRAW   r0,r1,$7 Draw 7-byte sprite at r0, r1
end     JUMP   end      Loop infinitely
# Data for the program
sprite  FCB    $7C      Capital letter E
        FCB    $40
        FCB    $40
        FCB    $7C
        FCB    $40
        FCB    $40
        FCB    $7C

The assembled statements (with their memory locations and the program listing) are the following:

-- Assembled Statements --
0x0200 A20A  start LOADI   sprite  # Load the sprite location into index
0x0202 600A         LOAD    r0,$A  # Load 10 into register 0
0x0204 6105         LOAD    r1,$5  # Load 5 into register 1
0x0206 D017         DRAW r0,r1,$7  # Draw 7-byte sprite at r0, r1
0x0208 1208    end  JUMP      end  # Loop infinitely
0x020A 007C sprite   FCB      $7C  # Capital letter E
0x020B 0040          FCB      $40  #
0x020C 0040          FCB      $40  #
0x020D 007C          FCB      $7C  #
0x020E 0040          FCB      $40  #
0x020F 0040          FCB      $40  #
0x0210 007C          FCB      $7C  #

For those of you who don’t use my assembler, the second column in the output are the assembled statements. You can punch those into a hex editor manually to create the Chip 8 program. When we run the program, we get the following:

Program Output Screen

Wrapping Up

It is extremely easy to draw sprites on the screen. All you need to do is load the index register with the memory location of your data, set the X and Y coordinates into two registers, and then issue the DRAW command. In a future post, I’ll look at how you can make writing text in a Chip 8 program easier with the built in font file and the load sprite command (Fs29).