An instruction set
Memory and buses ended with the 6502 reading and writing memory, one byte per clock cycle. What it reads, mostly, is its own program. A program is just bytes in memory, and each instruction is one, two or three of them: the first says what to do (the opcode), and the rest, if any, say what to do it to.
This page introduces the instructions a processor needs first, using the real 6502’s, with its real opcodes, so everything here runs on a real one. It also gives you a little computer to run them on: a 6502 at 1 MHz, with the memory map from the last page (RAM from $0000, the program in ROM from $C000).
Hex numbers are written with a $, as in 6502 assembly.
1 · A program is bytes
Section titled “1 · A program is bytes”The 6502 keeps its place in the program in a 16-bit register, the program counter (PC). Over and over, it fetches the byte the PC points to, works out what it means (decodes it), and executes it, reading any more bytes it needs and moving the PC past them. Then it fetches the next.
Nobody writes programs as bytes, though. Each instruction has a three-letter name, a mnemonic, which is usually a squashed-up description of what it does: LDA is LoaD A. A program written in mnemonics is assembly language. LDA #25 means “load A with 25”: the opcode for that is $A9, and the 25 follows it, so it’s two bytes, A9 19. An assembler does the translating.
2 · The accumulator, and the first instructions
Section titled “2 · The accumulator, and the first instructions”The 6502 does its arithmetic in one register, A, the accumulator: every sum goes in and comes out there. The first instructions move numbers between A and memory, and do the ALU’s operations on it:
- LDA (load A) and STA (store A): A from memory, A to memory.
- ADC (add with carry) and SBC (subtract with carry): add to A, subtract from A, with the carry flag, so it’s CLC (clear carry) before adding and SEC (set carry) before subtracting, as on the ALU page.
- AND (AND with A), ORA (OR with A) and EOR (exclusive OR with A): the bit-by-bit operations.
- CMP (compare with A): compare A with something, setting the flags for a branch to test.
So AND #$0F means “AND A with the number $0F”, and ADC $10 “add the byte at $10 to A, with the carry”.
The little computer. Click Step to run one instruction at a time, and watch A, the flags and the PC; the listing highlights the next instruction, and memory shows the zero page, where the answer goes (address $0000, top left). Each program ends at a JMP (jump) to itself, where the computer stops. You can edit the program and click Assemble and reset. The larger of two numbers uses CMP and a branch, BCS (branch if carry set), from section 4.
3 · Where the operand comes from: addressing modes
Section titled “3 · Where the operand comes from: addressing modes”LDA can load A from several places, and each is a different opcode. These are the addressing modes:
- Immediate, LDA #25: the number itself follows the opcode (the # says so). Two bytes.
- Absolute, LDA $1234: load from address $1234, which follows the opcode, low byte first. Three bytes.
- Zero page, LDA $12: an address in the first 256 bytes, $0000 to $00FF, needs only one byte, so the instruction is shorter and a cycle faster. The 6502 has few registers, and programs use the zero page as 256 slower but plentiful ones.
- Indexed, LDA table,X: the address plus the value in register X (or Y). With X counting up, the same instruction reaches each entry of a table in turn.
X and Y are the 6502’s two index registers, with their own loads and stores: LDX and STX (load X, store X), LDY and STY (load Y, store Y). They can count:
- INX (increment X) adds 1 to X, and DEX (decrement X) takes 1 away; INY and DEY do the same for Y.
- CPX (compare with X) and CPY (compare with Y) compare them with something, as CMP does for A.
- TAX (transfer A to X) copies A into X, and TXA (transfer X to A) copies it back; TAY and TYA do the same with Y.
Add up a table steps X through five bytes, the table at $0010 (second row of the memory), adding each to A: the answer, 14, ends up at $0000, so everything the program works on is in view. (Here the table is loaded into RAM along with the program. A real computer’s RAM holds nothing useful when it’s switched on, so its program would copy the table there from ROM first.) Fill memory, counting down uses X as a counter and as an index at once, storing 10 at $001A down to 1 at $0011. Click Run to run at full speed, or choose slowly to watch.
4 · Branches and jumps
Section titled “4 · Branches and jumps”A program that only ever ran straight on would be short. JMP (jump) sets the PC to a new address, so the program continues from there. A branch does so only if a flag says so: BEQ (branch if equal) branches if Z is set (the last result was zero, or a comparison found them equal), BNE (branch if not equal) if it isn’t. There’s a pair for each flag:
- BCS and BCC: branch if carry set, or clear;
- BMI and BPL: branch if minus (N set), or plus (N clear);
- BVS and BVC: branch if overflow set, or clear.
A branch doesn’t store the address to go to; it stores how far to go, as a signed byte, from −128 to +127 bytes from the next instruction. Loops are usually short, so that saves a byte, and a branch that doesn’t jump far doesn’t care where the program is in memory. A loop is just a branch backwards: DEX, then BNE back to the start of the loop, goes round until X reaches 0.
5 · Instructions as bits
Section titled “5 · Instructions as bits”The 6502 has 151 opcodes, each an instruction with an addressing mode, and they aren’t scattered at random over the 256 possible bytes. Many follow a pattern: write the opcode in binary as three fields, aaa bbb cc. For the arithmetic and logic instructions (cc = 01), aaa says which operation, and bbb which addressing mode, the same eight modes for all eight operations. The decoder only has to look at the fields.
Every opcode, by its high hex digit (rows) and low hex digit (columns), coloured by cc. Click one to see its fields, size and timing (measured on this page’s emulator). The arithmetic group is the columns 1, 5, 9 and D: each pair of rows there is one operation (ORA in rows 0 and 1, AND in 2 and 3, and so on), and each column one addressing mode on the even rows and another on the odd. The 105 empty squares are the opcodes the 6502’s designers didn’t document.
6 · The assembler
Section titled “6 · The assembler”The assembler on this page reads the same syntax as ca65, the assembler in the cc65 tools, so programs here also build with real tools. Besides instructions, it understands:
- Labels, such as
loop:, naming an address, so a branch can say BNE loop instead of counting bytes. - Constants, such as
total = $00. - Directives:
.org $C000(put what follows there),.byteand.word(data),.res(reserve space).
It works through the program twice. A branch forward to a label that comes later can’t be finished the first time through, because the label’s address isn’t known yet, so the first pass only works out where everything goes and the second fills in the bytes. One choice has to be made in the first pass: an address below $0100 can use the shorter zero-page form, but only if it’s known then.
Summary
Section titled “Summary”- A program is bytes in memory: an opcode, then any operand bytes. The PC says where; the CPU fetches, decodes and executes, over and over.
- The 6502 computes in A, the accumulator: LDA, STA, ADC/SBC (with CLC/SEC), AND, ORA, EOR, CMP.
- Addressing modes say where the operand is: immediate (#), absolute, zero page (shorter and faster), indexed by X or Y.
- JMP goes anywhere; branches go a short way, if a flag says so. A loop is a branch backwards.
- Opcodes are encoded in fields, aaa bbb cc, so decoding is simpler than it looks.
- An assembler turns mnemonics and labels into bytes, in two passes.
Further reading
Section titled “Further reading”- Rodnay Zaks, Programming the 6502, 1978 (and later editions): the instruction set, gently, with programs.
- Andrew Jacobs’s 6502 reference (mirrored at 6502.org): every instruction, mode, size and timing.
- The cc65 documentation for ca65, the assembler this page’s follows.