p.enthalabs

GitHub - victorgomes/gb: Leiksveinn GameBoy

Leiksveinn GameBoy — a Game Boy (DMG-01 / Color) emulator

[](https://github.com/victorgomes/gb#leiksveinn-gameboy--a-game-boy-dmg-01--color-emulator)

A small, readable Game Boy (Color) emulator written in C with SDL3. The design favors a flat, globally-visible machine state and direct code over deep abstraction, so it stays easy to read and hack on. See ARCHITECTURE.md for how the pieces fit together, and TODO.md for the remaining gaps.

![Image 1: Leiksveinn running Pokémon Yellow in the browser PWA shell](https://github.com/victorgomes/gb/blob/main/gb.png)

Features

[](https://github.com/victorgomes/gb#features)

- Full SM83 CPU (validated against the SM83 single-step tests, 500/500 files, and Blargg).

- Dot-driven pixel-FIFO PPU (background, window, sprites); renders `dmg-acid2` pixel-perfect.

- All four APU channels + mixer; passes Blargg `dmg_sound` 12/12.

- Accurate timing: an M-cycle bus with T-cycle interrupt sampling. Passes Blargg `mem_timing` / `instr_timing` and 66/75 of the Mooneye acceptance suite (the remaining 9 need non-DMG hardware models).

- **Game Boy Color (CGB):** colour palettes + tile attributes, VRAM/WRAM banking, double-speed, and HDMA — CGB games (e.g. Pokémon Crystal) run in colour; DMG games are unaffected and get a compatibility colourisation on CGB. Model is taken from the cart header or forced with `--cgb` / `--dmg` / `--agb`.

- Mappers: ROM-only, MBC1 (incl. MBC1M multicart), MBC2, MBC3/MBC30 (live RTC), MBC5, MMM01, HuC1, HuC3 (RTC), BANDAI TAMA5 (RTC), and the Game Boy Camera.

- Battery SRAM and RTC persisted to `<rom>.sav` (VBA/BGB/mGBA-compatible footer).

- Full-machine save states, screenshots, fast-forward, and an FPS overlay.

- Two-player split-screen play over a local link cable (`--split`).

- Game Boy Printer (`--printer`); each print is saved as a BMP.

- Loads ROMs straight from `.zip` archives.

- Runs natively (SDL3) **and** in the browser (WebAssembly, `make web`) — the web build is an installable, offline PWA with an on-screen phone shell.

Build

[](https://github.com/victorgomes/gb#build) Requires a C23 compiler and SDL3.

brew install sdl3 pkgconf # macOS (Linux: apt install libsdl3-dev / dnf install SDL3-devel) make # produces ./gb make DEBUG=1 # AddressSanitizer + UBSan build make clean

SDL3 ships no `*-config` script, so the Makefile locates it via `pkg-config` (hence `pkgconf`). The Game Boy Camera shoots from a real webcam through SDL3's cross-platform camera API (macOS / Linux / Windows); with no camera or permission it falls back to a synthetic test image.

Web build (optional)

[](https://github.com/victorgomes/gb#web-build-optional)

make web # needs the Emscripten SDK (emcc) on PATH; writes web/gb.js open web/index.html # runs straight from file:// — no server needed

The wasm is base64-embedded into a single `gb.js`, so the page works from the filesystem. Battery saves and save states are kept in the browser's IndexedDB. Served over `https://` (or `localhost`) it is an **installable, offline PWA**: a service worker precaches the app shell, and there is an on-screen Game Boy shell (touch D-pad + face buttons, a navigable menu, fast-forward) so it plays on a phone. The Game Boy Camera uses the browser webcam via `getUserMedia` (which needs a secure context), falling back to the synthetic scene when access isn't granted. The link cable (`--split`) is native-only.

Run

[](https://github.com/victorgomes/gb#run)

./gb path/to/rom.gb # run a ROM (a .zip containing one .gb also works) ./gb # no ROM: just show the DMG test pattern ./gb rom.gb --printer # attach a Game Boy Printer (each print → a BMP) ./gb rom.gb --split [rom2] # two-player split screen over the link cable ./gb rom.gb --boot dmg_boot.bin # boot through the (optional) DMG boot ROM

Headless mode (no window/audio) is handy for CI and quick checks:

SDL_VIDEODRIVER=dummy SDL_AUDIODRIVER=dummy \ ./gb rom.gb --screenshot out.bmp --frames 600 # run 600 frames, dump a BMP, exit

Game ROMs are **not** included (they are copyrighted). Put your own under `roms/`, which is gitignored. Run `./gb --help` for the full option and config-key list.

Controls

[](https://github.com/victorgomes/gb#controls) | Game Boy | Key | | Hotkey | Key | | --- | --- | --- | --- | --- | | D-pad | Arrow keys | | Emulation speed ×1–×9 | 1–9 | | A | X | | Fast-forward (hold) | Tab | | B | Z | | Save / load state | F5/F6 | | Start | Enter | | Restore autosave | F7 | | Select | Backspace | | Screenshot (BMP) | P | | | | | Reset (keeps battery SRAM) | R | | | | | Toggle fullscreen | Esc | | | | | Toggle FPS overlay | F | | | | | Toggle audio mute | M | | | | | Pause / resume | Space | | | | | Quit | Cmd+Q |

All bindings are configurable in `gb.conf` (a flat `key = value` file, loaded from the working directory). It also sets the window scale, turbo speed, an optional DMG boot ROM, and folders for saves/screenshots. See `./gb --help` for every key and its default. In `--split` mode, player 1 (left screen) uses **WASD** + G/H/T/Y and player 2 (right screen) uses the **arrow keys** + K/L/RShift/Enter.

Legal

[](https://github.com/victorgomes/gb#legal)

The emulator's own code is released under the MIT license (LICENSE). It contains no Nintendo code and no ROMs: the optional DMG boot ROM and all game/test ROMs must be supplied by you, and are never committed to the repository. The only vendored third-party code is `src/puff.c` (zlib's public-domain inflate, for `.zip` loading), which keeps its own notice.