diff --git a/Core/display.c b/Core/display.c index 86a4e77..d815e22 100755 --- a/Core/display.c +++ b/Core/display.c @@ -661,6 +661,8 @@ static void update_display_state(GB_gameboy_t *gb, uint8_t cycles) void GB_display_run(GB_gameboy_t *gb, uint8_t cycles) { + if (gb->display_hack == 1) return; + if (gb->display_hack == 2) cycles *= 2; update_display_state(gb, cycles); if (gb->disable_rendering) { return; diff --git a/Core/gb.h b/Core/gb.h index ec3b328..c39fbea 100644 --- a/Core/gb.h +++ b/Core/gb.h @@ -340,6 +340,7 @@ struct GB_gameboy_internal_s { uint16_t serial_length; uint8_t future_interrupts; /* Interrupts can occur in any T-cycle. Some timings result in different interrupt timing when the CPU is in halt mode, and might also affect the DI instruction. */ + uint8_t display_hack; // Temporary hack until the display is rewritten to operate in T-cycle rates; ); /* APU */ diff --git a/Core/memory.c b/Core/memory.c index ca27741..d483506 100644 --- a/Core/memory.c +++ b/Core/memory.c @@ -484,7 +484,9 @@ static void write_high_memory(GB_gameboy_t *gb, uint16_t addr, uint8_t value) return; case GB_IO_DIV: - gb->div_state = 0; // Reset the div state machine + /* Reset the div state machine */ + gb->div_state = 0; + gb->div_cycles = 0; return; case GB_IO_JOYP: diff --git a/Core/timing.c b/Core/timing.c index 67d0190..57c9a69 100644 --- a/Core/timing.c +++ b/Core/timing.c @@ -96,13 +96,11 @@ static void GB_ir_run(GB_gameboy_t *gb) static void advance_tima_state_machine(GB_gameboy_t *gb) { - gb->io_registers[GB_IO_IF] |= gb->future_interrupts & 4; - gb->future_interrupts &= ~4; if (gb->tima_reload_state == GB_TIMA_RELOADED) { gb->tima_reload_state = GB_TIMA_RUNNING; } else if (gb->tima_reload_state == GB_TIMA_RELOADING) { - gb->future_interrupts |= 4; + gb->io_registers[GB_IO_IF] |= 4; gb->tima_reload_state = GB_TIMA_RELOADED; } } @@ -140,14 +138,16 @@ static void GB_timers_run(GB_gameboy_t *gb, uint8_t cycles) { GB_STATE_MACHINE(gb, div, cycles) { GB_STATE(gb, div, 1); + GB_STATE(gb, div, 2); } GB_set_internal_div_counter(gb, 0); + GB_SLEEP(gb, div, 1, 2); while (true) { advance_tima_state_machine(gb); GB_set_internal_div_counter(gb, gb->div_counter + 4); gb->apu.apu_cycles += 4 << !gb->cgb_double_speed; - GB_SLEEP(gb, div, 1, 4); + GB_SLEEP(gb, div, 2, 4); } } diff --git a/Core/timing.h b/Core/timing.h index 6875570..edc41fa 100644 --- a/Core/timing.h +++ b/Core/timing.h @@ -38,6 +38,6 @@ switch ((gb)->unit##_state) #define GB_STATE(gb, unit, state) case state: goto unit##state -#define GB_UNIT(unit) uint32_t unit##_cycles, unit##_state +#define GB_UNIT(unit) int32_t unit##_cycles, unit##_state #endif /* timing_h */ diff --git a/Core/z80_cpu.c b/Core/z80_cpu.c index d53e96d..863dc8b 100644 --- a/Core/z80_cpu.c +++ b/Core/z80_cpu.c @@ -1337,23 +1337,29 @@ static GB_opcode_t *opcodes[256] = { }; void GB_cpu_run(GB_gameboy_t *gb) { + if (gb->hdma_on) { + GB_advance_cycles(gb, 4); + return; + } + gb->vblank_just_occured = false; + if (gb->halted) { + gb->display_hack = 1; + GB_advance_cycles(gb, 2); + } + uint8_t interrupt_queue = gb->interrupt_enable & gb->io_registers[GB_IO_IF] & 0x1F; - if (!gb->halted) { - interrupt_queue |= gb->future_interrupts & gb->interrupt_enable; + + if (gb->halted) { + gb->display_hack = 2; + GB_advance_cycles(gb, 2); + gb->display_hack = 0; } gb->io_registers[GB_IO_IF] |= gb->future_interrupts; gb->future_interrupts = 0; - if (interrupt_queue) { - gb->halted = false; - } - - if (gb->hdma_on) { - GB_advance_cycles(gb, 4); - return; - } + bool effecitve_ime = gb->ime; if (gb->ime_toggle) { @@ -1361,11 +1367,15 @@ void GB_cpu_run(GB_gameboy_t *gb) gb->ime_toggle = false; } - if (effecitve_ime && interrupt_queue) { - - nop(gb, 0); + /* Wake up from HALT mode without calling interrupt code. */ + if (gb->halted && !effecitve_ime && interrupt_queue) { + gb->halted = false; + } + /* Call interrupt */ + else if (effecitve_ime && interrupt_queue) { + gb->halted = false; uint16_t call_addr = gb->pc - 1; - GB_advance_cycles(gb, 8); + GB_advance_cycles(gb, 12); gb->registers[GB_REGISTER_SP] -= 2; GB_write_memory(gb, gb->registers[GB_REGISTER_SP] + 1, (gb->pc) >> 8); interrupt_queue = gb->interrupt_enable; @@ -1391,6 +1401,7 @@ void GB_cpu_run(GB_gameboy_t *gb) gb->ime = false; GB_debugger_call_hook(gb, call_addr); } + /* Run mode */ else if(!gb->halted && !gb->stopped) { uint8_t opcode = GB_read_memory(gb, gb->pc++); if (gb->halt_bug) { @@ -1399,7 +1410,4 @@ void GB_cpu_run(GB_gameboy_t *gb) } opcodes[opcode](gb, opcode); } - else { - GB_advance_cycles(gb, 4); - } }