Skip to content

A real one: the 6502

The processor on the last three pages wasn’t a toy that resembles a 6502. It is one. Its emulator runs the 151 documented instructions exactly as the real chip does, cycle for cycle. It’s checked against Tom Harte’s test data, which gives, for 10,000 cases of each opcode, everything the real chip does, down to every bus cycle (all 1,510,000 cases match), and it passes Klaus Dormann’s functional test, a 6502 program that checks every instruction and flag and stops in a known place if everything’s right. So any 6502 program, built with any 6502 tools, runs here as it would on the real thing.

This page fills in what the earlier ones skipped, and looks at the chip as its designers saw it.

Hex numbers are written with a $, as in 6502 assembly.

The 6502 came out in 1975, from MOS Technology, designed by a small team led by Chuck Peddle, several of whom had worked on Motorola’s 6800. It was priced at $25, a fraction of what its rivals cost, and that price, more than any feature, is what put it in so many of the first home computers.

Cheap meant small, and small meant choices:

  • Few registers. A, X and Y are 8 bits each; the stack pointer is 8 bits too, which is why the stack is one page.
  • The zero page instead. With only three registers to work in, programs keep their variables in the first 256 bytes of memory, where instructions are a byte shorter and a cycle faster. The zero page is, in effect, 256 extra registers.
  • Mostly hardwired control, with a small decoding PLA (as on the CPU page).
  • No multiply or divide. Software does it.

It went on to run the Apple II, the Commodore PET and BBC Micro, the Atari 2600 (as the 6507, with fewer pins), the Commodore 64 (as the 6510, with a built-in I/O port), and the Nintendo Entertainment System (inside Ricoh’s 2A03, with decimal mode switched off). A CMOS version, the 65C02, is still made today.

2 · Pointers: the rest of the addressing modes

Section titled “2 · Pointers: the rest of the addressing modes”

The earlier pages used immediate, absolute, zero-page and indexed modes. The 6502 has three more, and two of them use a pointer: an address stored in the zero page, in two bytes, low first.

  • (zp),Y, indirect indexed: LDA ($10),Y reads the address stored at $10 and $11, adds Y, and loads from there. The pointer says where a buffer starts, and Y walks through it, which is how 6502 programs copy strings, fill screens and walk through tables anywhere in memory.
  • (zp,X), indexed indirect: LDA ($10,X) adds X to $10 first, and reads the pointer from there: a choice from a table of pointers.
  • (abs), indirect, for JMP only: JMP ($1234) jumps to the address stored at $1234 and $1235, so a program can jump through a table, or to an address it worked out.

Every chip has them, and some of the 6502’s became famous:

  • JMP ($xxFF). JMP ($12FF) should take its address from $12FF and $1300. The 6502 forgets to carry into the high byte, and takes it from $12FF and $1200. Programs just avoid putting pointers there; the 65C02 fixed it.
  • The extra cycles from the CPU page: one when an index crosses a page, and the unchanged write in read-modify-write instructions.
  • Decimal mode’s flags. After a decimal add, the N, V and Z flags don’t describe the decimal answer (the ALU page has more). The emulator copies exactly what the real chip does instead.
  • The undocumented opcodes. The 105 opcodes the 6502’s makers didn’t document still do something, the result of the decoding logic matching parts of patterns meant for others: some are useful combinations (load A and X at once), some are unstable, and a few freeze the chip. Programmers found them anyway, and some games use them. This emulator stops at them.

With no multiply instruction, programs multiply in software. The CPU page did it the long way, eight rounds of shift and add. When speed matters, a table is faster, and it starts from squaring a sum and a difference:

(a+b)2=a2+2ab+b2(a−b)2=a2−2ab+b2\begin{aligned} (a + b)^2 &= a^2 + 2ab + b^2 \\ (a - b)^2 &= a^2 - 2ab + b^2 \end{aligned}

The two differ only in the sign of the middle term. Take the second from the first, and a² and b² cancel, leaving the middle terms, 2ab − (−2ab):

(a+b)2−(a−b)2=4ab(a + b)^2 - (a - b)^2 = 4ab

Divide by 4, and the product is one square less another:

a⋅b=(a+b)24−(a−b)24a \cdot b = \frac{(a + b)^2}{4} - \frac{(a - b)^2}{4}

For 23 × 45: a + b = 68 and a − b = −22, and 68²/4 − 22²/4 = 1156 − 121 = 1035. Squaring loses the sign, so the program can use 45 − 23 = 22 just as well, and the table only needs positive numbers.

Store f(n) = n²/4, rounded down, for every n from 0 to 510, and a multiply becomes an add, a subtract, two lookups and one more subtract. (The rounding down never matters: a + b and a − b are both even or both odd, so the two fractions thrown away are equal.)

23 × 45 by a table of squares: 1035 ($040B) at $0002 and $0003 again. The whole program takes 70 cycles, against 200 for shift and add (switch programs to compare), but the table costs 1,022 bytes of ROM: speed traded for memory, as so often. Scroll the listing to see the table.

The reason these pages chose the 6502 is its software, and especially its compilers. cc65 compiles C for it, and so does llvm-mos, a newer port of the LLVM compiler. A C compiler for the 6502 has its work cut out: C wants a stack for its variables, and the 6502’s own stack is just one page, so cc65 keeps a second, software stack in RAM, with a pointer in the zero page.

A C program, compiled with cc65 for this computer: it finds prime numbers and shows each one on the digits, counting them on the LEDs, waiting between them on timer 1. The left is the C source, the right the 6502 code it became (953 bytes, with the startup code), disassembled around the PC. Click Run. The source, the linker settings for this computer’s memory map, and how to rebuild it are in the site’s repository, under sites/cpu/programs/c.

  • The emulator is a 6502, checked cycle for cycle against test data for the real chip.
  • It was designed to be cheap: few registers, the zero page as 256 more, mostly hardwired control, no multiply. It went into a generation of home computers and consoles, and is still made.
  • Pointers in the zero page, with (zp),Y, let programs reach anywhere in memory.
  • Its quirks: JMP ($xxFF), the extra cycles, decimal-mode flags, undocumented opcodes.
  • Without a multiply instruction, a table of squares multiplies in about a third of the time of shift and add.
  • C compilers (cc65, llvm-mos) target it, with a software stack for C’s variables.
  • Brian Bagnall, Commodore: A Company on the Edge, 2010: the story of MOS Technology and the 6502.
  • Tom Harte’s single-step tests (github.com/SingleStepTests/65x02) and Klaus Dormann’s functional tests (github.com/Klaus2m5/6502_65C02_functional_tests): how 6502 emulators are checked.
  • The cc65 documentation (cc65.github.io), and the llvm-mos project (llvm-mos.org).
  • The Visual6502 project (visual6502.org): the real chip, transistor by transistor, including what the undocumented opcodes do.