An open API service indexing awesome lists of open source software.

https://github.com/duysqubix/gobc


https://github.com/duysqubix/gobc

Last synced: about 1 month ago
JSON representation

Awesome Lists containing this project

README

          




Build Status
Coverage
Go Report Card
Go Reference
Latest Release

**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 β†’**](TESTS.md) Β Β 
[**🎡 Audio setup β†’**](docs/audio_tests.md) Β Β 
[**πŸ’¬ Discord β†’**](https://discord.gg/EVCX5X3A) Β Β 
[**πŸ“¦ Latest release β†’**](https://github.com/duysqubix/gobc/releases/latest)


























## Feature matrix

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](https://github.com/duysqubix/gobc/issues/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](https://github.com/duysqubix/gobc/issues/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`](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](https://github.com/duysqubix/gobc/issues/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](https://github.com/duysqubix/gobc/issues/17). |

### Cartridge MBC support

| MBC | Status | Issue |
|---|:-:|---|
| ROM_ONLY (no MBC) | βœ… | β€” |
| MBC1 (+ RAM + BATTERY) | βœ… | β€” |
| **MBC2** | ❌ | [#3](https://github.com/duysqubix/gobc/issues/3) |
| MBC3 (+ RTC + RAM + BATTERY) | βœ… | β€” |
| MBC5 (+ RAM + BATTERY + RUMBLE) | βœ… | β€” |
| **MMM01** (multi-game compilations) | ❌ | [#14](https://github.com/duysqubix/gobc/issues/14) |
| **HuC1** (Hudson IR) | ❌ | [#12](https://github.com/duysqubix/gobc/issues/12) |
| **HuC3** (Hudson IR + RTC + speaker) | ❌ | [#13](https://github.com/duysqubix/gobc/issues/13) |
| **Pocket Camera** ($FC) | ❌ | [#15](https://github.com/duysqubix/gobc/issues/15) |
| **Bandai TAMA5** ($FD) | ❌ | [#16](https://github.com/duysqubix/gobc/issues/16) |

### Blargg test ROM scorecard (regression-guarded in CI)

| 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](https://github.com/duysqubix/gobc/issues/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](https://github.com/duysqubix/gobc/issues/18). |

## Installing

You need:
- [Go 1.26+](https://golang.org/doc/install)
- [OpenGL + GLFW](https://github.com/gopxl/pixel#requirements) (`libgl1-mesa-dev xorg-dev` on Debian/Ubuntu)
- Audio (optional): on WSL2, follow the one-time setup in [`docs/audio_tests.md`](docs/audio_tests.md#wsl2-setup-one-time)

```bash
# 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 binary
```

The project uses [`just`](https://github.com/casey/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 %. |

## Usage

`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`. |

```bash
# 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.gb
```

Run `gobc --help` for the full flag reference and `gobc --help` for per-subcommand help.

## Key bindings

### Main window

| Key | Action |
|---|---|
| `F1` | Toggle gridlines |
| `F2` | Toggle debug viewer windows (VRAM / Memory / Cart / CPU / IO) |
| `F3` | Cycle DMG palette |
| `F4` | Save cartridge SRAM to `.sav` |
| `F5` | Save state to `.state` |
| `F6` | Load state from `.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 |

### Debug viewers

| 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 |

## Testing

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).

```bash
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 matrix
```

Every push runs the full test pipeline + ROM integration suite on GitHub Actions; coverage
is uploaded to [Codecov](https://codecov.io/gh/duysqubix/gobc).

## Known game bugs

| Game | Symptom | Issue |
|---|---|---|
| Link's Awakening (DMG) | Main menu doesn't render | [#5](https://github.com/duysqubix/gobc/issues/5) |
| PokΓ©mon Crystal | Battle scene doesn't animate | [#4](https://github.com/duysqubix/gobc/issues/4) |
| PokΓ©mon Crystal | Character sprite split entering battle | [#4](https://github.com/duysqubix/gobc/issues/4) |

## Project layout

```
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`](AGENTS.md) (root) before contributing.

## 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.

### Contributors

- Duan Uys β€” [@duysqubix](https://github.com/duysqubix)

## References

- [Pan Docs](https://gbdev.io/pandocs/About.html) β€” canonical Game Boy hardware reference
- [GBEDG](https://hacktix.github.io/GBEDG/) β€” Game Boy emulator development guide
- [pastraiser opcode table](https://www.pastraiser.com/cpu/gameboy/gameboy_opcodes.html)
- [SameBoy](https://github.com/LIJI32/SameBoy) β€” cycle-accurate reference emulator (consulted heavily for v2.0 APU + interrupt timing)
- [PyBoy](https://github.com/Baekalfen/PyBoy) β€” Python reference + huge inspiration; the v2.0 adaptive frame limiter is adapted from PyBoy's
- [Test ROMs Archive](https://gbdev.gg8.se/wiki/articles/Test_ROMs)