65c02 performance fixes
This commit is contained in:
parent
2e534a308a
commit
9805883806
|
@ -41,6 +41,18 @@ namespace BizHawk.Emulation.Cores.Components.vr6502
|
|||
[DllImport(lib, CallingConvention = cc)]
|
||||
public static extern byte vrEmu6502InstCycle(ref VrEmu6502State state);
|
||||
|
||||
/// <summary>
|
||||
/// Pointer to the NMI pin
|
||||
/// </summary>
|
||||
[DllImport(lib, CallingConvention = cc)]
|
||||
public static extern IntPtr vrEmu6502Nmi(ref VrEmu6502State state);
|
||||
|
||||
/// <summary>
|
||||
/// Pointer to the INT pin
|
||||
/// </summary>
|
||||
[DllImport(lib, CallingConvention = cc)]
|
||||
public static extern IntPtr vrEmu6502Int(ref VrEmu6502State state);
|
||||
|
||||
|
||||
[DllImport(lib, CallingConvention = cc)]
|
||||
public static extern IntPtr vrEmu6502OpcodeToMnemonicStr(ref VrEmu6502State state, byte opcode);
|
||||
|
|
|
@ -37,8 +37,7 @@ namespace BizHawk.Emulation.Cores.Components.vr6502
|
|||
|
||||
public IntPtr opcodes;
|
||||
public IntPtr mnemonicNames;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)]
|
||||
public VrEmu6502AddrMode[] addrModes;
|
||||
public IntPtr addrModes;
|
||||
}
|
||||
|
||||
public enum VrEmu6502Model
|
||||
|
|
|
@ -3,6 +3,7 @@ using BizHawk.Common.NumberExtensions;
|
|||
using BizHawk.Emulation.Common;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
using static BizHawk.Emulation.Cores.Components.vr6502.vr6502;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Components.vr6502
|
||||
{
|
||||
|
@ -49,9 +50,32 @@ namespace BizHawk.Emulation.Cores.Components.vr6502
|
|||
public delegate byte VrEmu6502MemRead(ushort addr, bool isDbg);
|
||||
public delegate void VrEmu6502MemWrite(ushort addr, byte val);
|
||||
|
||||
public void SetNMI() => _6502s.nmiPin = VrEmu6502Interrupt.IntLow;
|
||||
public void SetNMI() => WriteNMI(VrEmu6502Interrupt.IntRequested);
|
||||
public void SetIRQ() => WriteInt(VrEmu6502Interrupt.IntRequested);
|
||||
|
||||
public bool SetIRQ() => _6502s.intPin == VrEmu6502Interrupt.IntLow;
|
||||
private void WriteNMI(VrEmu6502Interrupt state)
|
||||
{
|
||||
IntPtr nmiPtr = VrEmu6502Interop.vrEmu6502Nmi(ref _6502s);
|
||||
Marshal.WriteInt32(nmiPtr, (int)state);
|
||||
}
|
||||
|
||||
private VrEmu6502Interrupt ReadNMI()
|
||||
{
|
||||
IntPtr nmiPtr = VrEmu6502Interop.vrEmu6502Nmi(ref _6502s);
|
||||
return (VrEmu6502Interrupt)Marshal.ReadInt32(nmiPtr);
|
||||
}
|
||||
|
||||
private void WriteInt(VrEmu6502Interrupt state)
|
||||
{
|
||||
IntPtr intPtr = VrEmu6502Interop.vrEmu6502Int(ref _6502s);
|
||||
Marshal.WriteInt32(intPtr, (int)state);
|
||||
}
|
||||
|
||||
private VrEmu6502Interrupt ReadInt()
|
||||
{
|
||||
IntPtr intPtr = VrEmu6502Interop.vrEmu6502Int(ref _6502s);
|
||||
return (VrEmu6502Interrupt)Marshal.ReadInt32(intPtr);
|
||||
}
|
||||
|
||||
public bool RDY;
|
||||
|
||||
|
@ -61,8 +85,8 @@ namespace BizHawk.Emulation.Cores.Components.vr6502
|
|||
}
|
||||
|
||||
public void ExecuteTick()
|
||||
{
|
||||
if (RDY)
|
||||
{
|
||||
if (!RDY)
|
||||
{
|
||||
VrEmu6502Interop.vrEmu6502Tick(ref _6502s);
|
||||
}
|
||||
|
@ -72,9 +96,9 @@ namespace BizHawk.Emulation.Cores.Components.vr6502
|
|||
|
||||
public byte ExecuteInstruction()
|
||||
{
|
||||
int cycles = 0;
|
||||
int cycles = 0;
|
||||
|
||||
if (RDY)
|
||||
if (!RDY)
|
||||
{
|
||||
cycles = VrEmu6502Interop.vrEmu6502InstCycle(ref _6502s);
|
||||
}
|
||||
|
@ -118,10 +142,8 @@ namespace BizHawk.Emulation.Cores.Components.vr6502
|
|||
ser.Sync(nameof(RDY), ref RDY);
|
||||
|
||||
ser.SyncEnum(nameof(_6502s.Model), ref _6502s.Model);
|
||||
// ReadFn not serializable
|
||||
// WriteFn not serializable
|
||||
ser.SyncEnum(nameof(_6502s.intPin), ref _6502s.intPin);
|
||||
ser.SyncEnum(nameof(_6502s.nmiPin), ref _6502s.nmiPin);
|
||||
//ser.SyncEnum(nameof(_6502s.intPin), ref _6502s.intPin);
|
||||
//ser.SyncEnum(nameof(_6502s.nmiPin), ref _6502s.nmiPin);
|
||||
ser.Sync(nameof(_6502s.step), ref _6502s.step);
|
||||
ser.Sync(nameof(_6502s.currentOpcode), ref _6502s.currentOpcode);
|
||||
ser.Sync(nameof(_6502s.currentOpcodeAddr), ref _6502s.currentOpcodeAddr);
|
||||
|
@ -136,9 +158,26 @@ namespace BizHawk.Emulation.Cores.Components.vr6502
|
|||
ser.Sync(nameof(_6502s.zpBase), ref _6502s.zpBase);
|
||||
ser.Sync(nameof(_6502s.spBase), ref _6502s.spBase);
|
||||
ser.Sync(nameof(_6502s.tmpAddr), ref _6502s.tmpAddr);
|
||||
// Opcodes????
|
||||
// MnemonicNames??
|
||||
// AddrModes??
|
||||
|
||||
VrEmu6502Interrupt nmiP = new VrEmu6502Interrupt();
|
||||
VrEmu6502Interrupt intP = new VrEmu6502Interrupt();
|
||||
|
||||
if (ser.IsReader)
|
||||
{
|
||||
// loading state
|
||||
ser.SyncEnum(nameof(nmiP), ref nmiP);
|
||||
ser.SyncEnum(nameof(intP), ref intP);
|
||||
WriteNMI(nmiP);
|
||||
WriteInt(intP);
|
||||
}
|
||||
else
|
||||
{
|
||||
// saving state
|
||||
nmiP = ReadNMI();
|
||||
intP = ReadInt();
|
||||
ser.SyncEnum(nameof(nmiP), ref nmiP);
|
||||
ser.SyncEnum(nameof(intP), ref intP);
|
||||
}
|
||||
|
||||
ser.Sync(nameof(TotalExecutedCycles), ref TotalExecutedCycles);
|
||||
ser.EndSection();
|
||||
|
|
|
@ -91,7 +91,50 @@ namespace BizHawk.Emulation.Cores.Consoles.SuperVision
|
|||
private int _vramStartAddress;
|
||||
|
||||
/// <summary>
|
||||
/// ASIC is clocked at the same rate as the CPU
|
||||
/// Runs 'ticks' clock cycles of the ASIC
|
||||
/// </summary>
|
||||
public void Clock(int ticks)
|
||||
{
|
||||
int dmaCycles = 0;
|
||||
int lcdCycles = 0;
|
||||
|
||||
// sequencer
|
||||
for (int i = 0; i < ticks; i++)
|
||||
{
|
||||
_seqCounter++;
|
||||
|
||||
if (_seqCounter == 7)
|
||||
{
|
||||
_seqCounter = 0;
|
||||
lcdCycles++;
|
||||
}
|
||||
else
|
||||
{
|
||||
dmaCycles++;
|
||||
}
|
||||
}
|
||||
|
||||
// DMA
|
||||
CheckDMA();
|
||||
if (_dmaInProgress)
|
||||
{
|
||||
DoDMA(dmaCycles);
|
||||
}
|
||||
|
||||
// interrupts
|
||||
CheckInterrupt(ticks);
|
||||
|
||||
// video
|
||||
|
||||
|
||||
// audio
|
||||
AudioClock();
|
||||
|
||||
_sv.FrameClock += ticks;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Runs a single clock cycle of the ASIC
|
||||
/// </summary>
|
||||
public void Clock()
|
||||
{
|
||||
|
@ -104,14 +147,14 @@ namespace BizHawk.Emulation.Cores.Consoles.SuperVision
|
|||
// 4: DMA byte transfer to VRAM (if DMA is active) / CPU RDY line false (if DMA is active)
|
||||
// 5: DMA byte transfer to VRAM (if DMA is active) / CPU RDY line false (if DMA is active)
|
||||
|
||||
CheckDMA();
|
||||
|
||||
|
||||
// so DMA can transfer 5 bytes to VRAM every 6 clocks, the 6th clock being the 1/2 byte transfer to the LCD
|
||||
switch (_seqCounter)
|
||||
{
|
||||
case 0:
|
||||
// there is no DMA on this cycle so CPU can run freely
|
||||
_sv._cpu.RDY = true;
|
||||
//_sv._cpu.RDY = true;
|
||||
|
||||
bool lineEnd = _byteCounter == CLOCK_WIDTH - 1;
|
||||
bool fieldEnd = _lineCounter == LINE_HEIGHT - 1 && lineEnd && _field == 0;
|
||||
|
@ -213,14 +256,14 @@ namespace BizHawk.Emulation.Cores.Consoles.SuperVision
|
|||
/// <summary>
|
||||
/// Interrupt management
|
||||
/// </summary>
|
||||
private void CheckInterrupt()
|
||||
private void CheckInterrupt(int ticks = 0)
|
||||
{
|
||||
_nmiTimer++;
|
||||
_nmiTimer += ticks;
|
||||
|
||||
// The NMI occurs every 65536 clock cycles (61.04Hz) regardless of the rate that the LCD refreshes
|
||||
if (_nmiTimer == 0x10000 && _regs[R_SYSTEM_CONTROL].Bit(0))
|
||||
if (_nmiTimer >= 0x10000 && _regs[R_SYSTEM_CONTROL].Bit(0))
|
||||
{
|
||||
_nmiTimer = 0;
|
||||
_nmiTimer %= 0x10000;
|
||||
//_sv._cpu.NMI = true;
|
||||
_sv._cpu.SetNMI();
|
||||
}
|
||||
|
@ -235,31 +278,34 @@ namespace BizHawk.Emulation.Cores.Consoles.SuperVision
|
|||
_intTimer = 0;
|
||||
}
|
||||
|
||||
if (_intTimerEnabled)
|
||||
for (int i = 0; i < ticks; i++)
|
||||
{
|
||||
if (_regs[R_IRQ_TIMER] == 0)
|
||||
if (_intTimerEnabled)
|
||||
{
|
||||
if (_regs[R_SYSTEM_CONTROL].Bit(1))
|
||||
if (_regs[R_IRQ_TIMER] == 0)
|
||||
{
|
||||
// raise IRQ
|
||||
// this handles IRQ after timer countdown AND instant IRQ when timer is set to 0
|
||||
_intFlag = true;
|
||||
_intTimerEnabled = false;
|
||||
if (_regs[R_SYSTEM_CONTROL].Bit(1))
|
||||
{
|
||||
// raise IRQ
|
||||
// this handles IRQ after timer countdown AND instant IRQ when timer is set to 0
|
||||
_intFlag = true;
|
||||
_intTimerEnabled = false;
|
||||
|
||||
// set IRQ Timer expired bit
|
||||
_regs[R_IRQ_STATUS] = (byte) (_regs[R_IRQ_STATUS] | 2);
|
||||
// set IRQ Timer expired bit
|
||||
_regs[R_IRQ_STATUS] = (byte) (_regs[R_IRQ_STATUS] | 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// timer should be counting down clocked by the prescaler
|
||||
if (_intTimer++ == IntPrescaler)
|
||||
else
|
||||
{
|
||||
// prescaler clock
|
||||
_intTimer = 0;
|
||||
// timer should be counting down clocked by the prescaler
|
||||
if (_intTimer++ == IntPrescaler)
|
||||
{
|
||||
// prescaler clock
|
||||
_intTimer = 0;
|
||||
|
||||
// decrement timer
|
||||
_regs[R_IRQ_TIMER]--;
|
||||
// decrement timer
|
||||
_regs[R_IRQ_TIMER]--;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -291,9 +337,9 @@ namespace BizHawk.Emulation.Cores.Consoles.SuperVision
|
|||
/// <summary>
|
||||
/// Perform a DMA transfer
|
||||
/// </summary>
|
||||
private void DoDMA()
|
||||
private void DoDMA(int dmaCycles = 1)
|
||||
{
|
||||
if (_dmaInProgress)
|
||||
for (int i = 0; i > dmaCycles; i++)
|
||||
{
|
||||
_dmaCounter++;
|
||||
|
||||
|
@ -302,9 +348,10 @@ namespace BizHawk.Emulation.Cores.Consoles.SuperVision
|
|||
// wraparound or length reached
|
||||
_dmaCounter = 0;
|
||||
_dmaInProgress = false;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
{
|
||||
ushort source = (ushort) (_regs[R_DMA_SOURCE_HIGH] << 8 | _regs[R_DMA_SOURCE_LOW]);
|
||||
ushort dest = (ushort) (_regs[R_DMA_DEST_HIGH] << 8 | _regs[R_DMA_DEST_LOW]);
|
||||
|
||||
|
|
|
@ -59,16 +59,16 @@ namespace BizHawk.Emulation.Cores.Consoles.SuperVision
|
|||
|
||||
PollInput();
|
||||
|
||||
_asic.FrameStart = true;
|
||||
//_asic.FrameStart = true;
|
||||
|
||||
while (_frameClock < _cpuClocksPerFrame)
|
||||
{
|
||||
_asic.Clock();
|
||||
int ticks = _cpu.ExecuteInstruction();
|
||||
_asic.Clock(ticks);
|
||||
//_cpu.ExecuteOne();
|
||||
_cpu.ExecuteTick();
|
||||
}
|
||||
|
||||
_frameClock = 0;
|
||||
_frameClock %= (int)_cpuClocksPerFrame;
|
||||
_frame++;
|
||||
|
||||
if (_isLag)
|
||||
|
|
Loading…
Reference in New Issue