Measured · not computed

An opcode is
not a number.

There is no instruction decoder in the 6502 in the sense a textbook means, and no microcode to step through. An opcode is eight bits sitting in a latch, and a grid of transistors turns them into about forty control lines combinationally, as a pure function of what is in the instruction register right now.

That grid has 122 product terms, and the die names 121 of them. This is every one, together with the opcodes that actually fire it, found by running the chip against all 256 opcodes rather than by reading the transistors and reasoning.

decode · measured Click an opcode, or a term to light every opcode that fires it

Loading the decode table…

What the table shows

Undocumented opcodes share product terms

Filter the terms for lda and select op-T0-lda. Sixteen opcodes light up: the eight documented LDA forms, and eight more that no datasheet lists. Those eight are LAX.

Nothing special happens for them. The PLA is a grid of switches, and the row that means “load the accumulator now” does not test every opcode bit: it tests the ones it needs. Opcodes it was never designed for satisfy the same pattern, and the row fires, because there is nothing in the silicon whose job is to say no. LAX loads both A and X for the plainest possible reason: the LDA row and the LDX row are both high at once.

The same thing explains $CB sitting alongside DEX, and a great many other quirks people have catalogued from the outside for forty years. Seen from the switches they stop being trivia and become the obvious consequence of a grid that was only ever built to answer 151 questions.

Why measured

Reading the gates gives the wrong answer twice

A product term looks like something you can just read off: it is pulled to ground through one transistor per opcode bit it rejects, so the pattern is right there. That was tried first, and checking it against the documented instruction set found it wrong in two different ways.

It over-matched. op-T0-jsr came out decoding four opcodes instead of one, because the low two bits are constrained through irline3, a derived line, not an IR bit. Following it means modelling the gate behind it, and the gate behind that.

And where it looked wrong, it was right. op-T0-lda matching sixteen opcodes is not an error to be corrected. Trusting the datasheet over the silicon there would have quietly deleted the most interesting thing on this page.

So the structure comes from the netlist and the behaviour comes from the engine: every opcode was run, three times each, and the terms were read out of the chip. All 122 fire. The last of them, op-branch-done, only once the test crossed a page boundary, which is itself the answer to what that term is for.

From term to control line

Two senses: drive, and override

This is the AND plane, plus as much of the path onward as could be verified. Selecting a term lists the control lines it was measured to explain, and each one is reached the same way: through the OR plane, a cclk pipeline latch, and a couple of inverters. That latch is why a line responds a half-cycle or two after its term, the lag shown is measured per line, not assumed.

Two senses turned out to be needed, and the second is the more common. A term can drive a line, or it can override one that is asserted by default. PCLPCL means “the program counter low byte keeps its value” and SS means “the stack pointer keeps its value”: the chip holds unless something says otherwise, so those lines are asserted by the absence of any term. Reading every line the first way explained 30% of what the chip did; allowing both explains 93%.

32 of the 46 control lines have a term set that survives that check, and the other 14 are listed as unresolved rather than guessed at. A backward walk through the netlist will always find something; the number it finds is not evidence that it is right, which is why every edge here had to predict 768 measured runs before it was allowed onto the page.

Timing is the other half. Each term's name carries the T-state it belongs to, and the half-cycle column shows when it actually went high, but the chain that produces those T-states is its own piece of silicon.