Skip to main content
Dolphin emulates the PowerPC 750CL (GameCube) and Broadway (Wii) processors using multiple execution backends optimized for different scenarios.

PowerPC Architecture

The emulated CPUs are 32-bit RISC processors:
FeatureGameCube (Gekko)Wii (Broadway)
Clock Speed486 MHz729 MHz
ArchitecturePowerPC 750CLPowerPC 750CL-based
L1 Cache32 KB I + 32 KB D32 KB I + 32 KB D
L2 Cache256 KB512 KB
Paired SinglesYesYes
SIMDLimitedLimited
Location: Source/Core/Core/PowerPC/

Execution Backends

Dolphin offers multiple CPU emulation modes in PowerPC/:
Location: PowerPC/Jit64/Default on x86-64 platforms. Compiles PowerPC code to native x86-64:
  • Block-level compilation with register allocation
  • Fastmem for direct memory access (when MMU allows)
  • Paired-single optimization using SSE/AVX
  • Fastest execution (5-10x interpreter speed)
// Enable in config
[Core]
CPUCore = 1  // JIT
The JIT handles:
  • Branch folding and block linking
  • Constant propagation
  • Register caching across instructions
  • Special handling for common idioms

JIT Compilation Process

The JIT operates on blocks of PowerPC code:
1

Block Discovery

Identify a basic block starting at PC
  • Follow instructions until branch/return
  • Respect block size limits
  • Check for compiled block in cache
2

Analysis

Analyze PowerPC instructionsFile: PowerPC/PPCAnalyst.cpp
  • Detect register usage
  • Find memory access patterns
  • Identify idle loops (for skip-idle optimization)
  • Determine instruction dependencies
3

Compilation

Generate native code
  • Allocate registers for PowerPC GPRs/FPRs
  • Emit x86-64/ARM64 instructions
  • Insert memory access trampolines
  • Add exception handling
4

Linking

Connect blocks together
  • Link direct branches between compiled blocks
  • Fast dispatch without dispatcher overhead
  • Invalidate on SMC (self-modifying code)

Register Mapping

PowerPC has extensive register state:
// From PowerPC/PowerPC.h
struct PowerPCState {
  u32 gpr[32];        // General purpose registers
  double fpr[32];     // Floating point (also used for paired singles)
  u32 spr[1024];      // Special purpose registers
  u32 cr;             // Condition register (8 x 4-bit fields)
  u32 pc;             // Program counter
  u32 npc;            // Next PC
  // ... more state
};
The JIT maps frequently-used registers:
  • r1 (stack pointer) → native register when possible
  • r13 (small data area) → cached
  • f0-f31 → x87/SSE registers or stack

Memory Management Unit

Location: PowerPC/MMU.cpp Translates virtual addresses to physical:
PowerPC uses segmented memory model:
  1. Segment lookup: Translate EA (effective address) to VA (virtual address)
  2. Page table lookup: Translate VA to PA (physical address)
  3. TLB caching: Translation Lookaside Buffer speeds up lookups
u32 TranslateAddress(u32 address, XCheckTLBFlag flag);
On x86-64/ARM64 with MMU disabled or known-safe access:
  • Direct pointer to emulated RAM
  • No translation overhead
  • Trap SIGSEGV/EXCEPTION_ACCESS_VIOLATION for bounds checking
  • 10x faster than full MMU emulation
Enabled automatically when safe.
Block Address Translation for large mappings:
  • 4 instruction BATs (IBAT0-3)
  • 4 data BATs (DBAT0-3)
  • Map large regions (128 KB - 256 MB)
  • Used by games for main RAM, I/O

Paired Singles

GameCube/Wii extension for SIMD floating-point:
// Each FPR can hold two 32-bit floats
struct PS {
  float ps0;
  float ps1;  
};
Common instructions:
  • ps_add, ps_sub, ps_mul - Paired arithmetic
  • psq_l, psq_st - Quantized loads/stores
  • ps_merge00, ps_merge01 - Shuffle operations
The JIT optimizes paired-singles using:
  • x86-64: SSE instructions (2x floats per XMM register)
  • ARM64: NEON instructions (2x floats per vector)

Gekko/Broadway Differences

Wii (Broadway) is mostly identical to GameCube (Gekko):
FeatureGekkoBroadway
Base ISAPowerPC 750CLPowerPC 750CL
ExtensionsPaired singlesPaired singles
Clock486 MHz729 MHz (1.5x)
Cache256 KB L2512 KB L2 (2x)
The main difference is clock speed and cache size. No new instructions were added.

Performance Optimization

Idle Skipping

Detect idle loops waiting for interrupts:
// Typical idle loop pattern
0x80001234: lwz r3, 0x800030E0  // Load interrupt flag
0x80001238: cmpwi r3, 0         // Compare to zero  
0x8000123C: beq 0x80001234      // Branch if zero (spin)
When detected:
  • Skip ahead to next event
  • Save thousands of CPU cycles
  • Enabled with SkipIdle = True

Branch Following

Compile through unconditional branches:
// Instead of two blocks:
block1: ...
        b block2
        
block2: ...  

// Compile as one block:
block1: ...
        (inline block2)

Register Allocation

Keep PowerPC registers in native registers:
  • Avoid memory loads/stores
  • Track liveness across block
  • Spill least-used registers

Debugging CPU Emulation

Tools for CPU debugging:
# Run with interpreter for accuracy
dolphin-emu --exec=game.iso --config=Core.CPUCore=0

# Enable code breakpoints
dolphin-emu --debugger --exec=game.iso
In debugger:
  • Set breakpoints on PowerPC addresses
  • Step through PowerPC instructions
  • Inspect GPR/FPR register values
  • View disassembly
Location: Source/Core/Core/Debugger/

See Also