Gameboy (DMG & CGB) emulator written in C#8 (dotnet core 3.1) as an educational exercise (not as a production emulator). Uses SDL2 for windowing & graphics and NAudio for playing raw audio samples.
- Passing test roms section at bottom of readme
- Most DMG games are playable, most CGB games have graphical glitches although DX style games are typically ok
- MBC1,2,3,5 all implemented and tested
- Lots of test failures specified in the table below
- Aladdin screwed up video after boot
- Sound channel 4 is screwed up (1 & 2 seem ok if badly aliased)
- Sounds start during copyright screen of tetris, so I've misunderstood something regarding how sounds are turned on/off. Think I need to rewrite the sound channels to call out the DAC as a separate unit
- Complete adding integration tests for all known test roms
- Add HDMA transfer tests
- Test timer subsystem
- Prevent pressing multiple buttons (just direction keys?) at a time
- RTC for MBC3 pretends to exist but doesn't really
- Fully update debugging spreadsheets for CGB and Audio
- Display FPS using SDL text rendering?
- Native debugger with winforms/wpf?
- SGB support
- Dot renderer rather than full line renderer
- Proper configurable serial port support
- IR port configuration
Test | Pass | Notes |
---|---|---|
Blargg - cpu_instrs | ✅ | |
Blargg - instr_timing | ✅ | |
Blargg - interrupt_time | ✅ | |
Blargg - mem_timing | ✅ | |
Blargg - mem_timing2 | ✅ | |
Blargg - cgb_sound | ❌ | All bar one fail, but this would fail on a DMG so doesn't matter overly |
Blargg - dmg_sound | ❌ | All 12 fail, but this also fails on a CGB console so doesn't matter too much |
Blargg - halt_bug | ❌ | Fails but no attempt to implement this bug |
Blargg - oam_bug | ❌ | Fails but no attempt to implement this bug |
Mooneye - MBC1 - bits_bank1 | ✅ | |
Mooneye - MBC1 - bits_bank2 | ✅ | |
Mooneye - MBC1 - bits_mode | ✅ | |
Mooneye - MBC1 - bits_ramg | ✅ | |
Mooneye - MBC1 - ram64kb | ✅ | |
Mooneye - MBC1 - ram256kb | ✅ | |
Mooneye - MBC1 - rom512kb | ✅ | |
Mooneye - MBC1 - rom1Mb | ✅ | |
Mooneye - MBC1 - rom2Mb | ✅ | |
Mooneye - MBC1 - rom4Mb | ✅ | |
Mooneye - MBC1 - rom8Mb | ✅ | |
Mooneye - MBC1 - rom16Mb | ✅ | |
Mooneye - MBC2 - bits_ramg | ✅ | |
Mooneye - MBC2 - bits_romb | ✅ | |
Mooneye - MBC2 - bits_unused | ✅ | |
Mooneye - MBC2 - ram | ✅ | |
Mooneye - MBC2 - rom1Mb | ✅ | |
Mooneye - MBC2 - rom2Mb | ✅ | |
Mooneye - MBC2 - rom512kb | ✅ | |
Mooneye - MBC5 - rom512kb | ✅ | |
Mooneye - MBC5 - rom1Mb | ✅ | |
Mooneye - MBC5 - rom2Mb | ✅ | |
Mooneye - MBC5 - rom4Mb | ✅ | |
Mooneye - MBC5 - rom8Mb | ✅ | |
Mooneye - MBC5 - rom16Mb | ✅ | |
Mooneye - MBC5 - rom32Mb | ✅ | |
Mooneye - MBC5 - rom64Mb | ✅ | |
Mooneye - BITS - mem_oam | ✅ | |
Mooneye - BITS - reg_f | ✅ | |
Mooneye - BITS - unused_hwio-GS | ✅ | |
Mooneye - Instr - daa | ✅ | |
Mooneye - Interrupts - ie_push | ❌ | Subtle bug relating to interrupt causing the PC to get put into the interrupt flag, not emulated |
Mooneye - OAM_DMA - basic | ✅ | |
Mooneye - OAM_DMA - reg_read | ✅ | |
Mooneye - OAM_DMA - sources-GS | ❌ | Not supposed to pass on CGB, not really clear what this actually does |
Mooneye - PPU - hblank_ly_scx_timing-GS | ❌ | Just says that the test fails without details, we do take SCX into account so this is a bit surprising |
Mooneye - PPU - intr_1_2_timing-GS | ❌ | Register values way off what they should be |
Mooneye - PPU - intr_2_0_timing | ✅ | |
Mooneye - PPU - intr_2_mode0_timing | ✅ | |
Mooneye - PPU - intr_2_mode0_timing_sprites | ❌ | TEST #00 FAILS |
Mooneye - PPU - intr_2_mode3_timing | ✅ | |
Mooneye - PPU - intr_2_oam_ok_timing | ✅ | |
Mooneye - PPU - lcd_on_timing | ❌ | LY=1 when it should be 0 - maybe a more serious bug than the timing issues we know about |
Mooneye - PPU - lcdon_write_timing | ❌ | Loads of bad assumptions cause this failure |
Mooneye - PPU - stat_irq_blocking | ❌ | Unknown reason |
Mooneye - PPU - stat_lyc_onoff | ❌ | Fail r1 step 1 reason unknown |
Mooneye - PPU - vblank_stat_intr-GS | ✅ | |
Mooneye - Timer - div_write | ✅ | |
Mooneye - Timer - rapid_toggle | ❌ | "the timer circuit design causes some unexpected timer increases" - unsure what this means in the test source so likely the cause of failure |
Mooneye - Timer - tim00 | ✅ | |
Mooneye - Timer - tim01 | ✅ | |
Mooneye - Timer - tim10 | ✅ | |
Mooneye - Timer - tim11 | ✅ | |
Mooneye - Timer - tim00_div_trigger | ❌ | Precise implementation of counts and interesting behavior of div register setting values in timer required to do this and following |
Mooneye - Timer - tim01_div_trigger | ❌ | |
Mooneye - Timer - tim10_div_trigger | ❌ | |
Mooneye - Timer - tim11_div_trigger | ❌ | |
Mooneye - Timer - tima_reload | ✅ | |
Mooneye - Timer - tima_write_reloading | ❌ | Fails, requires non-atomic CPU ops |
Mooneye - Timer - tma_write_reloading | ❌ | Fails, requires non-atomic CPU ops |
Mooneye - General - add_sp_e_timing | ✅ | |
Mooneye - General - boot_div-dmg0 | ❌ | Only passes on specific model of device |
Mooneye - General - boot_div-dmgABCmgb | ❌ | Only passes on specific model of device |
Mooneye - General - boot_div-S | ❌ | Only passes on specific model of device |
Mooneye - General - boot_div2-S | ❌ | Only passes on specific model of device |
Mooneye - General - boot_hwio-dmg0 | ❌ | Only passes on specific model of device |
Mooneye - General - boot_hwio-dmgABCmgb | ❌ | Only passes on specific model of device |
Mooneye - General - boot_hwio-S | ❌ | Only passes on specific model of device |
Mooneye - General - boot_regs-dmg0 | ❌ | Only passes on specific model of device |
Mooneye - General - boot_regs-dmgABC | ❌ | Only passes on specific model of device |
Mooneye - General - boot_regs-mgb | ❌ | Only passes on specific model of device |
Mooneye - General - boot_regs-sgb | ❌ | Only passes on specific model of device |
Mooneye - General - boot_regs-sgb2 | ❌ | Only passes on specific model of device |
Mooneye - General - call_cc_timing | ✅ | |
Mooneye - General - call_cc_timing2 | ✅ | |
Mooneye - General - call_timing | ✅ | |
Mooneye - General - call_timing2 | ✅ | |
Mooneye - General - div_timing | ✅ | |
Mooneye - General - di_timing-GS | ✅ | Passes in both DMG/CGB mode when it should only pass in DMG |
Mooneye - General - ei_sequence | ✅ | |
Mooneye - General - ei_timing | ✅ | |
Mooneye - General - halt_ime0_ei | ✅ | |
Mooneye - General - halt_ime0_nointr_timing | ✅ | |
Mooneye - General - halt_ime1_timing | ✅ | |
Mooneye - General - halt_ime1_timing2-GS | ❌ | Fails on CGB device, not sure why it fails on emulator though |
Mooneye - General - if_ie_registers | ✅ | |
Mooneye - General - intr_timing | ✅ | |
Mooneye - General - jp_cc_timing | ✅ | |
Mooneye - General - jp_timing | ✅ | |
Mooneye - General - ld_hl_sp_e_timing | ✅ | |
Mooneye - General - oam_dma_restart | ✅ | |
Mooneye - General - oam_dma_start | ❌ | Something isn't quite right with restarting DMA? |
Mooneye - General - oam_dma_timing | ✅ | |
Mooneye - General - pop_timing | ✅ | |
Mooneye - General - push_timing | ✅ | |
Mooneye - General - rapid_di_ei | ✅ | |
Mooneye - General - reti_intr_timing | ✅ | |
Mooneye - General - reti_timing | ✅ | |
Mooneye - General - ret_cc_timing | ✅ | |
Mooneye - General - ret_timing | ✅ | |
Mooneye - General - rst_timing | ✅ |