← All projects

1942 / Reverse engineering

Taking apart 1942,
byte for byte.

A complete cartridge reconstruction—and the extra work needed to understand what the bytes actually do.

Start with every byte.

The NES version of 1942 fits in a 40,976-byte cartridge image: a 16-byte header, 32 KiB of program ROM, and 8 KiB of graphics ROM. This project reconstructs that image from assembly source and documents its execution, graphics, sound, and gameplay systems.

The assembler and linker do not read the reference ROM. The verifier opens it afterward and compares the rebuilt cartridge. That separation matters: copying the original bytes into the build would produce a matching file without explaining anything.

40,976cartridge bytes matched
7,523decoded instructions
512graphics tiles

The checks account for every program-ROM byte, distinguish code from data, compare instruction encodings with linked output, and inspect direct and indirect control-flow targets. The result is a complete byte reconstruction, with documented behavioral coverage rather than a claim to have tested every possible game state.

Turning graphics data into something visible.

The graphics ROM stores 512 tiles in two pattern tables. Each tile is 8 × 8 pixels, encoded in two bitplanes. Combining those bits gives a two-bit pixel value; the game supplies the palette separately.

Grayscale atlas of decoded 1942 metasprites, with labeled frame entries
The decoded metasprite atlas. Grayscale shows the stored bitplane values; it does not invent an NES color palette. Open the image to inspect individual frames.

The frame table contains 199 pointers to 179 distinct metasprite records. Each record combines tile IDs, attribute controls, and a shared layout of signed X/Y offsets. Some records overlap: the last attribute byte of frame $0F is also the sprite-count byte of frame $10.

That shared byte has to appear once in the rebuilt cartridge while retaining both meanings in the analysis. Treating every apparent record as independent would change the binary.

Decoded grayscale background-page atlas for the NES game 1942
The 23 background map pages are built from 256 metatiles. The original-ROM comparison checks all 5,520 map cells.

Rebuilding bytes is only the first check.

A source listing can assemble perfectly while its labels and explanations are wrong. To check meaning, the analysis executes original ROM routines with controlled inputs and compares them with independently decoded models.

  • Graphics: sprite layouts, background cells, palette attributes, and scrolling VRAM commands.
  • Gameplay: stage events, formation allocation, movement, collisions, rewards, and boss damage thresholds.
  • Sound: all 23 programs, their control flow, and the resulting APU register writes.
  • Execution: cold boot, task scheduling, input, pause, two-player state, and recorded stage transitions.

The graphics checks cover 18,874 original-ROM comparison cases. Sound checks compare 13,134 ticks and 4,264 APU writes. Natural replays are kept separate from controlled-RAM tests, because a synthetic routine test cannot establish that a whole playthrough happened.

The interesting details were the awkward ones.

A coordinate is not always base 256.

The scrolling world uses 240-pixel Y pages. Interpreting the low byte as an ordinary base-256 coordinate misstates progress. The game also has a positive-Y wrap quirk in its original integrator:

LDA ObjWorldYLo,X   ; $B078
CMP #$F0           ; $B07B
BCC loc_B087       ; $B07D
ADC #$10           ; $B07F
STA ObjWorldYLo,X   ; $B081
INC TmpAltWorldYHi  ; $B084

On the path that reaches ADC #$10, the comparison has left carry set. The addition therefore adds $11, not $10, and a positive crossing gains an extra pixel. A faithful reconstruction preserves that behavior instead of silently fixing it.

The game has its own cooperative scheduler.

Tasks retain private stack slices and yield back to a dispatcher. NMI updates input and sound and decrements sleeping-task timers; it does not dispatch the gameplay tasks. A requested delay of D wakes on underflow after D + 1 NMIs. These timing details are easy to flatten into an incorrect “once per frame” description.

Suspicious code can still be original.

At $83C2, the cartridge contains JMP $0004. The conservative control-flow audit leaves the containing helper unreachable under valid game state and intact stacks. The reconstruction records the anomaly and keeps the original instruction.

The audit corrected an earlier success claim.

Earlier reinforcement-learning results used an invalid completion check. They also interpreted scroll progress in base 256. Those results do not establish a full-game win, even though the old filenames and website described them that way.

The newer audit distinguishes an ordinary stage transition, a real ending from a saved state, and a complete winning run from power-on. It verifies the recorded ending fixture, but there is no complete power-on winning replay in this evidence.

That correction is part of the project. A reward function or success counter can look convincing while measuring the wrong thing. Understanding the original program made the mistake visible.

What the evidence establishes.

The saved October 20, 2026 report records a passing cartridge reconstruction and subsystem suite. While preparing this article, I rechecked the SHA-256 hashes of all 33 source inputs against that report; they matched. I also checked the saved report hashes. The full emulator suite was not rerun for this publication.

The evidence does not establish physical NES timing or output fidelity. The trace emulator does not synthesize APU audio, so matching hardware writes does not establish matching sound. It also does not exhaust every reachable game state.

Rebuilt and reference cartridge SHA-256

34b3c8d72ca0558834f7daaba3b4d6dc25af8d331afdaf0ba4e81de7eed1a671
Another projectBuilding ForgeLM