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;
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;
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) {
gb->io_registers[GB_IO_STAT] &= ~3;
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 */
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) {
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);
uint16_t serial_cycles; /* This field changed its meaning in v0.10 */
uint16_t serial_length;
bool dont_delay_timer_interrupt; /* If the timer glitch causes a TIMA overflow, it causes the timer to overflow
with different timing, so the triggered interrupt is not delayed.
Todo: needs test ROM. */
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. */
);
/* APU */

View File

@ -136,7 +136,7 @@ static uint8_t read_high_memory(GB_gameboy_t *gb, uint16_t addr)
if (addr < 0xFF80) {
switch (addr & 0xFF) {
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:
return gb->io_registers[GB_IO_TAC] | 0xF8;
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:
GB_window_related_write(gb, addr & 0xFF, value);
break;
case GB_IO_SCX:
case GB_IO_IF:
gb->future_interrupts = 0;
case GB_IO_SCX:
case GB_IO_SCY:
case GB_IO_LYC:
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)
{
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->io_registers[GB_IO_IF] |= 4;
if (!gb->dont_delay_timer_interrupt) {
// Todo
}
gb->future_interrupts |= 4;
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]++;
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->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. */
if (!(new_tac & 4) || gb->div_cycles & (new_clocks >> 1)) {
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;
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) {
gb->halted = false;