DocBoy is an open source, accuracy-focused, GameBoy (DMG) emulator, written in C++17.
Can be used either with the standalone SDL frontend or as a libretro core (e.g. with RetroArch).
- CPU: M-cycle accurate
- PPU: T-cycle accurate (implements Pixel FIFO)
- APU (audio)
- Cartridges: NoMBC, MBC1, MBC2, MBC3, MBC5
- Real Time Clock (RTC) emulation
- Memory buses (EXT, CPU, OAM, VRAM) and MMU (for accurately handle read/write conflicts)
- Timers
- Interrupts
- DMA
- JoyPad
- CLI debugger (in GDB style): supports disassemble, breakpoints, watchpoints, step by step execution, rewind, memory viewer, interrupts viewer, IO viewer
- Serial Link (output to console)
- Save/Load
- Save/Load state
- Fast-forward
- Configurable palette
- Screenshots
- Graphical menu (SDL)
- GBC (add colors support)
You can find the latest executables for both Windows and Linux in the Releases Page.
Alternatively, you can build the project by yourself as explained below.
Clone the repository and its submodules.
git clone https://github.com/Docheinstein/docboy.git --recurse-submodules
DocBoy can be compiled as a static library which can be used by a frontend.
These are the CMake options for the available frontends.
BUILD_SDL_FRONTEND
(default)BUILD_LIBRETRO_CORE
BUILD_LIBRETRO_CORE_ANDROID
BUILD_NOGUI_FRONTEND
SDL
mkdir build
cd build
cmake ..
make -j 8
Additional dependencies:
- An audio framework: for Linux you can install alsa-lib
Libretro Core
mkdir build
cd build
cmake .. -DBUILD_LIBRETRO_CORE=ON
make -j 8
Android
- Install NDK.
- Enable the CMake option
BUILD_LIBRETRO_CORE_ANDROID
. - Set the CMake option
NDK_PATH
to your NDK path (the folder should contain thendk-path
executable).
That is:
mkdir build
cd build
cmake .. -DBUILD_LIBRETRO_CORE_ANDROID=ON -DNDK_PATH=/opt/AndroidSdk/ndk/25.2.9519653/build
make
Note: use just make
instead of make -j
; the latter does not work with NDK build.
usage: [rom] [--config CONFIG] [--serial] [--scaling SCALING] [--cartridge-info]
[--debugger] [--help]
positional arguments:
rom ROM
options:
-c, --config CONFIG Read configuration file
-s, --serial Display serial console
-z, --scaling SCALING Scaling factor
-i, --cartridge-info Dump cartridge info and quit
-d, --debugger Attach debugger
-h, --help Display this help message and quit
Controls
These are the default controls.
All the joypad keys can be remapped through the Control Options menu.
Button | Action |
---|---|
F1 | Save State |
F2 | Load State |
F11 | Dump framebuffer |
F12 | Screenshot |
F | Show / Hide FPS |
Q | Decrease speed |
W | Increase speed |
D | Attach / Detach debugger |
Enter | START |
Tab | SELECT |
Z | A |
X | B |
Up | UP |
Right | RIGHT |
Down | DOWN |
Left | LEFT |
With RetroArch (supported by almost every existing platform, including Android and iOS), you can Load Core the libretro core compiled with the BUILD_LIBRETRO_CORE
or BUILD_LIBRETRO_CORE_ANDROID
.
If you're on a desktop environment, you can also load the core from command line:
retroarch -L build/docboy_libretro.so <rom>
DocBoy offers a CLI debugger (in GDB style) that's really useful to see what's going on under the hood.
To build with the debugger support, enable the CMake ENABLE_DEBUGGER
option.
mkdir build
cd build
cmake .. -DENABLE_DEBUGGER=ON
make -j 8
Use the -d
option to run with the debugger already attached from the beginning, or press the key D
to attach/detach the debugger at any time.
Commands
With help
you can list the commands:
help
b <addr> : Set breakpoint at <addr>
w[/r|a] <start>,<end> [<cond>] : Set watchpoint from <start> to <end>
w[/r|a] <addr> [<cond>] : Set watchpoint at <addr>
del <num> : Delete breakpoint or watchpoint <num>
ad <num> : Automatically disassemble next <n> instructions (default = 10)
x[x][/<length><format>] <addr> : Display memory at <addr> (x: raw) (<format>: x, h[<cols>], b, d, i)
/b <bytes> : Search for <bytes>
/i <bytes> : Search for instructions matching <bytes>
display[x][/<length><format>] <addr> : Automatically display memory at <addr> (x: raw) (<format>: x, h[<cols>], b, d, i)
undisplay : Undisplay expressions set with display
t [<count>] : Continue running for <count> clock ticks (default = 1)
. [<count>] : Continue running for <count> PPU dots (default = 1)
s [<count>] : Continue running for <count> instructions (default = 1)
si [<count>] : Continue running for <count> micro-operations (default = 1)
n [<count>] : Continue running for <count> instructions at the same stack level (default = 1)
ni [<count>] : Continue running for <count> micro-operations at the same stack level (default = 1)
f [<count>] : Continue running for <count> frames (default = 1)
fb [<count>] : Step back by <count> frames (default = 1, max = 600)
l [<count>] : Continue running for <count> lines (default = 1)
c : Continue
trace [<level>] : Set the trace level or toggle it (output on stderr)
dump : Dump the disassemble (output on stderr)
h : Display help
q : Quit
Here's the debugger!
Test Rom | Result |
---|---|
blargg/cpu_instrs.gb | ✅ |
blargg/cpu_instrs.gb | ✅ |
blargg/cpu_instrs.gb | ✅ |
blargg/cpu_instrs.gb | ✅ |
blargg/cpu_instrs.gb | ✅ |
blargg/halt_bug.gb | ✅ |
blargg/instr_timing.gb | ✅ |
blargg/mem_timing-2.gb | ✅ |
blargg/mem_timing.gb | ✅ |
blargg/oam_bug/1-lcd_sync.gb | ✅ |
blargg/oam_bug/2-causes.gb | ✅ |
blargg/oam_bug/3-non_causes.gb | ✅ |
blargg/oam_bug/4-scanline_timing.gb | ✅ |
blargg/oam_bug/5-timing_bug.gb | ✅ |
blargg/oam_bug/6-timing_no_bug.gb | ✅ |
blargg/oam_bug/8-instr_effect.gb | ✅ |
blargg/dmg_sound/01-registers.gb | ✅ |
blargg/dmg_sound/02-len_ctr.gb | ✅ |
blargg/dmg_sound/03-trigger.gb | ✅ |
blargg/dmg_sound/04-sweep.gb | ✅ |
blargg/dmg_sound/05-sweep_details.gb | ✅ |
blargg/dmg_sound/06-overflow_on_trigger.gb | ✅ |
blargg/dmg_sound/07-len_sweep_period_sync.gb | ✅ |
blargg/dmg_sound/08-len_ctr_during_power.gb | ✅ |
blargg/dmg_sound/09-wave_read_while_on.gb | ✅ |
blargg/dmg_sound/10-wave_trigger_while_on.gb | ✅ |
blargg/dmg_sound/11-regs_after_power.gb | ✅ |
blargg/dmg_sound/12-wave_write_while_on.gb | ✅ |
Test Rom | Result |
---|---|
dmg-acid2/dmg-acid2.gb | ✅ |
Test Rom | Result |
---|---|
hacktix/bully.gb | ✅ |
hacktix/strikethrough.gb | ✅ |
Test Rom | Result |
---|---|
samesuite/ei_delay_halt.gb | ✅ |
samesuite/apu/div_trigger_volume_10.gb | ✅ |
samesuite/apu/div_write_trigger.gb | ✅ |
samesuite/apu/div_write_trigger_10.gb | ✅ |
samesuite/apu/div_write_trigger_volume.gb | ✅ |
samesuite/apu/div_write_trigger_volume_10.gb | ✅ |
Test Rom | Result |
---|---|
daid/stop_instr.gb | ✅ |
daid/ppu_scanline_bgp.gb | ✅ |
Test Rom | Result |
---|---|
little-things-gb/double-halt-cancel.gb | ✅ |
Test Rom | Result |
---|---|
aaaaaa123456789/rtc3test-1.gb | ✅ |
aaaaaa123456789/rtc3test-2.gb | ✅ |
aaaaaa123456789/rtc3test-3.gb | ✅ |
Test Rom | Result |
---|---|
cpp/latch-rtc-test | ✅ |
cpp/ramg-mbc3-test | ✅ |
cpp/rtc-invalid-banks-test | ✅ |
Test Rom | Result |
---|---|
mooneye/add_sp_e_timing.gb | ✅ |
mooneye/bits/mem_oam.gb | ✅ |
mooneye/bits/reg_f.gb | ✅ |
mooneye/bits/unused_hwio-GS.gb | ✅ |
mooneye/boot_div-dmgABCmgb.gb | ✅ |
mooneye/boot_hwio-dmgABCmgb.gb | ✅ |
mooneye/boot_regs-dmgABC.gb | ✅ |
mooneye/call_cc_timing2.gb | ✅ |
mooneye/call_cc_timing.gb | ✅ |
mooneye/call_timing2.gb | ✅ |
mooneye/call_timing.gb | ✅ |
mooneye/di_timing-GS.gb | ✅ |
mooneye/div_timing.gb | ✅ |
mooneye/ei_sequence.gb | ✅ |
mooneye/ei_timing.gb | ✅ |
mooneye/halt_ime0_ei.gb | ✅ |
mooneye/halt_ime0_nointr_timing.gb | ✅ |
mooneye/halt_ime1_timing2-GS.gb | ✅ |
mooneye/halt_ime1_timing.gb | ✅ |
mooneye/if_ie_registers.gb | ✅ |
mooneye/instr/daa.gb | ✅ |
mooneye/interrupts/ie_push.gb | ✅ |
mooneye/intr_timing.gb | ✅ |
mooneye/jp_cc_timing.gb | ✅ |
mooneye/jp_timing.gb | ✅ |
mooneye/ld_hl_sp_e_timing.gb | ✅ |
mooneye/mbc/mbc1/bits_bank1.gb | ✅ |
mooneye/mbc/mbc1/bits_bank2.gb | ✅ |
mooneye/mbc/mbc1/bits_mode.gb | ✅ |
mooneye/mbc/mbc1/bits_ramg.gb | ✅ |
mooneye/mbc/mbc1/multicart_rom_8Mb.gb | ✅ |
mooneye/mbc/mbc1/ram_256kb.gb | ✅ |
mooneye/mbc/mbc1/ram_64kb.gb | ✅ |
mooneye/mbc/mbc1/rom_16Mb.gb | ✅ |
mooneye/mbc/mbc1/rom_1Mb.gb | ✅ |
mooneye/mbc/mbc1/rom_2Mb.gb | ✅ |
mooneye/mbc/mbc1/rom_4Mb.gb | ✅ |
mooneye/mbc/mbc1/rom_512kb.gb | ✅ |
mooneye/mbc/mbc1/rom_8Mb.gb | ✅ |
mooneye/mbc/mbc2/bits_ramg.gb | ✅ |
mooneye/mbc/mbc2/bits_romb.gb | ✅ |
mooneye/mbc/mbc2/bits_unused.gb | ✅ |
mooneye/mbc/mbc2/ram.gb | ✅ |
mooneye/mbc/mbc2/rom_1Mb.gb | ✅ |
mooneye/mbc/mbc2/rom_2Mb.gb | ✅ |
mooneye/mbc/mbc2/rom_512kb.gb | ✅ |
mooneye/mbc/mbc5/rom_16Mb.gb | ✅ |
mooneye/mbc/mbc5/rom_1Mb.gb | ✅ |
mooneye/mbc/mbc5/rom_2Mb.gb | ✅ |
mooneye/mbc/mbc5/rom_32Mb.gb | ✅ |
mooneye/mbc/mbc5/rom_4Mb.gb | ✅ |
mooneye/mbc/mbc5/rom_512kb.gb | ✅ |
mooneye/mbc/mbc5/rom_64Mb.gb | ✅ |
mooneye/mbc/mbc5/rom_8Mb.gb | ✅ |
mooneye/oam_dma/basic.gb | ✅ |
mooneye/oam_dma/reg_read.gb | ✅ |
mooneye/oam_dma_restart.gb | ✅ |
mooneye/oam_dma/sources-GS.gb | ✅ |
mooneye/oam_dma_start.gb | ✅ |
mooneye/oam_dma_timing.gb | ✅ |
mooneye/pop_timing.gb | ✅ |
mooneye/ppu/hblank_ly_scx_timing-GS.gb | ✅ |
mooneye/ppu/intr_1_2_timing-GS.gb | ✅ |
mooneye/ppu/intr_2_0_timing.gb | ✅ |
mooneye/ppu/intr_2_mode0_timing.gb | ✅ |
mooneye/ppu/intr_2_mode0_timing_sprites.gb | ✅ |
mooneye/ppu/intr_2_mode3_timing.gb | ✅ |
mooneye/ppu/intr_2_oam_ok_timing.gb | ✅ |
mooneye/ppu/lcdon_timing-GS.gb | ✅ |
mooneye/ppu/lcdon_write_timing-GS.gb | ✅ |
mooneye/ppu/stat_irq_blocking.gb | ✅ |
mooneye/ppu/stat_lyc_onoff.gb | ✅ |
mooneye/ppu/vblank_stat_intr-GS.gb | ✅ |
mooneye/push_timing.gb | ✅ |
mooneye/rapid_di_ei.gb | ✅ |
mooneye/ret_cc_timing.gb | ✅ |
mooneye/reti_intr_timing.gb | ✅ |
mooneye/reti_timing.gb | ✅ |
mooneye/ret_timing.gb | ✅ |
mooneye/rst_timing.gb | ✅ |
mooneye/serial/boot_sclk_align-dmgABCmgb.gb | ✅ |
mooneye/timers/div_write.gb | ✅ |
mooneye/timers/rapid_toggle.gb | ✅ |
mooneye/timers/tim00_div_trigger.gb | ✅ |
mooneye/timers/tim00.gb | ✅ |
mooneye/timers/tim01_div_trigger.gb | ✅ |
mooneye/timers/tim01.gb | ✅ |
mooneye/timers/tim10_div_trigger.gb | ✅ |
mooneye/timers/tim10.gb | ✅ |
mooneye/timers/tim11_div_trigger.gb | ✅ |
mooneye/timers/tim11.gb | ✅ |
mooneye/timers/tima_reload.gb | ✅ |
mooneye/timers/tima_write_reloading.gb | ✅ |
mooneye/timers/tma_write_reloading.gb | ✅ |
mooneye/timers/tma_write_reloading.gb | ✅ |
Test Rom | Result |
---|---|
mealybug/m2_win_en_toggle.gb | ✅ |
mealybug/m3_bgp_change.gb | ✅ |
mealybug/m3_bgp_change_sprites.gb | ✅ |
mealybug/m3_lcdc_bg_en_change.gb | ✅ |
mealybug/m3_lcdc_bg_map_change.gb | ✅ |
mealybug/m3_lcdc_obj_en_change.gb | ✅ |
mealybug/m3_lcdc_obj_en_change_variant.gb | ✅ |
mealybug/m3_lcdc_obj_size_change.gb | ✅ |
mealybug/m3_lcdc_obj_size_change_scx.gb | ✅ |
mealybug/m3_lcdc_tile_sel_change.gb | ✅ |
mealybug/m3_lcdc_tile_sel_win_change.gb | ✅ |
mealybug/m3_lcdc_win_en_change_multiple.gb | ✅ |
mealybug/m3_lcdc_win_en_change_multiple_wx.gb | ✅ |
mealybug/m3_lcdc_win_map_change.gb | ✅ |
mealybug/m3_obp0_change.gb | ✅ |
mealybug/m3_scx_high_5_bits.gb | ✅ |
mealybug/m3_scx_low_3_bits.gb | ✅ |
mealybug/m3_scy_change.gb | ✅ |
mealybug/m3_window_timing.gb | ✅ |
mealybug/m3_window_timing_wx_0.gb | ✅ |
mealybug/m3_wx_4_change.gb | ✅ |
mealybug/m3_wx_4_change_sprites.gb | ✅ |
mealybug/m3_wx_5_change.gb | ✅ |
mealybug/m3_wx_6_change.gb | ✅ |