commit
627197aac6
|
@ -29,6 +29,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
|
|||
public int NoiseV = 247;
|
||||
public int DMCV = 167;
|
||||
|
||||
public int dmc_dma_countdown=-1;
|
||||
|
||||
public bool recalculate = false;
|
||||
|
||||
NES nes;
|
||||
|
@ -677,6 +679,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
|
|||
out_silence = true;
|
||||
DMC_RATE = pal ? DMC_RATE_PAL : DMC_RATE_NTSC;
|
||||
timer_reload = DMC_RATE[0];
|
||||
timer = timer_reload;
|
||||
sample_buffer_filled = false;
|
||||
out_deltacounter = 64;
|
||||
out_bits_remaining = 0;
|
||||
|
@ -687,8 +690,9 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
|
|||
int timer_reload;
|
||||
|
||||
int timer;
|
||||
int user_address, user_length;
|
||||
int sample_address, sample_length, sample_buffer;
|
||||
int user_address;
|
||||
uint user_length, sample_length;
|
||||
int sample_address, sample_buffer;
|
||||
bool sample_buffer_filled;
|
||||
|
||||
int out_shift, out_bits_remaining, out_deltacounter;
|
||||
|
@ -731,9 +735,10 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
|
|||
Clock();
|
||||
}
|
||||
|
||||
//Any time the sample buffer is in an empty state and bytes remaining is not zero, the following occur:
|
||||
if (!sample_buffer_filled && sample_length > 0)
|
||||
Fetch();
|
||||
//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 && timer % 2 == 1 && apu.dmc_dma_countdown==-1)
|
||||
apu.dmc_dma_countdown = 5;
|
||||
}
|
||||
|
||||
|
||||
|
@ -798,11 +803,12 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
|
|||
else
|
||||
{
|
||||
//only start playback if playback is stopped
|
||||
//Console.Write(sample_length); Console.Write(" "); Console.Write(sample_buffer_filled); Console.Write(" "); Console.Write(apu.dmc_irq); Console.Write("\n");
|
||||
if (sample_length == 0)
|
||||
{
|
||||
sample_address = user_address;
|
||||
sample_length = user_length;
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -837,7 +843,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
|
|||
user_address = 0xC000 | (val << 6);
|
||||
break;
|
||||
case 3:
|
||||
user_length = (val << 4) + 1;
|
||||
user_length = ((uint)val << 4) + 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -845,10 +851,15 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
|
|||
public void Fetch()
|
||||
{
|
||||
//TODO - cpu/apu DMC reads need to be emulated better!
|
||||
sample_buffer = apu.nes.ReadMemory((ushort)sample_address);
|
||||
sample_buffer_filled = true;
|
||||
sample_address = (ushort)(sample_address + 1);
|
||||
sample_length--;
|
||||
if (sample_length != 0)
|
||||
{
|
||||
sample_buffer = apu.nes.ReadMemory((ushort)sample_address);
|
||||
sample_buffer_filled = true;
|
||||
sample_address = (ushort)(sample_address + 1);
|
||||
//Console.WriteLine(sample_length);
|
||||
//Console.WriteLine(user_length);
|
||||
sample_length--;
|
||||
}
|
||||
if (sample_length == 0)
|
||||
{
|
||||
if (loop_flag)
|
||||
|
@ -878,6 +889,10 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
|
|||
ser.Sync("sequencer_irq_clear_pending", ref sequencer_irq_clear_pending);
|
||||
ser.Sync("sequencer_irq_assert", ref sequencer_irq_assert);
|
||||
|
||||
ser.Sync("dmc_dma_countdown", ref dmc_dma_countdown);
|
||||
ser.Sync("toggle", ref toggle);
|
||||
|
||||
|
||||
pulse[0].SyncState(ser);
|
||||
pulse[1].SyncState(ser);
|
||||
triangle.SyncState(ser);
|
||||
|
@ -1042,6 +1057,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
|
|||
triangle.set_lenctr_en((val >> 2) & 1);
|
||||
noise.set_lenctr_en((val >> 3) & 1);
|
||||
dmc.set_lenctr_en(val.Bit(4));
|
||||
|
||||
}
|
||||
else if (addr == 0x4017)
|
||||
{
|
||||
|
@ -1150,14 +1166,15 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
|
|||
//it can change the ouput values of the pulse/triangle channels
|
||||
//we want the changes to affect it on the *next* cycle.
|
||||
|
||||
if(DebugCallbackDivider != 0)
|
||||
if (DebugCallbackDivider != 0)
|
||||
{
|
||||
if(DebugCallbackTimer==0)
|
||||
if (DebugCallbackTimer == 0)
|
||||
{
|
||||
if(DebugCallback != null)
|
||||
if (DebugCallback != null)
|
||||
DebugCallback();
|
||||
DebugCallbackTimer = DebugCallbackDivider;
|
||||
} else DebugCallbackTimer--;
|
||||
}
|
||||
else DebugCallbackTimer--;
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -317,15 +317,36 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
|
|||
cpu_deadcounter += 514;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (apu.dmc_dma_countdown>0)
|
||||
{
|
||||
cpu.RDY = false;
|
||||
apu.dmc_dma_countdown--;
|
||||
if (apu.dmc_dma_countdown==0)
|
||||
{
|
||||
apu.RunDMCFetch();
|
||||
cpu.RDY = true;
|
||||
}
|
||||
|
||||
if (apu.dmc_dma_countdown==0)
|
||||
{
|
||||
|
||||
|
||||
apu.dmc_dma_countdown = -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (cpu_deadcounter > 0)
|
||||
{
|
||||
cpu_deadcounter--;
|
||||
else
|
||||
}
|
||||
else
|
||||
{
|
||||
cpu.IRQ = _irq_apu || Board.IRQSignal;
|
||||
cpu.ExecuteOne();
|
||||
}
|
||||
|
||||
ppu.ppu_open_bus_decay(0);
|
||||
apu.RunOne();
|
||||
Board.ClockCPU();
|
||||
ppu.PostCpuInstructionOne();
|
||||
|
|
|
@ -157,8 +157,13 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
|
|||
ser.Sync("Prev_soam_index", ref soam_index_prev);
|
||||
ser.Sync("Spr_Zero_Go", ref sprite_zero_go);
|
||||
ser.Sync("Spr_zero_in_Range", ref sprite_zero_in_range);
|
||||
ser.Sync("Is_even_cycle", ref is_even_cycle);
|
||||
ser.Sync("soam_index", ref soam_index);
|
||||
|
||||
ser.Sync("OAM", ref OAM, false);
|
||||
ser.Sync("ppu_open_bus", ref ppu_open_bus);
|
||||
ser.Sync("ppu_open_bus_decay_timer", ref ppu_open_bus_decay_timer, false);
|
||||
|
||||
ser.Sync("OAM", ref OAM, false);
|
||||
ser.Sync("PALRAM", ref PALRAM, false);
|
||||
|
||||
ser.Sync("Reg2002_objoverflow", ref Reg2002_objoverflow);
|
||||
|
@ -181,6 +186,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
|
|||
regs_reset();
|
||||
ppudead = 2;
|
||||
idleSynch = true;
|
||||
ppu_open_bus = 0;
|
||||
ppu_open_bus_decay_timer = new int[8];
|
||||
}
|
||||
|
||||
#if VS2012
|
||||
|
|
|
@ -55,6 +55,10 @@ 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[] ppu_open_bus_decay_timer = new int[8];
|
||||
|
||||
public struct PPUSTATUS
|
||||
{
|
||||
|
@ -338,9 +342,11 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
|
|||
NMI_PendingInstructions = 2;
|
||||
}
|
||||
reg_2000.Value = value;
|
||||
|
||||
|
||||
}
|
||||
byte read_2000() { return PPUGenLatch; }
|
||||
byte peek_2000() { return PPUGenLatch; }
|
||||
byte read_2000() { return ppu_open_bus; }
|
||||
byte peek_2000() { return ppu_open_bus; }
|
||||
|
||||
//PPU MASK (write)
|
||||
void write_2001(byte value)
|
||||
|
@ -348,8 +354,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
|
|||
//printf("%04x:$%02x, %d\n",A,V,scanline);
|
||||
reg_2001.Value = value;
|
||||
}
|
||||
byte read_2001() { return PPUGenLatch; }
|
||||
byte peek_2001() { return PPUGenLatch; }
|
||||
byte read_2001() { return ppu_open_bus; }
|
||||
byte peek_2001() { return ppu_open_bus; }
|
||||
|
||||
//PPU STATUS (read)
|
||||
void write_2002(byte value) { }
|
||||
|
@ -365,11 +371,14 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
|
|||
Reg2002_vblank_active = 0;
|
||||
Reg2002_vblank_active_pending = false;
|
||||
|
||||
// update the open bus here
|
||||
ppu_open_bus = ret;
|
||||
ppu_open_bus_decay(2);
|
||||
return ret;
|
||||
}
|
||||
byte peek_2002()
|
||||
{
|
||||
return (byte)((Reg2002_vblank_active << 7) | (Reg2002_objhit << 6) | (Reg2002_objoverflow << 5) | (PPUGenLatch & 0x1F));
|
||||
return (byte)((Reg2002_vblank_active << 7) | (Reg2002_objhit << 6) | (Reg2002_objoverflow << 5) | (ppu_open_bus & 0x1F));
|
||||
}
|
||||
|
||||
void clear_2002()
|
||||
|
@ -384,8 +393,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
|
|||
//just record the oam buffer write target
|
||||
reg_2003 = value;
|
||||
}
|
||||
byte read_2003() { return PPUGenLatch; }
|
||||
byte peek_2003() { return PPUGenLatch; }
|
||||
byte read_2003() { return ppu_open_bus; }
|
||||
byte peek_2003() { return ppu_open_bus; }
|
||||
|
||||
//OAM DATA (write)
|
||||
void write_2004(byte value)
|
||||
|
@ -397,37 +406,41 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
|
|||
}
|
||||
byte read_2004()
|
||||
{
|
||||
// behaviour depends on whether things are being rendered or not
|
||||
byte ret;
|
||||
// behaviour depends on whether things are being rendered or not
|
||||
if (reg_2001.show_bg || reg_2001.show_obj)
|
||||
{
|
||||
if (ppur.status.sl < 241)
|
||||
{
|
||||
if (ppur.status.cycle < 64)
|
||||
{
|
||||
return 0xFF; // during this time all reads return FF
|
||||
ret = 0xFF; // during this time all reads return FF
|
||||
}
|
||||
else if (ppur.status.cycle < 256)
|
||||
{
|
||||
return read_value;
|
||||
ret = read_value;
|
||||
}
|
||||
else if (ppur.status.cycle < 320)
|
||||
{
|
||||
return read_value;
|
||||
ret = read_value;
|
||||
}
|
||||
else
|
||||
{
|
||||
return soam[0];
|
||||
ret = soam[0];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return OAM[reg_2003];
|
||||
ret = OAM[reg_2003];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return OAM[reg_2003];
|
||||
ret = OAM[reg_2003];
|
||||
}
|
||||
ppu_open_bus = ret;
|
||||
ppu_open_bus_decay(1);
|
||||
return ret;
|
||||
}
|
||||
byte peek_2004() { return OAM[reg_2003]; }
|
||||
|
||||
|
@ -448,8 +461,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
|
|||
}
|
||||
vtoggle ^= true;
|
||||
}
|
||||
byte read_2005() { return PPUGenLatch; }
|
||||
byte peek_2005() { return PPUGenLatch; }
|
||||
byte read_2005() { return ppu_open_bus; }
|
||||
byte peek_2005() { return ppu_open_bus; }
|
||||
|
||||
//VRAM address register (write)
|
||||
void write_2006(byte value)
|
||||
|
@ -479,8 +492,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
|
|||
|
||||
vtoggle ^= true;
|
||||
}
|
||||
byte read_2006() { return PPUGenLatch; }
|
||||
byte peek_2006() { return PPUGenLatch; }
|
||||
byte read_2006() { return ppu_open_bus; }
|
||||
byte peek_2006() { return ppu_open_bus; }
|
||||
|
||||
//VRAM data register (r/w)
|
||||
void write_2007(byte value)
|
||||
|
@ -516,7 +529,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
|
|||
byte read_2007()
|
||||
{
|
||||
int addr = ppur.get_2007access() & 0x3FFF;
|
||||
|
||||
int bus_case = 0;
|
||||
//ordinarily we return the buffered values
|
||||
byte ret = VRAMBuffer;
|
||||
|
||||
|
@ -527,14 +540,25 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
|
|||
if ((addr & 0x3F00) == 0x3F00)
|
||||
{
|
||||
//TODO apply greyscale shit?
|
||||
ret = PALRAM[addr & 0x1F];
|
||||
ret = (byte)(PALRAM[addr & 0x1F] + ((byte)(ppu_open_bus & 0xC0)));
|
||||
bus_case = 1;
|
||||
}
|
||||
|
||||
ppur.increment2007(ppur.status.rendering && reg_2001.PPUON, reg_2000.vram_incr32 != 0);
|
||||
|
||||
//see comments in $2006
|
||||
nes.Board.AddressPPU(ppur.get_2007access());
|
||||
|
||||
nes.Board.AddressPPU(ppur.get_2007access());
|
||||
|
||||
// update open bus here
|
||||
ppu_open_bus = ret;
|
||||
if (bus_case==0)
|
||||
{
|
||||
ppu_open_bus_decay(1);
|
||||
} else
|
||||
{
|
||||
ppu_open_bus_decay(3);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
byte peek_2007()
|
||||
|
@ -580,12 +604,64 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
|
|||
public void WriteReg(int addr, byte value)
|
||||
{
|
||||
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;
|
||||
case 4: write_2004(value); break; case 5: write_2005(value); break; case 6: write_2006(value); break; case 7: write_2007(value); break;
|
||||
default: throw new InvalidOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void ppu_open_bus_decay(byte action)
|
||||
{
|
||||
// if there is no action, decrement the timer
|
||||
if (action==0)
|
||||
{
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
if (ppu_open_bus_decay_timer[i] == 0)
|
||||
{
|
||||
ppu_open_bus = (byte)(ppu_open_bus & (0xff - (1 << i)));
|
||||
ppu_open_bus_decay_timer[i] = 1786840; // about 1 second worth of cycles
|
||||
}
|
||||
else
|
||||
{
|
||||
ppu_open_bus_decay_timer[i]--;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// reset the timer for all bits (reg 2004 / 2007 (non-palette)
|
||||
if (action==1)
|
||||
{
|
||||
for (int i=0; i<8; i++)
|
||||
{
|
||||
ppu_open_bus_decay_timer[i] = 1786840;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// reset the timer for high 3 bits (reg 2002)
|
||||
if (action == 2)
|
||||
{
|
||||
ppu_open_bus_decay_timer[7] = 1786840;
|
||||
ppu_open_bus_decay_timer[6] = 1786840;
|
||||
ppu_open_bus_decay_timer[5] = 1786840;
|
||||
}
|
||||
|
||||
// reset the timer for all low 6 bits (reg 2007 (palette))
|
||||
if (action == 3)
|
||||
{
|
||||
for (int i = 0; i < 6; i++)
|
||||
{
|
||||
ppu_open_bus_decay_timer[i] = 1786840;
|
||||
}
|
||||
}
|
||||
// other values of action are reserved for possibly needed expansions, but this passes
|
||||
// ppu_open_bus for now.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -369,7 +369,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
|
|||
//1. is it sprite#0?
|
||||
//2. is the bg pixel nonzero?
|
||||
//then, it is spritehit.
|
||||
Reg2002_objhit |= (sprite_zero_go && s==0 && pixel != 0 && rasterpos < 255);
|
||||
Reg2002_objhit |= (sprite_zero_go && s==0 && pixel != 0 && rasterpos < 255 && reg_2001.show_bg && reg_2001.show_obj);
|
||||
|
||||
//priority handling, if in front of BG:
|
||||
bool drawsprite = !(((t_oam[s].oam_attr & 0x20) != 0) && ((pixel & 3) != 0));
|
||||
|
|
Loading…
Reference in New Issue