Merge pull request #659 from alyosha-tas/master

Pass a few more tests
This commit is contained in:
alyosha-tas 2016-07-01 22:32:19 -04:00 committed by GitHub
commit b788870fe6
5 changed files with 109 additions and 40 deletions

View File

@ -156,7 +156,17 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
//if (unit == 1) Console.WriteLine("{0} timer_reload_value: {1}", unit, timer_reload_value);
break;
case 3:
len_cnt = LENGTH_TABLE[(val >> 3) & 0x1F];
if (apu.len_clock_active)
{
if (len_cnt==0)
{
len_cnt = LENGTH_TABLE[(val >> 3) & 0x1F]+1;
}
} else
{
len_cnt = LENGTH_TABLE[(val >> 3) & 0x1F];
}
timer_reload_value = (timer_reload_value & 0xFF) | ((val & 0x07) << 8);
timer_raw_reload_value = timer_reload_value * 2 + 2;
//duty_step = 0; //?just a guess?
@ -165,6 +175,9 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
//allow the lenctr_en to kill the len_cnt
set_lenctr_en(lenctr_en);
//serves as a useful note-on diagnostic
//if(unit==1) Console.WriteLine("{0} timer_reload_value: {1}", unit, timer_reload_value);
@ -432,7 +445,18 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
//Console.WriteLine("noise period: {0}, vol: {1}", (val & 0xF), env_cnt_value);
break;
case 3:
len_cnt = LENGTH_TABLE[(val >> 3) & 0x1F];
if (apu.len_clock_active)
{
if (len_cnt == 0)
{
len_cnt = LENGTH_TABLE[(val >> 3) & 0x1F] + 1;
}
}
else
{
len_cnt = LENGTH_TABLE[(val >> 3) & 0x1F];
}
set_lenctr_en(lenctr_en);
env_start_flag = 1;
break;
@ -574,7 +598,17 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
case 3:
timer_cnt = (timer_cnt & 0xFF) | ((val & 0x7) << 8);
timer_cnt_reload = timer_cnt + 1;
len_cnt = LENGTH_TABLE[(val >> 3) & 0x1F];
if (apu.len_clock_active)
{
if (len_cnt == 0)
{
len_cnt = LENGTH_TABLE[(val >> 3) & 0x1F] + 1;
}
}
else
{
len_cnt = LENGTH_TABLE[(val >> 3) & 0x1F];
}
halt_flag = 1;
//allow the lenctr_en to kill the len_cnt
@ -963,6 +997,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
ser.Sync("sequencer_tick_delay", ref seq_tick);
ser.Sync("seq_val_to_apply", ref seq_val);
ser.Sync("sequencer_irq_flag", ref sequencer_irq_flag);
ser.Sync("len_clock_active", ref len_clock_active);
pulse[0].SyncState(ser);
@ -984,6 +1019,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
byte pending_val = 0;
public int seq_tick;
public byte seq_val;
public bool len_clock_active;
int sequencer_counter, sequencer_step, sequencer_mode, sequencer_irq_inhibit, sequencer_irq_assert;
bool sequencer_irq, sequence_reset_pending, sequencer_irq_clear_pending, sequencer_irq_flag;
@ -1012,7 +1048,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
//this is probably a hint that we're doing something a little wrong but making up for it with curcuitous chaos in other ways
static int[][] sequencer_lut = new int[][]{
new int[]{7457,14913,22372,29830},
new int[]{7458,14913,22372,29830,37282}
new int[]{7457,14913,22372,29830,37282}
};
@ -1128,7 +1164,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
sequencer_irq = false;
sequencer_irq_flag = false;
_WriteReg(0x4015, 0);
Console.WriteLine(seq_val);
//for 4017, its as if the last value written gets rewritten
sequencer_mode = (seq_val >> 7) & 1;
sequencer_irq_inhibit = (seq_val >> 6) & 1;
@ -1283,13 +1319,24 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
EmitSample();
//we need to predict if there will be a length clock here, because the sequencer ticks last, but the
// timer reload shouldn't happen if length clock and write happen simultaneously
// I'm not sure if we can avoid this by simply processing the sequencer first
// but at the moment that would break everything, so this is good enough for now
if (sequencer_counter==14912 ||
(sequencer_counter == 29828 && sequencer_mode==0) ||
(sequencer_counter == 37280 && sequencer_mode == 1))
{
len_clock_active = true;
}
//handle writes
//notes: this set up is a bit convoluded at the moment, mainly because APU behaviour is not entirely understood
//in partiuclar, there are several clock pulses affecting the APU, and when new written are latched is not known in detail
//the current code simply matches known behaviour
if (pending_reg != -1)
{
if (pending_reg == 4015 || pending_reg == 4017)
if (pending_reg == 0x4015 || pending_reg == 0x4017 || pending_reg==0x4003)
{
_WriteReg(pending_reg, pending_val);
pending_reg = -1;
@ -1301,7 +1348,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
}
}
len_clock_active = false;
sequencer_tick();
sequencer_write_tick(seq_val);
@ -1327,39 +1375,14 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
SyncIRQ();
nes.irq_apu = irq_pending;
if (sequencer_irq_flag == false)
sequencer_irq = false;
/*
//this (and the similar line below) is a crude hack
//we should be generating logic to suppress the $4015 clear when the assert signal is set instead
//be sure to test "apu_test" if you mess with this
//sequencer_irq |= sequencer_irq_assert;
//if (toggle == 0)
//{
//handle sequencer irq clear signal
sequencer_irq_assert = false;
if (sequencer_irq_clear_pending)
{
//Console.WriteLine("{0} {1,5} $4017 clear irq (delayed)", nes.Frame, sequencer_counter);
sequencer_irq_clear_pending = false;
sequencer_irq = false;
SyncIRQ();
}
toggle = 1;
//latch whatever irq logic we had and send to cpu
nes.irq_apu = irq_pending;
}
else toggle = 0;
*/
//since the units run concurrently, the APU frame sequencer is ran last because
//it can change the ouput values of the pulse/triangle channels
//we want the changes to affect it on the *next* cycle.
if (sequencer_irq_flag == false)
sequencer_irq = false;
if (DebugCallbackDivider != 0)
{
if (DebugCallbackTimer == 0)

View File

@ -305,6 +305,7 @@ 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;
#if VS2012
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@ -388,6 +389,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
apu.RunDMCFetch();
dmc_dma_exec = false;
apu.dmc_dma_countdown = -1;
do_the_reread = true;
}
}
@ -409,6 +411,12 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
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;
@ -432,6 +440,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
#endif
public byte ReadReg(int addr)
{
byte ret_spec;
switch (addr)
{
case 0x4000: case 0x4001: case 0x4002: case 0x4003:
@ -444,6 +453,17 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
case 0x4014: /*OAM DMA*/ break;
case 0x4015: return (byte)((byte)(apu.ReadReg(addr) & 0xDF) + (byte)(DB&0x20));
case 0x4016:
{
// special hardware glitch case
ret_spec = read_joyport(addr);
if (do_the_reread)
{
ret_spec = read_joyport(addr);
do_the_reread = false;
}
return ret_spec;
}
case 0x4017:
return read_joyport(addr);
default:

View File

@ -71,9 +71,10 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
ser.Sync("dmc_realign", ref dmc_realign);
ser.Sync("IRQ_delay", ref IRQ_delay);
ser.Sync("special_case_delay", ref special_case_delay);
ser.Sync("do_the_reread", ref do_the_reread);
ser.BeginSection("Board");
ser.BeginSection("Board");
Board.SyncState(ser);
if (Board is NESBoardBase && !((NESBoardBase)Board).SyncStateFlag)
throw new InvalidOperationException("the current NES mapper didnt call base.SyncState");

View File

@ -161,6 +161,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
ser.Sync("soam_index", ref soam_index);
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("OAM", ref OAM, false);

View File

@ -58,6 +58,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
// this byte is used to simulate open bus reads and writes
// it should be modified by every read and write to a ppu register
public byte ppu_open_bus;
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 struct PPUSTATUS
@ -354,8 +355,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
//printf("%04x:$%02x, %d\n",A,V,scanline);
reg_2001.Value = value;
}
byte read_2001() { return ppu_open_bus; }
byte peek_2001() { return ppu_open_bus; }
byte read_2001() {return ppu_open_bus; }
byte peek_2001() {return ppu_open_bus; }
//PPU STATUS (read)
void write_2002(byte value) { }
@ -585,10 +586,32 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
public byte ReadReg(int addr)
{
byte ret_spec;
switch (addr)
{
case 0: return read_2000(); case 1: return read_2001(); case 2: return read_2002(); case 3: return read_2003();
case 4: return read_2004(); case 5: return read_2005(); case 6: return read_2006(); case 7: return read_2007();
case 4: return read_2004(); case 5: return read_2005(); case 6: return read_2006();
case 7:
{
if (double_2007_read>0)
{
double_2007_read = 0;
return ppu_open_bus;
} else
{
ret_spec = read_2007();
double_2007_read = 2;
}
if (nes.do_the_reread)
{
ret_spec = read_2007();
ret_spec = read_2007();
nes.do_the_reread = false;
}
return ret_spec;
}
default: throw new InvalidOperationException();
}
}
@ -605,6 +628,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
{
PPUGenLatch = value;
ppu_open_bus = value;
switch (addr)
{
case 0: write_2000(value); break; case 1: write_2001(value); break; case 2: write_2002(value); break; case 3: write_2003(value); break;