mirror of https://github.com/bsnes-emu/bsnes.git
More accurate STAT interrupt. This fixes Altered Space and partially fixes Pinball Deluxe. It breaks GBVideoPlayer, however.
This commit is contained in:
parent
3e1863ec51
commit
aca5873de2
|
@ -250,6 +250,13 @@ void display_run(GB_gameboy_t *gb)
|
||||||
*/
|
*/
|
||||||
unsigned char last_mode = gb->io_registers[GB_IO_STAT] & 3;
|
unsigned char last_mode = gb->io_registers[GB_IO_STAT] & 3;
|
||||||
|
|
||||||
|
/*
|
||||||
|
STAT interrupt is implemented based on this finding:
|
||||||
|
http://board.byuu.org/phpbb3/viewtopic.php?p=25527#p25531
|
||||||
|
*/
|
||||||
|
unsigned char previous_stat_interrupt_line = gb->stat_interrupt_line;
|
||||||
|
gb->stat_interrupt_line = false;
|
||||||
|
|
||||||
if (gb->display_cycles >= LCDC_PERIOD) {
|
if (gb->display_cycles >= LCDC_PERIOD) {
|
||||||
/* VBlank! */
|
/* VBlank! */
|
||||||
gb->display_cycles -= LCDC_PERIOD;
|
gb->display_cycles -= LCDC_PERIOD;
|
||||||
|
@ -278,14 +285,10 @@ void display_run(GB_gameboy_t *gb)
|
||||||
|
|
||||||
gb->io_registers[GB_IO_LY] = gb->display_cycles / 456;
|
gb->io_registers[GB_IO_LY] = gb->display_cycles / 456;
|
||||||
|
|
||||||
bool previous_coincidence_flag = gb->io_registers[GB_IO_STAT] & 4;
|
|
||||||
|
|
||||||
gb->io_registers[GB_IO_STAT] &= ~4;
|
gb->io_registers[GB_IO_STAT] &= ~4;
|
||||||
if (gb->io_registers[GB_IO_LY] == gb->io_registers[GB_IO_LYC]) {
|
if (gb->io_registers[GB_IO_LY] == gb->io_registers[GB_IO_LYC]) {
|
||||||
gb->io_registers[GB_IO_STAT] |= 4;
|
gb->io_registers[GB_IO_STAT] |= 4;
|
||||||
if ((gb->io_registers[GB_IO_STAT] & 0x40) && !previous_coincidence_flag) { /* User requests an interrupt on coincidence*/
|
gb->stat_interrupt_line = true;
|
||||||
gb->io_registers[GB_IO_IF] |= 2;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Todo: This behavior is seen in BGB and it fixes some ROMs with delicate timing, such as Hitman's 8bit.
|
/* Todo: This behavior is seen in BGB and it fixes some ROMs with delicate timing, such as Hitman's 8bit.
|
||||||
|
@ -299,10 +302,10 @@ void display_run(GB_gameboy_t *gb)
|
||||||
gb->effective_window_enabled = false;
|
gb->effective_window_enabled = false;
|
||||||
gb->effective_window_y = 0xFF;
|
gb->effective_window_y = 0xFF;
|
||||||
|
|
||||||
if (last_mode != 1) {
|
|
||||||
if (gb->io_registers[GB_IO_STAT] & 16) { /* User requests an interrupt on VBlank*/
|
if (gb->io_registers[GB_IO_STAT] & 16) { /* User requests an interrupt on VBlank*/
|
||||||
gb->io_registers[GB_IO_IF] |= 2;
|
gb->stat_interrupt_line = true;
|
||||||
}
|
}
|
||||||
|
if (last_mode != 1) {
|
||||||
gb->io_registers[GB_IO_IF] |= 1;
|
gb->io_registers[GB_IO_IF] |= 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -328,7 +331,7 @@ void display_run(GB_gameboy_t *gb)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
goto updateSTAT;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Todo: verify this window behavior. It is assumed from the expected behavior of 007 - The World Is Not Enough.
|
// Todo: verify this window behavior. It is assumed from the expected behavior of 007 - The World Is Not Enough.
|
||||||
|
@ -338,16 +341,11 @@ void display_run(GB_gameboy_t *gb)
|
||||||
|
|
||||||
if (gb->display_cycles % 456 < 80) { /* Mode 2 */
|
if (gb->display_cycles % 456 < 80) { /* Mode 2 */
|
||||||
gb->io_registers[GB_IO_STAT] |= 2; /* Set mode to 2 */
|
gb->io_registers[GB_IO_STAT] |= 2; /* Set mode to 2 */
|
||||||
if (last_mode != 2) {
|
|
||||||
if (gb->io_registers[GB_IO_STAT] & 0x20) { /* User requests an interrupt on Mode 2 */
|
if (gb->io_registers[GB_IO_STAT] & 0x20) { /* User requests an interrupt on Mode 2 */
|
||||||
gb->io_registers[GB_IO_IF] |= 2;
|
gb->stat_interrupt_line = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* User requests an interrupt on LY=LYC*/
|
|
||||||
if (gb->io_registers[GB_IO_STAT] & 64 && gb->io_registers[GB_IO_STAT] & 4) {
|
|
||||||
gb->io_registers[GB_IO_IF] |= 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* See above comment about window behavior. */
|
/* See above comment about window behavior. */
|
||||||
if (gb->effective_window_enabled && gb->effective_window_y == 0xFF) {
|
if (gb->effective_window_enabled && gb->effective_window_y == 0xFF) {
|
||||||
gb->effective_window_y = gb->io_registers[GB_IO_LY];
|
gb->effective_window_y = gb->io_registers[GB_IO_LY];
|
||||||
|
@ -355,7 +353,7 @@ void display_run(GB_gameboy_t *gb)
|
||||||
/* Todo: Figure out how the Gameboy handles in-line changes to SCX */
|
/* Todo: Figure out how the Gameboy handles in-line changes to SCX */
|
||||||
gb->line_x_bias = - (gb->io_registers[GB_IO_SCX] & 0x7);
|
gb->line_x_bias = - (gb->io_registers[GB_IO_SCX] & 0x7);
|
||||||
gb->previous_lcdc_x = gb->line_x_bias;
|
gb->previous_lcdc_x = gb->line_x_bias;
|
||||||
return;
|
goto updateSTAT;
|
||||||
}
|
}
|
||||||
|
|
||||||
signed short current_lcdc_x = ((gb->display_cycles % 456 - 80) & ~7) + gb->line_x_bias;
|
signed short current_lcdc_x = ((gb->display_cycles % 456 - 80) & ~7) + gb->line_x_bias;
|
||||||
|
@ -372,19 +370,23 @@ void display_run(GB_gameboy_t *gb)
|
||||||
|
|
||||||
if (gb->display_cycles % 456 < 80 + 172) { /* Mode 3 */
|
if (gb->display_cycles % 456 < 80 + 172) { /* Mode 3 */
|
||||||
gb->io_registers[GB_IO_STAT] |= 3; /* Set mode to 3 */
|
gb->io_registers[GB_IO_STAT] |= 3; /* Set mode to 3 */
|
||||||
return;
|
goto updateSTAT;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* if (gb->display_cycles % 456 < 80 + 172 + 204) */ { /* Mode 0*/
|
/* if (gb->display_cycles % 456 < 80 + 172 + 204) */ { /* Mode 0*/
|
||||||
if (last_mode != 0) {
|
|
||||||
if (gb->io_registers[GB_IO_STAT] & 8) { /* User requests an interrupt on Mode 0 */
|
if (gb->io_registers[GB_IO_STAT] & 8) { /* User requests an interrupt on Mode 0 */
|
||||||
gb->io_registers[GB_IO_IF] |= 2;
|
gb->stat_interrupt_line = true;
|
||||||
}
|
}
|
||||||
|
if (last_mode != 0) {
|
||||||
if (gb->hdma_on_hblank) {
|
if (gb->hdma_on_hblank) {
|
||||||
gb->hdma_on = true;
|
gb->hdma_on = true;
|
||||||
gb->hdma_cycles = 0;
|
gb->hdma_cycles = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return;
|
}
|
||||||
|
|
||||||
|
updateSTAT:
|
||||||
|
if (gb->stat_interrupt_line && !previous_stat_interrupt_line) {
|
||||||
|
gb->io_registers[GB_IO_IF] |= 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include "apu.h"
|
#include "apu.h"
|
||||||
|
|
||||||
#define GB_STRUCT_VERSION 6
|
#define GB_STRUCT_VERSION 7
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
GB_REGISTER_AF,
|
GB_REGISTER_AF,
|
||||||
|
@ -225,6 +225,7 @@ typedef struct GB_gameboy_s{
|
||||||
signed short line_x_bias;
|
signed short line_x_bias;
|
||||||
bool effective_window_enabled;
|
bool effective_window_enabled;
|
||||||
unsigned char effective_window_y;
|
unsigned char effective_window_y;
|
||||||
|
bool stat_interrupt_line;
|
||||||
|
|
||||||
unsigned char bios[0x900];
|
unsigned char bios[0x900];
|
||||||
bool bios_finished;
|
bool bios_finished;
|
||||||
|
|
Loading…
Reference in New Issue