[] (https://travis-ci.org/simias/gb-rs)
Game Boy emulator written in rust. No unsafe code so far.
The CPU passes all the instruction tests as well as all the timing tests (see the "Ressources" section below for the links to the tests).
Saving is implemented, it creates a file with the ".sav" extension in the same directory as the ROM being executed if it supports saving.
Sound is implemented with adaptative resampling to match the sound card sample rate. Note that it might take a few seconds for the algorithm to settle on the correct sample rate so you might get a few dropped sound packets when you start the emulator. Normally once this training time has elapsed there should be no drops.
The sound unit is not completely accurate however, some games have weird glitches in the sounds (The Legend of Zelda in particular). I'm working on that...
Things that remain to be implemented:
- Serial link
- Support for various types of cartridges
- Maybe GameBoy Color support?
The emulator is not optimized at all but thanks to the GB's measly
4Mhz system clock it should run at speed on any half-decent desktop
CPU. Don't forget to build with cargo --release
do enable the
optimizations however.
The display and input are handled through SDL2. That code is modular and abstracted away from the emulator core so it shouldn't be difficult to add support for alternative backends if need be.
The controls are hardcoded in src/ui/sdl2/controller.rs
at the
moment: you'll have to edit the update_key
, update_button
and
update_axis
function if you want to rebind the various keyboard and
controller controls.
The defaults are:
GameBoy button | Keyboard | Controller |
---|---|---|
A | Left Alt | A |
B | Left Control | B |
Start | Return | Start |
Select | Right Shift | Back |
Up | Up | DPadUp / LeftY axis |
Down | Down | DPadDown / LeftY axis |
Left | Left | DPadLeft / LeftX axis |
Right | Right | DPadRight / LeftX axis |
The Escape
key exits the emulator.
By default the emulator is built with the original Gameboy bootrom
which scrolls the logo down the screen before actually jumping into
the game. By building with the --features sgb_bootrom
option you can
opt to use the Super Game Boy bootrom instead which is much faster to
boot up.
Games that have been tested:
- Tetris
- Bombjack
- DrMario
- Kirby's Dream Land
- The Legend of Zelda - Link's Awakening
- Motocross Maniacs
- Wario Land
- Bubble Ghost
- Castelian
- Earthworm Jim
- Super Mario Land 1, 2 and 3
- Pokemon Red/Blue
- Space Invaders
- Bomberman
- Trip World
- F-1 Race
The Game Boy CPU manual: https://marc.rawer.de/Gameboy/Docs/GBCPUman.pdf
The Game Boy Programming manual: https://www.romhacking.net/documents/544/
Opcode map: https://www.pastraiser.com/cpu/gameboy/gameboy_opcodes.html
Infos about many GB quircks: https://www.devrs.com/gb/files/faqs.html
Some extremely useful accuracy tests made by Shay Green: https://tasvideos.org/EmulatorResources/GBAccuracyTests.html
An introduction to GB emulation in Javascript: https://imrannazar.com/GameBoy-Emulation-in-JavaScript:-The-CPU
There are many small errors or discrepancies in the docs listed above, unfortunately I don't know if/how those docs are maintained so I'm going to list the errors I've found here for now:
-
RLCA
instruction: various sources disagree on whether theZ
flag should be modified by the operation. After some research I'm pretty sure it shouldn't be modified (the Z80 processor for instance does not modifyZ
). -
HALT
instruction: when this instruction is executed while interrupts are disabled in the CPU (for instance by aDI
instruction) the CPU will still be awoken by any interrupt enabled in theIE
register, however the interrupt handler will not be run and the control will be given back to the code that called theHALT
. Be careful that the instruction following anHALT
is glitchy but that's well documented. -
ADD SP,N
(opcode 0xe8) andLDHL SP,N
(opcode 0xf8): the values of the carry and halfcarry are computed on the low 8bits. -
RLCA
,RLA
,RRCA
,RRA
instructions: the flags are described wrong in the CPU manual: after the executionC
contains the rotated bit whileN
,H
andZ
are always 0. The equivalent instructions in the extendedCB
opcode space however setZ
if the result is 0 and that's correctly documented. -
Instruction timings: The GameBoy CPU manual gets all the timings of conditional branches wrong: it doesn't say that the number of cycles taken by the instruction to execute depends on whether or not the branch is taken. More generally, both this manual and the opcode map linked above have some discrepencies when it comes to instruction timings. In the end it's probably safer to use the timings directly from the assembly source for the accuracy tests.
-
The actual state machine for the configurable GPU LCD interrupt seems not well described anywhere. I tried to put a lot of comments in my code to describe my approach, however I'm not sure whether it's 100% accurate.
-
When there are more than 10 sprites on a line only the 10 first in OAM order are displayed. The sprite's X coordinates and priority don't matter, only the position in OAM.