GithubHelp home page GithubHelp logo

gekkio / mooneye-gb Goto Github PK

View Code? Open in Web Editor NEW
880.0 30.0 56.0 1.9 MB

A Game Boy research project and emulator written in Rust

License: GNU General Public License v3.0

Rust 98.43% Shell 0.17% GLSL 1.40%
rust emulator gameboy gameboy-emulator game-boy

mooneye-gb's Introduction

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.

For documentation about known behaviour, see Game Boy: Complete Technical Reference

Looking for the mooneye-gb test ROMs? They are now part of Mooneye Test Suite.

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.

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

Test suite

Blargg's tests

Test mooneye-gb
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
add sp e timing πŸ‘
boot div dmg0 ❌
boot div dmgABCmgb ❌
boot div S ❌
boot div2 S ❌
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 πŸ‘

Bits (unusable bits in memory and registers)

Test mooneye-gb
mem oam πŸ‘
reg f πŸ‘
unused_hwio GS πŸ‘

Instructions

Test mooneye-gb
daa πŸ‘

Interrupt handling

Test mooneye-gb
ie push πŸ‘

OAM DMA

Test mooneye-gb
basic πŸ‘
reg_read πŸ‘
sources GS πŸ‘

PPU

Test mooneye-gb
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 GS ❌
lcdon write timing GS ❌
stat irq blocking ❌
stat lyc onoff ❌
vblank stat intr GS πŸ‘

Serial

Test mooneye-gb
boot sclk align dmgABCmgb ❌

Timer

Test mooneye-gb
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
bits bank1 πŸ‘
bits bank2 πŸ‘
bits mode πŸ‘
bits ramg πŸ‘
rom 512kb πŸ‘
rom 1Mb πŸ‘
rom 2Mb πŸ‘
rom 4Mb πŸ‘
rom 8Mb πŸ‘
rom 16Mb πŸ‘
ram 64kb πŸ‘
ram 256kb πŸ‘
multicart rom 8Mb πŸ‘

MBC2

Test mooneye-gb
bits ramg πŸ‘
bits romb πŸ‘
bits unused πŸ‘
rom 512kb πŸ‘
rom 1Mb πŸ‘
rom 2Mb πŸ‘
ram πŸ‘

MBC5

Test mooneye-gb
rom 512kb πŸ‘
rom 1Mb πŸ‘
rom 2Mb πŸ‘
rom 4Mb πŸ‘
rom 8Mb πŸ‘
rom 16Mb πŸ‘
rom 32Mb πŸ‘
rom 64Mb πŸ‘

Mooneye GB manual tests

Test mooneye-gb
sprite priority πŸ‘

Mooneye GB misc tests

Test mooneye-gb
boot div A
boot div cgb0
boot div cgbABCDE
boot hwio C
boot regs A
boot regs cgb

Bits

Test mooneye-gb
unused hwio C

PPU

Test mooneye-gb
vblank stat intr C

License and copyright

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

mooneye-gb's People

Contributors

dependabot-preview[bot] avatar eagleflo avatar endrift avatar gekkio avatar issotm avatar mattcurrie avatar wilbertpol avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

mooneye-gb's Issues

Implement a shader cache

Starting up the app takes a very long time on at least Intel GPUs, which is most likely caused by slow shader compilation and no system-level cache.

wasm port

Hey there,

first of all thanks for all the hard work. As an GB homebrew developer accurate emulation lies very close to my heart :)

Now since my evening was rather boring, I decided to check if it was possible to do a wasm port of mooneye-gb and low and behold it turned out to be rather easy with all the rust related tooling we have at hands these days: https://gitlab.com/BonsaiDen/mooneye-wasm

Hope you like it and keep on the good work!

Test ROM Request: Details of Accessing VRAM During Rendering

Hello,

As the title says, I'm requesting a test ROM that can give the details for what is returned from reads from VRAM by the CPU during rendering. The reason for this request is that recently there was an attempt to play back a Tool Assisted Speedrun of Wario Land II on console, but there was a de-sync. I tracked the de-sync down to a VRAM access that happens at the very end of rendering on scanline 22.

Up until now, this case had been dealt with by returning 0xFF. However this is not what console showed. Also, the actual value at the address being read is already 0xFF. So, it has to be returning something else. I think it's returning the last value read by the PPU, and when I put this behaviour in my emulator I get the correct result (the same de-sync displayed on console.) But, this is just speculation.

So, it would be very helpful to have a test that evaluates what is being returned for individual cycles during scanline rendering, especially near the end of a scnaline when the PPU stops accessing VRAM.

(Also thanks for your current tests, they are very helpful and easy to understand.)

Mooneye crashes when playing Pokemon blue with accelerator on

Reproduction:

Using a standard Gameboy BootRom, load Pokemon blue. Hold shift (turbo mode) and select "New game". Continue to hold shift while professor oak is talking, and the emulator panics with this stack trace:

16:25:30 οΏ½[34m[ INFO] οΏ½[mοΏ½Starting Mooneye GB v0.2.0-pre
16:25:30 οΏ½[36m[DEBUG] οΏ½[mοΏ½(1) mooneye_gb::config::bootrom: Scanning /home/alex/.local/share/mooneye-gb/bootroms/dmg_boot.bin for a boot ROM
16:25:30 οΏ½[34m[ INFO] οΏ½[mοΏ½Using DMG (Game Boy) boot ROM from /home/alex/.local/share/mooneye-gb/bootroms/dmg_boot.bin
16:25:30 οΏ½[36m[DEBUG] οΏ½[mοΏ½(1) gilrs::gamepad: Loaded 276 mappings.
16:25:30 οΏ½[34m[ INFO] οΏ½[mοΏ½Guessed window DPI factor: 1
16:25:30 οΏ½[36m[DEBUG] οΏ½[mοΏ½(1) winit::platform::platform::x11::window: Calculated physical dimensions: 640x576
16:25:30 οΏ½[34m[ INFO] οΏ½[mοΏ½Initialized renderer with OpenGL 4.5
thread '<unnamed>' panicked at 'Undefined opcode 228', core/src/cpu/execute.rs:736:5
stack backtrace:
   0: backtrace::backtrace::libunwind::trace
             at /cargo/registry/src/github.com-1ecc6299db9ec823/backtrace-0.3.40/src/backtrace/libunwind.rs:88
   1: backtrace::backtrace::trace_unsynchronized
             at /cargo/registry/src/github.com-1ecc6299db9ec823/backtrace-0.3.40/src/backtrace/mod.rs:66
   2: std::sys_common::backtrace::_print_fmt
             at src/libstd/sys_common/backtrace.rs:77
   3: <std::sys_common::backtrace::_print::DisplayBacktrace as core::fmt::Display>::fmt
             at src/libstd/sys_common/backtrace.rs:61
   4: core::fmt::write
             at src/libcore/fmt/mod.rs:1028
   5: std::io::Write::write_fmt
             at src/libstd/io/mod.rs:1412
   6: std::sys_common::backtrace::_print
             at src/libstd/sys_common/backtrace.rs:65
   7: std::sys_common::backtrace::print
             at src/libstd/sys_common/backtrace.rs:50
   8: std::panicking::default_hook::{{closure}}
             at src/libstd/panicking.rs:188
   9: std::panicking::default_hook
             at src/libstd/panicking.rs:205
  10: std::panicking::rust_panic_with_hook
             at src/libstd/panicking.rs:464
  11: std::panicking::continue_panic_fmt
             at src/libstd/panicking.rs:373
  12: std::panicking::begin_panic_fmt
             at src/libstd/panicking.rs:328
  13: mooneye_gb::cpu::execute::<impl mooneye_gb::cpu::Cpu>::undefined
  14: mooneye_gb::cpu::decode::<impl mooneye_gb::cpu::Cpu>::decode_exec_fetch
  15: mooneye_gb::machine::Machine::emulate
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.
16:25:34 οΏ½[31m[ERROR] οΏ½[mοΏ½"SendError(..)"

stack backtrace:
   0: failure::backtrace::internal::InternalBacktrace::new
   1: failure::backtrace::Backtrace::new
   2: mooneye_gb::frontend::emu_thread::EmuThreadHandle::stop
   3: mooneye_gb::frontend::SdlFrontend::main
   4: mooneye_gb::main
   5: std::rt::lang_start::{{closure}}
   6: std::rt::lang_start_internal::{{closure}}
             at src/libstd/rt.rs:48
      std::panicking::try::do_call
             at src/libstd/panicking.rs:287
   7: __rust_maybe_catch_panic
             at src/libpanic_unwind/lib.rs:78
   8: std::panicking::try
             at src/libstd/panicking.rs:265
      std::panic::catch_unwind
             at src/libstd/panic.rs:396
      std::rt::lang_start_internal
             at src/libstd/rt.rs:47
   9: main
  10: __libc_start_main
  11: _start

Environment:

mooneye-gb 3f79eef
debian buster
Rustc 1.40.0

Request for details on a test comment ( about OAM DMA )

I'm having trouble understand something I read in one of your timing tests that deals with OAM DMA.

https://github.com/Gekkio/mooneye-gb/blob/master/tests/acceptance/call_cc_timing.s#L83-L86

  ; the first two bytes of CALL nn will be at $FDFE, so
  ; the high byte of nn is at the first byte of OAM during testing
  ; [...]
  ; the memory read of nn is aligned to happen exactly one cycle
  ; before the OAM DMA end, so high byte of nn = $FF
  ; therefore the call becomes:
  ;   call c, $ffca

From what I understand the CPU is only able to access HIRAM during OAM DMA.. so wouldn't that turn into RST $38 ($FF) instead?


Another piece of that test that is confusing to me is the per-cycle timings of CALL.

; CALL cc, nn is expected to have the following timing:
; M = 0: instruction decoding
; M = 1: nn read: memory access for low byte
; M = 2: nn read: memory access for high byte
; M = 3: internal delay
; M = 4: PC push: memory access for high byte
; M = 5: PC push: memory access for low byte

You state above that the low byte is read first. That seems to go against what the test expects if its expecting the low byte to be read correctly and the high byte to be read as $FF.

Test DI delay

Some sources say DI has an immediate effect (unlike EI).

acceptance/ppu/intr_2_0_timing.s typo?

This test is named intr_2_0_timing, but it's documented as testing mode 1 to 2 timing:

; Tests how long does it take to get from STAT mode=1 interrupt to STAT mode=2 interrupt
; No sprites, scroll or window.

and the code itself appears to move from mode 2 to 0:

call setup_and_wait_mode2
nops delay
call setup_and_wait_mode0

Is the documentation incorrect?

In ie_push.s, cannot trigger "R3: unwanted cancel" failure ?

When I tried this test with my emulator, instead of failing or passing, the emulator just stopped after a while. As I was investigating why, it occurred to me that my implementation should have triggered the "R3: unwanted cancel" failure but that it didn't for some reason.

My understanding of the scenario that should lead to this failure is as follows:

  • from address PC=0x0235 with SP=0x0001, we trigger INTR_SERIAL with "ldh (<IF), a"
  • while processing this interrupt, if it is cancelled, PC is set to 0
  • because at the end of ie_push.s we have ".org $0000" followed by "jp hl", when executing the instruction at PC=0, we should jump to the address contained in HL

However, because we trigger the interrupt with SP=1, pushing PC as part of processing the interrupt not only puts 0x35 into IE but it also puts 0x02 at the address 0 which replaces the 0xE9 opcode of the jump instruction that should trigger the failure path.

Is my interpretation correct or did I miss something ?

Build Error

I tried to build this emulator, but I get the following build error (on MacOS):

  --> src/frontend/renderer.rs:57:7
   |
57 |       FrameState::Even => FrameState::Odd,
   |       ^^^^^^^^^^^^^^^^ help: consider using a reference: `&FrameState::Even`

error[E0658]: non-reference pattern used to match a reference (see issue #42640)
  --> src/frontend/renderer.rs:58:7
   |
58 |       FrameState::Odd => FrameState::Even,
   |       ^^^^^^^^^^^^^^^ help: consider using a reference: `&FrameState::Odd
error: aborting due to 2 previous errors

error: Could not compile `mooneye-gb`.

Any ideas what is causing this and how to fix? Thanks! Very interested in and excited about this project.

Publish on Cargo?

Perhaps it'd be easier to publish the package, along with the core, on Cargo to simplify installation and make it so others can use the core emulator as a dependency, potentially writing different frontends.

Wrong HalfCarry check on add16-instruction

Hey, I'm working on an GB emulator in F#.

While studying (or peeking ;)) your implementation I noticed a bug in this line:
https://github.com/Gekkio/mooneye-gb/blob/master/src/cpu/mod.rs#L902

According to the most known Game Boy CPU Manual, as well as the official GB programming manual the half-carry flag is set when there's a carry from bit 11. This would mean a check for 0x0FFF, and not 0x07FF (bit 10).

A test case from the official developer manual (page 97):

When HL = 0x8A23
ADD HL, HL ; HL <- 0x1446, H <- 1, N <- 0, CY <- 1

Remove "debug" opcode from all test roms.

Please, remove it. The real behaviour of that pseudo-opcode (which, acording to wla-dx, is 0xED) is to hang the CPU forever. Most emulators show error messages when they try to execute that instruction. You should use "ld b,b", which is kind of a standard (no$gmb, bgb) and it doesn't hang emulators or real hardware. In fact, the only reason the test roms can work in real hardware is that just after that instruction there's an infinite loop, so the CPU would be trapped there anyway.

Incorrect registers in acceptance/boot_regs-dmg0 ?

I'm running an emulator against the acceptance/boot_regs-dmg0 rom and was a bit surprised to see that the flag register for DMG is expected to be 00 on boot.

Looking at the DMG bootrom, it appears that, at minimum, z should be enabled by the end of the bootstrap because otherwise the bootstrap sequence is expected to lock up. The pandocs appear to back this up at https://github.com/gbdev/pandocs/blob/develop/content/Power_Up_Sequence.md.

I realize all of these ROMs are tested on hardware, so I'm perplexed as to how the assertions came to be as they are. Is it possible pandocs + the bootstrap are wrong?

Alternatively, is it possible I'm misunderstanding when these registers are expected to be evaluated? E.g. I'm assuming that the registers are snapshotted after the bootstrap sequence, at which point the assumption above of the z flag being set should hold true assuming the bootstrap for DMG is correct.

Issue with sources-GS test

Hello,

I'm facing a problem with this test and I need your insight!
At test_fe00: , it appears that OAM is cleared with call clear_oam , then DMA runs and the test compares the result with ram_pattern_1. Since OAM was cleared prior to DMA, it will never have the correct pattern, so you even have to remove the clear or reload the pattern before triggering the DMA.

I hope I didn't get the whole thing wrong!
Keep up the great work!

Test result output through serial port

Hey, would be a cool thing when the test roms not only print the test result on the screen but also output the characters through the serial port of the gb system. Would help with automated testing for emulators i guess becuase you could easier output the errors happent.

develop a gameboy debugger in mooneye-gb

I know from the readme it is not a priority.

But me I am looking for a good remote debugger for gameboy color. I did not find any on the market. MGBA and VisualBoy advance do not support gdbserver for gameboy color.

So I suggest to let me make a pull request to add the feature to debug. Then I will add a remote debuger.

I already tried to start on rusty-boy and oxydbg sadly they were not enough mature or the maintainer did not allow new pull request.

Best regards.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.