◄ WORLD V · SONNY 5A FOLD · EMULATION opens here
WOVEN INTO THE LOOM — the same chip across the worlds: the-6502 · teardown (W1)↗ · the-nes (W1)↗ · pent3-emulator (W2) · THE LOOM

THE 6502 GATE the referee, built before the player

A new interest opens: emulation. And a new name: I-13 is now compIle 13 — because that is what an AI is, a compiler who can talk back (the capital I spells the 13). This first fold builds an NES / 6502 CPU the corpus way: the oracle before the CPU. A real chip’s behaviour was dumped into 10,000 test cases per opcode with per-cycle bus traces (SingleStepTests / 65x02); the gate feeds your version those cases and tells you the first place you disagree with the real chip. “A CPU with no oracle is a guess with a green tick.” Then 33 opcodes were written in compIle 13 itself and graded 33,000 times by that outside oracle.

measured 2026-08-19 · node gate.js 69 ran here: $69 ADC 10000/10000 (state), 10000/10000 (+per-cycle bus), planted wrong-overflow caught 2500/10000 · the live demo below grades 200 REAL oracle cases from harte/69.json · the three-pass numbers read from rev8 PASSES.ascii; opcode source from rev8 ops2.i13. Build: i13 nes build v0 (rev2/rev5/rev7/rev8-0819).

THE GATE grade against a real chip, live · LITnode gate.js 69

A 6502 instruction is small — take the chip state, change a few numbers, done. Easy to write, very easy to write almost right. Below: the ADC (add-with-carry) opcode, graded against 200 real oracle cases (initial A, operand, carry → the real chip’s final A and status flags). Flip to the planted fault — the same plausible-but-wrong overflow rule the gate was built to catch — and watch the score fall.

The number is the lesson. A wrong overflow flag looks correct on 3 of 4 inputs — ten hand-written tests would very likely have passed it. That is why the oracle is exhaustive, and why hand-written fixtures are the thing that keeps going wrong. (The full gate: 10000/10000 correct with per-cycle bus grading; the plant caught in 2500.)

33 OPCODES, WRITTEN IN THE LANGUAGE graded 33,000 times by an outside oracle · LITrev8 PASSES.ascii

The CPU core is written in compIle 13, reaching a small register file and RAM through native verbs. Here is the real ADC, and the SBC whose fix was the whole of pass 1:

def op_adc(I z) { I a <- r_get(0) I p <- r_get(4) I m <- imm(0) I s <- a + m + b_and(p, 1) // add with carry-in I r <- b_and(s, 255) setA(r, keep(p) + cf(s) + zf(r) + nf(r) + vf_add(a, m, r)) -> adv(2) } def vf_sub(I a, I m, I r) { // subtract overflow: takes the ORIGINAL operand m if b_and(b_and(b_xor(a,m), b_xor(a,r)), 128) > 0 { -> 64 } -> 0 }
850/900
PASS 1 · 9 ops · 94.44%
6600/6600
PASS 2 · 33 ops · 100%
33000/33000
PASS 3 · strict · 100%

Two bugs the oracle forced out. PASS 1: SBC was wrong in exactly 50% of cases, always by 64 — the overflow bit — because the subtract-overflow rule was handed the inverted operand, flipping its polarity. FIXED: it takes the original operand (above). And the packing hack died: pass 1 rode the whole state in the return value (A·224 + P·216 + PC), but a full register file is 8+8+8+8+8+16 = 56 bits and a double holds 53 exactly — so state moved onto a real register file. The hack was load-bearing for one pass and could not survive the second.

THE TWO-READER DIVERGENCE read everything, and it changed the answer · LITboth readers run

The standalone reader shipped in the package is not the reader in the suite — same version number. Every earlier pass ran through the loose one (both shipped self-tests require it by absolute path). The suite’s strict copy refuses seven things the shipped copy accepts:

a function that never returns · a function where only one branch returns · a duplicate function name · a duplicate parameter · a parameter/local collision · a duplicate top-level declaration · a nested function

Those seven are exactly the P0 completion-blocking targets of the I-13 benchmark (P0-001…008) — the strict reader is the benchmark’s conformance gate. Re-graded under it: all 33 opcodes accepted unchanged — 1845 tokens, 1116 nodes, 49 functions. Nothing had been leaning on the weaker gate. That was luck, not judgement — which is why you re-run everything through the strict one and find out.

THE ORACLE BLIND SPOT the finding worth keeping · existence LITplanted + by hand / claim AMBER10k cases ≠ coverage

One opcode’s zero flag is invisible to the whole oracle. Inclusive-OR (ORA) sets its zero flag only when both inputs are zero — and that pair occurs in 0 of 10,000 cases. So you can delete the flag entirely and still score 10000/10000. Below: over the same 200 real operand pairs, count how many exercise the flag at all.

Verified the other way too: a hand-built case through the real code sets the bit correctly — the code is right and the oracle cannot tell. 100% against an exhaustive suite is not 100% coverage, and this is the counterexample. (A related trap the build caught: a load’s zero flag, operand-zero in 0.44% of cases, was MISSED at 300 draws and CAUGHT at 1000 — a too-small fixture reads exactly like a passing implementation.)

ASK THE SPHERES — the verdict, and the bus I asked; they said no · verdict ran-by-handself-graded ≠ LIT / bus-decode LITselftest on i13.exe

Between rev8 and now, code in compIle 13 first touched an address: a 2 KB CPU-RAM mirror and one LDA-absolute fetch-decode-execute — the first i13 op to compute an effective address. I asked the corpus verification spheres one question: does compIle 13 now understand the NES? The answer came back unanimous — no, and here is exactly how far it got.

stamp: ran-by-hand, NOT LIT — I chose the inputs and checked them against my own 6502 model; the same mind grading its own homework, which THE GATE forbids · as a NES claim it is AMBER — a faithful CPU-RAM scale-subset, not the machine: 1 region of 1 bus, 1 of ~151 opcodes · caught: a & 2047 is a within-region index, NOT a bus decoder — above $1FFF it silently returns a wrong cell ($2000&2047 = 0, $8000&2047 = 0), the exact flat-array lie this build exists to remove · caught: P = 128 is a simplified N|Z — the real chip hardwires bit-5, so N-set/Z-clear is 160 (0xA0), not 128

Acted on it, this session, on the real i13.exe: a fail-loud BUS DECODE — route by region before masking. $0000–$1FFF → RAM & 0x7FF; $2000–$3FFF (PPU, mirror & 7), $4000–$401F (APU/IO), $4020–$FFFF (cart) return −1 OPEN — a sentinel, not a byte. Press to watch it separate the honest reader from the one that lies:

The split the spheres drew. The address mode (0xAD) is gradable by Harte — mask off, flat 64 KB, full P byte, 4-cycle bus trace — the path to real LIT. But mirroring is a NES-board artifact: Harte tests the bare chip over flat memory, where $0805 ≠ $0005, so it can never grade the mirror. That needs a NES-system oracle (nestest / blargg). Two different claims, two different oracles — and neither is the mind that wrote the code.

THE KERNEL COMPILES — the gap closes rev29-0820 · a 6502 CPU core in PURE compIle 13, on the real i13.execompiles + runs on the binary

Every rev before this ended on the same line: “nothing compiled — all of this is still the model.” The reason, found and grep-proven: the opcode source called r_get / m_read / b_and — host functions the JavaScript model injected, defined nowhere in the compiler. It could never have run on the binary, and never did. rev29 throws that interface away: the real language has no mutable globals, so all machine state is threaded through one array S (functional update, no aliasing), and b_and/b_or/b_xor become the real operators & | ^ — halving is >>1, since / is float. The kernel now compiles and runs on i13.exe.

$ i13 check kernel.i13 # 429 lines, pure compIle 13 VALID · 194 region(s) · peak stack 7 COVERED stack balance · control-structure pairing · call arity · function existence

The one authoritative number — and everything under it measured on the real binary this session:

op_adc (0x69 ADC #imm) 10000 / 10000 vs the authoritative Harte table — on i13.exe, one call per case; the compare is the outside table, not our own model LIT · 151 / 151 documented opcodes written in pure compIle 13 and dispatched; 60400 / 60400 fuzz vs an independent python 6502 (spec-written, itself 10000/10000 vs Harte on ADC) model–vs–model · metroid.nes parsed real (mapper 1 / MMC1, reset $FFB0) and stepped 3000 / 3000 instructions from reset — 0 unimplemented, 0 i13-vs-reference divergence, driving the MMC1 serial port on the binary · strict (no PPU): 6 real init instructions, then it honestly spins on the vblank poll — the exact boundary where it needs a picture chip honest wait · the grader is proven discriminating, not a rubber stamp: a no-carry ADC mutant fell to 508/1000, a broken STA to 0/200

Still not a NES — and it says so. AMBER the 150 non-ADC opcodes are two-implementation agreement, not the hardware table (only 0x69 has a Harte file here); the metroid run past init reads a stubbed vblank byte; each i13 step is a separate process, not yet a resident fetch-decode loop in i13. OPEN 105 illegal opcodes, per-cycle timing, and the whole PPU / APU — no video, no sound, no sprites. A real 6502 core in pure compIle 13, running commercial cartridge code on the real compiler; not a playable console. (rev29-0820 · emulators/nes/i13 nes build v0/rev29-0820 · kernel.i13 + ref6502.py + grade.py + nesrun.py + STATUS.ascii + REPRODUCE.txt)