CHIP-8 emulator in Rust

Phantom

A CPU emulator in Rust where the CPU is the star, not the graphics. A fully unit-tested CHIP-8 core, opcode by opcode.

PC 0x0200 · I 0x0000 · opcode 0000 · stopped

This is not a screenshot. The opcode table above is a JavaScript port of the same fetch, decode, and execute loop that lives in src/cpu.rs, running against a small bundled program that bounces a sprite around the 64 by 32 display. Run it, pause it, or step through it one opcode at a time.

Keyboard maps to the CHIP-8 hex keypad: 1234 / qwer / asdf / zxcv. Not used by the bundled demo, but wired up for any ROM you load in from the console.

The CPU is the star

Headless, deterministic core

Cpu::step() fetches, decodes, and executes exactly one opcode. No timing, no I/O, no hidden state, so every instruction is independently testable.

Injectable randomness

CXNN draws from a swappable RandSource. Tests use a fixed byte sequence, so masked-random behavior is asserted exactly, not just roughly right.

Exact state assertions

Carry and borrow flags, sprite collision, BCD digits, register dump and load: every test checks precise register, memory, and display state, not just that it ran.

Full opcode coverage

00E0 clear 00EE return 1NNN jump 2NNN call 3XNN skip eq 4XNN skip neq 5XY0 skip eq 9XY0 skip neq 6XNN set 7XNN add 8XY0-8XYE alu ANNN set I BNNN jump+V0 CXNN random DXYN draw EX9E/EXA1 keys FX07/15/18 timers FX0A wait key FX1E add I FX29 font FX33 BCD FX55/FX65 mem

Try it

Build the release binary and run the bundled demo ROM, or point it at your own.

cargo build --release
cargo run --release -- run path/to/rom.ch8
cargo run --release -- run          # bundled demo ROM
cargo test                          # 35 tests, every opcode