From df7a93e83a583958fd8b090c037a274ed55999ad Mon Sep 17 00:00:00 2001 From: alyosha-tas Date: Tue, 7 Mar 2017 22:30:41 -0500 Subject: [PATCH] NES Update $2003 behaviour Fixes Huge Insect Some debate reamins about what exactly is happening here though --- .../Consoles/Nintendo/NES/NES.BoardSystem.cs | 2 +- .../Consoles/Nintendo/NES/NES.Core.cs | 2 +- .../Consoles/Nintendo/NES/PPU.cs | 1 + .../Consoles/Nintendo/NES/PPU.regs.cs | 35 ++++++++++---- .../Consoles/Nintendo/NES/PPU.run.cs | 46 +++++++++++++------ 5 files changed, 62 insertions(+), 24 deletions(-) diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/NES.BoardSystem.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/NES.BoardSystem.cs index c22a282650..fdf0855b26 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/NES.BoardSystem.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/NES.BoardSystem.cs @@ -224,7 +224,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES public virtual void WriteReg2xxx(int addr, byte value) { - NES.ppu.WriteReg(addr & 7, value); + NES.ppu.WriteReg(addr, value); } public virtual void WritePPU(int addr, byte value) diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/NES.Core.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/NES.Core.cs index 485557fea2..6b3bacd257 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/NES.Core.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/NES.Core.cs @@ -796,7 +796,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES } else if (addr < 0x4000) { - ppu.WriteReg((addr & 0x07), value); + ppu.WriteReg(addr, value); } else if (addr < 0x4020) { diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/PPU.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/PPU.cs index 716ec6c9b4..c41b37738e 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/PPU.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/PPU.cs @@ -223,6 +223,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES ser.Sync("ppu_open_bus", ref ppu_open_bus); ser.Sync("double_2007_read", ref double_2007_read); ser.Sync("ppu_open_bus_decay_timer", ref ppu_open_bus_decay_timer, false); + ser.Sync("glitchy_reads_2003", ref glitchy_reads_2003, false); ser.Sync("OAM", ref OAM, false); ser.Sync("PALRAM", ref PALRAM, false); diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/PPU.regs.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/PPU.regs.cs index 5c9a36b5ca..d81f56fd4f 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/PPU.regs.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/PPU.regs.cs @@ -55,6 +55,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES public byte ppu_open_bus=0; public int double_2007_read; // emulates a hardware bug of back to back 2007 reads public int[] ppu_open_bus_decay_timer = new int[8]; + public byte[] glitchy_reads_2003 = new byte[8]; public struct PPUSTATUS { @@ -400,10 +401,28 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES } //OAM ADDRESS (write) - void write_2003(byte value) + void write_2003(int addr, byte value) { - //just record the oam buffer write target - reg_2003 = value; + if (region == PPU.Region.NTSC) + { + // in NTSC this does several glitchy things to corrupt OAM + // commented out for now until better understood + byte temp = (byte)(reg_2003 & 0xF8); + byte temp_2 = (byte)(addr >> 16 & 0xF8); + /* + for (int i=0;i<8;i++) + { + glitchy_reads_2003[i] = OAM[temp + i]; + //OAM[temp_2 + i] = glitchy_reads_2003[i]; + } + */ + reg_2003 = value; + } + else + { + // in PAL, just record the oam buffer write target + reg_2003 = value; + } } byte read_2003() { return ppu_open_bus; } byte peek_2003() { return ppu_open_bus; } @@ -424,15 +443,15 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES { if (ppur.status.sl < 241) { - if (ppur.status.cycle <= 64) + if (ppur.status.cycle < 64) { ret = 0xFF; // during this time all reads return FF } - else if (ppur.status.cycle <= 256) + else if (ppur.status.cycle < 256) { ret = read_value; } - else if (ppur.status.cycle <= 320) + else if (ppur.status.cycle < 320) { ret = read_value; } @@ -669,7 +688,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES PPUGenLatch = value; ppu_open_bus = value; - switch (addr) + switch (addr & 0x07) { case 0: if (nes._isVS2c05>0) @@ -684,7 +703,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES write_2001(value); break; case 2: write_2002(value); break; - case 3: write_2003(value); break; + case 3: write_2003(addr, value); break; case 4: write_2004(value); break; case 5: write_2005(value); break; case 6: write_2006(value); break; diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/PPU.run.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/PPU.run.cs index c39fc35886..c1418ba817 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/PPU.run.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/PPU.run.cs @@ -130,16 +130,18 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES ppu_addr_temp |= 8; bgdata.pt_1 = ppubus_read(ppu_addr_temp, true, true); + runppu(1); if (reg_2001.PPUON) { ppu_was_on = true; } + break; case 7: + race_2006 = false; runppu(1); - //horizontal scroll clocked at cycle 3 and then //vertical scroll at 256 if (ppu_was_on) @@ -148,6 +150,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES if (ppur.status.cycle == 256 && !race_2006) ppur.increment_vs(); } + ppu_was_on = false; break; } //switch(cycle) @@ -219,6 +222,16 @@ 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 fights in OAM and written to from + // the current location off PPUADDR" + if (sl == 0 && reg_2001.PPUON && reg_2003 >= 8) + { + for (int i = 0; i < 8; i++) + { + OAM[i] = OAM[reg_2003 & 0xF8 + i]; + } + } + if (NTViewCallback != null && yp == NTViewCallback.Scanline) NTViewCallback.Callback(); if (PPUViewCallback != null && yp == PPUViewCallback.Scanline) PPUViewCallback.Callback(); @@ -259,37 +272,38 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES if (ppur.status.cycle == 64) { soam_index = 0; + oam_index = 0;// reg_2003; } // otherwise, scan through OAM and test if sprites are in range // if they are, they get copied to the secondary OAM if (ppur.status.cycle >= 64) { - if (oam_index == 64) + if (oam_index >= 256) { oam_index = 0; sprite_eval_write = false; } - if (is_even_cycle && oam_index<64) + if (is_even_cycle && oam_index<256) { - if ((oam_index * 4 + soam_m_index) < 256) - read_value = OAM[oam_index * 4 + soam_m_index]; + if ((oam_index + soam_m_index) < 256) + read_value = OAM[oam_index + soam_m_index]; else - read_value = OAM[oam_index * 4 + soam_m_index - 256]; + read_value = OAM[oam_index + soam_m_index - 256]; } else if (!sprite_eval_write) { // if we don't write sprites anymore, just scan through the oam read_value = soam[0]; - oam_index++; + oam_index+=4; } else if (sprite_eval_write) { //look for sprites if (spr_true_count==0 && soam_index<8) { - soam[soam_index * 4] = read_value; + soam[soam_index*4] = read_value; } if (soam_index < 8) @@ -297,7 +311,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) + if (oam_index == 0)//reg_2003) sprite_zero_in_range = true; spr_true_count++; @@ -312,10 +326,14 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES spr_true_count++; if (spr_true_count == 4) { - oam_index++; + oam_index+=4; soam_index++; if (soam_index == 8) - oam_index_aux = oam_index; + { + // oam_index could be pathologically misaligned at this point, so we have to find the next + // nearest actual sprite to work on >8 sprites per scanline option + oam_index_aux = (oam_index%4)*4; + } soam_m_index = 0; spr_true_count = 0; @@ -323,7 +341,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES } else { - oam_index++; + oam_index+=4; } } else if (soam_index>=8) @@ -345,7 +363,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES spr_true_count++; if (spr_true_count == 4) { - oam_index++; + oam_index+=4; soam_index++; soam_m_index = 0; spr_true_count = 0; @@ -353,7 +371,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES } else { - oam_index++; + oam_index+=4; if (soam_index==8) { soam_m_index++; // glitchy increment