From 497513f93a3bb89216591bf918f481494260aad0 Mon Sep 17 00:00:00 2001 From: alyosha-tas Date: Wed, 2 Aug 2017 11:24:49 -0400 Subject: [PATCH] NESHawk: PPU: Fix OAMADDR -Implements $2004 write glitch -Correctly implements OAMADDR initialization --- .../Consoles/Nintendo/NES/PPU.cs | 5 +++ .../Consoles/Nintendo/NES/PPU.regs.cs | 35 +++++++++++++++---- .../Consoles/Nintendo/NES/PPU.run.cs | 13 ++++--- 3 files changed, 40 insertions(+), 13 deletions(-) diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/PPU.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/PPU.cs index 7e97f907cc..0b937975f8 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/PPU.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/PPU.cs @@ -297,6 +297,11 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES ppur.status.cycle++; is_even_cycle = !is_even_cycle; + if (PPUON && ppur.status.cycle >= 257 && ppur.status.cycle <= 320 && 0 <= ppur.status.sl && ppur.status.sl <= 240) + { + reg_2003 = 0; + } + // Here we execute a CPU instruction if enough PPU cycles have passed // also do other things that happen at instruction level granularity cpu_stepcounter++; diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/PPU.regs.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/PPU.regs.cs index 5e6865a382..332e4ab220 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/PPU.regs.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/PPU.regs.cs @@ -40,10 +40,10 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES show_obj_leftmost = (value >> 2) & 1; show_bg = (value >> 3) & 1; show_obj = (value >> 4) & 1; - intense_green = (value >> 5) & 1; intense_blue = (value >> 6) & 1; intense_red = (value >> 7) & 1; - intensity_lsl_6 = ((value >> 5) & 7)<<6; + intense_green = (value >> 5) & 1; + intensity_lsl_6 = ((value >> 5) & 7)<<6; } } } @@ -427,10 +427,33 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES //OAM DATA (write) void write_2004(byte value) { - if ((reg_2003 & 3) == 2) value &= 0xE3; //some of the OAM bits are unwired so we mask them out here - //otherwise we just write this value and move on to the next oam byte - OAM[reg_2003] = value; - reg_2003++; + if ((reg_2003 & 3) == 2) + { + //some of the OAM bits are unwired so we mask them out here + //otherwise we just write this value and move on to the next oam byte + value &= 0xE3; + } + if (0 <= ppur.status.sl && ppur.status.sl <= 240) + { + // don't write to OAM if the screen is on and we are in the active display area + // this impacts sprite evaluation + if (show_bg_new || show_obj_new) + { + // glitchy increment of OAM index + oam_index += 4; + } + else + { + OAM[reg_2003] = value; + reg_2003++; + } + } + else + { + OAM[reg_2003] = value; + reg_2003++; + } + } byte read_2004() { diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/PPU.run.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/PPU.run.cs index 781adc1ec4..331c2b665a 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/PPU.run.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/PPU.run.cs @@ -166,7 +166,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES //Not sure if this is correct. According to Matt Conte and my own tests, it is. Timing is probably off, though. //NOTE: Not having this here breaks a Super Donkey Kong game. - if (PPUON) reg_2003 = 0; + //if (PPUON) reg_2003 = 0; //this was repeatedly finetuned from the fceux days thrugh the old cpu core and into the new one to pass 05-nmi_timing.nes //note that there is still some leniency. for instance, 4,2 will pass in addition to 3,3 @@ -207,13 +207,13 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES yp = sl - 1; ppuphase = PPUPHASE.BG; - // "If PPUADDR is not less then 8 when rendering starts, the first 8 bytes in OAM and written to from - // the current location off PPUADDR" + // "If PPUADDR is not less then 8 when rendering starts, the first 8 bytes in OAM are written to from + // the current location of PPUADDR" if (sl == 0 && PPUON && reg_2003 >= 8 && region==Region.NTSC) { for (int i = 0; i < 8; i++) { - OAM[i] = OAM[reg_2003 & 0xF8 + i]; + OAM[i] = OAM[(reg_2003 & 0xF8) + i]; } } @@ -258,7 +258,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES if (ppur.status.cycle == 64) { soam_index = 0; - oam_index = 0;// reg_2003; + oam_index = reg_2003; } // otherwise, scan through OAM and test if sprites are in range @@ -297,7 +297,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES if (yp >= read_value && yp < read_value + spriteHeight && spr_true_count == 0) { //a flag gets set if sprite zero is in range - if (oam_index == 0)//reg_2003) + if (oam_index == reg_2003) sprite_zero_in_range = true; spr_true_count++; @@ -769,7 +769,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES { } else runppu(1); - } // scanline loop ppur.status.sl = 241;