Next (Running Programs) ⭆ |
In this series of posts we will be building an emulator for the Chip-8 system. If you are already interested in the Chip-8, or want to learn how emulators work, this is a great place to start.
If you are more familiar with emulators and instead want to learn about a more involed system, take a look at our NES series instead.
The Chip-8 is a very simple system, but has all the same parts as more complex systems. This presents a nice smaller project to work on while learning about digital systems and emulation. Now let’s dive in.
The Chip-8 is capable of much of what you see on typical video game systems, including:
We’ll cover each of these features eventually. First lets see how the system runs programs.
The Chip-8, like a physical CPU, is designed to execute programs. A program is a carefully selected list of instructions, which combine to accomplish some goal.
An instruction can be thought of as one of the operation buttons on a calculator. Each instruction does a basic operation, possibily involving some input data. The secret to a programmable system is that each of these instructions is given a representation as a number. The system has a way to run these instructions (like a calculator) but also has a way to look at a program and decide which of its “buttons” to press.
We’ll take a look at how to run programs work in a bit, but first a quick introduction to computer numbers.
To better understand the layout of Chip-8 programs, we’ll need to understand how computers represent numbers. If you already know binary and hexadecimal, feel free to skip this section.
Computers are good at storing information in two different forms. We can call these yes and no or true and false. This influences how computers represent numbers. Humans have 10 fingers, so we ended up using a base 10 number system. The right most position in a multi digit number is worth 1. As you move to the left, each value is worth 10x as much as the previous.
Computers instead use base 2, or “binary”. The right most position is still worth 1, and then each position is worth 2x the one on the right.
So in Decimal (our base 10):
123 = 1*100 + 2*10 + 3
If we wanted to represent this in binary, it would instead be:
1111011 = 1*64 + 1*32 + 1*16 + 1*8 + 0*4 + 1*2 + 1*1
To help distinguish between numbers of different bases, we often write binary numbers with a “0b” prefix to tell us that it is a number represented in base 2.
While binary numbers are convenient for computers, they’re somewhat clunky to work with for humans. They take a lot of space, and are easy to mistype or misread. Perhaps there is a compromise in the middle?
In practice, when talking about computer numbers we often use base 16, or hexadecimal. Sometimes shortened to “hex”. Here, each position is worth 16 times the one to its right.
One hurdle with hexadecimal is that we need 16 different stymbols for each position. We can borrow 0 through 9 from decimal, but need extra symbols. To solve this, we use the first 6 letters from the latin alphabet (ABCDEF). And just like with binary, we can use “0x” as a prefix when writing hexadecimal numbers to indicate that these are in base 16.
A few examples to help clarify:
Decimal | Hexadecimal |
---|---|
0 | 0x0 |
.. | .. |
9 | 0x9 |
10 | 0xA |
11 | 0xB |
.. | .. |
15 | 0xF |
16 | 0x10 |
17 | 0x11 |
123 | 0x7b = 7*16 + 11 |
Hexadecimal is nice because it represents the same chunking of information as binary. We can think of hexadecimal as a short hand for writing binary. Each symbol in hexadecimal (sometimes called a nibble) holds the value for 4 binary digits (or bits).
Looking at our 123 example again, we can see
123 decimal =
0b 0111 1011
With a leading zero to make sure we have full groups of 4. Then we represent each as a hex digit.
1011 = 8+4+1 = 11 = 0xB
0111 = 4+2+1 = 7 = 0x7
Which gives us 123 = 0x7B as we expected. This is how we can quickly convert between hex and binary.
There’s one last convenient feature of hexadecimal. Computers tend to store bits in groups of 8. We call this a byte. The values of bytes are easily represented in hex, with two hex digits.
Now we are ready to start looking at some Chip-8 instructions!
On the wiki page for Chip-8, you can find an “opcode table"for the system. The “opcode” is the numeric representation for each of the instructions the system knows about.
This table tells us how to represent commands or instructions for the system. Here we will find our hexadecimal knowledge helpful.
Looking at one of the first instructions, we see:
Code | Function |
---|---|
0x00E0 | Clear the display |
All this means is that when the system is looking at instructions, and stumbles across 0x00E0, it will clear the contents of its screen. The full opcode table contains both trickier instructions and opcode representations. We’ll look at both next time, and start writing a basic Chip-8 emulator.
Next (Running Programs) ⭆ |