Correct OAM interrupt behavior

This commit is contained in:
Lior Halphon 2016-04-02 16:29:27 +03:00
parent da00e240e5
commit b7555e9976
2 changed files with 17 additions and 18 deletions

View File

@ -243,22 +243,18 @@ void palette_changed(GB_gameboy_t *gb, bool background_palette, unsigned char in
void display_run(GB_gameboy_t *gb) void display_run(GB_gameboy_t *gb)
{ {
/* /*
Display controller bug: For some reason, the OAM STAT interrupt is called, as expected, for LY = 0..143.
However, it is also called from LY = 144.
<del>Display controller bug: For some reason, the OAM STAT interrupt is called, as expected, for LY = 0..143. See http://forums.nesdev.com/viewtopic.php?f=20&t=13727
However, it is also called from LY = 151! (The last LY is 153! Wonder why is it 151...).</del>
Todo: This discussion in NESDev proves this theory incorrect:
http://forums.nesdev.com/viewtopic.php?f=20&t=13727
Seems like there was a bug in one of my test ROMs.
This behavior needs to be corrected.
*/ */
unsigned char last_mode = gb->io_registers[GB_IO_STAT] & 3; unsigned char last_mode = gb->io_registers[GB_IO_STAT] & 3;
if (gb->display_cycles >= LCDC_PERIOD) { if (gb->display_cycles >= LCDC_PERIOD) {
/* VBlank! */ /* VBlank! */
gb->display_cycles -= LCDC_PERIOD; gb->display_cycles -= LCDC_PERIOD;
gb->ly151_bug_oam = false; gb->ly144_bug_oam = false;
gb->ly151_bug_hblank = false; gb->ly144_bug_hblank = false;
display_vblank(gb); display_vblank(gb);
} }
@ -310,22 +306,25 @@ void display_run(GB_gameboy_t *gb)
gb->io_registers[GB_IO_IF] |= 1; gb->io_registers[GB_IO_IF] |= 1;
} }
// LY = 151 interrupt bug // LY = 144 interrupt bug
if (gb->io_registers[GB_IO_LY] == 151) { if (gb->io_registers[GB_IO_LY] == 144) {
if (gb->display_cycles % 456 < 80) { // Mode 2 if (gb->display_cycles % 456 < 80) { // Mode 2
if (gb->io_registers[GB_IO_STAT] & 0x20 && !gb->ly151_bug_oam) { /* User requests an interrupt on Mode 2 */ if (gb->io_registers[GB_IO_STAT] & 0x20 && !gb->ly144_bug_oam) { /* User requests an interrupt on Mode 2 */
gb->io_registers[GB_IO_IF] |= 2; gb->io_registers[GB_IO_IF] |= 2;
} }
gb->ly151_bug_oam = true; gb->ly144_bug_oam = true;
} }
if (gb->display_cycles % 456 < 80 + 172) { /* Mode 3 */ if (gb->display_cycles % 456 < 80 + 172) { /* Mode 3 */
// Nothing to do // Nothing to do
} }
else { /* Mode 0 */ else { /* Mode 0 */
if (gb->io_registers[GB_IO_STAT] & 8 && !gb->ly151_bug_hblank) { /* User requests an interrupt on Mode 0 */ if (gb->io_registers[GB_IO_STAT] & 8 && !gb->ly144_bug_hblank) { /* User requests an interrupt on Mode 0 */
/*
Todo: Verify if this actually happens.
gb->io_registers[GB_IO_IF] |= 2; gb->io_registers[GB_IO_IF] |= 2;
*/
} }
gb->ly151_bug_hblank = true; gb->ly144_bug_hblank = true;
} }
} }

View File

@ -216,8 +216,8 @@ typedef struct GB_gameboy_s{
unsigned char sprite_palletes_data[0x40]; unsigned char sprite_palletes_data[0x40];
uint32_t background_palletes_rgb[0x20]; uint32_t background_palletes_rgb[0x20];
uint32_t sprite_palletes_rgb[0x20]; uint32_t sprite_palletes_rgb[0x20];
bool ly151_bug_oam; bool ly144_bug_oam;
bool ly151_bug_hblank; bool ly144_bug_hblank;
signed short previous_lcdc_x; signed short previous_lcdc_x;
signed short line_x_bias; signed short line_x_bias;
bool effective_window_enabled; bool effective_window_enabled;