Starting to remove the delayed interrupts hack – done for timer interrupt, broken for display interrupts

This commit is contained in:
Lior Halphon 2018-02-23 15:33:44 +02:00
parent c48097a484
commit 42ab746a66
6 changed files with 36 additions and 23 deletions

View File

@ -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) 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); update_display_state(gb, cycles);
if (gb->disable_rendering) { if (gb->disable_rendering) {
return; return;

View File

@ -340,6 +340,7 @@ struct GB_gameboy_internal_s {
uint16_t serial_length; uint16_t serial_length;
uint8_t future_interrupts; /* Interrupts can occur in any T-cycle. Some timings result in different interrupt 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. */ 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 */ /* APU */

View File

@ -484,7 +484,9 @@ static void write_high_memory(GB_gameboy_t *gb, uint16_t addr, uint8_t value)
return; return;
case GB_IO_DIV: 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; return;
case GB_IO_JOYP: case GB_IO_JOYP:

View File

@ -96,13 +96,11 @@ static void GB_ir_run(GB_gameboy_t *gb)
static void advance_tima_state_machine(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) { if (gb->tima_reload_state == GB_TIMA_RELOADED) {
gb->tima_reload_state = GB_TIMA_RUNNING; gb->tima_reload_state = GB_TIMA_RUNNING;
} }
else if (gb->tima_reload_state == GB_TIMA_RELOADING) { 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; 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_MACHINE(gb, div, cycles) {
GB_STATE(gb, div, 1); GB_STATE(gb, div, 1);
GB_STATE(gb, div, 2);
} }
GB_set_internal_div_counter(gb, 0); GB_set_internal_div_counter(gb, 0);
GB_SLEEP(gb, div, 1, 2);
while (true) { while (true) {
advance_tima_state_machine(gb); advance_tima_state_machine(gb);
GB_set_internal_div_counter(gb, gb->div_counter + 4); GB_set_internal_div_counter(gb, gb->div_counter + 4);
gb->apu.apu_cycles += 4 << !gb->cgb_double_speed; gb->apu.apu_cycles += 4 << !gb->cgb_double_speed;
GB_SLEEP(gb, div, 1, 4); GB_SLEEP(gb, div, 2, 4);
} }
} }

View File

@ -38,6 +38,6 @@ switch ((gb)->unit##_state)
#define GB_STATE(gb, unit, state) case state: goto 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 */ #endif /* timing_h */

View File

@ -1337,23 +1337,29 @@ static GB_opcode_t *opcodes[256] = {
}; };
void GB_cpu_run(GB_gameboy_t *gb) void GB_cpu_run(GB_gameboy_t *gb)
{ {
if (gb->hdma_on) {
GB_advance_cycles(gb, 4);
return;
}
gb->vblank_just_occured = false; 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; 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->io_registers[GB_IO_IF] |= gb->future_interrupts;
gb->future_interrupts = 0; 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; bool effecitve_ime = gb->ime;
if (gb->ime_toggle) { if (gb->ime_toggle) {
@ -1361,11 +1367,15 @@ void GB_cpu_run(GB_gameboy_t *gb)
gb->ime_toggle = false; gb->ime_toggle = false;
} }
if (effecitve_ime && interrupt_queue) { /* Wake up from HALT mode without calling interrupt code. */
if (gb->halted && !effecitve_ime && interrupt_queue) {
nop(gb, 0); gb->halted = false;
}
/* Call interrupt */
else if (effecitve_ime && interrupt_queue) {
gb->halted = false;
uint16_t call_addr = gb->pc - 1; uint16_t call_addr = gb->pc - 1;
GB_advance_cycles(gb, 8); GB_advance_cycles(gb, 12);
gb->registers[GB_REGISTER_SP] -= 2; gb->registers[GB_REGISTER_SP] -= 2;
GB_write_memory(gb, gb->registers[GB_REGISTER_SP] + 1, (gb->pc) >> 8); GB_write_memory(gb, gb->registers[GB_REGISTER_SP] + 1, (gb->pc) >> 8);
interrupt_queue = gb->interrupt_enable; interrupt_queue = gb->interrupt_enable;
@ -1391,6 +1401,7 @@ void GB_cpu_run(GB_gameboy_t *gb)
gb->ime = false; gb->ime = false;
GB_debugger_call_hook(gb, call_addr); GB_debugger_call_hook(gb, call_addr);
} }
/* Run mode */
else if(!gb->halted && !gb->stopped) { else if(!gb->halted && !gb->stopped) {
uint8_t opcode = GB_read_memory(gb, gb->pc++); uint8_t opcode = GB_read_memory(gb, gb->pc++);
if (gb->halt_bug) { if (gb->halt_bug) {
@ -1399,7 +1410,4 @@ void GB_cpu_run(GB_gameboy_t *gb)
} }
opcodes[opcode](gb, opcode); opcodes[opcode](gb, opcode);
} }
else {
GB_advance_cycles(gb, 4);
}
} }