NESHawk: more DMC work
This commit is contained in:
parent
01c0560c89
commit
9d8a80026e
|
@ -660,7 +660,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
|
|||
public DMCUnit(APU apu, bool pal)
|
||||
{
|
||||
this.apu = apu;
|
||||
this.nes = apu.nes;
|
||||
nes = apu.nes;
|
||||
out_silence = true;
|
||||
DMC_RATE = pal ? DMC_RATE_PAL : DMC_RATE_NTSC;
|
||||
timer_reload = DMC_RATE[0];
|
||||
|
@ -668,26 +668,28 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
|
|||
sample_buffer_filled = false;
|
||||
out_deltacounter = 64;
|
||||
out_bits_remaining = 7; //confirmed in VisualNES
|
||||
user_address = 0x8000; // even though this can't be accessed by writing, it is indeed the power up address
|
||||
user_address = 0xC000; // even though this can't be accessed by writing, it is indeed the power up address
|
||||
sample_address = 0xC000;
|
||||
user_length = 1;
|
||||
}
|
||||
|
||||
private bool irq_enabled;
|
||||
private bool loop_flag;
|
||||
private int timer_reload;
|
||||
public int timer_reload;
|
||||
|
||||
// dmc delay per visual 2a03
|
||||
private int delay;
|
||||
public int delay;
|
||||
|
||||
// this timer never stops, ever, so it is convenient to use for even/odd timing used elsewhere
|
||||
public int timer;
|
||||
private int user_address;
|
||||
public uint user_length, sample_length;
|
||||
private int sample_address, sample_buffer;
|
||||
public int sample_address, sample_buffer;
|
||||
private bool sample_buffer_filled;
|
||||
|
||||
private int out_shift, out_bits_remaining, out_deltacounter;
|
||||
public int out_shift, out_bits_remaining, out_deltacounter;
|
||||
private bool out_silence;
|
||||
public bool fill_glitch;
|
||||
|
||||
public int sample => out_deltacounter /* - 64*/;
|
||||
|
||||
|
@ -711,6 +713,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
|
|||
ser.Sync(nameof(out_bits_remaining), ref out_bits_remaining);
|
||||
ser.Sync(nameof(out_deltacounter), ref out_deltacounter);
|
||||
ser.Sync(nameof(out_silence), ref out_silence);
|
||||
ser.Sync(nameof(fill_glitch), ref fill_glitch);
|
||||
|
||||
ser.Sync(nameof(delay), ref delay);
|
||||
|
||||
|
@ -729,15 +732,15 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
|
|||
|
||||
// Any time the sample buffer is in an empty state and bytes remaining is not zero, the following occur:
|
||||
// also note that the halt for DMC DMA occurs on APU cycles only (hence the timer check)
|
||||
if (!sample_buffer_filled && sample_length > 0 && apu.dmc_dma_countdown == -1 && delay==0)
|
||||
if (!sample_buffer_filled && sample_length > 0 && apu.dmc_dma_countdown == -1 && delay==0)
|
||||
{
|
||||
if (!apu.call_from_write)
|
||||
{
|
||||
// when called due to empty bueffer while DMC running, there is no delay
|
||||
delay = 0;
|
||||
//delay = 1;
|
||||
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_dma_countdown = 3;
|
||||
apu.DMC_RDY_check = 2;
|
||||
}
|
||||
else
|
||||
|
@ -750,7 +753,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
|
|||
else
|
||||
{
|
||||
delay = 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -762,7 +765,13 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
|
|||
delay--;
|
||||
if (delay == 0)
|
||||
{
|
||||
if (!apu.call_from_write)
|
||||
if (fill_glitch)
|
||||
{
|
||||
//fill_glitch = false;
|
||||
apu.dmc_dma_countdown = 1;
|
||||
apu.DMC_RDY_check = -1;
|
||||
}
|
||||
else if (!apu.call_from_write)
|
||||
{
|
||||
apu.dmc_dma_countdown = 4;
|
||||
apu.DMC_RDY_check = 2;
|
||||
|
@ -825,11 +834,13 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
|
|||
|
||||
public void set_lenctr_en(bool en)
|
||||
{
|
||||
if (!en)
|
||||
// should this be delayed by two/three cycles?
|
||||
|
||||
if(!en)
|
||||
{
|
||||
// If the DMC bit is clear, the DMC bytes remaining will be set to 0
|
||||
// and the DMC will silence when it empties.
|
||||
sample_length = 0;
|
||||
sample_length = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -892,6 +903,9 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
|
|||
sample_buffer = apu.nes.ReadMemory((ushort)sample_address);
|
||||
sample_buffer_filled = true;
|
||||
sample_address = (ushort)(sample_address + 1);
|
||||
|
||||
//sample address wraps to 0xC000
|
||||
if (sample_address == 0) { sample_address = 0xC000;}
|
||||
// Console.WriteLine(sample_length);
|
||||
// Console.WriteLine(user_length);
|
||||
sample_length--;
|
||||
|
|
|
@ -442,7 +442,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
|
|||
public bool dmc_realign;
|
||||
public bool IRQ_delay;
|
||||
public bool special_case_delay; // very ugly but the only option
|
||||
public bool do_the_reread;
|
||||
public bool reread_trigger;
|
||||
public int do_the_reread_2002, do_the_reread_2007, do_the_reread_cont_1, do_the_reread_cont_2;
|
||||
public byte DB; //old data bus values from previous reads
|
||||
|
||||
internal void RunCpuOne()
|
||||
|
@ -489,7 +490,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
|
|||
|
||||
if (apu.dmc_dma_countdown > 0)
|
||||
{
|
||||
if (apu.dmc_dma_countdown == 1)
|
||||
if (apu.dmc_dma_countdown == 1 && !apu.dmc.fill_glitch)
|
||||
{
|
||||
dmc_realign = true;
|
||||
}
|
||||
|
@ -507,14 +508,47 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
|
|||
apu.dmc_dma_countdown--;
|
||||
if (apu.dmc_dma_countdown == 0)
|
||||
{
|
||||
apu.RunDMCFetch();
|
||||
if (!apu.dmc.fill_glitch)
|
||||
{
|
||||
reread_trigger = true;
|
||||
// if the DMA address has the same bits set as the re-read address, they don't occur
|
||||
if ((apu.dmc.sample_address & 0x2007) != 0x2002)
|
||||
{
|
||||
do_the_reread_2002++;
|
||||
}
|
||||
|
||||
if ((apu.dmc.sample_address & 0x2007) != 0x2007)
|
||||
{
|
||||
do_the_reread_2007++;
|
||||
}
|
||||
|
||||
if ((apu.dmc.sample_address & 0x401F) != 0x4016)
|
||||
{
|
||||
do_the_reread_cont_1++;
|
||||
}
|
||||
|
||||
if ((apu.dmc.sample_address & 0x401F) != 0x4017)
|
||||
{
|
||||
do_the_reread_cont_2++;
|
||||
}
|
||||
|
||||
apu.RunDMCFetch();
|
||||
}
|
||||
|
||||
dmc_dma_exec = false;
|
||||
apu.dmc_dma_countdown = -1;
|
||||
do_the_reread = true;
|
||||
|
||||
//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);
|
||||
apu.dmc.fill_glitch = false;
|
||||
/*
|
||||
//if (apu.dmc.timer == (apu.dmc.timer_reload-0) && apu.dmc.out_bits_remaining == 7)
|
||||
//if (apu.dmc.timer == 2 && apu.dmc.out_bits_remaining == 0)
|
||||
{
|
||||
Console.WriteLine("close " + cpu.TotalExecutedCycles + " " + apu.dmc.timer + " " + apu.dmc.sample_length);
|
||||
apu.dmc.fill_glitch = true;
|
||||
apu.dmc.delay = 3;
|
||||
}
|
||||
*/
|
||||
//Console.WriteLine("dmc RDY false " + cpu.TotalExecutedCycles + " " + cpu.opcode + " " + cpu.mi + " " + apu.dmc.timer);
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////
|
||||
|
@ -528,7 +562,9 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
|
|||
}
|
||||
else if (special_case_delay || apu.dmc_dma_countdown == 3)
|
||||
{
|
||||
|
||||
cpu.IRQ = _irq_apu || Board.IrqSignal;
|
||||
//if (cpu.IRQ) { Console.WriteLine("something IRQ"); }
|
||||
special_case_delay = false;
|
||||
}
|
||||
|
||||
|
@ -546,8 +582,15 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
|
|||
|
||||
apu.RunOneLast();
|
||||
|
||||
if (do_the_reread && cpu.RDY)
|
||||
do_the_reread = false;
|
||||
if (reread_trigger && cpu.RDY)
|
||||
{
|
||||
do_the_reread_2002 = 0;
|
||||
do_the_reread_2007 = 0;
|
||||
do_the_reread_cont_1 = 0;
|
||||
do_the_reread_cont_2 = 0;
|
||||
reread_trigger = false;
|
||||
}
|
||||
|
||||
|
||||
IRQ_delay = false;
|
||||
|
||||
|
@ -602,11 +645,14 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
|
|||
// special hardware glitch case
|
||||
ret_spec = read_joyport(addr);
|
||||
|
||||
if (do_the_reread && ppu.region==PPU.Region.NTSC)
|
||||
//if (reread_trigger && (do_the_reread_cont_1 == 0)) { Console.WriteLine("same 1 " + (apu.dmc.sample_address - 1)); }
|
||||
|
||||
if ((do_the_reread_cont_1 > 0) && ppu.region==PPU.Region.NTSC)
|
||||
{
|
||||
ret_spec = read_joyport(addr);
|
||||
do_the_reread = false;
|
||||
Console.WriteLine("DMC glitch player 1 ");
|
||||
do_the_reread_cont_1--;
|
||||
if (do_the_reread_cont_1 > 0) { ret_spec = read_joyport(addr); }
|
||||
//Console.WriteLine("DMC glitch player 1 " + cpu.TotalExecutedCycles + " addr " + (apu.dmc.sample_address - 1));
|
||||
}
|
||||
|
||||
return ret_spec;
|
||||
|
@ -626,12 +672,17 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
|
|||
{
|
||||
// special hardware glitch case
|
||||
ret_spec = read_joyport(addr);
|
||||
if (do_the_reread && ppu.region == PPU.Region.NTSC)
|
||||
|
||||
//if (reread_trigger && (do_the_reread_cont_2 == 0)) { Console.WriteLine("same 2 " + (apu.dmc.sample_address - 1)); }
|
||||
|
||||
if ((do_the_reread_cont_2 > 0) && ppu.region == PPU.Region.NTSC)
|
||||
{
|
||||
ret_spec = read_joyport(addr);
|
||||
do_the_reread = false;
|
||||
Console.WriteLine("DMC glitch player 2");
|
||||
do_the_reread_cont_2--;
|
||||
if (do_the_reread_cont_2 > 0) { ret_spec = read_joyport(addr); }
|
||||
//Console.WriteLine("DMC glitch player 2 " + cpu.TotalExecutedCycles + " addr " + (apu.dmc.sample_address - 1));
|
||||
}
|
||||
|
||||
return ret_spec;
|
||||
}
|
||||
default:
|
||||
|
|
|
@ -31,7 +31,11 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
|
|||
ser.Sync(nameof(dmc_realign), ref dmc_realign);
|
||||
ser.Sync(nameof(IRQ_delay), ref IRQ_delay);
|
||||
ser.Sync(nameof(special_case_delay), ref special_case_delay);
|
||||
ser.Sync(nameof(do_the_reread), ref do_the_reread);
|
||||
ser.Sync(nameof(reread_trigger), ref reread_trigger);
|
||||
ser.Sync(nameof(do_the_reread_2002), ref do_the_reread_2002);
|
||||
ser.Sync(nameof(do_the_reread_2007), ref do_the_reread_2007);
|
||||
ser.Sync(nameof(do_the_reread_cont_1), ref do_the_reread_cont_1);
|
||||
ser.Sync(nameof(do_the_reread_cont_2), ref do_the_reread_cont_2);
|
||||
|
||||
// VS related
|
||||
ser.Sync("VS", ref _isVS);
|
||||
|
|
|
@ -345,12 +345,24 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
|
|||
private byte read_2002()
|
||||
{
|
||||
byte ret = peek_2002();
|
||||
|
||||
|
||||
if (nes.do_the_reread_2002 > 0)
|
||||
{
|
||||
if (Reg2002_vblank_active || Reg2002_vblank_active_pending)
|
||||
Console.WriteLine("reread 2002");
|
||||
}
|
||||
|
||||
// reading from $2002 resets the destination for $2005 and $2006 writes
|
||||
vtoggle = false;
|
||||
Reg2002_vblank_active = 0;
|
||||
Reg2002_vblank_active_pending = false;
|
||||
|
||||
if (nes.do_the_reread_2002 > 0)
|
||||
{
|
||||
ret = peek_2002();
|
||||
// could be another reread, but no other side effects, so don't bother
|
||||
}
|
||||
|
||||
// update the open bus here
|
||||
ppu_open_bus = ret;
|
||||
PpuOpenBusDecay(DecayType.High);
|
||||
|
@ -679,11 +691,11 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
|
|||
double_2007_read = nes.cpu.TotalExecutedCycles + 1;
|
||||
}
|
||||
|
||||
if (nes.do_the_reread)
|
||||
if (nes.do_the_reread_2007 > 0)
|
||||
{
|
||||
ret_spec = read_2007();
|
||||
ret_spec = read_2007();
|
||||
nes.do_the_reread = false;
|
||||
// always 2?
|
||||
}
|
||||
return ret_spec;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue