mohanson / gameboy

Full featured Cross-platform GameBoy emulator by Rust. Forever boys!.
MIT License
1.36k stars 79 forks source link

incorrect speed switch implementation in CGB mode #31

Closed Hanaasagi closed 3 years ago

Hanaasagi commented 3 years ago

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.

Hanaasagi commented 3 years ago

Sorry, my bad.

Hanaasagi commented 3 years ago

But, if we handle a interrupt in the cpu next method. The switch_speed method will call twice. I'm not sure what will happen.

https://github.com/mohanson/gameboy/blob/e64757f0eca44ddcb4817c9736c8d74247667940/src/cpu.rs#L1677-L1689

mohanson commented 3 years ago

if self.mmu.borrow().get(self.cpu.cpu.reg.pc) == 0x10 {

To be honest, I don't know why I wrote this code a few years ago, it looks completely wrong now.

mohanson commented 3 years ago

I think what I want to do is if mem.get(FF4D) == 0x01, but now I am not really sure

Hanaasagi commented 3 years ago

Emm, I think there should be something here.

https://github.com/mohanson/gameboy/blob/e64757f0eca44ddcb4817c9736c8d74247667940/src/cpu.rs#L1019

Maybe

            0x10 => {
                self.mem.switch_speed();  // It will need the CPU struct receive `Mmunit` type, instead of a `dyn Memory`.
                if self.mem.speed == Speed::Double {
                    // Incr the timer's div register.
                    // self.mem.timer.

                    // And more
                }
            }