This 6502 Cheat Sheet encapsulates the core elements essential for programming with the 6502 microprocessor, covering registers, flags, addressing modes, and a succinct overview of memory layout. It breaks down the instruction set into logical categories like Load/Store operations, Arithmetic, and System Control, enhancing understanding with flag effects for each command. Highlighting illegal opcodes and offering practical tips, this guide is a handy reference for both beginners and experienced programmers, supplemented with useful links for deeper exploration.
Key Concepts
Registers
- A (Accumulator): Used for arithmetic, logic operations, and data transfer.
- X and Y (Index Registers): Used for indexing and loops.
- PC (Program Counter): Points to the next instruction to execute.
- SP (Stack Pointer): Points to the current top of the stack.
- SR (Status Register): Holds FLAGS [NV-BDIZC] that describe the state of the processor. See a detailed description in the following block.
Flags
- N (Negative): Set if the result of the last operation is negative.
- V (Overflow): Set if the last addition or subtraction resulted in an overflow.
- B (Break Command): Set when a software interrupt (BRK instruction) is executed.
- D (Decimal Mode): Set if the processor is in decimal mode.
- I (Interrupt Disable): Set to disable interrupts.
- Z (Zero): Set if the result of the last operation is zero.
- C (Carry): Set if the last operation resulted in a carry out or borrow into the high order bit.
Addressing Modes
- Immediate: LDA #$FF- Load immediate value into A.
- Zero Page: LDA $00- Access memory location on the zero page.
- Zero Page,X/Y: LDX $00,X- Access memory using zero page address offset by X or Y.
- Absolute: JMP $F000- Jump to a specific memory address.
- Absolute,X/Y: STA $3000,X- Store A at an address offset by X or Y.
- Indirect: JMP ($FFFC)- Jump to the address stored at a specific location.
- Indexed Indirect: LDA ($40,X)- Use X to find a zero page address which points to the target address.
- Indirect Indexed: LDA ($40),Y- Use a zero page address to find a base address, then add Y.
Memory Layout
- The 6502's program counter is 16 bits wide, so up to 2^16 (65536) bytes of memory are addressable.
- 16-bit values are stored in memory in little-endian.
- Signed integers can represent values from -128 (%10000000) to +127 (%01111111).
| Region | Contents | Description | 
|---|---|---|
| $0000 - $00FF | Zero page | Faster to access than other pages. | 
| $0100 - $01FF | Stack | Last-in first-out data structure (LIFO). Grows backwards from $01FF to $0100. Used by some transfer, stack, and subroutine instructions | 
| $0200 - $FFFF | General-purpose | Memory that can be used for whatever purpose needed. Devices that use the 6502 processor may choose to reserve sub-regions for other purposes. | 
Instructions
Load/Store Operations
- LDALoad Accumulator with Memory (M → A)
- LDXLoad X Register with Memory (M → X)
- LDYLoad Y Register with Memory (M → Y)
- STAStore Accumulator in Memory (A → M)
- STXStore X Register in Memory (X → M)
- STYStore Y Register in Memory (Y → M)
| Instr. | N | V | - | B | D | I | Z | C | 
|---|---|---|---|---|---|---|---|---|
| LDA | ✓ | - | - | - | - | - | ✓ | - | 
| LDX | ✓ | - | - | - | - | - | ✓ | - | 
| LDY | ✓ | - | - | - | - | - | ✓ | - | 
| STA | - | - | - | - | - | - | - | - | 
| STX | - | - | - | - | - | - | - | - | 
| STY | - | - | - | - | - | - | - | - | 
Transfer
- TAXTransfer Accumulator To X (A → X)
- TAYTransfer Accumulator To Y (A → Y)
- TSXTransfer Stack Pointer To X (S → X)
- TXATransfer X to Accumulator (X → A)
- TYATransfer Y to Accumulator (Y → A)
- TXSTransfer X to Stack Pointer (A → X)
| Instr. | N | V | - | B | D | I | Z | C | 
|---|---|---|---|---|---|---|---|---|
| TAX | ✓ | - | - | - | - | - | ✓ | - | 
| TAY | ✓ | - | - | - | - | - | ✓ | - | 
| TSX | ✓ | - | - | - | - | - | ✓ | - | 
| TXA | ✓ | - | - | - | - | - | ✓ | - | 
| TYA | ✓ | - | - | - | - | - | ✓ | - | 
| TXS | - | - | - | - | - | - | - | - | 
Stack
- PHAPush Accumulator On Stack (A↓)
- PHPPush Processor Status On Stack (P↓)
- PLAPull Accumulator From Stack (A↑)
- PLPPull Processor Status From Stack (P↑)
| Instr. | N | V | - | B | D | I | Z | C | 
|---|---|---|---|---|---|---|---|---|
| PHA | - | - | - | - | - | - | - | - | 
| PHP | - | - | - | - | - | - | - | - | 
| PLA | ✓ | - | - | - | - | - | ✓ | - | 
| PLP | ✓ | ✓ | - | - | ✓ | ✓ | ✓ | ✓ | 
Arithmetic
- ADCAdd Memory to Accumulator with Carry (A+M+C → A, C)
- SBCSubtract Memory from Accumulator with Borrow* (A-M -~C → A)
| Instr. | N | V | - | B | D | I | Z | C | 
|---|---|---|---|---|---|---|---|---|
| ADC | ✓ | ✓ | - | - | - | - | ✓ | ✓ | 
| SBC | ✓ | ✓ | - | - | - | - | ✓ | ✓ | 
- Borrow is defined as the carry flag complemented.
Increment/Decrement
- INCIncrement Memory by 1 (M+1 → M)
- INXIncrement X Register by 1 (X+1 → X)
- INYIncrement Y Register by 1 (Y+1 → Y)
- DECDecrement Memory by 1 (M-1 → M)
- DEXDecrement X Register by 1 (X-1 → X)
- DEYDecrement Y Register by 1 (Y-1 → Y)
| Instr. | N | V | - | B | D | I | Z | C | 
|---|---|---|---|---|---|---|---|---|
| INC | ✓ | - | - | - | - | - | ✓ | - | 
| INX | ✓ | - | - | - | - | - | ✓ | - | 
| INY | ✓ | - | - | - | - | - | ✓ | - | 
| DEC | ✓ | - | - | - | - | - | ✓ | - | 
| DEX | ✓ | - | - | - | - | - | ✓ | - | 
| DEY | ✓ | - | - | - | - | - | ✓ | - | 
Shifts and Rotations
- ASLArithmetic Shift Left (C←[M7...M0]←0)
- LSRLogical Shift Right (0→[M7...M0]→C)
- ROLRotate Left (C←[M7...M0]←C)
- RORRotate Right (C→[M7...M0]→C)
| Instr. | N | V | - | B | D | I | Z | C | 
|---|---|---|---|---|---|---|---|---|
| ASL | ✓ | - | - | - | - | - | ✓ | ✓ | 
| LSR | 0 | - | - | - | - | - | ✓ | ✓ | 
| ROL | ✓ | - | - | - | - | - | ✓ | ✓ | 
| ROR | ✓ | - | - | - | - | - | ✓ | ✓ | 
Logical
- ANDAND Memory with Accumulator (A ∧ M → A)
- ORAOR Memory with Accumulator (A ∨ M → A)
- EORExclusive OR Memory with Accumulator (A ⊻ M → A)
- BITTest Bits in Memory with Accumulator (A ∧ M, M7→N, M6 → V)
| Instr. | N | V | - | B | D | I | Z | C | 
|---|---|---|---|---|---|---|---|---|
| AND | ✓ | - | - | - | - | - | ✓ | - | 
| ORA | ✓ | - | - | - | - | - | ✓ | - | 
| EOR | ✓ | - | - | - | - | - | ✓ | - | 
| BIT | ✓ | ✓ | - | - | - | - | ✓ | - | 
Compare
- CMPCompare Memory and Accumulator
- CPXCompare Memory and Index X
- CPYCompare Memory and Index Y
| Compare Result | N | Z | C | 
|---|---|---|---|
| A, X, or Y < Memory | * | 0 | 0 | 
| A, X, or Y = Memory | 0 | 1 | 1 | 
| A, X, or Y > Memory | * | 0 | 1 | 
Branching
- BCCBranch on Carry Clear (C = 0)
- BCSBranch on Carry Set (C = 1)
- BEQBranch on Result Zero (Z = 1)
- BMIBranch on Result Minus (N = 1)
- BNEBranch on Result not Zero (Z = 0)
- BPLBranch on Result Plus (N = 0)
- BVCBranch on Overflow Clear (V = 0)
- BVSBranch on Overflow Set (V = 1)
Flags
- CLCClear Carry Flag (0 → C)
- CLDClear Decimal Mode (0 → D)
- CLIClear Interrupt Disable (0 → I)
- CLVClear Overflow Flag (0 → V)
- SECSet Carry Flag (1 → C)
- SEDSet Decimal Mode (1 → D)
- SEISet Interrupt Disable (1 → I)
- NOPNo Operation
| Instr. | N | V | - | B | D | I | Z | C | 
|---|---|---|---|---|---|---|---|---|
| CLC | - | - | - | - | - | - | - | 0 | 
| CLD | - | - | - | - | 0 | - | - | - | 
| CLI | - | - | - | - | - | 0 | - | - | 
| CLV | - | 0 | - | - | - | - | - | - | 
| SEC | - | - | - | - | - | - | - | 1 | 
| SED | - | - | - | - | 1 | - | - | - | 
| SEI | - | - | - | - | - | 1 | - | - | 
| NOP | - | - | - | - | - | - | - | - | 
System Control
- BRKForce Break (PC + 2↓)
- JMPJump to New Location ([PC + 1]→PCL, [PC + 2]→PCH)
- JSRJump to Subroutine (PC + 2↓)
- RTIReturn from Interrupt (P↑ PC↑)
- RTSReturn from Subroutine (PC↑, PC + 1→PC)
- NOPNo Operation
| Instr. | N | V | - | B | D | I | Z | C | 
|---|---|---|---|---|---|---|---|---|
| BRK | - | - | - | - | - | 1 | - | - | 
| JMP | - | - | - | - | - | - | - | - | 
| JSR | - | - | - | - | - | - | - | - | 
| RTI | ✓ | ✓ | - | - | ✓ | ✓ | ✓ | ✓ | 
| RTS | - | - | - | - | - | - | - | - | 
| NOP | - | - | - | - | - | - | - | - | 
Illegal opcodes
- ALRAND + LSR (A AND oper, 0 → [M7...M0] → C)
- ANCAND + set C as ASL (A AND oper, bit(7) → C)
- ANC(ANC2) AND oper + set C as ROL (A AND oper, bit(7) → C)
- ANE(XAA) AND X + AND oper (unsatble)
- ARRAND oper + ROR (A AND oper, C → [M7...M0] → C)
- DCP(DCM) DEC oper + CMP oper (M - 1 → M, A - M)
- ISC(ISB, INS) INC oper + SBC oper (M + 1 → M, A - M - C → A)
- LAS(LAR) LDA/TSX oper (M AND SP → A, X, SP)
- LAXLDA oper + LDX oper (M → A → X)
- LXAStore * AND oper in A and X (highly unstable)
- RLAROL oper + AND oper (M = C ← [M7...M0] ← C, A AND M → A)
- RRAROR oper + ADC oper (M = C → [M7...M0] → C, A + M + C → A, C)
- SAX(AXS, AAX) A AND X → M
- SBX(AXS, SAX) (A AND X) - oper → X
- SHA(AHX, AXA) A AND X AND (H+1) → M
- SHX(A11, SXA, XAS) Stores X AND (high-byte of addr. + 1) at addr.
- SHY(A11, SYA, SAY) Stores Y AND (high-byte of addr. + 1) at addr.
- SLO(ASO) ASL oper + ORA oper
- SRE(LSE) LSR oper + EOR oper
- TAS(XAS, SHS) Puts A AND X in SP and stores A AND X AND (high-byte of addr. + 1) at addr.
- USBC(SBC) SBC oper + NOP (A - M - C → A)
- JAM(KIL, HLT) Freezes the CPU.
- 6502 Illegal opcodes
Basic Code Snippets
Subroutine Call and Return
JSR mySubroutine ; Call subroutine
; Code continues here after subroutine returns
JMP endProgram ;Jump to the end of the program or other operations
mySubroutine:
;Subroutine operations here
RTS  ;Return from subroutine
endProgram:
; Program end or halt
Delay Loop
    `LDX #$FF`  ; Outer loop counterouterLoop:
    `LDY #$FF`  ; Inner loop counterinnerLoop:
    `DEY`  ; Decrement Y
    `BNE innerLoop ` ; Continue inner loop until Y=0
    `DEX`  ; Decrement X
    `BNE outerLoop`  ; Continue outer loop until X=0; Delay complete
Useful Tips
General Tips
- Use comments to make your code understandable.
- Remember to set and clear the decimal mode (D flag) as needed.
- Use stack operations (PHA,PLA, etc.) to save and restore registers during subroutine calls.
- Keep track of the zero page for quick and efficient data access.
- Utilize loops and conditional branches effectively to control program flow.
