diff --git a/Core/gb.h b/Core/gb.h index 536e6fd..8ec5e1c 100644 --- a/Core/gb.h +++ b/Core/gb.h @@ -559,6 +559,8 @@ struct GB_gameboy_internal_s { bool lcd_disabled_outside_of_vblank; int32_t allowed_pending_cycles; uint16_t mode3_batching_length; + uint8_t joyp_switching_delay; + uint8_t joyp_switch_value; ) /* APU */ diff --git a/Core/memory.c b/Core/memory.c index dd8e88b..6bbc949 100644 --- a/Core/memory.c +++ b/Core/memory.c @@ -627,6 +627,10 @@ static uint8_t read_high_memory(GB_gameboy_t *gb, uint16_t addr) case GB_IO_JOYP: gb->joyp_accessed = true; GB_timing_sync(gb); + if (unlikely(gb->joyp_switching_delay)) { + return (gb->io_registers[addr & 0xFF] & ~0x30) | (gb->joyp_switch_value & 0x30); + } + return gb->io_registers[addr & 0xFF]; case GB_IO_TMA: case GB_IO_LCDC: case GB_IO_SCY: @@ -1497,6 +1501,14 @@ static void write_high_memory(GB_gameboy_t *gb, uint16_t addr, uint8_t value) GB_update_joyp(gb); } else if ((gb->io_registers[GB_IO_JOYP] & 0x30) != (value & 0x30)) { + if (gb->model < GB_MODEL_SGB) { // DMG only + if (gb->joyp_switching_delay) { + gb->io_registers[GB_IO_JOYP] = (gb->joyp_switch_value & 0xF0) | (gb->io_registers[GB_IO_JOYP] & 0x0F); + } + gb->joyp_switch_value = value; + gb->joyp_switching_delay = 24; + value &= gb->io_registers[GB_IO_JOYP]; + } GB_sgb_write(gb, value); gb->io_registers[GB_IO_JOYP] = (value & 0xF0) | (gb->io_registers[GB_IO_JOYP] & 0x0F); GB_update_joyp(gb); diff --git a/Core/timing.c b/Core/timing.c index 91191cf..1cd04be 100644 --- a/Core/timing.c +++ b/Core/timing.c @@ -449,6 +449,16 @@ void GB_advance_cycles(GB_gameboy_t *gb, uint8_t cycles) gb->rumble_on_cycles += gb->rumble_strength & 3; gb->rumble_off_cycles += (gb->rumble_strength & 3) ^ 3; + if (gb->joyp_switching_delay) { + if (gb->joyp_switching_delay > cycles) { + gb->joyp_switching_delay -= cycles; + } + else { + gb->joyp_switching_delay = 0; + gb->io_registers[GB_IO_JOYP] = (gb->joyp_switch_value & 0xF0) | (gb->io_registers[GB_IO_JOYP] & 0x0F); + GB_update_joyp(gb); + } + } GB_apu_run(gb, false); GB_display_run(gb, cycles, false);