この文書はまだ翻訳されていません。本文は英語のまま表示されています。
N3 plan: the 2A03 ladder, measured before it is built
The console sketch (nes-bus, docs/nes-end-to-end-v0_2.md, milestone
N3) asks for v2a03-micro: the 6502's rung 3 for the core with the
decimal adjust disconnected and verified against N1's divergence list,
plus the APU as tables measured out of rung 0 the way the 6502's decode
was, with the probes that measure them kept as deliverables. This
document is the plan, written before the rung; docs/n3-report.md
carries what each step measured. The order is the sketch's own:
measure first, author from the measurement, hold the authored thing to
the chip.
Step 1: the divergence list (the pin-lockstep gate, second half)
N1 left the cross-chip comparison to "where both chips are reachable".
Both are reachable here without a 6502 engine: the 6502 repository
records its rung 0 at the pins as text (tools/pin-golden/*.pins, 274
traces, NC-SA-derived and gitignored there), and v6502-pins (MIT, no
die data) parses and replays it. So the second half is a test in this
repository that reads a sibling checkout's recordings (PIN_GOLDEN=
names another place; without them it SKIPS by name).
src/pins.rs: the 2A03 core as av6502_pins::PinEngine(CorePins), one frame per clk0 phase, driven by the contract's ownrunso a script cannot be applied differently to the two chips. The alignment between the two reset sequences is MEASURED (examples/lockstep-probe.rs) and then asserted at every power cycle.src/lockstep.rs: the comparison, every differing field classified by a rule with a name. Anything unnamed is loud and fails.- Gate: every trace agrees pin for pin except the named classes, each
bounded exactly (the stack offset derived from the two dies' own S
registers, the decimal stores listed byte by byte from the program's
operands, the reset window bounded by the script and the vector read,
the write-phi1 bytes counted).
MUTATE=1flips one serviced bit and must go red as an unnamed difference.
Step 2: the core rung
v2a03-micro depends on v6502-micro (a git dependency on the 6502
repository, pinned by revision; its table is measured out of the 6502's
rung 0 at build time, NC-SA-derived, never committed) and configures it
with the two knobs step 1's list justifies: set_decimal_adjust(false)
and set_stack_at_h0(Some(s)), with s READ off this chip's rung 0
register nodes rather than typed. Nothing else in the core is authored
here.
- Gate: every recorded trace's program runs on this chip's rung 0 (via
CorePins) and on the core rung under the same script; the two agree in every field except the write-phi1 byte (the class step 1 names; the core rung reproduces the 6502's pins there, and nothing crosses the pins in that half). The decimal chains agree outright: the binary bytes are the 2A03's. Throughput measured beside rung 0. MUTATE=1leaves the adjust connected: the decimal traces must go red by name.- Anything the core rung does not reproduce of this die is listed by name with its bound and the measurement it waits on (the ladder's rule for undocumented behaviour), never masked.
Step 3: the APU probes
Headless dumps off rung 0, each an example whose output is recorded in the report before any table is authored from it:
- the frame sequencer:
frm_*per CPU half-step over a full 4-step and a full 5-step sequence from a $4017 write, the phase pulses' positions in CPU cycles; - one channel: timer (
sq0_t*), period, duty step (sq0_c*), length (sq0_len*), envelope (sq0_env*), sweep (sq0_swp*), output; - the length table: all 32 indices written to $4003, the loaded counter read off the nodes;
- the noise LFSR and its period table, the triangle's linear counter and 32-step sequence, the DMC's rate table and sample path;
- OUT0..2 and the controller strobes on $4016 writes and $4016/$4017 reads;
- RDY during a $4014 write (
spr_dma_/rdy, the address bus, the 513/514-cycle question) and during a DMC fetch (pcm_dma_/rdy).
Step 4: the APU as tables
build.rs runs rung 0 and writes the tables to OUT_DIR (NC-SA, never
committed): the length table, the noise and DMC period tables, the duty
sequences, the frame sequencer's step positions in both modes. The
datapath around them (timers, counters, envelope, sweep, the mixer
already authored in src/mixer.rs) is authored from the probes and
labelled.
- Gate: a register program that exercises every channel; the five
output codes (the AD1/AD2 tap,
sq0_out,sq1_out,tri_out,noi_out,pcm_out) bit-exact against rung 0 every CPU half-step; frame IRQ and DMC IRQ timing against rung 0; throughput measured.MUTATE=1drops a table entry and must go red.
Step 5: the stalls
$4014 and the DMC fetch as RDY spans on the core rung, replayed against rung 0 goldens that show which half-cycle each steal lands in.
Real time
The 2A03's core runs at 1.789773 MHz (the master clock over 12), which is 3.58 M half-cycles per second. The 6502's rung 3 measured 39.0 M half-cycles/s, so the core alone is about 11x inside real time; the APU tables add per-half-cycle work and the report records what is left. The gate is stated the way P3's was: real time is a property, measured with its margin, and nothing is built for speed until a shortfall is recorded.
Pulled at build time from 2a03/docs/n3-plan.md; the repository is the one copy.