CHIP-8 emulator in Rust
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.
Press Run to start the bundled ROM and watch the sprite bounce, Step to advance exactly one opcode at a time (the state line shows PC, I, and the current opcode after each step), and Reset to reload from the start. The same fetch-decode-execute loop from src/cpu.rs drives every frame here.
Cpu::step() fetches, decodes, and executes exactly one opcode. No timing, no I/O, no hidden state, so every instruction is independently testable.
CXNN draws from a swappable RandSource. Tests use a fixed byte sequence, so masked-random behavior is asserted exactly, not just roughly right.
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.
Not eyeballed on a screen. The core is checked instruction by instruction, and this is a real run.
$ cargo test
Compiling phantom v0.1.0 (/Users/pavan/builds/phantom)
Finished `test` profile [unoptimized + debuginfo] target(s)
running 35 tests
test result: ok. 35 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out
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