NESHawk: Tweaks to APU timing

This commit is contained in:
alyosha-tas 2021-07-22 08:42:29 -04:00
parent 726f1f3f11
commit 335c8104b6
4 changed files with 29 additions and 21 deletions

View File

@ -652,17 +652,19 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
}
} // class TriangleUnit
private sealed class DMCUnit
public sealed class DMCUnit
{
private readonly APU apu;
private readonly NES nes;
private readonly int[] DMC_RATE;
public DMCUnit(APU apu, bool pal)
{
this.apu = apu;
this.nes = apu.nes;
out_silence = true;
DMC_RATE = pal ? DMC_RATE_PAL : DMC_RATE_NTSC;
timer_reload = DMC_RATE[0];
timer = 1021; // confirmed in VisualNES although aligning controller read glitches still doesn't work
timer = 1020; // confirmed in VisualNES although aligning controller read glitches still doesn't work
sample_buffer_filled = false;
out_deltacounter = 64;
out_bits_remaining = 7; //confirmed in VisualNES
@ -732,7 +734,11 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
if (!apu.call_from_write)
{
// when called due to empty bueffer while DMC running, there is no delay
delay = 1;
delay = 0;
nes.cpu.RDY = false;
nes.dmc_dma_exec = true;
apu.dmc_dma_countdown = 3; // 3 here but this actually stops 4 cpu cycles because it starts before the cpu is run
apu.DMC_RDY_check = 2;
}
else
{
@ -763,7 +769,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
}
else
{
apu.dmc_dma_countdown = 3;
apu.DMC_RDY_check = 2;
apu.call_from_write = false;
@ -945,7 +950,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
public PulseUnit[] pulse = new PulseUnit[2];
public TriangleUnit triangle;
public NoiseUnit noise;
private readonly DMCUnit dmc;
public readonly DMCUnit dmc;
private bool irq_pending;
private bool dmc_irq;

View File

@ -282,6 +282,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
private bool resetSignal;
private bool hardResetSignal;
public bool FrameAdvance(IController controller, bool render, bool rendersound)
{
_controller = controller;
@ -454,7 +455,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
{
if (cpu_deadcounter == 0)
{
if (oam_dma_index % 2 == 0)
{
oam_dma_byte = ReadMemory(oam_dma_addr);
@ -465,8 +465,10 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
WriteMemory(0x2004, oam_dma_byte);
}
oam_dma_index++;
if (oam_dma_index == 512) oam_dma_exec = false;
if (oam_dma_index == 512)
{
oam_dma_exec = false;
}
}
else
{
@ -495,7 +497,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
// By this point the cpu should be frozen, if it is not, then we are in a multi-write opcode, add another cycle delay
if (!cpu.RDY && !cpu.rdy_freeze && (apu.dmc_dma_countdown == apu.DMC_RDY_check))
{
//Console.WriteLine("dmc RDY false " + cpu.TotalExecutedCycles + " " + apu.call_from_write + " " + cpu.opcode + " " + oam_dma_exec);
//Console.WriteLine("dmc double " + cpu.TotalExecutedCycles + " " + cpu.opcode + " " + cpu.mi);
apu.dmc_dma_countdown += 2;
apu.DMC_RDY_check = -1;
}
@ -509,9 +511,10 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
dmc_dma_exec = false;
apu.dmc_dma_countdown = -1;
do_the_reread = true;
}
//Console.WriteLine("dmc RDY false " + cpu.TotalExecutedCycles + " " + apu.call_from_write + " " + cpu.opcode);
//Console.WriteLine("dmc RDY false " + cpu.TotalExecutedCycles + " " + (apu.dmc.timer & 1));
}
//Console.WriteLine("dmc RDY false " + cpu.TotalExecutedCycles + " " + cpu.opcode + " " + cpu.mi + " " + apu.dmc_dma_countdown);
}
/////////////////////////////
@ -598,14 +601,15 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
{
// special hardware glitch case
ret_spec = read_joyport(addr);
if (do_the_reread && ppu.region==PPU.Region.NTSC)
{
ret_spec = read_joyport(addr);
do_the_reread = false;
Console.WriteLine("DMC glitch player 1");
do_the_reread = false;
Console.WriteLine("DMC glitch player 1 ");
}
return ret_spec;
return ret_spec;
}
case 0x4017:
if (_isVS)
@ -617,7 +621,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
ret = (byte)(ret | (VS_dips[2] << 2) | (VS_dips[3] << 3) | (VS_dips[4] << 4) | (VS_dips[5] << 5) | (VS_dips[6] << 6) | (VS_dips[7] << 7));
return ret;
}
else
{
@ -714,7 +717,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
sprdma_countdown--;
if (sprdma_countdown == 0)
{
if (cpu.TotalExecutedCycles % 2 == 0)
if (apu.dmc.timer % 2 == 0)
{
cpu_deadcounter = 2;
}

View File

@ -288,8 +288,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
private Bit Reg2002_objoverflow; //Sprite overflow. The PPU can handle only eight sprites on one scanline and sets this bit if it starts drawing sprites.
private Bit Reg2002_objhit; //Sprite 0 overlap. Set when a nonzero pixel of sprite 0 is drawn overlapping a nonzero background pixel. Used for raster timing.
private Bit Reg2002_vblank_active; //Vertical blank start (0: has not started; 1: has started)
private bool Reg2002_vblank_active_pending; //set if Reg2002_vblank_active is pending
public Bit Reg2002_vblank_active; //Vertical blank start (0: has not started; 1: has started)
public bool Reg2002_vblank_active_pending; //set if Reg2002_vblank_active is pending
private bool Reg2002_vblank_clear_pending; //ppu's clear of vblank flag is pending
public PPUREGS ppur;
public Reg_2000 reg_2000;

View File

@ -133,7 +133,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
private bool nmi_destiny;
private bool evenOddDestiny;
private int start_up_offset;
public int start_up_offset;
private int NMI_offset;
private int yp_shift;
private int sprite_eval_cycle;
@ -532,7 +532,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
{
if (ppu_was_on_spr && !PPUON)
{
Console.WriteLine("oam addr glitch " + ppur.status.sl + " " + ppur.status.cycle);
//Console.WriteLine("oam addr glitch " + ppur.status.sl + " " + ppur.status.cycle);
reg_2003++;
}
}