The Commodore 64 uses the MOS 6510 processor, which is a slightly modified 6502 with an additional 8-bit I/O port at addresses $0000–$0001. It runs at:
| Register | Size | Description |
|---|---|---|
| A (Accumulator) | 8-bit | Primary arithmetic/logic register |
| X (Index X) | 8-bit | Index register, loop counter, offset |
| Y (Index Y) | 8-bit | Index register, loop counter, offset |
| PC (Program Counter) | 16-bit | Address of next instruction |
| SP (Stack Pointer) | 8-bit | Points into stack ($0100–$01FF) |
| SR (Status Register) | 8-bit | Processor flags |
Bit 7 N Negative — Set if result bit 7 = 1
Bit 6 V Overflow — Set on signed arithmetic overflow
Bit 5 - (always 1)
Bit 4 B Break — Set when BRK instruction executed
Bit 3 D Decimal — Decimal mode (BCD arithmetic)
Bit 2 I IRQ Mask — 1 = IRQ disabled
Bit 1 Z Zero — Set if result = 0
Bit 0 C Carry — Set on unsigned arithmetic carry/borrow
| Mode | Syntax | Bytes | Example | Description |
|---|---|---|---|---|
| Implied | — | 1 | CLC |
Operand implied by opcode |
| Accumulator | A | 1 | LSR A |
Operand is accumulator |
| Immediate | #$nn | 2 | LDA #$41 |
Literal value |
| Zero Page | $nn | 2 | LDA $FB |
Byte in zero page (fast!) |
| Zero Page,X | $nn,X | 2 | LDA $FB,X |
Zero page + X |
| Zero Page,Y | $nn,Y | 2 | LDX $FB,Y |
Zero page + Y |
| Absolute | $nnnn | 3 | LDA $C000 |
16-bit address |
| Absolute,X | $nnnn,X | 3 | LDA $C000,X |
16-bit + X |
| Absolute,Y | $nnnn,Y | 3 | LDA $C000,Y |
16-bit + Y |
| Indirect | ($nnnn) | 3 | JMP ($0314) |
Jump via pointer |
| (Indirect,X) | ($nn,X) | 2 | LDA ($FC,X) |
Zero-page ptr + X (pre-indexed) |
| (Indirect),Y | ($nn),Y | 2 | LDA ($FC),Y |
Zero-page ptr, then + Y (post-indexed) |
| Relative | $nn | 2 | BEQ $+5 |
Branch offset (-128 to +127) |
Performance note: Zero-page addressing is 1 cycle faster than absolute and uses 1 fewer byte. Use zero page for frequently accessed variables.
LDA Load Accumulator N Z
LDX Load X Register N Z
LDY Load Y Register N Z
STA Store Accumulator
STX Store X Register
STY Store Y Register
TAX Transfer A to X N Z
TAY Transfer A to Y N Z
TXA Transfer X to A N Z
TYA Transfer Y to A N Z
TSX Transfer SP to X N Z
TXS Transfer X to SP
ADC Add with Carry N V Z C
SBC Subtract with Carry N V Z C
INC Increment Memory N Z
INX Increment X N Z
INY Increment Y N Z
DEC Decrement Memory N Z
DEX Decrement X N Z
DEY Decrement Y N Z
Important: Always use CLC before ADC and SEC before SBC unless chaining multi-byte math.
AND AND with Accumulator N Z
ORA OR with Accumulator N Z
EOR XOR with Accumulator N Z
BIT Bit Test N V Z
ASL Arithmetic Shift Left N Z C (multiply by 2)
LSR Logical Shift Right N Z C (divide by 2)
ROL Rotate Left N Z C (shift through carry)
ROR Rotate Right N Z C (shift through carry)
CMP Compare A with Memory N Z C
CPX Compare X with Memory N Z C
CPY Compare Y with Memory N Z C
BCC Branch if Carry Clear (C=0)
BCS Branch if Carry Set (C=1)
BEQ Branch if Equal (zero) (Z=1)
BNE Branch if Not Equal (Z=0)
BMI Branch if Minus (N=1)
BPL Branch if Plus (N=0)
BVC Branch if Overflow Clear (V=0)
BVS Branch if Overflow Set (V=1)
JMP Jump (absolute or indirect)
JSR Jump to Subroutine (pushes PC-1 to stack)
RTS Return from Subroutine (pulls PC+1 from stack)
RTI Return from Interrupt (pulls SR then PC from stack)
BRK Software Break/Interrupt
PHA Push Accumulator to Stack
PLA Pull Accumulator from Stack N Z
PHP Push Status Register to Stack
PLP Pull Status Register from Stack
CLC Clear Carry
SEC Set Carry
CLI Clear IRQ Mask (enable IRQs)
SEI Set IRQ Mask (disable IRQs)
CLD Clear Decimal Mode
SED Set Decimal Mode
CLV Clear Overflow
NOP No Operation (2 cycles)
; Add 16-bit values at $FB/$FC to $FD/$FE
; Result in $FB/$FC
CLC
LDA $FB
ADC $FD
STA $FB
LDA $FC
ADC $FE ; carry propagates
STA $FC
SEC
LDA $FB
SBC $FD
STA $FB
LDA $FC
SBC $FE
STA $FC
10 FOR I=49152 TO 49152+N : READ D : POKE I,D : NEXT
20 SYS 49152
100 DATA 169,72,32,210,255,169,73,32,210,255,96
; After loading SUPERMON:
A C000 ; assemble at $C000
LDA #$41
JSR $FFD2 ; BSOUT - print char
RTS
; Press RETURN on empty line to exit
G C000 ; execute from $C000
SYS 1536 ; enter monitor (if SUPERMON at $0600)
SYS 49152 ' call ML at $C000
SYS 49152,A,X,Y ' with register values (some monitors)
POKE 251,LO : POKE 252,HI ' pass address in ZP
SYS 49152
RESULT = PEEK(253) ' read result back
Location $0311-$0312 contains the USR vector (default: $FFB7)
POKE 785, LO : POKE 786, HI ' point USR to your routine
X = USR(VALUE) ' call from BASIC, float in FAC
LDA #0 ; or: AND #0 or: EOR #$FF ; not #$FF
BEQ zero ; branch if A was 0 (after any instruction that sets Z)
DELAY LDX #$FF
OUTER LDY #$FF
INNER DEY
BNE INNER
DEX
BNE OUTER
RTS
; Copy $C000-$C0FF to $D000 (100 bytes example — NOT I/O area in practice!)
LDX #0
LOOP LDA $C000,X
STA $CC00,X ; adjust destination
INX
BNE LOOP ; loop 256 times
INC $FB
BNE SKIP
INC $FC
SKIP ...
The 6510 has a built-in 8-bit I/O port multiplexed at $0000 (direction) and $0001 (data):
$0000 Direction: 1=output, 0=input (default: $2F = %00101111)
$0001 Data port:
Bit 0: LORAM — 0=BASIC ROM off, 1=on
Bit 1: HIRAM — 0=Kernal ROM off, 1=on
Bit 2: CHAREN — 0=Char ROM at $D000, 1=I/O at $D000
Bit 3: Cassette data output
Bit 4: Cassette switch sense (input)
Bit 5: Cassette motor control
To bank out ROMs and access full RAM:
LDA #$34 ; %00110100 - RAM everywhere, I/O still visible
STA $0001
To restore normal operation:
LDA #$37 ; %00110111 - BASIC+Kernal+I/O (normal)
STA $0001
Powered by TurnKey Linux.