The Instruction Set#
The 6502’s instruction set is small — about 56 mnemonics — and you can write whole games with maybe two dozen of them. This page is a grouped tour, not an exhaustive datasheet: enough to recognize what you read and reach for what you need. Cycle counts live in Cycles & Timing; flag effects are in Registers & Status Flags.
Moving data#
The most common instructions by far — nothing computes until data is in a register.
- Load:
LDALDXLDY— register ← memory (or an immediate). Sets N and Z. - Store:
STASTXSTY— register → memory. Sets no flags. This is how you write every TIA/RIOT register. - Transfer:
TAXTAYTXATYA— copy between A and an index register (2 cycles, sets N/Z).TSX/TXSmove between X and the stack pointer.
Arithmetic and logic (through A)#
All of these operate on the accumulator.
- Add / subtract:
ADC(add with carry),SBC(subtract with carry). There is no plain add — the carry is always involved, soCLC/ADCandSEC/SBCare the idioms (Numbers & Arithmetic). - Bitwise:
ANDORAEOR— clear, set, and toggle bits against a mask (Thinking in Bits). BIT— sets Z fromA AND memory, and copies memory bits 7→N and 6→V. The standard way to test a register’s top two bits (collisions, inputs) without touching A.
Counting and shifting#
- Increment / decrement:
INXDEXINYDEYon the index registers (2 cycles);INCDECon a memory location (read-modify-write, 5–7 cycles). Note: there is noINA— you can’t increment A directly; useCLC/ADC #1. - Shift / rotate:
ASLLSRROLROR— move bits left/right by one, through the carry.ASL/LSRare your ×2 and ÷2 (Numbers).
Comparing#
CMPCPXCPY— subtract (register − memory) without storing the result, just to set the flags. Follow with a branch:CMP #10thenBCS("≥ 10"),BEQ("= 10"),BCC("< 10").
Branching and jumping#
- Branches test one flag and are relative (a short hop, ±127 bytes):
BEQ/BNE(Z),BCS/BCC(C),BMI/BPL(N),BVS/BVC(V). JMP— unconditional jump (absolute or indirect).JSR/RTS— call and return from a subroutine, using the stack.
Stack and flags#
- Stack:
PHA/PLApush and pull A;PHP/PLPpush and pull the status register. - Flag set/clear:
CLCSEC(carry),CLDSED(decimal),CLV(overflow),CLISEI(interrupt — moot on the VCS). NOP— do nothing, for 2 cycles. Sounds useless; it’s a precision tool for burning exact time in a kernel.
In Practice#
- A handful does almost everything. A typical kernel line is some mix of
LDA/LDX/STA/INX/DEX/BNEand aSTA WSYNC. Master those and most VCS source reads fluently. - Stores set no flags — loads do. Because
LDA/AND/INXalready update Z and N, you can often branch immediately without a separateCMP. Recognizing when the flag is “already right” saves both bytes and cycles. - There’s no multiply, divide, or
INA. The gaps in the set are as defining as its contents — they’re why shifts, tables, and BCD carry so much weight in 6502 code.