Full featured Cross-platform GameBoy emulator by Rust. Forever boys!.

Overview

Gameboy

Full featured Cross-platform GameBoy emulator. Forever boys!.

sample.gif

You can start a game with the following command, here with a built-in game "Boxes" as an example:

$ cargo run --release -- "./res/boxes.gb"

The following options are supported:

-a, --enable-audio    Enable audio, default is false
-x, --scale-factor    Scale the video by a factor of 1, 2, 4, or 8

Gameboy is developed by Rust, and fully tested on Windows, Ubuntu and Mac.

Control

                _n_________________
                |_|_______________|_|
                |  ,-------------.  |
                | |  .---------.  | |
                | |  |         |  | |
                | |  |         |  | |
                | |  |         |  | |
                | |  |         |  | |
                | |  `---------'  | |
                | `---------------' |
                |   _ GAME BOY      |
   Up           | _| |_         ,-. | ----> Z
Left/Right <--- ||_ O _|   ,-. "._,"|
  Down          |  |_|    "._,"   A | ----> X
                |    _  _    B      |
                |   // //           |
                |  // //    \\\\\\  | ----> Enter/BackSpace
                |  `  `      \\\\\\ ,
                |________...______,"

Tests

Thanks for Blargg's Gameboy hardware test ROMs, I can simply verify my code. Run tests by:

$ cargo run --example blargg
Test Name Result
cpu_instrs img
instr_timing img

Reference

Licenses

WTFPL.

Comments
  • incorrect speed switch implementation in CGB mode

    incorrect speed switch implementation in CGB mode

    Hello, the speed switch code should get the value in the address that the PC register pointed instead of the value of in register.

    https://github.com/mohanson/gameboy/blob/ff9c35b3957b4c215bd817c4d2ca18de0fb7f25e/src/motherboard.rs#L21

    Reference: https://gbdev.gg8.se/wiki/articles/CGB_Registers#FF4D_-KEY1-CGB_Mode_Only-_Prepare_Speed_Switch

    The actual speed switch is performed by executing a STOP command after Bit 0 has been set. After that Bit 0 will be cleared automatically, and the gameboy will operate at the 'other' speed.

    opened by Hanaasagi 5
  • Please add Cargo.lock to .gitignore

    Please add Cargo.lock to .gitignore

    Cargo.lock is a generated file by cargo, but build fail if your generated Cargo.lock is present. Suggestion: delete Cargo.lock and add it to .gitignore

    opened by eduardossampaio 5
  • render in terminal via blockish

    render in terminal via blockish

    • adds terminal rendering w/ blockish (-t flag)
    • handles input w/ crossterm_input

    video demos:

    zelda: https://www.youtube.com/watch?v=ou_4WSuYRHk pokemon yellow: https://youtu.be/XcrkZnIS1lM

    opened by yazgoo 4
  • intermitant clock changes

    intermitant clock changes

    As I've been playing with this emulator I've noticed that the clock rate seems to jump around. Sometimes the game will slow the a crawl, and other times it runs so fast that it becomes hard to control. I think this may be because my machine isn't that powerful, and it may be missing frame timing (it was taking ~30ms a cpu cycle rather than the target 16 when I threw some prints in there).

    I think the following diff might fix things:

    diff --git a/src/cpu.rs b/src/cpu.rs
    index bb07a5e..80f3556 100644
    --- a/src/cpu.rs
    +++ b/src/cpu.rs
    @@ -1693,7 +1693,7 @@ impl Cpu {
     pub struct Rtc {
         pub cpu: Cpu,
         step_cycles: u32,
    -    step_zero: time::SystemTime,
    +    step_zero: time::Instant,
         step_flip: bool,
     }
     
    @@ -1703,7 +1703,7 @@ impl Rtc {
             Self {
                 cpu,
                 step_cycles: 0,
    -            step_zero: time::SystemTime::now(),
    +            step_zero: time::Instant::now(),
                 step_flip: false,
             }
         }
    @@ -1713,14 +1713,20 @@ impl Rtc {
             if self.step_cycles > STEP_CYCLES {
                 self.step_flip = true;
                 self.step_cycles -= STEP_CYCLES;
    -            let d = time::SystemTime::now().duration_since(self.step_zero).unwrap();
    +            let now = time::Instant::now();
    +            let d = now.duration_since(self.step_zero);
                 let s = u64::from(STEP_TIME.saturating_sub(d.as_millis() as u32));
                 rog::debugln!("CPU: sleep {} millis", s);
                 thread::sleep(time::Duration::from_millis(s));
    -            self.step_zero = self
    -                .step_zero
    +            self.step_zero = self.step_zero
                     .checked_add(time::Duration::from_millis(u64::from(STEP_TIME)))
                     .unwrap();
    +
    +            // If now is after the just updated target frame time, reset to
    +            // avoid drift.
    +            if now.checked_duration_since(self.step_zero).is_some() {
    +                self.step_zero = now;
    +            }
             }
             let cycles = self.cpu.next();
             self.step_cycles += cycles;
    

    I don't think switching from SystemTime to monotonic time is actually that important, but I think it is probably the right thing to do here since we are just using this stuff for frame timing and it doesn't really have to relate to the real wallclock time.

    But the bug can take a while to manifest, so I can't really confirm yet. I'm going to run an emulator with this patch for a while and update this thread.

    opened by ethanpailes 4
  • Segfault on start, I believe I know the problem

    Segfault on start, I believe I know the problem

    I'm currently running bspwm, and everything is set to tiling.

    I believe the issue is that gameboy is trying to launch with specific geometry size, but since it can't due to tiling, it segfaults.

    If I'm right, I can fix this by setting bspwm to float that window.

    The problem though, is that I can't obtain the wm_class since the window instantly closes.

    So could you tell me what the wm_class is?

    opened by Phate6660 2
  • Fix(Hdma): fix the address value in get method.

    Fix(Hdma): fix the address value in get method.

    Hello, there is a small typo in Hdma. 0xff43 should be 0xff53.

    Reference: https://gbdev.gg8.se/wiki/articles/Video_Display#FF53_-HDMA3-CGB_Mode_Only-_New_DMA_Destination.2C_High

    图片
    opened by Hanaasagi 1
  • make command line options more discoverable

    make command line options more discoverable

    First, this is an awesome project! I looked into a couple of other gameboy emulators with many more commits and contributors before trying out this one, and this was the first project that worked.

    I'm fortunate enough to be able to figure out the command line flags by reading sources, but I suspect that not everyone who is interested in using this project will have that option open to them so I thought I would send you a patch to try to make the command line flags a little more discoverable.

    Adding the long-form flags gives argparse something to use as the argument name in its help message. The new usage message is:

    Usage:
      target/debug/gameboy [OPTIONS] [ROM]
    
    Gameboy emulator
    
    Positional arguments:
      rom                   Rom name
    
    Optional arguments:
      -h,--help             Show this help message and exit
      -a,--enable-audio     Enable audio
      -x,--scale-factor SCALE_FACTOR
                            Scale the video by a factor of 1, 2, 4, or 8
    

    I also fixed a compiler warning.

    opened by ethanpailes 1
  • Fix half carry flag logic in alu_add_hl

    Fix half carry flag logic in alu_add_hl

    Correct me if I'm wrong, but I think a mask of 0x0FFF is consistent with the 8-bit alu_add function:

    self.reg.set_flag(C, u16::from(a) + u16::from(n) > 0xff);
    self.reg.set_flag(H, (a & 0x0f) + (n & 0x0f) > 0x0f);
    

    and other emulators I've checked with: SameBoy, binjgb, CoffeeGB

    opened by nwtnni 1
  • Ambiguous function names in src/memory.rs

    Ambiguous function names in src/memory.rs

    While I review your code in src/memory.rs, one thing makes me confused. There are two functions named as get_halfword and set_halfword. Literally, they are used to get half of a WORD length data from a specific memory address, or setting half of a WORD length data. In fact, they are designed as 16-bit version getter and setter for memory.

    ARM64 and x86 family of CPU defined a WORD as 16 bits(2 bytes). Back to time of Intel 8080 and Zilog 80, a WORD stands for 8 bits. I have not found any LR35902 specifications, indicating that a WORD is 32 bits.

    So I wonder if a correctly expressed version of those function names should be get_word(for widely used x86 and ARM standard) or get_dword(for 8080 and Z80 standard), the same for setter.

    Thanks for your hard work.

    opened by DarkKowalski 1
  • English Please

    English Please

    What is the problem with Chinese README's

    Firstly, we congratulate you for getting so much star by sharing this repository with humanity.

    But it is very disappointing for non-Chinese speakers when one couldn't understand what a trending repository is about.

    When we see such a repo on trending, our minds are blurring like Gollum's.

    Gollum Image

    There is a way you can help to solve this disappointment which I believe is experienced by many people who want to know more about your valuable work and appreciate it.

    What we want:

    • Please add English translation of your README so you are sharing your work and knowledge with more people.

    How this will help you:

    • More feedback to fix and improve your project.
    • New ideas about your project.
    • Greater fame.
    • SungerBob Image

    “Sharing knowledge is the most fundamental act of friendship. Because it is a way you can give something without loosing something.”

    — Richard Stallman

    Thank you!

    This issue created by us/english-please script. Please report on any error. Thank you!

    opened by us 1
  • WIP ssh container

    WIP ssh container

    I dont know if this is the right repo for this, please tell me if it is not.

    Adds a dockerfile to host the emulator in tty mode as an SSH container. On ssh connection:

    1. prompts for a zip HTTP url from which to download the rom
    2. downloads the rom and unzip it
    3. starts the emulator with the rom
    opened by yazgoo 0
  • Noise divisor code should not be incremented

    Noise divisor code should not be incremented

    https://github.com/mohanson/gameboy/blob/87865c1b7317e631ef375476311cc5c5ae9e95c8/src/apu.rs#L998 n should not be incremented by 1. Otherwise, by example, if n = 1 you will get a divisor value of 32 instead of the 16 expected.

    You can also use this operation instead:

    n => u32::from(n) << 4
    
    opened by 42plamusse 0
  • SUB A, r8/d8 command to set flag C

    SUB A, r8/d8 command to set flag C

    According to the GBCPUmanC - Set if no borrow. In my opinion, the code should be:

    self.reg.set_flag(Flag::C, a >= n);
    

    when the value of register A is greater then the number n, a-n is not borrowed. But in the project, the code is:

    self.reg.set_flag(C, u16::from(a) < u16::from(n));
    

    Which I couldn't understand.

    opened by hcoderLee 1
  • 在M1芯片的macOS下编译报错

    在M1芯片的macOS下编译报错

    cargo run --release -- "./res/boxes.gb"

    Compiling coreaudio-sys v0.2.2
    error: failed to run custom build command for `coreaudio-sys v0.2.2`
    
    Caused by:
      process didn't exit successfully: `/Users/my/Projects/gameboy/target/release/build/coreaudio-sys-8d0fefacc2d2969d/build-script-build` (exit code: 101)
      --- stdout
      cargo:rustc-link-lib=framework=AudioUnit
      cargo:rustc-link-lib=framework=CoreAudio
    
      --- stderr
      error: header '/System/Library/Frameworks/CoreAudio.framework/Headers/CoreAudio.h' does not exist.
      thread 'main' panicked at 'unable to generate bindings: ()', /Users/my/.cargo/registry/src/github.com-1ecc6299db9ec823/coreaudio-sys-0.2.2/build.rs:144:10
      note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
    
    opened by heropoo 2
Owner
Mohanson
http://accu.cc
Mohanson
Cycle-accurate Gameboy Color emulator in Rust

Description Currently intended only for personal research, this is a WIP cycle-accurate GB/C emulator written in Rust. Building If you wish to build f

Luke Stadem 3 May 5, 2022
GameBoy emulator.

yobemag GameBoy emulator. WIP for now :) General knowledge ROM This is the read-only memory, it's also called "cartridge" and holds the data of the ga

Federico Guerinoni 4 Aug 31, 2022
Gameboy Advance emulator.

Clementine - A collaborative approach to GBA emulation Welcome to the first ripsters' project. Our goal is to understand how GameBoy Advance works and

RIPsters 32 Dec 14, 2022
A cross-platform sequencer that internally uses a Game Boy emulator to synthesize the sound

chiptrack chiptrack is a cross-platform sequencer that internally uses a Game Boy emulator to synthesize the sound. It uses: SixtyFPS for the UI. RBoy

Jocelyn Turcotte 26 Dec 7, 2022
Nes-emulator - A NES emulator made to learn the Rust programming language

nes-emulator Building $ rustc --version rustc 1.32.0 (9fda7c223 2019-01-16) $ cargo --version cargo 1.32.0 (8610973aa 2019-01-02) $ cargo build --rel

Michael Burge 225 Dec 23, 2022
NES emulator written in Rust to learn Rust

OxideNES A NES emulator in Rust. CPU should be accurate, PPU is mostly accurate, timing between the 2 is off for some corner cases and hardware qui

null 37 Nov 7, 2022
Chip8 emulator written in pure rust, using rust-sdl2 for graphics

Rust-8 chip8 emulator written in rust, using rust-sdl2 for graphics. Features Fully implemented all 35 original chip8 opcodes. This emulator does NOT

Chris Hinson 7 Dec 28, 2022
Commodore 64 emulator written in Rust

Rust64 - a C64 emulator written in Rust This is my attempt to study the Rust programming language and have fun at the same time. The goal is to presen

Krzysztof Kondrak 214 Dec 27, 2022
A Flash Player emulator written in Rust

website | demo | nightly builds | wiki Ruffle Ruffle is an Adobe Flash Player emulator written in the Rust programming language. Ruffle targets both t

Ruffle 11.2k Jan 8, 2023
A Game Boy research project and emulator written in Rust

Mooneye GB Mooneye GB is a Game Boy research project and emulator written in Rust. The main goals of this project are accuracy and documentation. Some

Joonas Javanainen 802 Dec 28, 2022
RGB (Rust Game Boy) is a simple emulator for the original game boy

RGB RGB (Rust Game Boy) is a simple emulator for the original game boy and the color game boy. Warning: This no longer compiles in the latest versions

Niven Achenjang 18 Dec 2, 2022
RustBoyAdvance-NG is a Nintendo™ Game Boy Advance emulator and debugger, written in the rust programming language.

RustBoyAdvance-NG Nintendo GameBoy Advance ™ emulator and debugger, written in rust. WebAssembly Demo: https://michelhe.github.io/rustboyadvance-ng/ P

MishMish 510 Dec 30, 2022
An NES emulator written in Rust

Pinky Pinky is an NES emulator written in Rust completely from scratch based only on publicly available documentation. You can run it in your Web brow

Koute 709 Dec 23, 2022
NES emulator written in Rust

sprocketnes is an emulator for the Nintendo Entertainment System written in the Rust programming language. Its purpose is to serve as a technology dem

Patrick Walton 725 Dec 27, 2022
NES emulator in rust

NES emulator in Rust plastic is a NES emulator built from scratch using Rust. This is a personal project for fun and to experience emulating hardware

Amjad Alsharafi 27 Dec 15, 2022
ZX Spectrum emulator written in Rust

rustzx ZX Spectrum emulator which I writing in rust. I develop this project just for fun and for learning the basics of computer architecture. License

Vladislav Nikonov 162 Dec 27, 2022
Intel 8080 cpu emulator by Rust

i8080 i8080 is a emulator for Intel 8080 cpu. 8080 Programmers Manual 8080 opcodes [dependencies] i8080 = { git = "https://github.com/mohanson/i8080"

Mohanson 83 Dec 27, 2022
CHIP-8 emulator written in Rust

CHIP-8 emulator written in Rust. This is intended to be a project for gaining experience writing emulators and practice Rust.

Pedro Rodrigues 4 May 21, 2021
A CHIP-8 emulator for Rust in ~350 LOC

chip8 An implementation of the CHIP-8 for Rust in ~350 lines of code. What is CHIP-8? CHIP-8 is a virtual machine (along with a supporting programming

Daniel Gatis 8 Apr 23, 2022