65c02 performance fixes

This commit is contained in:
ASNiVOR 2024-11-03 13:35:12 +00:00
parent 2e534a308a
commit 9805883806
5 changed files with 144 additions and 47 deletions

View File

@ -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);

View File

@ -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

View File

@ -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();

View File

@ -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]);

View File

@ -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)