rommage
Brute-force search for NES Game Genie codes. Patch a byte, run the game, compare the frames against a clean run, and keep the codes that change things without crashing.

A Game Genie code patches a single CPU read: when the game reads a given address in ROM, it gets a different byte back. Finding good ones used to mean reading disassembly and guessing. rommage tries a lot of them instead and looks at what happens on screen.
The pipeline
Each candidate is run on nes-py, with a small C++ patch that adds a cheat table to the CPU bus. Stages get more expensive as the candidate pool shrinks:
- Trace. Perturb each PRG byte once and run a short rollout. Addresses the game never reads during that play sequence are dropped. On Super Mario Bros. walking right through 1-1, this cuts 32,768 addresses to 1,789.
- Boot check (optional). Reject codes that change the title screen.
- Stage 1. A 60-frame rollout scored by dHash distance alone. Nulls (no change) and crashes (maximal change) are thrown out.
- Stage 2. A full rollout scored by dHash plus a 64-bin colour histogram, then ranked into an HTML gallery.
Each worker process keeps one emulator alive and restores a saved state, so no candidate pays for boot or the title screen. Runs can be resumed. On eight cores a sampled SMB1 search takes about 12 minutes.
Some finds
| Code | Patch | Effect |
|---|---|---|
KAAYPYSA |
$F701 85→84 |
STA becomes STY in sound init; scrambled music and SFX |
VSZAPEPZ |
$80A1 29→D6 |
an AND in the NMI becomes a DEC; level terrain keeps mutating |
AELUNLAL |
$BBBF 30→00 |
an object timer cap drops to zero; hammers rain after a block hit |
The repo includes a long writeup that frames all this as a search problem: cascaded classifiers, ablation as dimensionality reduction, perceptual hashing, and a few fights with multiprocessing.Pool.
Limits
Mapper 0 (NROM) only for now, which covers SMB1, Donkey Kong, Excitebike, Ice Climber and similar early titles. You need to patch and rebuild nes-py first; docs/PORTING.md has the steps. Then:
cd genie_search
python3 rommage.py search ../smb1.nes --trace-live-addrs \
--sample 2000 --workers 8 --out ./results/smb1