Introduction[edit | edit source]

The MOS Technology 6502 was first released in 1975 and was the dominant CPU in home computers for a decade, appearing in the Atari 2600, Apple II, NES, Commodore PET/VIC20/C64. It is an 8-bit processor with 16 bit address space. It included 3 registers (Accumulator and two general purpose X, Y registers) and a status register.

The instruction sets allowed for loading, storing, and transferring data between the A, X, and Y registers, arithmetic, shifting and rotating, logic AND and OR, comparison, branching, jumping and subroutines, interrupts, and stack operations.

Memory to the 6502 spans its entire 16-bit address space and allows for up to 64 KB of memory to be addressed. Though, this space may also be used for ROM, screen memory, or hardware peripherals via memory mapped IO. While the address space can be divided up in various ways depending on the hardware designer, the 6502 is hard coded to use the following memory mapping.

Address Purpose
0000 - 00FF First page is known as the Zero page and used for variables.

Instructions can reference a single-byte address which references the zero page.

0100 - 01FF Second page reserved for the stack. Initializes at 0x1FF.

The 8-bit stack location is stored in the S register. S initializes to FF and grows down as the stack is used.

FFFA - FFFF Typically a ROM address space containing the:
  • Reset routine (FFFC - FFFD)
  • Interrupt Request (IRQ) Interrupt Service Routine (ISR), FFFA - FFFB
  • Non-Maskable Interrupt (NMI) ISR, FFFE - FFFF

A ROM is typically required in order to tell the 6502 where to begin execution (the reset routine) and provide the instructions to execute.

A hardware designer can choose to divide the memory up, for example to have the upper half of the address space as ROM and the lower half as RAM while reserving a small address space for memory mapped IO. To implement this, some type of address decoding logic is needed to convert the raw address value asserted by the processor on the address bus into enable/disable signals that are sent to the ROM, RAM, or hardware peripheral. It's a good idea to have the mapping as simple as possible so that implementing the address decoding logic requires fewer parts since additional hardware increases propagation delay which can be problematic especially if the processor runs at a high clock rate.

Instruction Set[edit | edit source]

Description Instructions Examples and notes
Load from memory LDA, LDX, LDY LDA #$22 to load 0x22 to accumulator

LDA $D010 to load value at memory location 0xD010

LDA $0400,X to load the value at 0x0400+Register X useful for index addressing

Store to memory STA, STX, STY
Transfer from Accumulator TAX, TAY
Transfer to Accumulator TXA, TYA Note: No way to directly transfer between registers X and Y
Arithmetic on accumulator ADC add

SBC - subtract

ADC #$02 add 2 to accumulator

ADC $4050 add value at 0x4050 to accumulator

Increment and Decrement INC, INX, INY

DEC, DEX, DEY

Note: May set carry, overflow, or zero flags.
Rotate ROL, ROR Rotate left or right
Shifting ASL, ASR

LSL, LSR

Arithmetic shift will set carry bit, Logical uses carry bit (?)

ASL 1111000 (C=0) results 1110000 (C=1)

LSR 11110000 (C=1) results 11111000 (C=0)

Set Flags SEC, SED, SEI Sets carry, decimal, interrupt
Clear Flags CLC, CLV, CLI, CLD Clear carry, overflow, interrupt, decimal
Jumping JMP
Branching BCC - carry clear

BCS - carry set

BNE - zero clear

BEQ - zero set

BPL - negative clear

BMI - negative set

BVC - overflow clear

BVS - overflow set

Stack PUSH, PULL

PHP, PLP - push/pull flags

PHA, PLA - push/pull accumulator

Subroutine JSR - jump to subroutine

RTS - return

JSR pushes the current address to the stack before jumping. RTS pops and jumps back to this location and adds one.

Flags[edit | edit source]

  • Carry set if add/inc >255 or sub/dec <0.
  • Overflow if numbers >255
  • Zero: operation results in 0
  • Negative: bit 7 is set
  • Break
  • Interrupt
  • Decimal

Other Notes[edit | edit source]

The processor is little endian. The least significant value is always first. In the case of a 16-bit value, the lower 8-bits are sent, then the higher 8-bits.

See Also[edit | edit source]