GBCee is a work-in-progress Gameboy (DMG-01) emulator written from scratch in C. This project is a deep dive into low-level systems programming, computer architecture, and the intricacies of early handheld gaming hardware. The primary goal is to create a cycle-accurate and well-documented emulator for fun and learning.
Current State: Tetris is Running!
After nearly a year of development, GBCee has reached a major milestone — it can now successfully boot and run Tetris end-to-end. This required a fully operational CPU core, PPU pipeline, interrupt system, timer subsystem, MMU, and cartridge support all working in concert.
The emulator renders the full 160×144 pixel Game Boy framebuffer to an SDL2 window, correctly handles VBlank and LCD STAT interrupts, and executes the Sharp LR35902 instruction set with enough accuracy to run commercial ROM software.
A runtime diagnostics and tracing subsystem is also in place, which logs a detailed snapshot of the CPU state for each instruction — invaluable for debugging and cross-referencing against known-good emulator traces.
# Example of the current debug output
AF: 01B0 BC: 0013 DE: 00D8 HL: 014D SP: FFFE PC: 0100 | Opcode: 00 (NOP)
AF: 01B0 BC: 0013 DE: 00D8 HL: 014D SP: FFFE PC: 0101 | Opcode: 21 (LD HL,d16) | Operand: 014D
AF: 01B0 BC: 0013 DE: 00D8 HL: 014D SP: FFFC PC: 0104 | Opcode: 32 (LD (HL-),A)
AF: F1B0 BC: 0013 DE: 00D8 HL: 014C SP: FFFC PC: 0105 | Opcode: CB 7C (BIT 7,H)
...The emulator has a solid foundation with several core components already in place.
-
Complete CPU Core:
- Full implementation of the ~500 standard and CB-prefixed Gameboy opcodes.
- Correctly manages all 8-bit and 16-bit registers.
- Handles the fetch-decode-execute cycle with proper program counter management.
-
Memory Management Unit (MMU):
- Maps the entire Gameboy memory layout (VRAM, WRAM, OAM, IO, etc.).
- Abstracted memory access via
mmu_read()andmmu_write()functions.
-
Cartridge Support:
- Loads
.gbROM files directly into memory. - MBC0 (No banking) support for simple games like Tetris.
- MBC1 support, enabling bank switching for more complex games.
- Loads
-
Debugging & Display:
- Real-time disassembly and register logging to the console.
- Basic window scaffolding using the SDL2 library, ready for PPU integration.
This is the roadmap to a fully functional emulator. Items will be checked off as they are implemented.
- Implement the PPU state machine (OAM Scan, Drawing, HBlank, VBlank).
- Render background and window tiles from VRAM.
- Render sprites (OAM).
- Draw the final 160x144 pixel buffer to the SDL window.
- Handle VBlank interrupts correctly.
- Implement DIV, TIMA, TMA, and TAC timer registers.
- Implement the Interrupt Master Enable (IME) flag and handler.
- Fire interrupts correctly for VBlank, LCD STAT, Timer, etc.
- Map keyboard keys to the Gameboy's button inputs (A, B, Start, Select, D-Pad).
- Write button press states to the JOYP register (0xFF00).
- Save States: Serialise and restore complete emulator state to/from disk.
- Fast-forward / Rewind: Frame-skip for fast-forward; circular frame buffer for rewind.
- Sound (APU): Emulate the four sound channels.
- Additional MBCs: Add support for MBC2, MBC3 (with RTC), and MBC5.
- BIOS Emulation: Load and execute the original DMG BIOS ROM.
- Testing: Pass Blargg's instruction and memory timing test ROMs.
- Additional MBCs: Add support for MBC2, MBC3 (with RTC), and MBC5.
- BIOS Emulation: Load and execute the original DMG boot ROM.
- Testing: Pass Blargg's
cpu_instrs,instr_timing, andmem_timingtest ROMs. - Accuracy & Performance Optimisations: Improve cycle-level timing accuracy and rendering performance.
You will need the SDL2 development library to compile the project.
-
On Debian/Ubuntu:
sudo apt-get install libsdl2-dev
-
On macOS (using Homebrew):
brew install sdl2
-
On Windows:
The recommended approach (and the one i use) is MSYS2, which provides a Unix-like shell environment and the MinGW-w64 toolchain on Windows.
-
Download and install MSYS2 from msys2.org.
-
Open the MSYS2 MINGW64 shell and update the package database:
pacman -Syu
- Install the MinGW-w64 GCC toolchain and SDL2 development libraries:
pacman -S mingw-w64-x86_64-gcc mingw-w64-x86_64-SDL2 make
- After building, copy
SDL2.dllfromC:\msys64\mingw64\bin\into the same directory as your compiledgbcee.exeso it can be found at runtime. Alternatively, addC:\msys64\mingw64\binto your systemPATH.
-
Alternative (without MSYS2): Download the SDL2 MinGW development libraries directly from the SDL2 releases page, extract them, and point your compiler at the
includeandlibdirectories manually. This requires more manual setup of include/library paths in your build script.
- Clone the repository (in your MSYS2 MINGW64 shell or Git Bash):
git clone https://github.com/AndyFerns/GBCee.git
cd GBCee- Compile using the provided build script:
./build.bat- Run the emulator with a Gameboy ROM:
./gbcee.exe /path/to/your/rom.gb- Clone the repository:
git clone https://github.com/AndyFerns/GBCee.git
cd GBCee- Compile the project:
./build- Run the emulator with a Gameboy ROM:
./gbcee /path/to/your/rom.gb- Nintendo Game Boy Programming Manual
- Pan Docs — Game Boy Technical Reference
Andrew Fernandes :)