parent
a69640e745
commit
663aded7b2
|
@ -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)
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue