Skip to content

Latest commit

 

History

69 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

gbbcpp_emu

A C++ Game Boy emulator project.

The emulator loads a .gb ROM, runs the CPU on a worker thread, renders the LCD output through SDL2, and opens a second debug window that shows tile data from VRAM.

Dr Mario running in the emulator

Emulator architecture

Current Status

This project is a work in progress, but the core pieces are already in place:

  • CPU instruction decoding and execution.
  • MMU/bus routing for cartridge ROM/RAM, VRAM, WRAM, OAM, IO, HRAM, and interrupt enable.
  • PPU/LCD timing model with OAM, transfer, HBlank, and VBlank modes.
  • Timer, interrupts, DMA, gamepad input, and serial IO registers.
  • Cartridge support for ROM-only, MBC1, MBC3, and MBC5 cartridges.
  • Battery-backed RAM loading/saving for supported cartridge types.
  • SDL2 UI with main display and VRAM tile debug display.
  • GoogleTest target for library tests.

The checked-in roms/ directory contains public test ROMs that are useful for emulator validation. The games/ directory is local/private content and should be treated separately from distributable project assets.

How It Works

The executable starts by loading cartridge metadata from the ROM header and selecting a cartridge implementation. It then creates the CPU with the initial Game Boy register state, starts CPU execution on a std::jthread, and keeps the SDL UI loop on the main thread.

Frame loop

At runtime:

  • The CPU fetches, decodes, and executes instructions.
  • Memory reads and writes go through the MMU.
  • The MMU forwards accesses to cartridge banking, RAM, PPU memory, LCD/device registers, DMA, and interrupt registers.
  • The timer and PPU advance with CPU cycles.
  • The PPU fills a 160x144 video buffer.
  • SDL scales that buffer into the main window and renders a separate VRAM tile viewer.

Controls

Keyboard controls

Game Boy input Keyboard
D-pad Arrow keys
A X
B Z
Start K
Select Enter

Close either SDL window to stop the emulator.

Requirements

  • CMake 3.26 or newer.
  • Ninja.
  • A compiler with C++23 support.
  • Conan 2.

Conan resolves the C++ dependencies declared in conanfile.py:

  • Boost.
  • SDL2.
  • SDL2_ttf.
  • GoogleTest.
  • portable-file-dialogs.

When using a custom GCC installation, such as GCC 16 under /opt/gcc, the build embeds that compiler's libstdc++ runtime path into the emulator binary. This avoids runtime errors where Linux finds an older system libstdc++.so.6 first.

Build

Install dependencies, configure, and build the release preset:

conan install . --output-folder=build-release/conan --settings=build_type=Release --build=missing
cmake --fresh --preset Release
cmake --build build-release

The emulator binary is produced at:

build-release/app/emulator

Run

Run the emulator and load a ROM from the filesystem using L, Enter, or Ctrl+O:

./build-release/app/emulator

You can still start directly with a Game Boy ROM:

./build-release/app/emulator roms/cpu_instrs.gb

Or use a local game ROM:

./build-release/app/emulator games/dr_mario.gb

The app opens two SDL windows:

  • gbemu_cpp: scaled Game Boy screen.
  • Debug tile window: VRAM tile viewer.

ROM loading shortcuts:

Action Keyboard
Open ROM file dialog L, Ctrl+O, or Enter when no ROM is loaded

Test

Build first, then run CTest from the release build directory:

ctest --test-dir build-release/lib/tests

You can also run the GoogleTest binary directly:

./build-release/lib/tests/test_gbemu_lib

The historical manual CPU-log comparison note was:

vimdiff <(head -n 200000 "log2.txt") <(head -n 200000 "/path/to/reference/log2.txt")

That workflow is not automated in the repository yet.

Debug Build

Install debug dependencies and configure the debug build directory:

conan install . --output-folder=build-debug/conan --settings=build_type=Debug --build=missing
cmake --fresh --preset Coverage
cmake --build build-debug

Project Layout

app/
  emulator.cpp       SDL app entry point and emulation loop
  gameboy_ui.h       SDL rendering, debug tile window, and keyboard input

lib/include/
  cartridge/         ROM header parsing, cartridge interface, MBC1/MBC3/MBC5, battery save support
  cpu/               CPU context, instructions, interrupt handling, timer
  io/                LCD, gamepad, serial/device registers
  mmu/               Memory map, DMA, RAM
  ppu/               PPU state machine, tile fetch pipeline, OAM
  utils/             Logging and ROM loading helpers

lib/src/             Main library implementation
lib/tests/           GoogleTest target
roms/                Test ROMs
docs/images/         README diagrams

Known Gaps Before Further Improvements

  • Test coverage is minimal and does not yet encode the manual validation workflow.
  • Cartridge support is focused on ROM-only, MBC1, MBC3, and MBC5.
  • Audio/APU emulation is not implemented.
  • Some IO and memory edge cases are still logged as unsupported.
  • The README diagrams describe the current implementation; they are not emulator screenshots.

Roadmap

The original project structure is a good foundation: the emulator is already split around the main Game Boy hardware concepts, with separate areas for CPU, MMU, PPU, IO, cartridge handling, and the SDL app. That layout made it practical to add ROM loading, resizable rendering, input overlays, and MBC5 support without rewriting the whole project.

The next improvements should focus on reducing coupling between those pieces while keeping the existing design recognizable.

  1. Introduce a GameBoy or Emulator facade that owns the core components and exposes a small API for loading ROMs, ticking frames, reading the framebuffer, handling input, and saving state.
  2. Keep SDL, menus, file dialogs, overlays, and debug windows in the app layer so the emulation core can also run headless.
  3. Move timing-sensitive behavior, such as DMA progression, into explicit implementation files and give it focused tests.
  4. Share common cartridge mapper behavior for RAM banking, battery-backed saves, and bounds-safe ROM/RAM access.
  5. Add automated test ROM execution with pass/fail detection.
  6. Capture real screenshots for dmg-acid2.gb, cpu_instrs.gb, and a small homebrew ROM.
  7. Document compatibility by ROM and cartridge type.
  8. Add CI for configure, build, and tests.

Additional design notes:

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages