deltabeard / Peanut-GB

A Game Boy (DMG) emulator single header library written in C99. Performance is prioritised over accuracy.
https://projects.deltabeard.com/peanutgb/
276 stars 35 forks source link

Add GBC support #93

Closed tvecera closed 10 months ago

tvecera commented 1 year ago

Adapt and merge two branches, 'froggestspirit' (which provides GBC support) and 'fix-rtc2', into the current version of the main branch.

I implemented some recommendations from the comment at https://github.com/deltabeard/Peanut-GB/issues/50#issuecomment-1027766693:

Tested on:

deltabeard commented 1 year ago

Thanks for your work. 😃 I will do a thorough review when I have time. Preliminarily speaking, I think it would be good to separate the RTC work and the CGB work into two separate commits.

Also, do you have an idea as to how complete the CGB support is?

Thanks.

The issue for RTC support is at https://github.com/deltabeard/Peanut-GB/issues/90. I think I was planning something different for RTC, but I'll have to look into it again.

tvecera commented 1 year ago

Thanks, I'll separate the RTC fix and update the pull request. I must admit, I'm not sure how complete the implementation is. The games I've tested are functioning well. However, to the best of my knowledge, there is still a minor issue with the "Object Priority Mode (DMG/CGB) $FF6C (bit 0)" from the cgb-acid2 test, which should prioritize by OAM position. I have tried to resolve it, however, the bug is still there.

This version I'm using for the Picopad RB PI emulator, and with CGB support enabled, it's almost pushing the limits of memory.

But for basic CGB support, it's fine 😄.

tvecera commented 1 year ago

I have fixed the object priority bug for full CGB mode.

Test ROM that I used: cgb-acid2

Screenshot 2023-07-18 at 12 49 55
tvecera commented 1 year ago

Thank you very much for the code review and your advice. I've prepared a version that incorporates the necessary modifications. However, the one issue I haven't resolved is the dynamic cycle count for STAT mode 3 and 4.

deltabeard commented 1 year ago

Thank you very much for the code review and your advice. I've prepared a version that incorporates the necessary modifications. However, the one issue I haven't resolved is the dynamic cycle count for STAT mode 3 and 4.

Thanks for your work. I'll check it out later. Don't work on the dynamic cycle count for STAT modes for this commit, as it's a problem for DMG as well as CGB modes. Fixing that issue isn't a prerequisite for getting this merged, so you don't have to work on that if you don't want to. 👍

deltabeard commented 1 year ago

I noticed that the serial connection works at different speeds in CGB mode, so made a commit for that (untested though).

I testing this working with Shantae.

https://github.com/deltabeard/Peanut-GB/assets/3747104/859b7a0a-3ea9-4ca5-bf85-9c7285084524

The latest version of Pokemon Prism doesn't work though. I assume it's doing some cycle accurate stuff that is causing some odd behaviour with Peanut-GB. Pokemon Gold and Crystal seem to work fine though.

Another issue that might need to be fixed is the fact that the RTC seems to tick twice as fast. I can't tell if it's an issue with Pokemon Prism or because of doublespeed.

tvecera commented 1 year ago

I tried Pokemon Prism with the modification below and it works, I don't know if it's a timing issue or a dynamic cycle count issue for STAT mod 3 and 4, however after commenting out the modification with CGB double speed Prism doesn't stall (some animations are just slowed down).

//      /* LCD Timing */
//#if PEANUT_FULL_GBC_SUPPORT
//      gb->counter.lcd_count += (inst_cycles >> gb->cgb.doubleSpeed);
//#else
        gb->counter.lcd_count += inst_cycles;
//#endif
tvecera commented 1 year ago

I've identified a problem with the modification for the full GBC support. The issue arises from the line of code where, when inst_cycles == 1, the expression gb->counter.lcd_count += (inst_cycles >> gb->cgb.doubleSpeed) always adds only 0. This causes the emulator run to get stuck.

I've uploaded a revised version.

deltabeard commented 1 year ago

Thank you very much for identifying the cause of the problem. Once I've tested a few games, I'll merge the pull request.

tvecera commented 1 year ago

I have tested several games and below are the results.

Working:

Not Working

Worms Armageddon

Spider-Man (USA, Europe)

In general, most problems with games appear to be related to CGB double speed mode and STAT mode cycles.

FF04 — DIV: Divider Register Note: The Divider is affected by CGB double speed mode, and will increment at 32768Hz in double speed.

In the documentation for the DIV: Divider Register, I came across a mention of CGB double speed mode: Note: The divider is affected by CGB double speed mode, and will increment at 32768Hz in double speed. https://gbdev.io/pandocs/Timer_and_Divider_Registers.html#ff04--div-divider-register

This doesn't seem to be a current issue in games, but it could potentially be resolved with the following modification:

        /* DIV register timing */
#if PEANUT_FULL_GBC_SUPPORT
        if (gb->cgb.doubleSpeed)
            gb->counter.div_count += (inst_cycles << gb->cgb.doubleSpeed);
        else
#endif
deltabeard commented 1 year ago

Thanks for testing and debugging. I also noticed that the clock in Pokemon Prism was ticking too fast and the time is completely incorrect on reset, but otherwise the game works fine. Pokemon Crystal works completely fine. I was unable to determine whether this was an issue with the MBC3 logic or whether it is due to double speed. As you suggest, some of these problems are most likely due to double speed mode and STAT mode cycles.

tvecera commented 12 months ago

I ran a few tests against the Blargg and Mooneye test ROMs (for GB and Full GBC mode). I'm posting the results below. I believe the most problems will be caused by the failed tests: memory timing, OAM_Bug, and 1-lcd_sync.

Blargg test ROMS

Passed: CPU Instructions, 01-special.gb CPU Instructions, 02-interrupts.gb CPU Instructions, 03-op sp,hl.gb CPU Instructions, 04-op r,imm.gb CPU Instructions, 05-op rp.gb CPU Instructions, 06-ld r,r.gb CPU Instructions, 07-jr,jp,call,ret,rst.gb CPU Instructions, 08-misc instrs.gb CPU Instructions, 09-op r,r.gb CPU Instructions, 10-bit ops.gb CPU Instructions, 11-op a,(hl).gb Instruction Timing, instr_timing.gb Halt bug, halt_bug.gb OAM_Bug, 3-non_causes.gb

Failed: Memory Timing, 01-read_timing.gb Memory Timing, 02-write_timing.gb Memory Timing, 03-modify_timing.gb Memory Timing 2, 01-read_timing2.gb Memory Timing 2, 02-write_timing2.gb Memory Timing 2, 03-modify_timing2.gb OAM_Bug, 1-lcd_sync.gb OAM_Bug, 2-causes.gb

Mooneye test ROMS

Passed: bits, mem_oam.gb bits, reg_f.gb instr, daa.gb oam_dma, basic.gb oam_dma, reg_read.gb timer, tim00_div_trigger.gb timer, tim01.gb timer, tim11_div_trigger.gb root, halt_ime1_timing.gb root, if_ie_registers.gb MBC2, bits_romb.gb MBC2, bits_unused.gb MBC2, rom_1Mb.gb MBC2, rom_2Mb.gb MBC2, rom_512kb.gb MBC5, rom_16Mb.gb
MBC5, rom_1Mb.gb
MBC5, rom_2Mb.gb
MBC5, rom_32Mb.gb
MBC5, rom_4Mb.gb
MBC5, rom_512kb.gb
MBC5, rom_64Mb.gb
MBC5, rom_8Mb.gb MBC1, bits_bank1.gb MBC1, bits_bank2.gb MBC1, bits_mode.gb MBC1, bits_ramg.gb MBC1, ram_256kb.gb MBC1, ram_64kb.gb MBC1, rom_1Mb.gb MBC1, rom_2Mb.gb MBC1, rom_4Mb.gb MBC1, rom_512kb.gb

Failed: timer, div_write.gb timer, rapid_toggle.gb timer, tim00.gb timer, tim01_div_trigger.gb timer, tim10.gb timer, tim10_div_trigger.gb timer, tim11.gb timer, tima_reload.gb timer, tima_write_reloading.gb timer, tma_write_reloading.gb root, call_cc_timing.gb root, call_timing.gb root, div_timing.gb root, ei_sequence.gb root, ei_timing.gb root, intr_timing.gb root, jp_cc_timing.gb root, jp_timing.gb
root, ld_hl_sp_e_timing.gb root, oam_dma_restart.gb root, oam_dma_start.gb root, oam_dma_timing.gb root, pop_timing.gb root, push_timing.gb root, rapid_di_ei.gb root, ret_cc_timing.gb root, ret_timing.gb root, reti_intr_timing.gb root, reti_timing.gb MBC2, bits_ramg.gb MBC2, ram.gb MBC1, rom_16Mb.gb MBC1, rom_8Mb.gb MBC1, multicart_rom_8Mb.gb

deltabeard commented 11 months ago

Thank you for the thorough testing! Regarding the failures in the memory timing tests, I think that the commits in branch https://github.com/deltabeard/Peanut-GB/tree/mem-accuracy had fixes for them. They were not merged because it would slow down emulation a bit and it wasn't clear if any game requires these fixes (I think only one game does?).

I think these failed tests could constitute as a separate issue. I haven't had time to think about how I want the CGB API to work just yet. I think I will write a gb_init_ex function to allow the programmer to set additional options, such as forcing DMG mode, or preferring CGB or DMG, etc. Or I could add a new function gb_set_console to set whether the console is DMG, CGB, or automatic. I may also use a separate lcd_draw_line() function specifically for CGB games.

deltabeard commented 10 months ago

Thank you for the hard work and apologies for the delay. I've merged into the cgb branch because I'm planning some API changes with how CGB mode is activated and used. Once I've made those changes, I'll merge this feature into master.

The bugs mentioned here will be opened into separate issues and worked on separately.