WDC 65C816 CPU Reference
Overview
The 65C816 is a 16-bit extension of the 6502 processor, designed by Western Design Center. It maintains backward compatibility with 6502 code while adding 16-bit operations, a 24-bit address space, and new addressing modes. This implementation provides a reusable, generic 65C816 CPU core that can be used by any system (SNES, Apple IIgs, etc.) by implementing the Memory65c816 trait.
Implementation: crates/core/src/cpu_65c816.rs
Architecture
Registers
The 65C816 has several operating modes that affect register sizes:
In Native Mode (16-bit)
- A (Accumulator): 16-bit (or 8-bit when M flag is set)
- X (Index Register X): 16-bit (or 8-bit when X flag is set)
- Y (Index Register Y): 16-bit (or 8-bit when X flag is set)
- SP (Stack Pointer): 16-bit
- PC (Program Counter): 16-bit
- PBR (Program Bank Register): 8-bit (forms 24-bit address with PC)
- DBR (Data Bank Register): 8-bit (default bank for data access)
- D (Direct Page Register): 16-bit (base for direct page addressing)
- Status: 8-bit processor status register
Status Register Flags
NVMXDIZC (Native Mode)
││││││││
││││││││└─ Carry flag
│││││││└── Zero flag
││││││└─── IRQ Disable flag
│││││└──── Decimal mode flag
││││└───── Index register size (0=16-bit, 1=8-bit)
│││└────── Memory/Accumulator size (0=16-bit, 1=8-bit)
││└─────── Overflow flag
│└──────── Negative flag
E flag (separate): Emulation mode (0=Native, 1=6502 Emulation)
Memory Map
The 65C816 has a 24-bit address space (16MB):
- $00:0000-$00:00FF: Direct Page (relocatable via D register)
- $00:0100-$00:01FF: Stack in emulation mode
- $00:0000-$00:FFFF: Bank 0
- $01:0000-$FF:FFFF: Banks 1-255
Interrupt Vectors
Native Mode Vectors
- $00:FFE4: COP (Co-processor)
- $00:FFE6: BRK
- $00:FFE8: ABORT
- $00:FFEA: NMI
- $00:FFEE: IRQ
Emulation Mode Vectors (6502 compatibility)
- $00:FFFA-$00:FFFB: NMI
- $00:FFFC-$00:FFFD: RESET
- $00:FFFE-$00:FFFF: IRQ/BRK
Operating Modes
Emulation Mode (E=1)
- Acts like a 6502 with some enhancements
- 8-bit accumulator and index registers
- 8-bit stack pointer (in page 1)
- Compatible with 6502 code
Native Mode (E=0)
- Full 16-bit capabilities
- Configurable register sizes via M and X flags
- 16-bit stack pointer
- 24-bit addressing
Usage
Systems using the 65C816 must implement the Memory65c816 trait:
pub trait Memory65c816 {
fn read(&self, bank: u8, addr: u16) -> u8;
fn write(&mut self, bank: u8, addr: u16, val: u8);
}
Example
use emu_core::cpu_65c816::{Cpu65c816, Memory65c816};
struct MySystem {
ram: [u8; 0x1000000], // 16MB
}
impl Memory65c816 for MySystem {
fn read(&self, bank: u8, addr: u16) -> u8 {
let full_addr = ((bank as usize) << 16) | (addr as usize);
self.ram[full_addr]
}
fn write(&mut self, bank: u8, addr: u16, val: u8) {
let full_addr = ((bank as usize) << 16) | (addr as usize);
self.ram[full_addr] = val;
}
}
let system = MySystem { ram: [0; 0x1000000] };
let mut cpu = Cpu65c816::new(system);
cpu.reset();
Instruction Set
The 65C816 includes all 6502 instructions plus:
New 16-bit Instructions
- 16-bit versions of most 6502 arithmetic and logical operations
- Conditional execution based on M and X flags
Block Move Instructions
- MVN: Move Negative (block copy, decrementing)
- MVP: Move Positive (block copy, incrementing)
Stack Operations
- PHB: Push Data Bank Register
- PLB: Pull Data Bank Register
- PHD: Push Direct Page Register
- PLD: Pull Direct Page Register
- PHK: Push Program Bank Register
- PHX: Push X Register
- PHY: Push Y Register
- PLX: Pull X Register
- PLY: Pull Y Register
Transfer Instructions
- TCD: Transfer 16-bit A to Direct Page Register
- TDC: Transfer Direct Page Register to 16-bit A
- TCS: Transfer 16-bit A to Stack Pointer
- TSC: Transfer Stack Pointer to 16-bit A
- TXY: Transfer X to Y
- TYX: Transfer Y to X
Status/Mode Instructions
- XCE: Exchange Carry and Emulation flags (mode switch)
- REP: Reset Processor Status Bits
- SEP: Set Processor Status Bits
New Addressing Modes
- Stack Relative: (SP),Y
- Direct Page Indirect Long: [D]
- Direct Page Indirect Long Indexed: [D],Y
- Absolute Long: 24-bit absolute addressing
- Absolute Long Indexed: 24-bit absolute,X
Other New Instructions
- COP: Co-processor
- WDM: Reserved for future expansion
- PEA: Push Effective Absolute Address
- PEI: Push Effective Indirect Address
- PER: Push Effective PC Relative Address
- WAI: Wait for Interrupt
- STP: Stop the processor
Addressing Modes
The 65C816 supports all 6502 addressing modes plus:
- Stack Relative:
LDA $03,S - Stack Relative Indirect Indexed:
LDA ($03,S),Y - Direct Page Indirect Long:
LDA [$42] - Direct Page Indirect Long Indexed:
LDA [$42],Y - Absolute Long:
LDA $123456(24-bit) - Absolute Long Indexed:
LDA $123456,X(24-bit) - Program Counter Relative Long:
BRL label(16-bit offset)
Systems Using 65C816
This CPU core is used by the following systems in Hemulator:
- SNES (Super Nintendo Entertainment System) -
crates/systems/snes/
Implementation Notes
Mode Switching
Switching between emulation and native mode is done via the XCE instruction:
CLC ; Clear carry
XCE ; Switch to native mode (E=0)
SEC ; Set carry
XCE ; Switch to emulation mode (E=1)
Register Size Management
In native mode, the M and X flags control register sizes:
- M=0: 16-bit accumulator/memory operations
- M=1: 8-bit accumulator/memory operations
- X=0: 16-bit index registers
- X=1: 8-bit index registers
Use REP and SEP to change these flags:
REP #$30 ; Clear M and X flags (16-bit mode)
SEP #$30 ; Set M and X flags (8-bit mode)
Bank Wrapping
Address calculations wrap within banks:
- Incrementing $00:FFFF goes to $00:0000, not $01:0000
- The bank register (PBR or DBR) determines which bank
Direct Page
The Direct Page register allows relocating zero page anywhere in bank 0:
LDA #$2000
TCD ; Move direct page to $2000
LDA $42 ; Accesses $00:2042, not $00:0042
Performance Considerations
Variable Timing
Instruction timing depends on:
- Register size (8-bit vs 16-bit operations)
- Direct page alignment (D register low byte = $00 saves 1 cycle)
- Memory access patterns
- Emulation vs native mode
References
- 65816 Programming Manual - Official WDC documentation
- 65816 Opcodes - Complete instruction reference
- SNES Development Manual - Practical 65C816 usage examples