6502 Assembly Language
The Language of the Revolution
6502 Assembly Language is the native instruction set for the MOS Technology 6502 processor, the chip that powered the personal computer revolution. From the Apple II to the Commodore 64 to the Nintendo Entertainment System, 6502 assembly was the language of choice for programmers who needed maximum performance and hardware control.
Processor Architecture
Registers
The 6502 has a minimal but efficient register set:
- A (Accumulator): Primary data register for arithmetic and logic
- X, Y: Index registers for addressing and counting
- SP (Stack Pointer): Points to current stack location ($0100-$01FF)
- PC (Program Counter): Current instruction address
- P (Processor Status): Flags register (N, V, B, D, I, Z, C)
Memory Organization
- Zero Page: $0000-$00FF (fast access, special addressing)
- Stack: $0100-$01FF (hardware stack for subroutines)
- General RAM: $0200+ (varies by system)
- I/O Area: Memory-mapped hardware registers
- ROM: System firmware and cartridge code
Addressing Modes
Immediate
Load constant values:
LDA #$42 ; Load hex 42 into accumulator
LDX #100 ; Load decimal 100 into X
Zero Page
Fast access to first 256 bytes:
LDA $80 ; Load from zero page address $80
STA $81 ; Store to zero page address $81
Absolute
Full 16-bit addressing:
LDA $2000 ; Load from address $2000
JMP $C000 ; Jump to address $C000
Indexed Addressing
Using X or Y registers as offsets:
LDA $2000,X ; Load from $2000 + X
STA $3000,Y ; Store to $3000 + Y
Indirect Addressing
Pointer-based memory access:
JMP ($2000) ; Jump to address stored at $2000
LDA ($80),Y ; Load from address at $80/$81 + Y
Core Instructions
Data Movement
LDA #$42 ; Load accumulator with immediate value
LDX $80 ; Load X from zero page
LDY $2000 ; Load Y from absolute address
STA $81 ; Store accumulator to zero page
STX $2001 ; Store X to absolute address
STY $82 ; Store Y to zero page
TAX ; Transfer A to X
TAY ; Transfer A to Y
TXA ; Transfer X to A
Arithmetic and Logic
ADC #$10 ; Add with carry
SBC #$05 ; Subtract with carry
AND #$0F ; Bitwise AND
ORA #$80 ; Bitwise OR
EOR #$FF ; Exclusive OR
ASL ; Arithmetic shift left
LSR ; Logical shift right
ROL ; Rotate left through carry
ROR ; Rotate right through carry
Comparison and Testing
CMP #$42 ; Compare accumulator with value
CPX $80 ; Compare X with zero page
CPY $2000 ; Compare Y with absolute
BIT $81 ; Test bits (affects N, V, Z flags)
Program Flow
JMP $2000 ; Unconditional jump
JSR $C000 ; Jump to subroutine
RTS ; Return from subroutine
BEQ label ; Branch if equal (Z=1)
BNE label ; Branch if not equal (Z=0)
BCC label ; Branch if carry clear
BCS label ; Branch if carry set
BMI label ; Branch if minus (N=1)
BPL label ; Branch if plus (N=0)
Programming Techniques
Zero Page Optimization
Using zero page for frequently accessed variables:
player_x = $80 ; Define zero page variable
player_y = $81
enemy_x = $82
LDA player_x ; Fast zero page access
CMP enemy_x ; Compare positions
BEQ collision ; Branch if equal
Stack Operations
Managing the hardware stack:
LDA #$42
PHA ; Push accumulator to stack
LDA #$24
PHA ; Push another value
PLA ; Pull last value (gets $24)
PLA ; Pull first value (gets $42)
Subroutines
Modular programming with JSR/RTS:
main:
JSR init_screen
JSR game_loop
RTS
init_screen:
LDA #$20
STA $D020 ; Set border color
RTS
game_loop:
JSR read_input
JSR update_sprites
JSR check_collisions
JMP game_loop
Hardware Programming
Memory-Mapped I/O
Direct hardware control through memory addresses:
; Commodore 64 examples
LDA #$00
STA $D020 ; Black border
LDA #$01
STA $D021 ; White background
LDA #$0F
STA $D418 ; Full SID volume
Interrupt Handling
Custom interrupt routines:
; Set up custom IRQ
SEI ; Disable interrupts
LDA #<irq_handler
STA $0314 ; IRQ vector low byte
LDA #>irq_handler
STA $0315 ; IRQ vector high byte
CLI ; Enable interrupts
irq_handler:
; Save registers
PHA
TXA
PHA
TYA
PHA
; Do interrupt work
INC $D020 ; Flash border
; Restore registers
PLA
TAY
PLA
TAX
PLA
RTI ; Return from interrupt
Sprite Programming (C64)
Hardware sprite control:
; Enable sprite 0
LDA #$01
STA $D015 ; Sprite enable register
; Set sprite position
LDA #100
STA $D000 ; Sprite 0 X position
LDA #150
STA $D001 ; Sprite 0 Y position
; Set sprite data pointer
LDA #192 ; Sprite data at $3000
STA $07F8 ; Sprite 0 data pointer
Advanced Concepts
Timing-Critical Code
Precise cycle counting for raster effects:
wait_raster:
LDA $D012 ; Current raster line
CMP #$80 ; Wait for line 128
BNE wait_raster ; Loop until reached
; Now we're synchronized to raster line 128
NOP ; 2 cycles
NOP ; 2 cycles
LDA #$02 ; 2 cycles
STA $D020 ; 4 cycles - border changes here
Self-Modifying Code
Programs that modify themselves:
LDA #$EA ; NOP instruction
STA skip_code ; Modify the instruction
skip_code:
LDA #$42 ; This becomes NOP if modified
Bank Switching
Managing more memory than addressable:
; C64 example - switching BASIC ROM out
LDA $01 ; Current memory configuration
AND #$FE ; Clear bit 0
STA $01 ; BASIC ROM now switched out
System-Specific Features
Commodore 64
; Screen memory at $0400
LDA #$01 ; White character
STA $0400 ; Top-left corner
; Color RAM at $D800
LDA #$02 ; Red color
STA $D800 ; Color for top-left character
Apple II
; Text mode screen at $0400
LDA #$C8 ; 'H' with high bit set
STA $0400 ; Display on screen
; Switch to graphics mode
STA $C050 ; Graphics mode
STA $C057 ; Hi-res mode
Nintendo NES
; PPU control
LDA #$90 ; Enable NMI, use $1000 for sprites
STA $2000 ; PPU control register
; Set scroll position
LDA #$00
STA $2005 ; Scroll X
STA $2005 ; Scroll Y
Development Tools
Cross-Assemblers
Modern tools for 6502 development:
- ACME: Flexible macro assembler
- ca65: Part of cc65 C compiler suite
- DASM: Originally for Atari 2600
- 64tass: Advanced assembler with modern features
Native Development
Historical on-system development:
- Turbo Macro Pro: C64 native assembler
- Merlin: Apple II assembler
- MAC/65: Atari 8-bit assembler
Educational Value
Fundamental Concepts
6502 assembly teaches:
- Computer architecture basics
- Memory management principles
- Interrupt-driven programming
- Hardware/software interaction
- Optimization techniques
Historical Significance
Understanding 6502 provides insight into:
- Evolution of computer architecture
- Constraints-driven design
- Performance optimization techniques
- Hardware abstraction development
Modern Relevance
Retro Development
Active community creating new software:
- Homebrew games for classic systems
- Demoscene productions
- Educational tools
- Hardware expansions
Emulation and Preservation
Critical for:
- Accurate emulator development
- Software preservation projects
- Historical documentation
- Educational research
Embedded Systems
6502 variants still used in:
- Microcontrollers
- Industrial automation
- Educational systems
- Hobbyist projects
Performance Characteristics
Advantages
- Simple, orthogonal instruction set
- Efficient zero page addressing
- Fast interrupt handling
- Compact code generation
- Predictable timing
Limitations
- No multiply/divide instructions
- Limited registers
- No stack-relative addressing
- 64KB address space limit
- No memory protection
Conclusion
6502 Assembly Language represents the perfect balance between simplicity and power. Its clean design and logical addressing modes made it accessible to programmers while still providing the control needed for sophisticated software.
Learning 6502 assembly provides deep insights into computer architecture, performance optimization, and the elegant solutions possible with limited resources. It remains one of the best assembly languages for understanding fundamental computing concepts, making it invaluable for both historical study and modern education.
The languageβs influence extends far beyond its original platforms, establishing patterns and principles still found in modern processors and development tools. For anyone interested in understanding how computers really work, 6502 assembly provides an excellent starting point.