Skip to content

The CPU

An instruction set treated the processor from outside: an instruction goes in, registers and memory change. This page opens it up. Every instruction is carried out in steps, one per clock cycle, and in every cycle the 6502 reads or writes one byte. The work is split between two parts: the datapath, which holds and moves the numbers, and control, which says what the datapath does in each cycle.

The datapath is the parts Part 1 built, wired together:

  • Registers: the PC, A, X and Y, the stack pointer S, and the flags P, each a register of flip-flops. Plus two the programmer never sees: the instruction register (IR), which holds the opcode being carried out, and a latch for addresses being built up a byte at a time.
  • Buses: the address bus out to memory, and the data bus, both ways.
  • The ALU, for the sums and the logic.

In each cycle, one register drives the address bus: usually the PC (fetching the program), sometimes the latch (an address the instruction gave), the stack pointer, or a fixed vector address. A byte moves on the data bus, into a register or out to memory, and the registers update.

The datapath, cycle by cycle, running real 6502 code. Click Next cycle: the register driving the address bus lights up on top, and the one taking (or giving) the data underneath. Below, the program is on the left, with the instruction being carried out highlighted, and beside it are that instruction’s steps, with the current one highlighted. LDA $10 takes 3 cycles: fetch the opcode, fetch the address, read the value. JSR takes 6, two of them pushing the return address. Choose Indexed, crossing a page for the stranger ones.

Each instruction is a fixed sequence of steps, the same every time: that list under the datapath. Control is the part that, given the opcode in the IR and a count of which cycle this is, produces the signals for that step: which register drives the address bus, whether to read or write, which register loads the data, what the ALU does, and whether to add 1 to the PC.

There are two ways to build it.

  • Hardwired: control is a state machine, and its outputs are logic. The opcode and the cycle count go in, and gates work out every control signal. It’s fast and small, but every change means redesigning the logic.
  • Microcoded: each instruction’s steps are stored as words in a small ROM, the microcode, one word per step with a bit for each control signal. Control just reads them out in order. It’s easier to design and to change, and complicated instructions cost only more ROM, so most large processors of the 1960s and 70s were built this way, including most of IBM’s System/360 range and, later, Motorola’s 68000.

The 6502 sits in between. A decoding ROM (a PLA) matches the opcode and the cycle count against a list of patterns, and random logic combines what matched into the control signals. It’s mostly hardwired, which is part of why it was so small and cheap.

Step through the second program above and some cycles are labelled “ignored”: the 6502 reads an address and throws the byte away. It does this because it uses the bus in every cycle, even when it has nothing to read. When it’s busy inside, adding an index to an address for instance, it simply reads from whatever address is on the bus, which was simpler to build than switching the bus off.

These extra cycles show up in the timing:

  • Crossing a page. For LDA $20F8,Y, the 6502 adds Y to the low byte of the address first. If that carries, the high byte is now wrong, so it reads from the wrong address (ignored), fixes the high byte, and reads again: one extra cycle, only when the index crosses into the next page.
  • Read, modify, write. INC $13 reads the byte, then writes it back unchanged while the ALU adds 1, then writes the new value. The extra write is harmless in RAM, but not always for I/O: a device register that reacts to being written sees it twice.

The test data that checks this page’s emulator gives every cycle of the real chip, and the emulator matches it, ignored reads and all.

Put together, a processor is a loop: fetch an opcode, step through its list, fetch the next. At 1 MHz, a million steps a second.

Multiply: shift and add multiplies 23 by 45, the way long multiplication works in binary: for each bit of one number, add the other or not, and shift. It shifts with LSR (logical shift right) and ROR (rotate right), from the ALU page. The answer, 1035 ($040B), ends up at $0002 (low byte) and $0003 (high). The whole program takes 200 cycles. Fibonacci numbers fills memory from $0010 with 1, 1, 2, 3, 5 and on, stopping before a number would be too big for a byte. Step through either and the panel below the memory shows each instruction’s bus cycles.

  • A processor is a datapath (registers, buses, the ALU) and control, which says what the datapath does each cycle.
  • Every instruction is a fixed list of steps, one per clock cycle, each with one bus access.
  • Control can be hardwired (logic works out the signals) or microcoded (the steps are stored in a ROM). The 6502 is mostly hardwired, using a decoding PLA.
  • The 6502 uses the bus every cycle, so it makes reads it ignores, an extra cycle when an index crosses a page, and a write of the unchanged value in read-modify-write instructions.
  • David Harris and Sarah Harris, Digital Design and Computer Architecture, chapter 7: a processor’s datapath and control, built step by step (for a different instruction set, RISC-V or ARM, but the same ideas).
  • The Visual6502 project (visual6502.org): the real 6502’s transistors, photographed, traced and simulated, running in a browser.
  • Charles Petzold, Code, 2nd edition, 2022: the chapters on building a processor, from relays up.