Step 1 of 5 · Reading · ~3 min
Read
CHIP-8 Architecture
Fetch-Decode-Execute
Every CPU ever built does the same three things forever: fetch the next instruction, work out what it means, do it. This lesson is the first two. After it your program can take the raw bytes of a real ROM and tell you what each instruction is, which is exactly what a disassembler does, and it is the front half of the emulator.
Fetch: two bytes, high first
An instruction is two bytes at the address in PC. The byte at PC is the high half, so the word is (byte at PC) * 256 + (byte at PC+1). The bytes 6A 02 are the word 0x6A02; read backwards they would be 0x026A, a completely different instruction. After the fetch PC moves up by 2 so it names the next instruction. Fetching never looks at what the bytes mean.
Decode: the word is four nibbles
Write the word as four hex digits, H X Y N. Most instructions use them like this:
0x D 3 A 7
| | | +-- N low nibble: a count or a sub-opcode
| | +---- Y a register number, V0..VF
| +------ X a register number
+-------- H the family of instruction
KK = low byte (0xA7) an 8-bit constant
NNN = low 12 bits (0x3A7) an address
You get a nibble by shifting right and masking with 0xF: the third digit is the word shifted right by 4, then ANDed with 0xF. KK is the word ANDed with 0xFF, NNN the word ANDed with 0xFFF. D3A7 is family D with X = 3, Y = A, N = 7: draw 7 rows at the position held in V3 and VA.
The instruction set in one table
Dispatch on H first. Seven families need a second look because their meaning lives in the low digits.
0NNN ignored system call except 00E0 clear screen, 00EE return
1NNN jump 2NNN call BNNN jump to NNN + V0
3XKK skip if VX == KK 4XKK skip if VX != KK
5XY0 skip if VX == VY 9XY0 skip if VX != VY
6XKK VX = KK 7XKK VX += KK ANNN I = NNN
8XYn ALU: n = 0 move, 1 or, 2 and, 3 xor, 4 add, 5 sub,
6 shift right, 7 reversed sub, E shift left
CXKK VX = random AND KK DXYN draw N rows at (VX, VY)
EX9E skip if key VX down EXA1 skip if key VX up
FX07 VX = delay timer FX0A wait for a key into VX
FX15 delay timer = VX FX18 sound timer = VX
FX1E I += VX FX29 I = font digit VX FX33 decimal digits of VX
FX55 store V0..VX FX65 load V0..VX
Two traps hide in that table. In 5XY0 and 9XY0 the last digit must be 0; 5AB1 is not a valid instruction. In the E and F families the identity is the whole low byte, not the low nibble: E19E is a skip, E19F is nothing. Treat anything the table does not list as unknown.
Common mistakes
- Reading the two bytes in the wrong order.
- Dispatching on H alone, so
5AB1andE19Flook valid. - Taking N from the wrong digit. X is the second digit, Y the third, N the fourth.
- Forgetting that
0NNNis a family of its own: everything starting with 0 except00E0and00EEis a system call. - Ignoring a trailing odd byte: a file may end in the middle of a word.
Your exercise
The input is a ROM as a hex dump. You print one line per instruction: its address, the word, and a name for it. The starter reads the bytes and prints the lines; you write decode, which turns one word into text. The IBM logo from the next lessons is one of the tests.
Discussion
Ask a question, share an insight, or help someone who’s stuck.
Sign in to post a comment or reply.
Loading…