mohanson/gameboy

incorrect speed switch implementation in CGB mode

Hanaasagi opened this issue · 5 comments

Hello, the speed switch code should get the value in the address that the PC register pointed instead of the value of in register.

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

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.

Sorry, my bad.

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.

gameboy/src/cpu.rs

Lines 1677 to 1689 in e64757f

pub fn next(&mut self) -> u32 {
let mac = {
let c = self.hi();
if c != 0 {
c
} else if self.halted {
OP_CYCLES[0]
} else {
self.ex()
}
};
mac * 4
}

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.

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

Emm, I think there should be something here.

0x10 => {}

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
                }
            }