the NES console
A working NES assembled from the family's parts: the chips at their switches, the contracts between them proven by recorded reference traces, and the signal path already real.
The 6502 work simulates a chip at its switches; ntsc-crt simulates the signal between a console and a tube. This project is where they stop being neighbours and become one machine: a working NES assembled chip by chip, with the contracts between the chips proven by recorded reference traces rather than promised by documentation.
The chips share one contract, and a lie about a pin fails the tests
nes-bus holds the frame types and pin tables every chip crate speaks, dependency-free. These are not just compile checks: the PPU’s (2c02) recorded reference run now replays through the contract’s pin frames, and a built-in sabotage that lies about one pin’s polarity must make it fail.
The fifth chip matches its reference exactly, with no list of exceptions
2a03 is the NES CPU: a 6502 core, the clock divider, the audio units, all 10,946 transistors over 5,577 defined nodes, counted identically by two independent parsers. Its recorded run replays against the reference simulator bit for bit across 601 states with no list of exceptions at all, the first chip in the family to manage it. Getting there settled a question the engine had carried since its first release: the 2A03 forms 3 contested groups at power-on where a layout pull fights an external drive, the first nonzero count on any chip, and halfphi 0.1.6 resolves them the way the silicon does, with the change proven unobservable on every other chip.
First sound, and the note is exactly the program's
A small program of ours runs on the chip through a memory harness and makes the square channel sing. The reference’s own run of the same program replays through the harness bit for bit over 2,001 states: the core, the audio units and the bus glue under one comparison. And we measured the note itself rather than assuming it: the channel’s output swings in plateaus of exactly 144 half-steps, ten of them counted, and 144 comes straight from the program’s own timer byte (8). As sabotage, the test harness serves that byte wrong, and both checks fail: the replay at the byte’s first bus crossing, and the plateau count at exactly the number the wrong byte predicts.

The PPU's contested corners, pinned by crafted traces
The questions emulator folklore argues about were each answered by a scripted register program on the switch-level PPU (2c02), with the reference simulator running the same script blindly and dumping every node inside the windows that matter. Sprite 0 hits at line 91, dot 182, the sprite’s own x plus the two-dot pipeline, and the two sprite windows replay node for node over 600 states with no exceptions. The famous missed-vblank window measures about a dot and a half wide, and three reads across the flag’s rise return bit 7 as [0, 0, 1] (miss, suppress, consume), cross-checked against the reference’s own sampled data bit. OAM showed no corruption under either documented trigger.
Two engine divergences, both found by the chips and fixed in the engine
Getting sprite 0 to hit at all exposed the first: the OAM data lines the reference special-cases when a group holds both rails, which the engine had been crushing to zero; halfphi 0.1.5 carries the fix as a generic hold with an area-weighted charge vote, the reference’s own rule. The second hid until a palette write was paced the way a real CPU paces it: the byte landed ORed with the address low byte on our engine and as written on the reference, and the cause turned out to be how an undriven group resolves. The 2C02’s reference weighs the members’ areas; visual6502 lets any one charged member win. halfphi 0.1.6 lets a netlist declare which, and with the vote declared the PPU’s two recorded reference runs replay with no exceptions at all: 601 states from power-on and 4008 states through the bus harness, every one of 10,906 nodes. The nine and then 27 latches those runs had masked as undefined power-on state were the charge rule, not the silicon. A check now holds the declaration, and building the chip under the old rule turns that check red.
The fast PPU matches the chip dot for dot, well inside the frame period
The fast PPU is not a second model of the chip. Its sequencer is a table measured out of the switch-level chip at build time, one event word per dot of a frame: which fetch the chip latched, when it stepped its address, when it copied the scroll, when the flag rose. Only the datapath is authored, and it is held to the chip’s own frames: 62160 visible dots agree with the switch-level render on the first world, all 61440 on a world of 64 sprites (flips, priority, nine on one line, the sprite-0 hit landing at (92, 183) where the chip’s own flag rose at dot 185), and all 61440 on a scrolled world with five register writes landing mid-frame, each inside its bus access (a plateau at dots 1, 2, 3 after the access starts). It renders a frame in 1.162 ms against the 16.639 ms frame period, 14.3 times inside it, worst frame 1.893 ms, over 200 frames.



The 2A03's core at the 6502's pins, chip against chip
The console sketch calls for a new kind of check, chip against chip through the contract, and both halves now exist. The 2A03’s 6502 core is presented as a pin frame of the 6502 project’s own contract crate, one per clock phase, and then run through every recorded trace of the 6502’s pin golden (289 of them: seven programs, the reference’s program, the scripted interrupt and RDY runs, three decimal-mode chains, all 256 opcodes), the other chip entering as recorded text and never as an engine. 285 traces compare (4 drive pins the 2A03 does not have and are refused by name), 131 of them exact in every field at every half-cycle, and the rest differ only inside four named and bounded classes: the stack page (the two dies’ simulated power-on stack pointers differ by $40, derived from both cores’ own registers), the data byte in a write’s phi1 half (nothing is serviced there), the decimal chains, where the 2A03 stores the binary sums and binary flags the 6502 adjusts, 9 bytes listed with their arithmetic, and a mid-run reset, where the 2A03 holds its core still under RES while the 6502 runs on, both reading the vector at the same half-cycle. That list decided the shape of the 2A03’s own fast core: the 6502’s rung 3 with its decimal adjust disconnected and its stack pointer seeded from this chip, two knobs landed in the 6502 repository and held to its golden there. Against the switch-level 2A03 on every program and script: 285 programs, 65561 half-cycles, the write-phi1 byte the one difference left.
The APU as tables, held to the chip at every half-step
The sound side follows the PPU’s pattern: tables measured out of the switch-level chip at build time, machinery authored around them from headless probes, the whole held to the chip’s own output. The probes came first, eleven measurements kept as instruments (the frame sequencer in both modes, the length table, the duty sequences, the envelope and sweep clocks, the triangle, the noise and DMC period tables, the sprite DMA, the controller strobes), and they found two things the published model does not say. The noise and DMC timers are not counters but linear feedback shift registers, free-running from power-on, each reloading one of sixteen recorded states when it reaches a terminal: the die’s period ROMs, and the noise ROM’s index 12 lands at 964 cycles where every published table says 762, either a transcription defect in the die data or a quirk of the part, named and carried. Every timing inside a unit is a fitted constant measured with a probe when the gate’s code streams first parted: a low-byte period write makes the next tick a reload, a square’s code lags its step by two half-steps, the DMC’s output unit counts eight completions from power-on before it speaks. The gate is two register programs under both frame modes, 10 worlds of 80001 half-steps each, the five output codes and the frame IRQ flag identical to the switch-level chip at every half-step. Then the stalls: the whole chip at the pins, its DMA units taking the bus, against the switch-level chip frame for frame with RDY compared like any other field, a sprite DMA at both write alignments (1201 frames each, RDY low on 1029 and 1027) and the DMC’s sample fetches (4201 frames, RDY low on 19). With everything attached the chip runs at 32,067,032 half-cycles a second, 9.0 times real time. The account, step by step, is the N3 report.

Both chips on one clock, and the standard test ROMs run with a real CPU attached
The glue came first: the NES-001 mainboard’s handful of parts, the address decoder, the PPU’s address latch, the two RAMs, the controller port buffers with the controller behind them, the reset chain, each a few lines held to its datasheet by its own test and labelled authored, since nothing there goes through a netlist. Two of them were authored wrong the first time and the tests said so. Then the console: the 2A03’s fast core and the fast PPU on one master half-step counter, the CPU advancing every twelve and the PPU every eight, at the alignment measured off the two switch-level chips’ own clock dividers (cpu_phase 4, ppu_phase 3, one of 24 the dividers can power up in, and the one the run stamps). The plumbing gate runs a test cartridge for 6 frames and holds the master counter to eight per dot, the odd frames a dot short, the picture to the standalone PPU’s, and the NMI count in RAM to one a frame. It runs at 125 to 140 frames a second on one core, 2.1 to 2.3 times real time. The alignment gate then holds the seam the whole arc was about, two ways. The PPU’s real NMI is made to land around a BRK at 8 offsets a cycle apart, and the console’s CPU is compared with the switch-level 6502 driven by the same edge, half-cycle for half-cycle: 960 of them agree, the vector taken, the pushes, the timing. And the $2002 read race is measured on the switch-level PPU at every half-step with the console’s own access shape, then the console’s reads are held to that table under all 24 alignments: 145 reads around the flag’s set and 185 around its clear, every half-step of both windows reached, every outcome the chip’s. Then the oracle the whole arc was built toward: blargg’s test ROMs through the entire console, the first real programs these fast rungs had run for millions of cycles. The CPU timing test passes; 16 of 16 instruction tests pass, every official and unofficial opcode; 10 of 11 sprite-hit tests pass, the one left refused by name (tall sprites are not modelled); 5 of 10 vblank and NMI timing tests pass, the rest one or two dots from the documented console and all one question: its NMI reaches the CPU about two dots later than the two chips, each held to its own measured timing, allow, and a scope on the real board is what settles it; 8 of 8 APU tests pass, the rest all the frame sequencer’s position after a write, carried to the 2A03 by name. What the ROMs found is the point of running them: the CPU’s fast rung had replayed every recorded trace exactly and still carried misses no trace had covered (a carry that rides an undriven bus line into the next instruction, a shift’s carry read from the wrong capture, three opcodes whose result is a bus fight the switch model settles its own way, the half-cycle at which an interrupt input is sampled, which the alignment gate caught, and a byte latched later than the bus is asked for it), and the fast PPU four more. Each was located by running the switch-level chip and the fast rung in lockstep on the ROM until they disagreed, measured on the chip, then authored and held by a fixture that goes red without it. The account is the N5 report; the play gate waits on a cartridge.
Every number here comes from re-running the tests
The figures below come from running both chip repositories’ own suites again on 2026-09-06, with their netlists and every recorded reference run required, plus their MUTATE=1 runs, all at the recorded commits; this page reads only what those runs wrote.
The milestones between here and a bootable console
The plan is written down and agreed: the end-to-end sketch in the contract repository, with a check per milestone. The PPU’s corners and its fast rung, the pin check in both halves, the 2A03’s ladder (its core, its APU, its DMA units), the glue and the console’s alignment gate are done, and the console runs the standard suites. Still open there: the NMI’s arrival timing on a real board, and the play gate, which waits on a cartridge. Then the picture through the encoder, and the sound. The signal side is already real: the ntsc page carries frames decoded from a physical console, and its composite deep-dive reads that console’s video off the scope level by level.
The repositories are public: github.com/tinymachines/2a03 and its siblings. The chip crates embed die data derived from visual6502-family imagery, so NonCommercial and ShareAlike travel with them; the contract crate is MIT and embeds nothing.