proper Peek support in NES and 6502X
This commit is contained in:
parent
5bf33b54a6
commit
aa161d8910
|
@ -41,7 +41,7 @@ namespace BizHawk.Emulation.CPUs.M6502
|
|||
public string State()
|
||||
{
|
||||
int notused;
|
||||
string a = string.Format("{0:X4} {1:X2} {2} ", PC, ReadMemory(PC), Disassemble(PC, out notused)).PadRight(30);
|
||||
string a = string.Format("{0:X4} {1:X2} {2} ", PC, PeekMemory(PC), Disassemble(PC, out notused)).PadRight(30);
|
||||
string b = string.Format("A:{0:X2} X:{1:X2} Y:{2:X2} P:{3:X2} SP:{4:X2} Cy:{5}", A, X, Y, P, S, TotalExecutedCycles);
|
||||
string val = a + b + " ";
|
||||
if (FlagN) val = val + "N";
|
||||
|
@ -167,18 +167,21 @@ namespace BizHawk.Emulation.CPUs.M6502
|
|||
|
||||
public Func<ushort, byte> ReadMemory;
|
||||
public Func<ushort, byte> DummyReadMemory;
|
||||
public Func<ushort, byte> PeekMemory;
|
||||
public Action<ushort, byte> WriteMemory;
|
||||
|
||||
public void SetCallbacks
|
||||
(
|
||||
Func<ushort, byte> ReadMemory,
|
||||
Func<ushort, byte> DummyReadMemory,
|
||||
Func<ushort, byte> PeekMemory,
|
||||
Action<ushort, byte> WriteMemory,
|
||||
Action<System.Runtime.InteropServices.GCHandle> DisposeBuilder
|
||||
)
|
||||
{
|
||||
this.ReadMemory = ReadMemory;
|
||||
this.DummyReadMemory = DummyReadMemory;
|
||||
this.PeekMemory = PeekMemory;
|
||||
this.WriteMemory = WriteMemory;
|
||||
}
|
||||
|
||||
|
|
|
@ -34,6 +34,12 @@ namespace BizHawk.Emulation.CPUs.M6502
|
|||
reads.Enqueue(ret);
|
||||
return ret;
|
||||
},
|
||||
delegate(ushort addr)
|
||||
{
|
||||
byte ret = PeekMemory(addr);
|
||||
reads.Enqueue(ret);
|
||||
return ret;
|
||||
},
|
||||
delegate(ushort addr, byte value)
|
||||
{
|
||||
writes.Enqueue(value);
|
||||
|
@ -108,18 +114,21 @@ namespace BizHawk.Emulation.CPUs.M6502
|
|||
|
||||
public Func<ushort, byte> ReadMemory; //{ set { m.ReadMemory = value; n.ReadMemory = value; } }
|
||||
public Func<ushort, byte> DummyReadMemory; //{ set { m.DummyReadMemory = value; n.DummyReadMemory = value; } }
|
||||
public Func<ushort, byte> PeekMemory; //{ set { m.ReadMemory = value; n.ReadMemory = value; } }
|
||||
public Action<ushort, byte> WriteMemory; //{ set { m.WriteMemory = value; n.WriteMemory = value; } }
|
||||
|
||||
public void SetCallbacks
|
||||
(
|
||||
Func<ushort, byte> ReadMemory,
|
||||
Func<ushort, byte> DummyReadMemory,
|
||||
Func<ushort, byte> PeekMemory,
|
||||
Action<ushort, byte> WriteMemory,
|
||||
Action<System.Runtime.InteropServices.GCHandle> DisposeBuilder
|
||||
)
|
||||
{
|
||||
this.ReadMemory = ReadMemory;
|
||||
this.DummyReadMemory = DummyReadMemory;
|
||||
this.PeekMemory = PeekMemory;
|
||||
this.WriteMemory = WriteMemory;
|
||||
}
|
||||
|
||||
|
|
|
@ -104,6 +104,15 @@ namespace BizHawk
|
|||
return temp;
|
||||
}
|
||||
|
||||
public byte PeekMemory(ushort addr)
|
||||
{
|
||||
//TODO - this is dangerous, because at least, the lag flag can get set by a read
|
||||
|
||||
byte temp = mapper.ReadMemory((ushort)(addr & 0x1FFF));
|
||||
|
||||
return temp;
|
||||
}
|
||||
|
||||
public void WriteMemory(ushort addr, byte value)
|
||||
{
|
||||
mapper.WriteMemory((ushort)(addr & 0x1FFF), value);
|
||||
|
@ -154,6 +163,7 @@ namespace BizHawk
|
|||
//cpu.debug = true;
|
||||
cpu.ReadMemory = ReadMemory;
|
||||
cpu.WriteMemory = WriteMemory;
|
||||
cpu.PeekMemory = PeekMemory;
|
||||
cpu.DummyReadMemory = ReadMemory;
|
||||
|
||||
// Setup TIA
|
||||
|
|
|
@ -926,13 +926,14 @@ namespace BizHawk.Emulation.Consoles.Nintendo
|
|||
}
|
||||
}
|
||||
|
||||
public byte ReadReg(int addr)
|
||||
|
||||
public byte PeekReg(int addr)
|
||||
{
|
||||
switch (addr)
|
||||
{
|
||||
case 0x4015:
|
||||
{
|
||||
//notice a missing bit here. should properly emulate with empty bus
|
||||
//notice a missing bit here. should properly emulate with empty / Data bus
|
||||
//if an interrupt flag was set at the same moment of the read, it will read back as 1 but it will not be cleared.
|
||||
int dmc_nonzero = dmc.IsLenCntNonZero() ? 1 : 0;
|
||||
int noise_nonzero = noise.IsLenCntNonZero() ? 1 : 0;
|
||||
|
@ -940,10 +941,25 @@ namespace BizHawk.Emulation.Consoles.Nintendo
|
|||
int pulse1_nonzero = pulse[1].IsLenCntNonZero() ? 1 : 0;
|
||||
int pulse0_nonzero = pulse[0].IsLenCntNonZero() ? 1 : 0;
|
||||
int ret = ((dmc_irq ? 1 : 0) << 7) | ((sequencer_irq ? 1 : 0) << 6) | (dmc_nonzero << 4) | (noise_nonzero << 3) | (tri_nonzero << 2) | (pulse1_nonzero << 1) | (pulse0_nonzero);
|
||||
return (byte)ret;
|
||||
}
|
||||
default:
|
||||
//don't return 0xFF here or SMB will break
|
||||
return 0x00;
|
||||
}
|
||||
}
|
||||
|
||||
public byte ReadReg(int addr)
|
||||
{
|
||||
switch (addr)
|
||||
{
|
||||
case 0x4015:
|
||||
{
|
||||
byte ret = PeekReg(0x4015);
|
||||
//Console.WriteLine("{0} {1,5} $4015 clear irq, was at {2}", nes.Frame, sequencer_counter, sequencer_irq);
|
||||
sequencer_irq = false;
|
||||
SyncIRQ();
|
||||
return (byte)ret;
|
||||
return ret;
|
||||
}
|
||||
default:
|
||||
//don't return 0xFF here or SMB will break
|
||||
|
|
|
@ -26,6 +26,8 @@ namespace BizHawk.Emulation.Consoles.Nintendo
|
|||
//gets called once per CPU clock; typically for boards with M2 counters
|
||||
void ClockCPU();
|
||||
|
||||
byte PeekCart(int addr);
|
||||
|
||||
byte ReadPRG(int addr);
|
||||
byte ReadPPU(int addr); byte PeekPPU(int addr);
|
||||
void AddressPPU(int addr);
|
||||
|
@ -236,6 +238,28 @@ namespace BizHawk.Emulation.Consoles.Nintendo
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// derived classes should override this if they have peek-unsafe logic
|
||||
/// </summary>
|
||||
public virtual byte PeekCart(int addr)
|
||||
{
|
||||
byte ret;
|
||||
if (addr >= 0x8000)
|
||||
{
|
||||
ret = ReadPRG(addr - 0x8000); //easy optimization, since rom reads are so common, move this up (reordering the rest of these elseifs is not easy)
|
||||
}
|
||||
else if (addr < 0x6000)
|
||||
{
|
||||
ret = ReadEXP(addr - 0x4000);
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = ReadWRAM(addr - 0x6000);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
public virtual byte[] SaveRam
|
||||
{
|
||||
get
|
||||
|
|
|
@ -121,7 +121,7 @@ namespace BizHawk.Emulation.Consoles.Nintendo
|
|||
cpu = new MOS6502X((h) => DisposeList.Add(h));
|
||||
//cpu = new MOS6502X_CPP((h) => DisposeList.Add(h));
|
||||
//cpu = new MOS6502XDouble((h) => DisposeList.Add(h));
|
||||
cpu.SetCallbacks(ReadMemory, ReadMemory, WriteMemory, (h) => DisposeList.Add(h));
|
||||
cpu.SetCallbacks(ReadMemory, ReadMemory, PeekMemory, WriteMemory, (h) => DisposeList.Add(h));
|
||||
cpu.BCD_Enabled = false;
|
||||
ppu = new PPU(this);
|
||||
ram = new byte[0x800];
|
||||
|
@ -303,6 +303,29 @@ namespace BizHawk.Emulation.Consoles.Nintendo
|
|||
return 0xFF;
|
||||
}
|
||||
|
||||
public byte PeekReg(int addr)
|
||||
{
|
||||
switch (addr)
|
||||
{
|
||||
case 0x4000: case 0x4001: case 0x4002: case 0x4003:
|
||||
case 0x4004: case 0x4005: case 0x4006: case 0x4007:
|
||||
case 0x4008: case 0x4009: case 0x400A: case 0x400B:
|
||||
case 0x400C: case 0x400D: case 0x400E: case 0x400F:
|
||||
case 0x4010: case 0x4011: case 0x4012: case 0x4013:
|
||||
return apu.PeekReg(addr);
|
||||
case 0x4014: /*OAM DMA*/ break;
|
||||
case 0x4015: return apu.PeekReg(addr);
|
||||
case 0x4016:
|
||||
case 0x4017:
|
||||
return peek_joyport(addr);
|
||||
default:
|
||||
//Console.WriteLine("read register: {0:x4}", addr);
|
||||
break;
|
||||
|
||||
}
|
||||
return 0xFF;
|
||||
}
|
||||
|
||||
void WriteReg(int addr, byte val)
|
||||
{
|
||||
switch (addr)
|
||||
|
@ -336,14 +359,24 @@ namespace BizHawk.Emulation.Consoles.Nintendo
|
|||
byte read_joyport(int addr)
|
||||
{
|
||||
if (CoreInputComm.InputCallback != null) CoreInputComm.InputCallback();
|
||||
return handle_read_joyport(addr, false);
|
||||
}
|
||||
|
||||
byte peek_joyport(int addr)
|
||||
{
|
||||
return handle_read_joyport(addr, true);
|
||||
}
|
||||
|
||||
byte handle_read_joyport(int addr, bool peek)
|
||||
{
|
||||
//read joystick port
|
||||
//many todos here
|
||||
lagged = false;
|
||||
byte ret;
|
||||
if (addr == 0x4016)
|
||||
ret = ports[vs_io ? 1 : 0].Read();
|
||||
ret = ports[vs_io ? 1 : 0].Read(peek);
|
||||
else
|
||||
ret = ports[vs_io ? 0 : 1].Read();
|
||||
ret = ports[vs_io ? 0 : 1].Read(peek);
|
||||
if (vs_io)
|
||||
{
|
||||
if (addr == 0x4016)
|
||||
|
@ -444,6 +477,39 @@ namespace BizHawk.Emulation.Consoles.Nintendo
|
|||
}
|
||||
}
|
||||
|
||||
public byte PeekMemory(ushort addr)
|
||||
{
|
||||
byte ret;
|
||||
|
||||
if (addr >= 0x4020)
|
||||
{
|
||||
ret = board.PeekCart(addr); //easy optimization, since rom reads are so common, move this up (reordering the rest of these elseifs is not easy)
|
||||
}
|
||||
else if (addr < 0x0800)
|
||||
{
|
||||
ret = ram[addr];
|
||||
}
|
||||
else if (addr < 0x1000)
|
||||
{
|
||||
ret = ram[addr & 0x7FF];
|
||||
}
|
||||
else if (addr < 0x4000)
|
||||
{
|
||||
ret = ppu.ReadReg(addr & 7);
|
||||
}
|
||||
else if (addr < 0x4020)
|
||||
{
|
||||
ret = ReadReg(addr); //we're not rebasing the register just to keep register names canonical
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception("Woopsie-doodle!");
|
||||
ret = 0xFF;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
//old data bus values from previous reads
|
||||
public byte DB;
|
||||
|
||||
|
|
|
@ -247,7 +247,7 @@ namespace BizHawk.Emulation.Consoles.Nintendo
|
|||
interface IPortDevice
|
||||
{
|
||||
void Write(int value);
|
||||
byte Read();
|
||||
byte Read(bool peek);
|
||||
void Update();
|
||||
}
|
||||
|
||||
|
@ -284,10 +284,10 @@ namespace BizHawk.Emulation.Consoles.Nintendo
|
|||
Strobe();
|
||||
state = value;
|
||||
}
|
||||
public override byte Read()
|
||||
public override byte Read(bool peek)
|
||||
{
|
||||
int ret = value & 1;
|
||||
value >>= 1;
|
||||
if(!peek) value >>= 1;
|
||||
return (byte)(ret | nes.DB);
|
||||
}
|
||||
public override void Update()
|
||||
|
@ -302,7 +302,7 @@ namespace BizHawk.Emulation.Consoles.Nintendo
|
|||
public virtual void Write(int value)
|
||||
{
|
||||
}
|
||||
public virtual byte Read()
|
||||
public virtual byte Read(bool peek)
|
||||
{
|
||||
return 0xFF;
|
||||
}
|
||||
|
|
|
@ -346,6 +346,7 @@ namespace BizHawk.Emulation.Consoles.Nintendo
|
|||
reg_2000.Value = value;
|
||||
}
|
||||
byte read_2000() { return PPUGenLatch; }
|
||||
byte peek_2000() { return PPUGenLatch; }
|
||||
|
||||
//PPU MASK (write)
|
||||
void write_2001(byte value)
|
||||
|
@ -354,6 +355,7 @@ namespace BizHawk.Emulation.Consoles.Nintendo
|
|||
reg_2001.Value = value;
|
||||
}
|
||||
byte read_2001() { return PPUGenLatch; }
|
||||
byte peek_2001() { return PPUGenLatch; }
|
||||
|
||||
//PPU STATUS (read)
|
||||
void write_2002(byte value) { }
|
||||
|
@ -363,14 +365,19 @@ namespace BizHawk.Emulation.Consoles.Nintendo
|
|||
//i think we should only reset the state machine for 2005/2006
|
||||
//ppur.clear_latches();
|
||||
|
||||
vtoggle = false;
|
||||
int ret = (Reg2002_vblank_active << 7) | (Reg2002_objhit << 6) | (Reg2002_objoverflow << 5) | (PPUGenLatch & 0x1F);
|
||||
byte ret = peek_2002();
|
||||
|
||||
vtoggle = false;
|
||||
Reg2002_vblank_active = 0;
|
||||
Reg2002_vblank_active_pending = false;
|
||||
|
||||
return (byte)ret;
|
||||
return ret;
|
||||
}
|
||||
byte peek_2002()
|
||||
{
|
||||
return (byte)((Reg2002_vblank_active << 7) | (Reg2002_objhit << 6) | (Reg2002_objoverflow << 5) | (PPUGenLatch & 0x1F));
|
||||
}
|
||||
|
||||
void clear_2002()
|
||||
{
|
||||
Reg2002_objhit = Reg2002_objoverflow = 0;
|
||||
|
@ -384,6 +391,7 @@ namespace BizHawk.Emulation.Consoles.Nintendo
|
|||
reg_2003 = value;
|
||||
}
|
||||
byte read_2003() { return PPUGenLatch; }
|
||||
byte peek_2003() { return PPUGenLatch; }
|
||||
|
||||
//OAM DATA (write)
|
||||
void write_2004(byte value)
|
||||
|
@ -393,9 +401,8 @@ namespace BizHawk.Emulation.Consoles.Nintendo
|
|||
OAM[reg_2003] = value;
|
||||
reg_2003++;
|
||||
}
|
||||
byte read_2004() {
|
||||
return OAM[reg_2003];
|
||||
}
|
||||
byte read_2004() { return OAM[reg_2003]; }
|
||||
byte peek_2004() { return OAM[reg_2003]; }
|
||||
|
||||
//SCROLL (write)
|
||||
void write_2005(byte value)
|
||||
|
@ -415,6 +422,7 @@ namespace BizHawk.Emulation.Consoles.Nintendo
|
|||
vtoggle ^= true;
|
||||
}
|
||||
byte read_2005() { return PPUGenLatch; }
|
||||
byte peek_2005() { return PPUGenLatch; }
|
||||
|
||||
//VRAM address register (write)
|
||||
void write_2006(byte value)
|
||||
|
@ -445,6 +453,7 @@ namespace BizHawk.Emulation.Consoles.Nintendo
|
|||
vtoggle ^= true;
|
||||
}
|
||||
byte read_2006() { return PPUGenLatch; }
|
||||
byte peek_2006() { return PPUGenLatch; }
|
||||
|
||||
//VRAM data register (r/w)
|
||||
void write_2007(byte value)
|
||||
|
@ -501,6 +510,25 @@ namespace BizHawk.Emulation.Consoles.Nintendo
|
|||
|
||||
return ret;
|
||||
}
|
||||
byte peek_2007()
|
||||
{
|
||||
int addr = ppur.get_2007access() & 0x3FFF;
|
||||
|
||||
//ordinarily we return the buffered values
|
||||
byte ret = VRAMBuffer;
|
||||
|
||||
//in any case, we read from the ppu bus
|
||||
VRAMBuffer = ppubus_peek(addr);
|
||||
|
||||
//but reads from the palette are implemented in the PPU and return immediately
|
||||
if ((addr & 0x3F00) == 0x3F00)
|
||||
{
|
||||
//TODO apply greyscale shit?
|
||||
ret = PALRAM[addr & 0x1F];
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
//--------
|
||||
|
||||
public byte ReadReg(int addr)
|
||||
|
@ -512,6 +540,15 @@ namespace BizHawk.Emulation.Consoles.Nintendo
|
|||
default: throw new InvalidOperationException();
|
||||
}
|
||||
}
|
||||
public byte PeekReg(int addr)
|
||||
{
|
||||
switch (addr)
|
||||
{
|
||||
case 0: return peek_2000(); case 1: return peek_2001(); case 2: return peek_2002(); case 3: return peek_2003();
|
||||
case 4: return peek_2004(); case 5: return peek_2005(); case 6: return peek_2006(); case 7: return peek_2007();
|
||||
default: throw new InvalidOperationException();
|
||||
}
|
||||
}
|
||||
public void WriteReg(int addr, byte value)
|
||||
{
|
||||
PPUGenLatch = value;
|
||||
|
|
Loading…
Reference in New Issue