mirror of https://github.com/bsnes-emu/bsnes.git
Reimplemented delayed/future interrupts, currently correct only for CGB.
This commit is contained in:
parent
742c9e95d3
commit
1e90400916
|
@ -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;
|
||||||
|
if (gb->is_cgb) {
|
||||||
|
gb->future_interrupts |= 1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
gb->io_registers[GB_IO_IF] |= 1;
|
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,9 +581,14 @@ 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) {
|
||||||
|
if (gb->is_cgb) {
|
||||||
|
gb->future_interrupts |= 2;
|
||||||
|
}
|
||||||
|
else {
|
||||||
gb->io_registers[GB_IO_IF] |= 2;
|
gb->io_registers[GB_IO_IF] |= 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
/* The value of LY is glitched in the last cycle of every line in CGB mode CGB in single speed
|
/* The value of LY is glitched in the last cycle of every line in CGB mode CGB in single speed
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Loading…
Reference in New Issue