CHIP-8 Interpreter in Rust
CHIP-8 is an interpreted programming language run on a CHIP-8 virtual machine.
There are 4096 memory locations, each 1 byte in size, addressed from 0x000 to 0xFFF.
FONT 0x000 - 0x200
ROM 0x200 - 0xFA0
CALL STACK 0xFA0 - 0xFFF
--------------------------
TOTAL 0x000 - 0xFFF
There are 16 data registers, each 1 byte in size, addressed from 0x0 to 0xF.
The 0xF register is used as a flag for some operations, and should not be written by other programs.
There is 1 address register, 2 bytes in size, called I.
The call stack stores return addresses when subroutines are called.
Modern interpreters support at least 16 levels of nesting, requiring a call stack size of 32 bytes.
Timers count down to zero at a rate of 60 Hz.
Used for timing game events
Beeps when value is non-zero
CHIP-8 was used with a hexidecimal keypad:
,---,---,---,---,
| 1 | 2 | 3 | C |
|---|---|---|---|
| 4 | 5 | 6 | D |
|---|---|---|---|
| 7 | 8 | 9 | E |
|---|---|---|---|
| A | 0 | B | F |
'---'---'---'---'
Rusty CHIP instead uses ArrowUp, ArrowDown, ArrowLeft, ArrowRight, and hexidecimal characters (0 - F).
,---------------------,
|(0, 0) ... (63, 0)|
| . . |
| . . |
| . . |
|(0, 31) ... (63, 31)|
'---------------------'
The monochrome display is 64 pixels wide by 32 pixels high. A sprite is 8 pixels wide by 1 - 15 pixels high. Sprites are drawn to the screen using XOR. The 0xF register flag is set to 1 if any true pixels become false, indicating a collision.
Rusty CHIP's beep tone is a 1000 Hz sine wave because I don't find it as annoying as the other frequencies I tried.
| Opcode | Instruction |
|---|---|
| 0NNN | Execute machine language subroutine at address NNN |
| 00E0 | Clear the screen |
| 00EE | Return from a subroutine |
| 1NNN | Jump to address NNN |
| 2NNN | Execute subroutine starting at address NNN |
| 3XNN | Skip the following instruction if the value of register VX equals NN |
| 4XNN | Skip the following instruction if the value of register VX is not equal to NN |
| 5XY0 | Skip the following instruction if the value of register VX is equal to the value of register VY |
| 6XNN | Store number NN in register VX |
| 7XNN | Add the value NN to register VX |
| 8XY0 | Store the value of register VY in register VX |
| 8XY1 | Set VX to VX OR VY |
| 8XY2 | Set VX to VX AND VY |
| 8XY3 | Set VX to VX XOR VY |
| 8XY4 | Add the value of register VY to register VX, Set VF to 01 if a carry occurs, Set VF to 00 if a carry does not occur |
| 8XY5 | Subtract the value of register VY from register VX, Set VF to 00 if a borrow occurs, Set VF to 01 if a borrow does not occur |
| 8XY6 | Store the value of register VY shifted right one bit in register VX, Set register VF to the least significant bit prior to the shift |
| 8XY7 | Set register VX to the value of VY minus VX, Set VF to 00 if a borrow occurs, Set VF to 01 if a borrow does not occur |
| 8XYE | Store the value of register VY shifted left one bit in register VX, Set register VF to the most significant bit prior to the shift |
| 9XY0 | Skip the following instruction if the value of register VX is not equal to the value of register VY |
| ANNN | Store memory address NNN in register I |
| BNNN | Jump to address NNN + V0 |
| CXNN | Set VX to a random number with a mask of NN |
| DXYN | Draw a sprite at position VX, VY with N bytes of sprite data starting at the address stored in I, Set VF to 01 if any set pixels are changed to unset, and 00 otherwise |
| EX9E | Skip the following instruction if the key corresponding to the hex value currently stored in register VX is pressed |
| EXA1 | Skip the following instruction if the key corresponding to the hex value currently stored in register VX is not pressed |
| FX07 | Store the current value of the delay timer in register VX |
| FX0A | Wait for a keypress and store the result in register VX |
| FX15 | Set the delay timer to the value of register VX |
| FX18 | Set the sound timer to the value of register VX |
| FX1E | Add the value stored in register VX to register I |
| FX29 | Set I to the memory address of the sprite data corresponding to the hexadecimal digit stored in register VX |
| FX33 | Store the binary-coded decimal equivalent of the value stored in register VX at addresses I, I+1, and I+2 |
| FX55 | Store the values of registers V0 to VX inclusive in memory starting at address I, I is set to I + X + 1 after operation |
| FX65 | Fill registers V0 to VX inclusive with the values stored in memory starting at address I, I is set to I + X + 1 after operation |
Source: Mastering CHIP-8 by Matthew Mikolay
Thank you to the following people who discussed, reviewed, or paired on this project with me!
