π¦ Curious what happens when you hand the same project to an AI team? Check out rubc β a sister Game Boy / Game Boy Color emulator written in Rust, built almost entirely by an AI as an experiment. It went a good bit further on hardware accuracy than this one did.
gobcis the hand-written, human original that started it all.
gobc is a Game Boy / Game Boy Color emulator written in Go. Standing on the shoulders of giants β Pan Docs, SameBoy, PyBoy, mooneye, gbdev β it aims to be a fast, hackable, hardware-accurate emulator with a real focus on passing the canonical test suites (Blargg, Mooneye) rather than just "running games".
π Tests passing β Β Β π΅ Audio setup β Β Β π¬ Discord β Β Β π¦ Latest release β
|
|
|
|
|
|
Legend: β = full hardware accuracy (regression-guarded in CI) Β Β·Β π‘ = partial / WIP Β Β·Β β = not started
| Subsystem | Status | Notes |
|---|---|---|
| SM83 CPU | β | All 245 implemented opcodes + CB-prefix; passes Blargg cpu_instrs 11/11 + instr_timing. Atomic-instruction model β sub-instruction T-cycle timing is #18. |
| Interrupts | β | EI 1-instruction delay, HALT bug, peripherals ticked during ISR. Passes interrupt_time and halt_bug. |
| Joypad | β | All 8 buttons, D-pad + face buttons + Start/Select. |
| Timers (DIV/TIMA) | β | Including CGB double-speed scaling. |
| LCD / PPU | β | Tile + sprite render, STAT interrupts, mode 0/1/2/3 transitions, BG-OBJ priority. Pixel-FIFO accuracy and cycle-accurate mode 2 timing tracked in #19. |
| APU (sound) | β | NEW in v2.0. Full 4-channel emulation on gopxl/beep/v2. Square Γ 2 with NR10 sweep, wave with 32-sample wave RAM, noise with 7/15-bit LFSR, frame sequencer at 512 Hz. Passes all 12/12 Blargg dmg_sound AND all 12/12 cgb_sound. Setup guide: docs/audio_tests.md. |
| CGB mode | β | BG / OBJ palette RAM, VRAM bank switching, double-speed switching via STOP + KEY1, APU scaling. |
| Serial port | β | Output captured for test ROMs; full serial transfers / link cable: #11. |
| Save / load states | β | Snapshot the full Motherboard (CPU + memory + cart + APU + PPU). |
| Debugger | β | VRAM viewer, tile data + tilemap, CPU registers, IO regs, cart RAM browser, breakpoints, single-step. |
| Shaders | β | CRT / LCD / GBC palette post-processing: #17. |
| MBC | Status | Issue |
|---|---|---|
| ROM_ONLY (no MBC) | β | β |
| MBC1 (+ RAM + BATTERY) | β | β |
| MBC2 | β | #3 |
| MBC3 (+ RTC + RAM + BATTERY) | β | β |
| MBC5 (+ RAM + BATTERY + RUMBLE) | β | β |
| MMM01 (multi-game compilations) | β | #14 |
| HuC1 (Hudson IR) | β | #12 |
| HuC3 (Hudson IR + RTC + speaker) | β | #13 |
| Pocket Camera ($FC) | β | #15 |
| Bandai TAMA5 ($FD) | β | #16 |
| Suite | gobc v2.2 | Notes |
|---|---|---|
cpu_instrs |
β PASS | All 11 sub-tests. |
instr_timing |
β PASS | |
halt_bug |
β PASS | |
interrupt_time |
β PASS | Both DMG and CGB double-speed iterations. |
dmg_sound |
β 12/12 | All 6 DMG quirks (length-clock-on-trigger, NR41 power-off, wave RAM bus contention, wave retrigger corruption, etc.). |
cgb_sound |
β 12/12 | DMG-vs-CGB-aware quirks; same code paths gated on mb.Cgb. |
oam_bug |
π‘ 6/8 with --force-dmg |
Sub-tests 2β7 PASS. Sub-test 1 (LCD-on cycle sync) + sub-test 8 (POP CRC under cumulative delay-loop corruption) tracked in #19. Use gobc --no-gui --force-dmg oam_bug.gb β the test ROM's header is CGB-flagged but it exercises DMG-only hardware quirks. |
mem_timing / mem_timing-2 |
β | Requires sub-instruction T-cycle accurate CPU. Tracked in #18. |
You need:
- Go 1.26+
- OpenGL + GLFW (
libgl1-mesa-dev xorg-devon Debian/Ubuntu) - Audio (optional): on WSL2, follow the one-time setup in
docs/audio_tests.md
# Option 1 β pre-built release binary (Linux x86_64)
curl -L https://github.com/duysqubix/gobc/releases/latest/download/gobc-v2.0-linux-x86_64 -o gobc
chmod +x gobc
# Option 2 β go install
go install github.com/duysqubix/gobc/cmd/gobc@latest
# Option 3 β build from source
git clone https://github.com/duysqubix/gobc && cd gobc
cargo install just # or: brew install just / apt install just
just bootstrap # installs Go (if missing) + gopls + staticcheck + dlv + goimports
just install-hooks # wires the repo pre-commit hook (gofmt + vet + staticcheck)
just build # vet + race-test + compile to bin/gobc + bin/cartdump
just build-release # stripped (-trimpath -s -w) release binaryThe project uses just as its task runner. Run just with no
arguments to list every recipe. Useful environment overrides:
| Env | Effect |
|---|---|
GO_VERSION=1.27.0 just bootstrap |
Pin a specific Go release. |
GO_INSTALL_DIR=$HOME/.local just bootstrap |
Install Go to a user-local prefix (no sudo). |
COVER_MIN=70 just test-cover-check |
Fail if line coverage drops below 70 %. |
gobc exposes two subcommands plus a shorthand:
| Command | Purpose |
|---|---|
gobc run ROM_File [options] |
Boot the emulator and run a ROM. |
gobc cartdump ROM_File [options] |
Dump cartridge header (and optional opcode disassembly). |
gobc ROM_File [options] |
Shorthand for gobc run. |
# Run a ROM
gobc run roms/cpu_instrs.gb
gobc run roms/zelda.gb --debug --breakpoints 0x100,0x200,0x300
gobc run roms/pokemon.gb --force-cgb # force CGB on a DMG ROM
gobc run roms/blargg.gb --no-gui # headless (CI / test ROMs)
LOG_LEVEL=debug gobc run roms/zelda.gb
# Audio (new in v2.0)
gobc run roms/crystal.gbc --audio-rate 32000 # match host throughput on slow CPUs
gobc run roms/crystal.gbc --audio-smooth # calibrate to host (5% pitch trade-off)
gobc run roms/crystal.gbc --no-audio # silent run
# Inspect a cartridge
gobc cartdump roms/pokemon.gb # writes cartdump.txt
gobc cartdump --raw roms/pokemon.gb # raw header to stdout
gobc cartdump --instruction-set --include-nop -o dump.txt roms/pokemon.gbRun gobc --help for the full flag reference and gobc <command> --help for per-subcommand help.
| Key | Action |
|---|---|
F1 |
Toggle gridlines |
F2 |
Toggle debug viewer windows (VRAM / Memory / Cart / CPU / IO) |
F3 |
Cycle DMG palette |
F4 |
Save cartridge SRAM to <rom>.sav |
F5 |
Save state to <rom>.state |
F6 |
Load state from <rom>.state |
A |
Game Boy B button |
S |
Game Boy A button |
Enter |
Start |
Shift |
Select |
| Arrow keys | D-pad |
Space (debug on) |
Pause / resume emulation |
N (debug on) |
Step N CPU cycles |
M / B (debug on) |
Increase / decrease cycles-per-frame 10Γ |
F (debug on) |
Step one frame |
| Window | Keys |
|---|---|
| VRAM | T toggle tile addressing Β· B toggle tilemap addressing Β· G toggle grid Β· V toggle VRAM bank 0/1 |
| Memory | Arrow keys page/scroll Β· mouse wheel scrolls |
| Cart | Arrow keys page/scroll Β· [ / ] switch RAM bank |
Unit tests use the stdlib testing package + testify. ROM integration tests under
default_rom/ run gobc --no-gui against Blargg ROMs and grep the serial output (or
cart-RAM .sav for the newer dmg_sound/cgb_sound/oam_bug suites).
just test # go test -race ./...
just test-cover # writes coverage.out + summary
just test-cover-html # generates coverage.html
COVER_MIN=70 just test-cover-check # fail if coverage drops below threshold
just bench # benchmarks
just test-rom-audio # runs the full 12-ROM dmg_sound matrixEvery push runs the full test pipeline + ROM integration suite on GitHub Actions; coverage is uploaded to Codecov.
| Game | Symptom | Issue |
|---|---|---|
| Link's Awakening (DMG) | Main menu doesn't render | #5 |
| PokΓ©mon Crystal | Battle scene doesn't animate | #4 |
| PokΓ©mon Crystal | Character sprite split entering battle | #4 |
gobc/
βββ cmd/
β βββ gobc/ # main binary; urfave/cli/v2 app with run + cartdump subcommands
β βββ cartdump/ # standalone cart-dump binary (same logic as gobc cartdump)
βββ internal/
β βββ motherboard/ # CPU + opcodes + memory + timer + interrupts + PPU + APU
β βββ cartridge/ # header parser + ROM_ONLY / MBC1 / MBC3+RTC / MBC5
β βββ windows/ # Pixel/GLFW GUI: 1 main + 5 viewer windows
β βββ bootrom/ # DMG + CGB boot ROMs as hex blobs
β βββ root.go # shared utilities: Logger, constants, bit-ops, state save/load
βββ default_rom/ # Blargg + Mooneye test ROMs
βββ docs/ # audio_tests.md and project docs
βββ .githooks/ # repo-tracked pre-commit hook
βββ .github/workflows/ # CI: unit tests + coverage + ROM integration
βββ justfile # task runner (run `just` to list recipes)
Each subdirectory has its own AGENTS.md with conventions, anti-patterns, and quirks. Start
with AGENTS.md (root) before contributing.
The known problems are tracked in the Issues tab β grab anything that looks interesting!
For substantial new features, open an issue first to align on the approach. We follow the
existing per-package conventions (see each subdirectory's AGENTS.md) and the pre-commit
hook enforces gofmt, vet, and staticcheck. Tests must stay green.
- Duan Uys β @duysqubix
- Pan Docs β canonical Game Boy hardware reference
- GBEDG β Game Boy emulator development guide
- pastraiser opcode table
- SameBoy β cycle-accurate reference emulator (consulted heavily for v2.0 APU + interrupt timing)
- PyBoy β Python reference + huge inspiration; the v2.0 adaptive frame limiter is adapted from PyBoy's
- Test ROMs Archive






