Reimplemented delayed/future interrupts, currently correct only for CGB.

This commit is contained in:
Lior Halphon 2017-09-09 13:32:12 +03:00
parent 742c9e95d3
commit 1e90400916
5 changed files with 27 additions and 13 deletions

View File

@ -305,6 +305,9 @@ static void update_display_state(GB_gameboy_t *gb, uint8_t cycles)
uint8_t vram_blocking_rush = gb->is_cgb? 0 : 4; uint8_t vram_blocking_rush = gb->is_cgb? 0 : 4;
for (; cycles; cycles -= atomic_increase) { for (; cycles; cycles -= atomic_increase) {
gb->io_registers[GB_IO_IF] |= gb->future_interrupts & 3;
gb->future_interrupts &= ~3;
bool previous_stat_interrupt_line = gb->stat_interrupt_line; bool previous_stat_interrupt_line = gb->stat_interrupt_line;
gb->stat_interrupt_line = false; gb->stat_interrupt_line = false;
@ -351,7 +354,12 @@ static void update_display_state(GB_gameboy_t *gb, uint8_t cycles)
else if (gb->display_cycles == LINES * LINE_LENGTH + stat_delay) { else if (gb->display_cycles == LINES * LINE_LENGTH + stat_delay) {
gb->io_registers[GB_IO_STAT] &= ~3; gb->io_registers[GB_IO_STAT] &= ~3;
gb->io_registers[GB_IO_STAT] |= 1; gb->io_registers[GB_IO_STAT] |= 1;
gb->io_registers[GB_IO_IF] |= 1; if (gb->is_cgb) {
gb->future_interrupts |= 1;
}
else {
gb->io_registers[GB_IO_IF] |= 1;
}
/* Entering VBlank state triggers the OAM interrupt. In CGB, it happens 4 cycles earlier */ /* Entering VBlank state triggers the OAM interrupt. In CGB, it happens 4 cycles earlier */
if (gb->io_registers[GB_IO_STAT] & 0x20 && !gb->is_cgb) { if (gb->io_registers[GB_IO_STAT] & 0x20 && !gb->is_cgb) {
@ -573,7 +581,12 @@ static void update_display_state(GB_gameboy_t *gb, uint8_t cycles)
} }
if (gb->stat_interrupt_line && !previous_stat_interrupt_line) { if (gb->stat_interrupt_line && !previous_stat_interrupt_line) {
gb->io_registers[GB_IO_IF] |= 2; if (gb->is_cgb) {
gb->future_interrupts |= 2;
}
else {
gb->io_registers[GB_IO_IF] |= 2;
}
} }
} }

View File

@ -332,9 +332,8 @@ struct GB_gameboy_internal_s {
GB_PADDING(uint16_t, serial_cycles); GB_PADDING(uint16_t, serial_cycles);
uint16_t serial_cycles; /* This field changed its meaning in v0.10 */ uint16_t serial_cycles; /* This field changed its meaning in v0.10 */
uint16_t serial_length; uint16_t serial_length;
bool dont_delay_timer_interrupt; /* If the timer glitch causes a TIMA overflow, it causes the timer to overflow uint8_t future_interrupts; /* Interrupts can occur in any T-cycle. Some timings result in different interrupt
with different timing, so the triggered interrupt is not delayed. timing when the CPU is in halt mode, and might also affect the DI instruction. */
Todo: needs test ROM. */
); );
/* APU */ /* APU */

View File

@ -136,7 +136,7 @@ static uint8_t read_high_memory(GB_gameboy_t *gb, uint16_t addr)
if (addr < 0xFF80) { if (addr < 0xFF80) {
switch (addr & 0xFF) { switch (addr & 0xFF) {
case GB_IO_IF: case GB_IO_IF:
return gb->io_registers[GB_IO_IF] | 0xE0; return gb->io_registers[GB_IO_IF] | 0xE0 | gb->future_interrupts;
case GB_IO_TAC: case GB_IO_TAC:
return gb->io_registers[GB_IO_TAC] | 0xF8; return gb->io_registers[GB_IO_TAC] | 0xF8;
case GB_IO_STAT: case GB_IO_STAT:
@ -416,8 +416,9 @@ static void write_high_memory(GB_gameboy_t *gb, uint16_t addr, uint8_t value)
case GB_IO_WX: case GB_IO_WX:
GB_window_related_write(gb, addr & 0xFF, value); GB_window_related_write(gb, addr & 0xFF, value);
break; break;
case GB_IO_SCX:
case GB_IO_IF: case GB_IO_IF:
gb->future_interrupts = 0;
case GB_IO_SCX:
case GB_IO_SCY: case GB_IO_SCY:
case GB_IO_LYC: case GB_IO_LYC:
case GB_IO_BGP: case GB_IO_BGP:

View File

@ -82,14 +82,13 @@ 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->io_registers[GB_IO_IF] |= 4; gb->future_interrupts |= 4;
if (!gb->dont_delay_timer_interrupt) {
// Todo
}
gb->tima_reload_state = GB_TIMA_RELOADED; gb->tima_reload_state = GB_TIMA_RELOADED;
} }
} }
@ -157,7 +156,6 @@ static void increase_tima(GB_gameboy_t *gb)
{ {
gb->io_registers[GB_IO_TIMA]++; gb->io_registers[GB_IO_TIMA]++;
if (gb->io_registers[GB_IO_TIMA] == 0) { if (gb->io_registers[GB_IO_TIMA] == 0) {
gb->dont_delay_timer_interrupt = false;
gb->io_registers[GB_IO_TIMA] = gb->io_registers[GB_IO_TMA]; gb->io_registers[GB_IO_TIMA] = gb->io_registers[GB_IO_TMA];
gb->tima_reload_state = GB_TIMA_RELOADING; gb->tima_reload_state = GB_TIMA_RELOADING;
} }
@ -197,7 +195,6 @@ void GB_emulate_timer_glitch(GB_gameboy_t *gb, uint8_t old_tac, uint8_t new_tac)
/* And now either the timer must be disabled, or the new bit used for overflow testing be 0. */ /* And now either the timer must be disabled, or the new bit used for overflow testing be 0. */
if (!(new_tac & 4) || gb->div_cycles & (new_clocks >> 1)) { if (!(new_tac & 4) || gb->div_cycles & (new_clocks >> 1)) {
increase_tima(gb); increase_tima(gb);
gb->dont_delay_timer_interrupt = true;
} }
} }
} }

View File

@ -1338,6 +1338,10 @@ void GB_cpu_run(GB_gameboy_t *gb)
{ {
gb->vblank_just_occured = false; gb->vblank_just_occured = false;
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 (interrupt_queue) { if (interrupt_queue) {
gb->halted = false; gb->halted = false;