Skip to content

A Game Boy research project and emulator written in Rust

License

Notifications You must be signed in to change notification settings

Gekkio/mooneye-gb

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Mooneye GB

Mooneye GB is a Game Boy research project and emulator written in Rust.

Build Status

The main goals of this project are accuracy and documentation. Some existing emulators are very accurate (Gambatte, BGB >= 1.5) but are not documented very clearly, so they are not that good references for emulator developers. I want this project to document as clearly as possible why certain behaviour is emulated in a certain way. This also means writing a lot of test ROMs to figure out corner cases and precise behaviour on real hardware.

Binary test ROMs are available here in a zip package and also as individual .gb files. They are automatically built and deployed whenever there's new changes in the master branch.

Non-goals:

  • CGB (Game Boy Color) support. It would be nice, but I want to make the normal Game Boy support extremely robust first.
  • A debugger
  • A good user interface. Building native UIs with Rust is a bit painful at the moment.

Warning:

  • Project is WIP
  • Doesn't work properly without a boot ROM
  • The emulator is lagging behind hardware research. I don't want to spend time making short-lived and probably incorrect fixes to the emulator if I'm not sure about the hardware behaviour.

Hardware testing

There's tons of documentation and tons of emulators in the internet, but in the end I only trust real hardware. I follow a fairly "scientific" process when developing emulation for a feature:

  1. Think of different ways how it might behave on real hardware
  2. Make a hypothesis based on the most probable behaviour
  3. Write a test ROM for such behaviour
  4. Run the test ROM on real hardware. If the test ROM made an invalid hypothesis, go back to 1.
  5. Replicate the behaviour in the emulator

All test ROMs are manually run with these devices:

Device Model Mainboard CPU Detailed information
Game Boy DMG-01 DMG-CPU-01 DMG-CPU G01176542
Game Boy DMG-01 DMG-CPU-02 DMG-CPU A G02487032
Game Boy DMG-01 DMG-CPU-04 DMG-CPU B G10888299
Game Boy DMG-01Β  DMG-CPU-06 DMG-CPU C GM6058180
Super Game Boy SHVC-027 SGB-R-10 SGB-CPU-01 SGB Unit #2 [gekkio]
Game Boy Pocket MGB-001 MGB-CPU-01 CPU MGB Β  M10280516
Super Game Boy 2 SHVC-042 SHVC-SGB2-01 CPU SGB2 SGB2 Unit #1 [gekkio]
Game Boy Color CGB-001 CGB-CPU-01 CPU CGB C10203977
Game Boy Color CGB-001 CGB-CPU-01 CPU CGB A C10400331
Game Boy Color CGB-001 CGB-CPU-02 CPU CGB B C11778414
Game Boy Color CGB-001 CGB-CPU-03 CPU CGB C CGB Unit #1 [gekkio]
Game Boy Color CGB-001 CGB-CPU-05 CPU CGB D CH20983903
Game Boy Color CGB-001 CGB-CPU-06 CPU CGB E CH24224683
Game Boy Advance AGB-001 AGB-CPU-01 CPU AGB AH10045235
Game Boy Advance AGB-001 AGB-CPU-10 CPU AGB A AH12465671
Game Boy Player DOL-017 DOL-GBS-20 CPU AGB A E GBS Unit #3 [gekkio]
Game Boy Advance SP AGS-001Β  C/AGS-CPU-01 CPU AGB B XJH10027945
Game Boy Advance SP AGS-001Β  C/AGS-CPU-21 CPU AGB B E XEH17807928

Additional devices

I also have access to more devices with different mainboard revisions, but I think the CPU revision is all that matters if we study the behaviour and not analog characteristics (e.g. audio filtering). Even if audio sounded different between two units with the same CPU revision but different mainboard revisions, I'd expect the difference to be caused by individual device variation or different revisions of support chips (e.g. RAM/AMP/REG).

The main "test fleet" is already very big, so I will only use these devices if there's evidence of behaviour that depends on mainboard revision or individual units.

Device Model Mainboard CPU Detailed information
Game Boy DMG-01 DMG-CPU-01 DMG-CPU G01036814
Game Boy DMG-01 DMG-CPU-03 DMG-CPU B G06551776
Game Boy DMG-01 DMG-CPU-05 DMG-CPU B G13289095
Game Boy DMG-01 DMG-CPU-06 DMG-CPU B
Game Boy DMG-01 DMG-CPU-07 DMG-CPU B (blob) G38953646
Game Boy DMG-01 DMG-CPU-08 DMG-CPU C (blob)
Super Game Boy SNSP-027 SGB-R-10 SGB-CPU-01 SGB Unit #7 [gekkio]
Game Boy Pocket MGB-001 MGB-ECPU-01 CPU MGB Β  MH12573718
Game Boy Pocket MGB-001 MGB-LCPU-01 CPU MGB Β  M12827347
Game Boy Pocket MGB-001 MGB-LCPU-02 CPU MGB Β  MH20284468
Game Boy Light MGB-101 MGL-CPU-01 CPU MGB L10610653
Game Boy Color CGB-001 CGB-CPU-04 CPU CGB D C19220030
Game Boy Advance AGB-001 AGB-CPU-02 CPU AGB AJ12569062
Game Boy Advance AGB-001 AGB-CPU-03 CPU AGB A AJ14804298
Game Boy Advance AGB-001 AGB-CPU-04 CPU AGB A AJ15529163
Game Boy Player DOL-017 DOL-GBS-10 CPU AGB A GBS Unit #1 [gekkio]
Game Boy Advance SP AGS-001Β  C/AGS-CPU-10 CPU AGB B XEH12776954
Game Boy Advance SP AGS-001Β  C/AGS-CPU-11 CPU AGB B XJF10485171
Game Boy Advance SP AGS-001Β  C/AGS-CPU-30 CPU AGB B E XEH20137204
Game Boy Advance SP AGS-101Β  C/AGT-CPU-01 CPU AGB B E XU72764025-1

I'm still looking for the following mainboards, but these are probably not required for reverse engineering:

  • SGB-R-01
  • SGB-N-01
  • SGB-N-10
  • C/AGS-CPU-20
  • DOL-GBS-01

For now, the focus is on DMG/MGB/SGB/SGB2 emulation, so not all tests pass on CGB/AGB/AGS or emulators emulating those devices.

Performance

Always compile in release mode if you care about performance!

On a i7-3770K desktop machine I can usually run ROMs with 2000 - 4000% speed. Without optimizations the speed drops to 150 - 200%, which is still fine for development purposes.

Raspberry Pi with X11 desktop works but is too slow because there is no OpenGL acceleration.

The emulator is runnable on Android, but cross-compiling and packaging is a huge pain and touch controls would have to be implemented, so I'm not supporting Android at the moment.

Running the emulator

Requirements:

  • Rust 1.26
  • SDL2 development libraries for your platform must be installed

GUI

  1. cargo run --release
  2. Follow the instructions

Command-line

  1. Acquire a Game Boy bootrom, and put it to $HOME/.local/share/mooneye-gb/bootroms/dmg_boot.bin
  2. cargo build --release
  3. cargo run --release -- PATH_TO_GAMEBOY_ROM

On Windows, also download an SDL2 package containing SDL2.dll, and put it to target/debug and target/release.

Game Boy keys

Game Boy Key
Dpad Arrow keys
A Z
B X
Start Return
Select Backspace

Other keys

Function Key
Fast forward Shift
Toggle performance overlay F2

Accuracy comparison

Versions used:

  • mooneye-gb (master)
  • BGB 1.5.6
  • Gambatte 2015-03-23 (f9fb003)
  • Higan v098 (in Game Boy mode, except for SGB/SGB2-specific test ROMs)
  • MESS 0.179

Symbols:

  • πŸ‘ pass
  • ❌ fail
  • β­• pass with caveats, see notes

These emulators are omitted:

  • KiGB. This emulator has bold claims about accuracy and compatibility. However, version 2.05 was tested and it barely passed any tests at all. See the accuracy table from history
  • GiiBiiAdvance. This emulator seems to be unmaintained, but you can check the accuracy table from history for old results.

Blargg's tests

Test mooneye-gb BGB Gambatte Higan MESS
cpu instrs πŸ‘ πŸ‘ πŸ‘ πŸ‘ πŸ‘
dmg sound 2 ❌ πŸ‘ πŸ‘ ❌ β­•
instr timing πŸ‘ πŸ‘ πŸ‘ πŸ‘ πŸ‘
mem timing 2 πŸ‘ πŸ‘ πŸ‘ πŸ‘ πŸ‘
oam bug 2 ❌ ❌ ❌ ❌ ❌
cgb sound 2 πŸ‘ πŸ‘ ❌ πŸ‘

Notes:

  • cpu_instrs fails on MGB/SGB2 hardware and emulators emulating them correctly. The ROM incorrectly detects the device as CGB, and attempts to perform a CPU speed change which causes a freeze (STOP instruction with joypad disabled)
  • dmg_sound-2 test #10 can fail randomly on real hardware and seems to depend on non-deterministic behaviour.
  • oam_bug-2 fails on all CGB, AGB, and AGS devices
  • cgb_sound-2 test #03 fails on CPU CGB, CPU CGB A, and CPU CGB B

Mooneye GB acceptance tests

Test mooneye-gb BGB Gambatte Higan MESS
add sp e timing πŸ‘ ❌ πŸ‘ πŸ‘ πŸ‘
boot hwio dmg0 ❌ β­• πŸ‘
boot hwio dmgABCmgb ❌ πŸ‘ πŸ‘ ❌ πŸ‘
boot hwio S πŸ‘ β­• Β  πŸ‘ ❌
boot regs dmg0 πŸ‘ β­• πŸ‘
boot regs dmgABC πŸ‘ πŸ‘ πŸ‘ πŸ‘ πŸ‘
boot regs mgb πŸ‘ β­• πŸ‘
boot regs sgb πŸ‘ β­• πŸ‘ πŸ‘
boot regs sgb2 πŸ‘ β­• ❌ πŸ‘
call timing πŸ‘ ❌ πŸ‘ πŸ‘ πŸ‘
call timing2 πŸ‘ ❌ πŸ‘ πŸ‘ πŸ‘
call cc_timing πŸ‘ ❌ πŸ‘ πŸ‘ πŸ‘
call cc_timing2 πŸ‘ ❌ πŸ‘ πŸ‘ πŸ‘
di timing GS πŸ‘ πŸ‘ πŸ‘ πŸ‘ πŸ‘
div timing πŸ‘ πŸ‘ πŸ‘ πŸ‘ πŸ‘
ei sequence πŸ‘ πŸ‘ πŸ‘ πŸ‘ ❌
ei timing πŸ‘ πŸ‘ πŸ‘ πŸ‘ πŸ‘
halt ime0 ei πŸ‘ πŸ‘ πŸ‘ πŸ‘ πŸ‘
halt ime0 nointr_timing πŸ‘ πŸ‘ πŸ‘ πŸ‘ πŸ‘
halt ime1 timing πŸ‘ πŸ‘ πŸ‘ πŸ‘ πŸ‘
halt ime1 timing2 GS πŸ‘ πŸ‘ πŸ‘ πŸ‘ πŸ‘
if ie registers πŸ‘ πŸ‘ πŸ‘ πŸ‘ πŸ‘
intr timing πŸ‘ πŸ‘ πŸ‘ πŸ‘ πŸ‘
jp timing πŸ‘ ❌ πŸ‘ πŸ‘ πŸ‘
jp cc timing πŸ‘ ❌ πŸ‘ πŸ‘ πŸ‘
ld hl sp e timing πŸ‘ ❌ πŸ‘ πŸ‘ πŸ‘
oam dma_restart πŸ‘ ❌ πŸ‘ πŸ‘ πŸ‘
oam dma start πŸ‘ ❌ πŸ‘ πŸ‘ πŸ‘
oam dma timing πŸ‘ ❌ πŸ‘ πŸ‘ πŸ‘
pop timing πŸ‘ ❌ πŸ‘ πŸ‘ πŸ‘
push timing πŸ‘ ❌ ❌ πŸ‘ πŸ‘
rapid di ei πŸ‘ πŸ‘ πŸ‘ πŸ‘ πŸ‘
ret timing πŸ‘ ❌ πŸ‘ πŸ‘ πŸ‘
ret cc timing πŸ‘ ❌ πŸ‘ πŸ‘ πŸ‘
reti timing πŸ‘ ❌ πŸ‘ πŸ‘ πŸ‘
reti intr timing πŸ‘ πŸ‘ πŸ‘ πŸ‘ πŸ‘
rst timing πŸ‘ ❌ ❌ πŸ‘ πŸ‘

Notes:

  • BGB passes most boot tests only if you explicitly enable boot ROMs and give it the right one. This makes sense for DMG0, MGB, and SGB2 because they are not selectable, but SGB should work without boot ROMs out of the box.

Bits (unusable bits in memory and registers)

Test mooneye-gb BGB Gambatte Higan MESS
mem oam πŸ‘ πŸ‘ πŸ‘ πŸ‘ πŸ‘
reg f πŸ‘ πŸ‘ πŸ‘ πŸ‘ πŸ‘
unused_hwio GS πŸ‘ ❌ πŸ‘ ❌ πŸ‘

Interrupt handling

Test mooneye-gb BGB Gambatte Higan MESS
ie push πŸ‘ ❌ ❌ ❌ ❌

OAM DMA

Test mooneye-gb BGB Gambatte Higan MESS
basic πŸ‘ πŸ‘ πŸ‘ πŸ‘ πŸ‘
reg_read πŸ‘ πŸ‘ πŸ‘ ❌ ❌
sources dmgABCmgbS πŸ‘ πŸ‘ ❌ ❌ ❌

PPU

Test mooneye-gb BGB Gambatte Higan MESS
hblank ly scx timing GS πŸ‘ ❌ ❌ ❌ πŸ‘
intr 1 2 timing GS πŸ‘ πŸ‘ πŸ‘ πŸ‘ πŸ‘
intr 2 0 timing πŸ‘ πŸ‘ ❌ πŸ‘ πŸ‘
intr 2 mode0 timing πŸ‘ πŸ‘ ❌ ❌ πŸ‘
intr 2 mode3 timing πŸ‘ πŸ‘ ❌ ❌ πŸ‘
intr 2 oam ok timing πŸ‘ πŸ‘ ❌ ❌ πŸ‘
intr 2 mode0 timing sprites ❌ ❌ ❌ ❌ πŸ‘
lcdon timing dmgABCmgbS ❌ πŸ‘ ❌ ❌ ❌
lcdon write timing GS ❌ ❌ ❌ ❌ ❌
stat irq blocking ❌ ❌ πŸ‘ ❌ πŸ‘
stat lyc onoff ❌ ❌ ❌ ❌ ❌
vblank stat intr GS πŸ‘ πŸ‘ ❌ πŸ‘ πŸ‘

Serial

Test mooneye-gb BGB Gambatte Higan MESS
boot sclk align dmgABCmgb ❌ ❌ πŸ‘ ❌ ❌

Timer

Test mooneye-gb BGB Gambatte Higan MESS
div write πŸ‘ πŸ‘ ❌ πŸ‘ πŸ‘
rapid toggle πŸ‘ ❌ ❌ ❌ πŸ‘
tim00 div trigger πŸ‘ ❌ πŸ‘ ❌ πŸ‘
tim00 πŸ‘ πŸ‘ ❌ πŸ‘ πŸ‘
tim01 div trigger πŸ‘ πŸ‘ ❌ ❌ πŸ‘
tim01Β  πŸ‘ πŸ‘ πŸ‘ πŸ‘ πŸ‘
tim10 div trigger πŸ‘ πŸ‘ ❌ ❌ πŸ‘
tim10 πŸ‘ πŸ‘ ❌ πŸ‘ πŸ‘
tim11 div trigger πŸ‘ ❌ ❌ ❌ πŸ‘
tim11 πŸ‘ πŸ‘ ❌ πŸ‘ πŸ‘
tima reload πŸ‘ ❌ ❌ ❌ πŸ‘
tima write reloading πŸ‘ ❌ ❌ ❌ πŸ‘
tma write reloading πŸ‘ ❌ ❌ ❌ πŸ‘

Mooneye GB emulator-only tests

MBC1

Test mooneye-gb BGB Gambatte Higan MESS
bits ram en πŸ‘ πŸ‘ πŸ‘ πŸ‘ πŸ‘
rom 512Kb πŸ‘ ❌ πŸ‘ πŸ‘ πŸ‘
rom 1Mb πŸ‘ ❌ πŸ‘ πŸ‘ πŸ‘
rom 2Mb πŸ‘ ❌ πŸ‘ πŸ‘ πŸ‘
rom 4Mb πŸ‘ πŸ‘ πŸ‘ πŸ‘ πŸ‘
rom 8Mb πŸ‘ ❌ ❌ ❌ πŸ‘
rom 16Mb πŸ‘ ❌ ❌ ❌ πŸ‘
ram 64Kb πŸ‘ πŸ‘ πŸ‘ πŸ‘ πŸ‘
ram 256Kb πŸ‘ πŸ‘ ❌ ❌ πŸ‘
multicart rom 8Mb πŸ‘ ❌ πŸ‘

Notes:

  • Most emulators don't support MBC1 multicart ROMs at all
  • Higan requires manual manifest file creation to trigger MBC1 multicart mode, but doesn't pass the test.

Mooneye GB manual tests

Test mooneye-gb BGB Gambatte Higan MESS
sprite priority πŸ‘ πŸ‘ πŸ‘ πŸ‘ ❌

Mooneye GB misc tests

Test mooneye-gb BGB Gambatte Higan MESS
boot hwio C πŸ‘ ❌
boot regs A ❌
boot regs cgb πŸ‘ πŸ‘

Bits

Test mooneye-gb BGB Gambatte Higan MESS
unused hwio C ❌ ❌

PPU

Test mooneye-gb BGB Gambatte Higan MESS
vblank stat intr C ❌ πŸ‘

Test naming

Some tests are expected to pass only a single model:

  • dmg = Game Boy
  • mgb = Game Boy Pocket
  • sgb = Super Game Boy
  • sgb2 = Super Game Boy 2
  • cgb = Game Boy Color
  • agb = Game Boy Advance
  • ags = Game Boy Advance SP

In addition to model differences, CPU revisions can affect the behaviour. Revision 0 refers always to the initial version of a CPU (e.g. CPU CGB). AGB and AGS use the same CPU models. The following CPU models have several revisions:

  • DMG: 0, A, B, C
  • CGB: 0, A, B, C, D, E
  • AGB: 0, A, A E, B, B E. Revision E also exists, but only in Game Boy Micro (OXY) so it is out of this project's scope. However, A E and B E are most likely actually just E revision in A or B-compatible package.

In general, hardware can be divided to a couple of groups based on their behaviour. Some tests are expected to pass on a single or multiple groups:

  • G = dmg+mgb
  • S = sgb+sgb2
  • C = cgb+agb+ags
  • A = agb+ags

For example, a test with GS in the name is expected to pass on dmg+mgb + sgb+sgb2.

License and copyright

Mooneye GB is licensed under GPLv3+. Copyright (C) 2014-2018 Joonas Javanainen [email protected]

The test framework and hardware tests under tests/ are licensed under MIT. Copyright (C) 2014-2018 Joonas Javanainen [email protected]