Game Boy Emulator

Created on February 1, 2026


A ground-up emulator for the Nintendo Game Boy (DMG-01) written in Rust. The project focuses on accuracy, readability, and clean architecture rather than raw performance.


🎯 Core Goals

  • Accurate hardware emulation: Detailed representation of the Game Boy CPU (LR35902)
  • Educational: Each component is documented and easy to follow
  • Transparent: No “magic” — code is testable and explicit
  • Modular: Clear separation of CPU, memory, PPU and timer

🏗️ Architecture

The emulator design follows the real hardware structure:

┌──────────────────────────────────────┐
│         Main Emulator Loop           │
│  • Input Processing (Joypad)         │
│  • CPU Step                          │
│  • PPU Step                          │
│  • Frame Rendering                   │
└──────────────────────────────────────┘
         ↓         ↓         ↓
    ┌─────────┬──────────┬──────────┐
    │   CPU   │   MMU    │   PPU    │
    │ LR35902 │ Memory   │ Graphics │
    └─────────┴──────────┴──────────┘
         ↓         ↓          ↓
    [Register]   [RAM]    [Display]

CPU (LR35902)

pub struct Cpu {
    pub program_counter: u16,
    pub stack_pointer: u16,
    pub registers: Registers,      // A, F, B, C, D, E, H, L
    pub ime: bool,                 // Interrupt Master Enable
    pub halted: bool,              // HALT-Status
}

The CPU implements the complete Game Boy (LR35902) instruction set:

  • 256 base opcodes
  • 256 CB-prefixed opcodes (bit operations)
  • ALU operations: ADD, ADC, SUB, SBC, AND, OR, XOR, CP
  • Flag handling (Z, N, H, C)
  • Interrupts & HALT states

Note: Opcode decoding is implemented with explicit match arms for clarity and better compiler optimization.

Memory Management Unit (MMU)

pub struct Mmu {
    rom: Vec<u8>,             // 0x0000–0x7FFF (ROM)
    wram: [u8; 0x2000],       // 0xC000–0xDFFF (Working RAM)
    hram: [u8; 0x80],         // 0xFF80–0xFFFE (High RAM)
    io_registers: [u8; 0x80], // Hardware-Register
}

The MMU is the single access point for CPU memory access. It provides:

  • Correct memory mapping
  • Lazy loading of ROM data
  • Hardware register emulation
  • Interrupt flag management

PPU (Graphics Processor)

pub enum PpuMode {
    OamScan, // 80 Zyklen – OAM-Scan
    Drawing, // 172 Zyklen – draw Scanline
    HBlank,  // 204 Zyklen – Horizontal Blanking
    VBlank,  // Vertical Blanking (10 Scanlines)
}

The PPU follows the exact timing specification of the Game Boy:

  • Mode transitions driven by CPU cycles
  • Scanline rendering with background and sprite layers
  • Framebuffer output (160×144 pixels)
  • VBlank interrupt for frame updates

💻 Technical highlights

1. Complete opcode decoding

// Example: 8-Bit Addition with Carry Flag
0x89 => {  // ADD A, C
    let val = self.registers.read8(&Reg8::C);
    self.alu_add_u8(val);
    4  // Cycles
}

Over 500 opcodes are explicitly defined with correct cycle timings.

2. Precise flag handling

All CPU flags are updated correctly after every operation:

  • Z flag: set when the result is zero
  • N flag: set for subtraction operations
  • H flag: set on half-carry (bit 3→4)
  • C flag: set on carry/borrow
fn alu_add_u8(&mut self, value: u8) {
    let result = self.registers.a.wrapping_add(value);
    
    self.registers.flags.z = result == 0;
    self.registers.flags.n = false;
    self.registers.flags.h = (self.registers.a & 0xF) + (value & 0xF) > 0xF;
    self.registers.flags.c = (self.registers.a as u16) + (value as u16) > 0xFF;
    
    self.registers.a = result;
}

3. Hardware-accurate timing

Each opcode has its correct cycle timing:

  • NOP: 4 cycles
  • Memory accesses: 8 or 16 cycles
  • Conditional jumps: 12/8 cycles (depending on condition)

This enables correct synchronization with the PPU and timer.

4. Modular input handling

pub enum Key {
    Right, Left, Up, Down,
    Start, Select, B, A,
}

// Real-time Input Processing
match key {
    Key::A => self.mmu.key_down(key),
    Key::B => self.mmu.key_down(key),
    _ => {}
}

The joypad is integrated into the MMU and triggers interrupts on key presses.


🎮 Supported ROMs

✅ Pokemon Red
✅ Tetris
✅ Mooneye Test Suite (used for correctness validation)

📊 Code structure

src/
├── main.rs              # event loop & window management
├── gameboy.rs           # main emulator struct
├── rom.rs               # ROM loading & parsing
└── gameboy/
    ├── cpu.rs           # CPU logic
    ├── mmu.rs           # Memory Management Unit
    ├── ppu.rs           # Graphics Processor
    ├── timer.rs         # Timer emulation
    ├── joypad.rs        # Input handling
    └── screen/
        ├── window.rs    # GUI (minifb)
        └── framebuffer.rs   # pixel buffer

🚀 Performance & optimisations

  • Rust Memory Safety: No segmentation faults thanks to borrow checker
  • Zero-Cost Abstractions: High performance despite clear structure
  • Inlining: Frequently called functions are optimised inline
  • Direct Memory Access: Fast RAM access without indirection

Measurements:

  • ✅ Real-time execution for most ROMs
  • ✅ CPU runs stably at 4.194 MHz

📚 References & Data Sources

This project is based on the most authoritative Game Boy documentation:


🔧 Build & Run

# execute ROM file
cargo run --release -- --rom_path roms/games/Pokemon_Red.gb

# with debugging
cargo run -- --rom_path roms/games/Tetris.gb

Dependencies:

  • minifb: Cross-platform window handling & rendering

📈 Concepts learned

Low-level emulation: hardware timing, instruction decoding
Rust systems programming: memory safety in critical systems
CPU architecture: registers, flags, interrupts, stack
Graphics pipelines: scanline rendering, mode timing
Timing-critical systems: cycle-accurate emulation


🔮 Future enhancements

  • Sound (APU) – Audio chip emulation
  • MBC1/MBC3/MBC5 – Cartridge support
  • Memory persistence (save states)
  • Debugger with breakpoints
  • Performance profiling

💡 Why this project?

Gameboy emulation is a classic in emulator development – it offers the perfect balance between:

  • Complexity: Real CPU, memory management, timing
  • Learning potential: Hardware details are accessible and well documented
  • Sense of achievement: Functional games run
  • Rust application: Perfect use case for systems programming

This project demonstrates both technical understanding and clean software architecture in a language that combines security and performance.