NESHawk: Clean up and minor refactor
Simplify the code base a bit and gets a performance boost as well.
This commit is contained in:
parent
7bb76f9f03
commit
13b99bafd0
|
@ -385,10 +385,10 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
|
|||
//at least it should be, but something is off with that (start up time?) so it is 3,3,3,4,3 for now
|
||||
//NTSC:
|
||||
//sequence of ppu clocks per cpu clock: 3
|
||||
ByteBuffer cpu_sequence;
|
||||
public ByteBuffer cpu_sequence;
|
||||
static ByteBuffer cpu_sequence_NTSC = new ByteBuffer(new byte[] { 3, 3, 3, 3, 3 });
|
||||
static ByteBuffer cpu_sequence_PAL = new ByteBuffer(new byte[] { 3, 3, 3, 4, 3 });
|
||||
public int cpu_step, cpu_stepcounter, cpu_deadcounter;
|
||||
public int cpu_deadcounter;
|
||||
|
||||
public int oam_dma_index;
|
||||
public bool oam_dma_exec = false;
|
||||
|
@ -401,140 +401,122 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
|
|||
public bool do_the_reread;
|
||||
public byte DB; //old data bus values from previous reads
|
||||
|
||||
|
||||
#if VS2012
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#endif
|
||||
internal void RunCpuOne()
|
||||
{
|
||||
cpu_stepcounter++;
|
||||
if (cpu_stepcounter == cpu_sequence[cpu_step])
|
||||
///////////////////////////
|
||||
// OAM DMA start
|
||||
///////////////////////////
|
||||
|
||||
if (sprdma_countdown > 0)
|
||||
{
|
||||
cpu_step++;
|
||||
if (cpu_step == 5) cpu_step = 0;
|
||||
cpu_stepcounter = 0;
|
||||
|
||||
///////////////////////////
|
||||
// OAM DMA start
|
||||
///////////////////////////
|
||||
|
||||
if (sprdma_countdown > 0)
|
||||
sprdma_countdown--;
|
||||
if (sprdma_countdown == 0)
|
||||
{
|
||||
sprdma_countdown--;
|
||||
if (sprdma_countdown == 0)
|
||||
if (cpu.TotalExecutedCycles % 2 == 0)
|
||||
{
|
||||
if (cpu.TotalExecutedCycles % 2 == 0)
|
||||
{
|
||||
cpu_deadcounter = 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
cpu_deadcounter = 1;
|
||||
}
|
||||
oam_dma_exec = true;
|
||||
cpu.RDY = false;
|
||||
oam_dma_index = 0;
|
||||
special_case_delay = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (oam_dma_exec && apu.dmc_dma_countdown != 1 && !dmc_realign)
|
||||
{
|
||||
if (cpu_deadcounter == 0)
|
||||
{
|
||||
|
||||
if (oam_dma_index % 2 == 0)
|
||||
{
|
||||
oam_dma_byte = ReadMemory(oam_dma_addr);
|
||||
oam_dma_addr++;
|
||||
}
|
||||
else
|
||||
{
|
||||
WriteMemory(0x2004, oam_dma_byte);
|
||||
}
|
||||
oam_dma_index++;
|
||||
if (oam_dma_index == 512) oam_dma_exec = false;
|
||||
|
||||
cpu_deadcounter = 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
cpu_deadcounter--;
|
||||
cpu_deadcounter = 1;
|
||||
}
|
||||
}
|
||||
else if (apu.dmc_dma_countdown == 1)
|
||||
{
|
||||
dmc_realign = true;
|
||||
}
|
||||
else if (dmc_realign)
|
||||
{
|
||||
dmc_realign = false;
|
||||
}
|
||||
/////////////////////////////
|
||||
// OAM DMA end
|
||||
/////////////////////////////
|
||||
|
||||
|
||||
/////////////////////////////
|
||||
// dmc dma start
|
||||
/////////////////////////////
|
||||
|
||||
if (apu.dmc_dma_countdown > 0)
|
||||
{
|
||||
oam_dma_exec = true;
|
||||
cpu.RDY = false;
|
||||
dmc_dma_exec = true;
|
||||
apu.dmc_dma_countdown--;
|
||||
if (apu.dmc_dma_countdown == 0)
|
||||
{
|
||||
apu.RunDMCFetch();
|
||||
dmc_dma_exec = false;
|
||||
apu.dmc_dma_countdown = -1;
|
||||
do_the_reread = true;
|
||||
}
|
||||
oam_dma_index = 0;
|
||||
special_case_delay = true;
|
||||
}
|
||||
|
||||
/////////////////////////////
|
||||
// dmc dma end
|
||||
/////////////////////////////
|
||||
apu.RunOne(true);
|
||||
|
||||
if (cpu.RDY && !IRQ_delay)
|
||||
{
|
||||
cpu.IRQ = _irq_apu || Board.IRQSignal;
|
||||
}
|
||||
else if (special_case_delay || apu.dmc_dma_countdown == 3)
|
||||
{
|
||||
cpu.IRQ = _irq_apu || Board.IRQSignal;
|
||||
special_case_delay = false;
|
||||
}
|
||||
|
||||
cpu.ExecuteOne();
|
||||
apu.RunOne(false);
|
||||
|
||||
if (ppu.double_2007_read > 0)
|
||||
ppu.double_2007_read--;
|
||||
|
||||
if (do_the_reread && cpu.RDY)
|
||||
do_the_reread = false;
|
||||
|
||||
if (IRQ_delay)
|
||||
IRQ_delay = false;
|
||||
|
||||
if (!dmc_dma_exec && !oam_dma_exec && !cpu.RDY)
|
||||
{
|
||||
cpu.RDY = true;
|
||||
IRQ_delay = true;
|
||||
}
|
||||
|
||||
ppu.ppu_open_bus_decay(0);
|
||||
|
||||
Board.ClockCPU();
|
||||
ppu.PostCpuInstructionOne();
|
||||
}
|
||||
|
||||
if (oam_dma_exec && apu.dmc_dma_countdown != 1 && !dmc_realign)
|
||||
{
|
||||
if (cpu_deadcounter == 0)
|
||||
{
|
||||
|
||||
if (oam_dma_index % 2 == 0)
|
||||
{
|
||||
oam_dma_byte = ReadMemory(oam_dma_addr);
|
||||
oam_dma_addr++;
|
||||
}
|
||||
else
|
||||
{
|
||||
WriteMemory(0x2004, oam_dma_byte);
|
||||
}
|
||||
oam_dma_index++;
|
||||
if (oam_dma_index == 512) oam_dma_exec = false;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
cpu_deadcounter--;
|
||||
}
|
||||
}
|
||||
else if (apu.dmc_dma_countdown == 1)
|
||||
{
|
||||
dmc_realign = true;
|
||||
}
|
||||
else if (dmc_realign)
|
||||
{
|
||||
dmc_realign = false;
|
||||
}
|
||||
/////////////////////////////
|
||||
// OAM DMA end
|
||||
/////////////////////////////
|
||||
|
||||
|
||||
/////////////////////////////
|
||||
// dmc dma start
|
||||
/////////////////////////////
|
||||
|
||||
if (apu.dmc_dma_countdown > 0)
|
||||
{
|
||||
cpu.RDY = false;
|
||||
dmc_dma_exec = true;
|
||||
apu.dmc_dma_countdown--;
|
||||
if (apu.dmc_dma_countdown == 0)
|
||||
{
|
||||
apu.RunDMCFetch();
|
||||
dmc_dma_exec = false;
|
||||
apu.dmc_dma_countdown = -1;
|
||||
do_the_reread = true;
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////
|
||||
// dmc dma end
|
||||
/////////////////////////////
|
||||
apu.RunOne(true);
|
||||
|
||||
if (cpu.RDY && !IRQ_delay)
|
||||
{
|
||||
cpu.IRQ = _irq_apu || Board.IRQSignal;
|
||||
}
|
||||
else if (special_case_delay || apu.dmc_dma_countdown == 3)
|
||||
{
|
||||
cpu.IRQ = _irq_apu || Board.IRQSignal;
|
||||
special_case_delay = false;
|
||||
}
|
||||
|
||||
cpu.ExecuteOne();
|
||||
apu.RunOne(false);
|
||||
|
||||
if (ppu.double_2007_read > 0)
|
||||
ppu.double_2007_read--;
|
||||
|
||||
if (do_the_reread && cpu.RDY)
|
||||
do_the_reread = false;
|
||||
|
||||
if (IRQ_delay)
|
||||
IRQ_delay = false;
|
||||
|
||||
if (!dmc_dma_exec && !oam_dma_exec && !cpu.RDY)
|
||||
{
|
||||
cpu.RDY = true;
|
||||
IRQ_delay = true;
|
||||
}
|
||||
|
||||
Board.ClockCPU();
|
||||
}
|
||||
|
||||
#if VS2012
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#endif
|
||||
public byte ReadReg(int addr)
|
||||
{
|
||||
byte ret_spec;
|
||||
|
@ -681,7 +663,12 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
|
|||
case 0x4013:
|
||||
apu.WriteReg(addr, val);
|
||||
break;
|
||||
case 0x4014: Exec_OAMDma(val); break;
|
||||
case 0x4014:
|
||||
//schedule a sprite dma event for beginning 1 cycle in the future.
|
||||
//this receives 2 because thats just the way it works out.
|
||||
oam_dma_addr = (ushort)(val << 8);
|
||||
sprdma_countdown = 1;
|
||||
break;
|
||||
case 0x4015: apu.WriteReg(addr, val); break;
|
||||
case 0x4016:
|
||||
if (_isVS)
|
||||
|
@ -740,15 +727,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
|
|||
return 0;
|
||||
}
|
||||
|
||||
void Exec_OAMDma(byte val)
|
||||
{
|
||||
//schedule a sprite dma event for beginning 1 cycle in the future.
|
||||
//this receives 2 because thats just the way it works out.
|
||||
oam_dma_addr = (ushort)(val << 8);
|
||||
|
||||
sprdma_countdown = 1;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the provided palette as current.
|
||||
/// Applies the current deemph settings if needed to expand a 64-entry palette to 512
|
||||
|
|
|
@ -60,8 +60,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
|
|||
ser.Sync("cpu_accumulate", ref cpu_accumulate);
|
||||
ser.Sync("_irq_apu", ref _irq_apu);
|
||||
ser.Sync("sprdma_countdown", ref sprdma_countdown);
|
||||
ser.Sync("cpu_step", ref cpu_step);
|
||||
ser.Sync("cpu_stepcounter", ref cpu_stepcounter);
|
||||
ser.Sync("cpu_deadcounter", ref cpu_deadcounter);
|
||||
|
||||
//oam related
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
//http://nesdev.parodius.com/bbs/viewtopic.php?p=4571&sid=db4c7e35316cc5d734606dd02f11dccb
|
||||
|
||||
using System;
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using BizHawk.Common;
|
||||
|
||||
|
@ -8,6 +6,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
|
|||
{
|
||||
public sealed partial class PPU
|
||||
{
|
||||
public int cpu_step, cpu_stepcounter;
|
||||
|
||||
// this only handles region differences within the PPU
|
||||
int preNMIlines;
|
||||
int postNMIlines;
|
||||
|
@ -203,6 +203,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
|
|||
|
||||
public void SyncState(Serializer ser)
|
||||
{
|
||||
ser.Sync("cpu_step", ref cpu_step);
|
||||
ser.Sync("cpu_stepcounter", ref cpu_stepcounter);
|
||||
ser.Sync("ppudead", ref ppudead);
|
||||
ser.Sync("idleSynch", ref idleSynch);
|
||||
ser.Sync("NMI_PendingInstructions", ref NMI_PendingInstructions);
|
||||
|
@ -255,32 +257,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
|
|||
ppu_open_bus_decay_timer = new int[8];
|
||||
}
|
||||
|
||||
#if VS2012
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#endif
|
||||
void TriggerNMI()
|
||||
{
|
||||
nes.cpu.NMI = true;
|
||||
}
|
||||
|
||||
//this gets called once after each cpu instruction executes.
|
||||
//anything that needs to happen at instruction granularity can get checked here
|
||||
//to save having to check it at ppu cycle granularity
|
||||
public void PostCpuInstructionOne()
|
||||
{
|
||||
if (NMI_PendingInstructions > 0)
|
||||
{
|
||||
NMI_PendingInstructions--;
|
||||
if (NMI_PendingInstructions <= 0)
|
||||
{
|
||||
TriggerNMI();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if VS2012
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#endif
|
||||
void runppu(int x)
|
||||
{
|
||||
//run one ppu cycle at a time so we can interact with the ppu and clockPPU at high granularity
|
||||
|
@ -318,13 +294,36 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
|
|||
|
||||
ppur.status.cycle++;
|
||||
is_even_cycle = !is_even_cycle;
|
||||
//might not actually run a cpu cycle if there are none to be run right now
|
||||
nes.RunCpuOne();
|
||||
|
||||
// Here we execute a CPU instruction if enough PPU cycles have passed
|
||||
// also do other things that happen at instruction level granularity
|
||||
cpu_stepcounter++;
|
||||
if (cpu_stepcounter == nes.cpu_sequence[cpu_step])
|
||||
{
|
||||
cpu_step++;
|
||||
if (cpu_step == 5) cpu_step = 0;
|
||||
cpu_stepcounter = 0;
|
||||
|
||||
// this is where the CPU instruction is called
|
||||
nes.RunCpuOne();
|
||||
|
||||
// decay the ppu bus, approximating real behaviour
|
||||
ppu_open_bus_decay(0);
|
||||
|
||||
// Check for NMIs
|
||||
if (NMI_PendingInstructions > 0)
|
||||
{
|
||||
NMI_PendingInstructions--;
|
||||
if (NMI_PendingInstructions <= 0)
|
||||
{
|
||||
nes.cpu.NMI = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (Reg2002_vblank_active_pending)
|
||||
{
|
||||
//if (Reg2002_vblank_active_pending)
|
||||
Reg2002_vblank_active = 1;
|
||||
Reg2002_vblank_active = 1;
|
||||
Reg2002_vblank_active_pending = false;
|
||||
}
|
||||
|
||||
|
@ -337,10 +336,5 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
|
|||
nes.Board.ClockPPU();
|
||||
}
|
||||
}
|
||||
|
||||
//hack
|
||||
//public bool PAL = false;
|
||||
//bool SPRITELIMIT = true;
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -309,6 +309,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
|
|||
public Reg_2000 reg_2000;
|
||||
public Reg_2001 reg_2001;
|
||||
byte reg_2003;
|
||||
|
||||
void regs_reset()
|
||||
{
|
||||
//TODO - would like to reconstitute the entire PPU instead of all this..
|
||||
|
@ -396,12 +397,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
|
|||
return (byte)((Reg2002_vblank_active << 7) | (Reg2002_objhit << 6) | (Reg2002_objoverflow << 5) | (ppu_open_bus & 0x1F));
|
||||
}
|
||||
|
||||
void clear_2002()
|
||||
{
|
||||
Reg2002_objhit = Reg2002_objoverflow = 0;
|
||||
Reg2002_vblank_clear_pending = true;
|
||||
}
|
||||
|
||||
//OAM ADDRESS (write)
|
||||
void write_2003(int addr, byte value)
|
||||
{
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
//http://nesdev.parodius.com/bbs/viewtopic.php?p=4571&sid=db4c7e35316cc5d734606dd02f11dccb
|
||||
|
||||
//TODO - correctly emulate PPU OFF state
|
||||
//TODO - correctly emulate PPU OFF state
|
||||
|
||||
using BizHawk.Common;
|
||||
using System;
|
||||
|
@ -10,6 +8,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
|
|||
sealed partial class PPU
|
||||
{
|
||||
const int kFetchTime = 2;
|
||||
const int kLineTime = 341;
|
||||
|
||||
struct BGDataRecord
|
||||
{
|
||||
|
@ -78,7 +77,9 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
|
|||
if (reg_2001.color_disable)
|
||||
pixelcolor_latch_2 &= 0x30;
|
||||
|
||||
xbuf[(target - 2)] = PaletteAdjustPixel(pixelcolor_latch_2);
|
||||
//TODO - check flashing sirens in werewolf
|
||||
//tack on the deemph bits. THESE MAY BE ORDERED WRONG. PLEASE CHECK IN THE PALETTE CODE
|
||||
xbuf[(target - 2)] = (short)(pixelcolor_latch_2 | reg_2001.intensity_lsl_6);
|
||||
}
|
||||
|
||||
if (row_check >= 1)
|
||||
|
@ -158,14 +159,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
|
|||
} //switch(cycle)
|
||||
}
|
||||
|
||||
//TODO - check flashing sirens in werewolf
|
||||
short PaletteAdjustPixel(int pixel)
|
||||
{
|
||||
//tack on the deemph bits. THESE MAY BE ORDERED WRONG. PLEASE CHECK IN THE PALETTE CODE
|
||||
return (short)(pixel | reg_2001.intensity_lsl_6);
|
||||
}
|
||||
|
||||
const int kLineTime = 341;
|
||||
public unsafe void FrameAdvance()
|
||||
{
|
||||
BGDataRecord* bgdata = stackalloc BGDataRecord[34]; //one at the end is junk, it can never be rendered
|
||||
|
@ -191,12 +184,13 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
|
|||
runppu(3);
|
||||
bool nmi_destiny = reg_2000.vblank_nmi_gen && Reg2002_vblank_active;
|
||||
runppu(3);
|
||||
if (nmi_destiny) TriggerNMI();
|
||||
if (nmi_destiny) nes.cpu.NMI = true;
|
||||
nes.Board.AtVsyncNMI();
|
||||
runppu(postNMIlines * kLineTime - delay);
|
||||
|
||||
//this seems to run just before the dummy scanline begins
|
||||
clear_2002();
|
||||
//this seems to happen just before the dummy scanline begins
|
||||
Reg2002_objhit = Reg2002_objoverflow = 0;
|
||||
Reg2002_vblank_clear_pending = true;
|
||||
|
||||
idleSynch ^= true;
|
||||
|
||||
|
@ -224,8 +218,8 @@ 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 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 (sl == 0 && PPUON && reg_2003 >= 8 && region==Region.NTSC)
|
||||
{
|
||||
for (int i = 0; i < 8; i++)
|
||||
|
@ -233,7 +227,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
|
|||
OAM[i] = OAM[reg_2003 & 0xF8 + i];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (NTViewCallback != null && yp == NTViewCallback.Scanline) NTViewCallback.Callback();
|
||||
if (PPUViewCallback != null && yp == PPUViewCallback.Scanline) PPUViewCallback.Callback();
|
||||
|
||||
|
@ -255,7 +249,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
|
|||
|
||||
//check all the conditions that can cause things to render in these 8px
|
||||
bool renderspritenow = show_obj_new && (xt > 0 || reg_2001.show_obj_leftmost);
|
||||
bool renderbgnow;
|
||||
bool renderbgnow;
|
||||
bool hit_pending = false;
|
||||
|
||||
for (int xp = 0; xp < 8; xp++, rasterpos++)
|
||||
{
|
||||
|
@ -350,7 +345,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
|
|||
{
|
||||
if (yp >= read_value && yp < read_value + spriteHeight && PPUON)
|
||||
{
|
||||
Reg2002_objoverflow = true;
|
||||
hit_pending = true;
|
||||
//Reg2002_objoverflow = true;
|
||||
}
|
||||
|
||||
if (yp >= read_value && yp < read_value + spriteHeight && spr_true_count == 0)
|
||||
|
@ -400,6 +396,12 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
|
|||
else
|
||||
runppu(1);
|
||||
|
||||
if (hit_pending)
|
||||
{
|
||||
hit_pending = false;
|
||||
Reg2002_objoverflow = true;
|
||||
}
|
||||
|
||||
renderbgnow = show_bg_new && (xt > 0 || reg_2001.show_bg_leftmost);
|
||||
//bg pos is different from raster pos due to its offsetability.
|
||||
//so adjust for that here
|
||||
|
|
Loading…
Reference in New Issue