This is an attempt to write a GameBoy emulator in C99. This is a personal project to learn more about computers and emulation. SDL3 is used to draw the pixels and handle input. Emscripten is used to compile the project into WebAssembly. At the moment, this project is still a work in progress.
You can try out this emulator in your web browser at this link: https://hagemu.dev/
Disclaimers:
- You need to use a keyboard or game controller. There is no key remapping or touch screen support at the moment.
- To run a .gb file, please drag and drop the file directly onto the web page.
Most original gameboy games should run fine. If you find any glitches, please let me know. The following games have been tested:
- Tetris
- Dr. Mario
- Super Mario Land
- Metroid II
- Zelda: Link's Awakening
- Pokemon Red, Blue, and Yellow
- Finish the CPU
- Parse opcodes
- Implement double registers
- Write functions for the opcodes
- Set flags in the f register
- Write the interrupt dispatch code
- Add a clock and timer interrupts
- Fix cycle timing of opcodes
- Cycle-correct memory reads/writes
- Pass Blargg's CPU test roms
- cpu_instrs test
- instr_timing test
- mem_timing test
- mem_timing_2 test
- Finish the PPU (Picture Processing Unit)
- Display tiles from VRAM
- Draw tiles to window
- Draw the background layer
- Add window overlay
- Implement the scroll registers SCX and SCY
- Switch to a scanline based renderer
- Update the scroll registers per scanline
- Implement DMA transfers
- Add sprites
- Implement sprite attributes
- Support for 8x16 sprite mode
- Implement LCD STAT interrupts
- Respond to the LCD control register (except for disabling the PPU)
- Pass dmg-acid2 test rom
- Finish the APU (Audio Processing Unit)
- Setup sound and add an audio callback function
- Synchronize the length, sweep, and envelope timers
- Downsample from 2MHz to 48kHz
- Implement a IIR butterworth low pass filter to cut down on audio aliasing
- Synchronize the sample rates of the individual sound channels
- Finish Master controls
- Turn APU on/off
- Mono volume control
- Panning left/right per channel
- Volume control left/right per channel
- Finish channels 1 and 2 (pulse waves)
- Turn DAC on/off
- Basic volume
- Correct frequency
- Wave duty
- Envelope
- Reset trigger
- Sweep (channel 1 only)
- Length timer
- Finish channel 3 (custom waveform)
- Turn DAC on/off
- Correct frequency
- Basic volume
- Read and output the custom wave data
- Reset trigger
- Length timer
- Finish channel 4 (random noise)
- Turn DAC on/off
- Basic volume
- Correct frequency
- Linear-feedback shift register
- Envelope
- Reset trigger
- Length timer
- Implement support for various Memory Bank Controller (MBC) chips
- Separate MBC code into its own file
- MCB1 (Basic support)
- MCB1 (Full support)
- MCB3 (except for Real Time Clock)
- Basic support for saving and loading .sav files
- Real Time Clock support
- Minor fixes
- Separate the joypad logic from the Raylib library
- Add support for gamepads
- Test gamepad support
- Calculate the half-carry as (a ^ b ^ result) & 0x10
- Add 'inline' the CPU opcode functions
- Rewrite the f register as separate bools
- Fix glitch where a sprite partially clips if it's on the left or top border
- Fix bug where window X Position is less than 7
- Make the color palette settable instead of internal to the ppu
- Fill the sound buffer directly instead of using a callback
- Make the audio registers readable
- Maybe use float instead of int16_t for audio bit depth
- Maybe use RGBA8888 instead of RGBA5551 pixel format
- Mute a sound channel if its frequency is above 20kHz
- Add support for the VIN sound channel
- Rewrite PPU to be more modular
- Add option to blend frames
- Emulate the timing of the DMA
- Add support for disabling the PPU
- Implement the STOP instruction
- Test the HALT instruction
- Add support for the serial data port
- Pass Blargg's interrupt_time test
- Run the Mooneye Test Suite
- Make a cool logo
- Add a custom boot rom
- Use _Static_assert to ensure endianness
- Use some profiling tools to find critical code blocks
- Compile program using -O3 and -flto and -ffast-math
- Known glitches
- Pokemon Red corrupted save data
- Fixed! My SRAM implementation was off-by-one
- Pokemon Aka character constantly moves up
- Fixed! The upper two bits of joypad register should always be 1
- Pokemon Red corrupted save data
- WebAssembly version
- Get the WebAssembly version working
- Add a simple front-end UI
- Upload to my website (https://uezu.dev/projects/hagemu)
- Automatically save and load .sav files using a local IndexedDB file system
- Progressive Web Application support
- Basic support
- Add a service worker for caching and retrieving files without the internet
- Rewrite the html index file from scratch
- Automatically cache and load the last played game
- Select file using a mobile browser
- Touchscreen support
- Download and upload save files
- Put the loading bar where the canvas is
- Add a UI
- Drag and drop rom files onto the window
- Select file using a file dialog window
- Add custom shaders (mostly for a grid overlay)
- Settings menu
- Button mapping menu
- Audio menu
- Color palette menu
- Save state menu
- Add GBC functionality
- Double speed mode
- Extra work and video ram
- HDMA features
- Pass cgb-acid2
- Future Refactoring Ideas
- Separate the core from the interface
- Switch from Raylib to SDL3
- Synchronize the APU along with the CPU and PPU
- Separate cart.c and joypad.c from mmu.c
- Use CMake instead of make
- Organize all state into a gameboy struct
- Support save/load states
- Rewrite the CPU so that it can tick 1 m-cycle per call
- Rewrite the PPU using a pixel pusher renderer
- Remove the union type punning of the CPU registers
- Links for the future
- Gameboy Color differences: https://jsgroth.dev/blog/posts/game-boy-color/
- Gameboy Color PPU: https://github.com/mattcurrie/cgb-acid2
- Gameboy Color HDMA: https://gbdev.io/pandocs/CGB_Registers.html
- Using WASM: https://gioarc.me/posts/games/wasm.html
- Sound info: https://gbdev.gg8.se/wiki/articles/Gameboy_sound_hardware
- General info: https://hacktix.github.io/GBEDG/
- Timing of the LYC STAT: https://gbdev.io/guides/lyc_timing.html
- Custom bootrom: https://github.com/Hacktix/Bootix
- Links about MBC3's real-time clock
- MBC3 .sav format: https://bgb.bircd.org/rtcsave.html
- MBC3 RTC test rom: https://github.com/aaaaaa123456789/rtc3test
- Discussion about MBC3 RTC: https://www.reddit.com/r/EmuDev/comments/12vk8io/gameboy_color_mbc3_rtc/
- MBC3 Pandocs: https://gbdev.io/pandocs/MBC3.html
- More detail about the implementation: https://hacktix.github.io/GBEDG/mbcs/mbc3/
