Merge branch 'mgba-hooks'
This commit is contained in:
commit
e357ed3dbc
|
@ -8,15 +8,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBA
|
||||||
const string dll = "mgba.dll";
|
const string dll = "mgba.dll";
|
||||||
const CallingConvention cc = CallingConvention.Cdecl;
|
const CallingConvention cc = CallingConvention.Cdecl;
|
||||||
|
|
||||||
[DllImport(dll, CallingConvention = cc)]
|
|
||||||
public static extern void BizDestroy(IntPtr ctx);
|
|
||||||
|
|
||||||
[DllImport(dll, CallingConvention = cc)]
|
|
||||||
public static extern IntPtr BizCreate(byte[] bios, byte[] data, int length, [In]OverrideInfo dbinfo, bool skipBios);
|
|
||||||
|
|
||||||
[DllImport(dll, CallingConvention = cc)]
|
|
||||||
public static extern void BizReset(IntPtr ctx);
|
|
||||||
|
|
||||||
public enum SaveType : int
|
public enum SaveType : int
|
||||||
{
|
{
|
||||||
Autodetect = -1,
|
Autodetect = -1,
|
||||||
|
@ -41,6 +32,35 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBA
|
||||||
NoOverride = 0x8000 // can probably ignore this
|
NoOverride = 0x8000 // can probably ignore this
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Flags]
|
||||||
|
public enum Layers : int
|
||||||
|
{
|
||||||
|
BG0 = 1,
|
||||||
|
BG1 = 2,
|
||||||
|
BG2 = 4,
|
||||||
|
BG3 = 8,
|
||||||
|
OBJ = 16
|
||||||
|
}
|
||||||
|
|
||||||
|
[Flags]
|
||||||
|
public enum Sounds : int
|
||||||
|
{
|
||||||
|
CH0 = 1,
|
||||||
|
CH1 = 2,
|
||||||
|
CH2 = 4,
|
||||||
|
CH3 = 8,
|
||||||
|
CHA = 16,
|
||||||
|
CHB = 32
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum mWatchpointType
|
||||||
|
{
|
||||||
|
WATCHPOINT_WRITE = 1,
|
||||||
|
WATCHPOINT_READ = 2,
|
||||||
|
WATCHPOINT_RW = 3,
|
||||||
|
WATCHPOINT_WRITE_CHANGE = 4,
|
||||||
|
};
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential)]
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
public class OverrideInfo
|
public class OverrideInfo
|
||||||
{
|
{
|
||||||
|
@ -50,13 +70,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBA
|
||||||
public const uint IDLE_LOOP_NONE = unchecked((uint)0xffffffff);
|
public const uint IDLE_LOOP_NONE = unchecked((uint)0xffffffff);
|
||||||
}
|
}
|
||||||
|
|
||||||
[DllImport(dll, CallingConvention = cc)]
|
|
||||||
public static extern bool BizAdvance(IntPtr ctx, LibVBANext.Buttons keys, int[] vbuff, ref int nsamp, short[] sbuff,
|
|
||||||
long time, short gyrox, short gyroy, short gyroz, byte luma);
|
|
||||||
|
|
||||||
[DllImport(dll, CallingConvention = cc)]
|
|
||||||
public static extern void BizSetPalette(IntPtr ctx, int[] palette);
|
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential)]
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
public class MemoryAreas
|
public class MemoryAreas
|
||||||
{
|
{
|
||||||
|
@ -72,11 +85,28 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBA
|
||||||
public int sram_size;
|
public int sram_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[DllImport(dll, CallingConvention = cc)]
|
||||||
|
public static extern void BizDestroy(IntPtr ctx);
|
||||||
|
|
||||||
|
[DllImport(dll, CallingConvention = cc)]
|
||||||
|
public static extern IntPtr BizCreate(byte[] bios, byte[] data, int length, [In]OverrideInfo dbinfo, bool skipBios);
|
||||||
|
|
||||||
|
[DllImport(dll, CallingConvention = cc)]
|
||||||
|
public static extern void BizReset(IntPtr ctx);
|
||||||
|
|
||||||
|
[DllImport(dll, CallingConvention = cc)]
|
||||||
|
public static extern bool BizAdvance(IntPtr ctx, LibVBANext.Buttons keys, int[] vbuff, ref int nsamp, short[] sbuff,
|
||||||
|
long time, short gyrox, short gyroy, short gyroz, byte luma);
|
||||||
|
|
||||||
|
[DllImport(dll, CallingConvention = cc)]
|
||||||
|
public static extern void BizSetPalette(IntPtr ctx, int[] palette);
|
||||||
|
|
||||||
[DllImport(dll, CallingConvention = cc)]
|
[DllImport(dll, CallingConvention = cc)]
|
||||||
public static extern void BizGetMemoryAreas(IntPtr ctx, [Out]MemoryAreas dst);
|
public static extern void BizGetMemoryAreas(IntPtr ctx, [Out]MemoryAreas dst);
|
||||||
|
|
||||||
[DllImport(dll, CallingConvention = cc)]
|
[DllImport(dll, CallingConvention = cc)]
|
||||||
public static extern int BizGetSaveRam(IntPtr ctx, byte[] dest, int maxsize);
|
public static extern int BizGetSaveRam(IntPtr ctx, byte[] dest, int maxsize);
|
||||||
|
|
||||||
[DllImport(dll, CallingConvention = cc)]
|
[DllImport(dll, CallingConvention = cc)]
|
||||||
public static extern void BizPutSaveRam(IntPtr ctx, byte[] src, int size);
|
public static extern void BizPutSaveRam(IntPtr ctx, byte[] src, int size);
|
||||||
|
|
||||||
|
@ -101,30 +131,9 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBA
|
||||||
[DllImport(dll, CallingConvention = cc)]
|
[DllImport(dll, CallingConvention = cc)]
|
||||||
public static extern bool BizPutState(IntPtr ctx, byte[] src, int size);
|
public static extern bool BizPutState(IntPtr ctx, byte[] src, int size);
|
||||||
|
|
||||||
[Flags]
|
|
||||||
public enum Layers : int
|
|
||||||
{
|
|
||||||
BG0 = 1,
|
|
||||||
BG1 = 2,
|
|
||||||
BG2 = 4,
|
|
||||||
BG3 = 8,
|
|
||||||
OBJ = 16
|
|
||||||
}
|
|
||||||
|
|
||||||
[DllImport(dll, CallingConvention = cc)]
|
[DllImport(dll, CallingConvention = cc)]
|
||||||
public static extern void BizSetLayerMask(IntPtr ctx, Layers mask);
|
public static extern void BizSetLayerMask(IntPtr ctx, Layers mask);
|
||||||
|
|
||||||
[Flags]
|
|
||||||
public enum Sounds : int
|
|
||||||
{
|
|
||||||
CH0 = 1,
|
|
||||||
CH1 = 2,
|
|
||||||
CH2 = 4,
|
|
||||||
CH3 = 8,
|
|
||||||
CHA = 16,
|
|
||||||
CHB = 32
|
|
||||||
}
|
|
||||||
|
|
||||||
[DllImport(dll, CallingConvention = cc)]
|
[DllImport(dll, CallingConvention = cc)]
|
||||||
public static extern void BizSetSoundMask(IntPtr ctx, Sounds mask);
|
public static extern void BizSetSoundMask(IntPtr ctx, Sounds mask);
|
||||||
|
|
||||||
|
@ -139,9 +148,23 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBA
|
||||||
|
|
||||||
[UnmanagedFunctionPointer(cc)]
|
[UnmanagedFunctionPointer(cc)]
|
||||||
public delegate void TraceCallback(string msg);
|
public delegate void TraceCallback(string msg);
|
||||||
|
|
||||||
[DllImport(dll, CallingConvention = cc)]
|
[DllImport(dll, CallingConvention = cc)]
|
||||||
public static extern void BizSetTraceCallback(TraceCallback cb);
|
public static extern void BizSetTraceCallback(TraceCallback cb);
|
||||||
|
|
||||||
|
[UnmanagedFunctionPointer(cc)]
|
||||||
|
public delegate void MemCallback(uint addr, mWatchpointType type, uint oldValue, uint newValue);
|
||||||
|
[DllImport(dll, CallingConvention = cc)]
|
||||||
|
public static extern void BizSetMemCallback(MemCallback cb);
|
||||||
|
|
||||||
|
[UnmanagedFunctionPointer(cc)]
|
||||||
|
public delegate void ExecCallback(uint pc);
|
||||||
|
[DllImport(dll, CallingConvention = cc)]
|
||||||
|
public static extern void BizSetExecCallback(ExecCallback cb);
|
||||||
|
|
||||||
|
[DllImport(dll, CallingConvention = cc)]
|
||||||
|
public static extern int BizSetWatchpoint(IntPtr ctx, uint addr, mWatchpointType type);
|
||||||
|
|
||||||
|
[DllImport(dll, CallingConvention = cc)]
|
||||||
|
public static extern bool BizClearWatchpoint(IntPtr ctx, int id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBA
|
||||||
public IDictionary<string, RegisterValue> GetCpuFlagsAndRegisters()
|
public IDictionary<string, RegisterValue> GetCpuFlagsAndRegisters()
|
||||||
{
|
{
|
||||||
var values = new int[RegisterNames.Length];
|
var values = new int[RegisterNames.Length];
|
||||||
LibmGBA.BizGetRegisters(_core, values);
|
LibmGBA.BizGetRegisters(Core, values);
|
||||||
var ret = new Dictionary<string, RegisterValue>();
|
var ret = new Dictionary<string, RegisterValue>();
|
||||||
for (var i = 0; i < RegisterNames.Length; i++)
|
for (var i = 0; i < RegisterNames.Length; i++)
|
||||||
{
|
{
|
||||||
|
@ -27,7 +27,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBA
|
||||||
}
|
}
|
||||||
|
|
||||||
[FeatureNotImplemented]
|
[FeatureNotImplemented]
|
||||||
public IMemoryCallbackSystem MemoryCallbacks => throw new NotImplementedException();
|
public IMemoryCallbackSystem MemoryCallbacks { get; }
|
||||||
|
|
||||||
public bool CanStep(StepType type) => false;
|
public bool CanStep(StepType type) => false;
|
||||||
|
|
||||||
|
|
|
@ -43,7 +43,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBA
|
||||||
throw new ArgumentOutOfRangeException();
|
throw new ArgumentOutOfRangeException();
|
||||||
}
|
}
|
||||||
|
|
||||||
return LibmGBA.BizReadBus(_core, a);
|
return LibmGBA.BizReadBus(Core, a);
|
||||||
},
|
},
|
||||||
delegate (long addr, byte val)
|
delegate (long addr, byte val)
|
||||||
{
|
{
|
||||||
|
@ -53,7 +53,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBA
|
||||||
throw new ArgumentOutOfRangeException();
|
throw new ArgumentOutOfRangeException();
|
||||||
}
|
}
|
||||||
|
|
||||||
LibmGBA.BizWriteBus(_core, a, val);
|
LibmGBA.BizWriteBus(Core, a, val);
|
||||||
}, 4));
|
}, 4));
|
||||||
|
|
||||||
_memoryDomains = new MemoryDomainList(mm);
|
_memoryDomains = new MemoryDomainList(mm);
|
||||||
|
@ -63,7 +63,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBA
|
||||||
private void WireMemoryDomainPointers()
|
private void WireMemoryDomainPointers()
|
||||||
{
|
{
|
||||||
var s = new LibmGBA.MemoryAreas();
|
var s = new LibmGBA.MemoryAreas();
|
||||||
LibmGBA.BizGetMemoryAreas(_core, s);
|
LibmGBA.BizGetMemoryAreas(Core, s);
|
||||||
|
|
||||||
_iwram.Data = s.iwram;
|
_iwram.Data = s.iwram;
|
||||||
_ewram.Data = s.wram;
|
_ewram.Data = s.wram;
|
||||||
|
|
|
@ -10,7 +10,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBA
|
||||||
{
|
{
|
||||||
public byte[] CloneSaveRam()
|
public byte[] CloneSaveRam()
|
||||||
{
|
{
|
||||||
int len = LibmGBA.BizGetSaveRam(_core, _saveScratch, _saveScratch.Length);
|
int len = LibmGBA.BizGetSaveRam(Core, _saveScratch, _saveScratch.Length);
|
||||||
if (len == _saveScratch.Length)
|
if (len == _saveScratch.Length)
|
||||||
{
|
{
|
||||||
throw new InvalidOperationException("Save buffer not long enough");
|
throw new InvalidOperationException("Save buffer not long enough");
|
||||||
|
@ -33,10 +33,10 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBA
|
||||||
data = LegacyFix(data);
|
data = LegacyFix(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
LibmGBA.BizPutSaveRam(_core, data, data.Length);
|
LibmGBA.BizPutSaveRam(Core, data, data.Length);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool SaveRamModified => LibmGBA.BizGetSaveRam(_core, _saveScratch, _saveScratch.Length) > 0;
|
public bool SaveRamModified => LibmGBA.BizGetSaveRam(Core, _saveScratch, _saveScratch.Length) > 0;
|
||||||
|
|
||||||
private static byte[] LegacyFix(byte[] saveram)
|
private static byte[] LegacyFix(byte[] saveram)
|
||||||
{
|
{
|
||||||
|
|
|
@ -23,7 +23,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBA
|
||||||
if (o.DisplayBG2) mask |= LibmGBA.Layers.BG2;
|
if (o.DisplayBG2) mask |= LibmGBA.Layers.BG2;
|
||||||
if (o.DisplayBG3) mask |= LibmGBA.Layers.BG3;
|
if (o.DisplayBG3) mask |= LibmGBA.Layers.BG3;
|
||||||
if (o.DisplayOBJ) mask |= LibmGBA.Layers.OBJ;
|
if (o.DisplayOBJ) mask |= LibmGBA.Layers.OBJ;
|
||||||
LibmGBA.BizSetLayerMask(_core, mask);
|
LibmGBA.BizSetLayerMask(Core, mask);
|
||||||
|
|
||||||
LibmGBA.Sounds smask = 0;
|
LibmGBA.Sounds smask = 0;
|
||||||
if (o.PlayCh0) smask |= LibmGBA.Sounds.CH0;
|
if (o.PlayCh0) smask |= LibmGBA.Sounds.CH0;
|
||||||
|
@ -32,7 +32,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBA
|
||||||
if (o.PlayCh3) smask |= LibmGBA.Sounds.CH3;
|
if (o.PlayCh3) smask |= LibmGBA.Sounds.CH3;
|
||||||
if (o.PlayChA) smask |= LibmGBA.Sounds.CHA;
|
if (o.PlayChA) smask |= LibmGBA.Sounds.CHA;
|
||||||
if (o.PlayChB) smask |= LibmGBA.Sounds.CHB;
|
if (o.PlayChB) smask |= LibmGBA.Sounds.CHB;
|
||||||
LibmGBA.BizSetSoundMask(_core, smask);
|
LibmGBA.BizSetSoundMask(Core, smask);
|
||||||
|
|
||||||
var palette = new int[65536];
|
var palette = new int[65536];
|
||||||
GBColors.ColorType c = GBColors.ColorType.vivid;
|
GBColors.ColorType c = GBColors.ColorType.vivid;
|
||||||
|
@ -48,7 +48,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBA
|
||||||
GBColors.GetLut(c, palette);
|
GBColors.GetLut(c, palette);
|
||||||
for (var i = 32768; i < 65536; i++)
|
for (var i = 32768; i < 65536; i++)
|
||||||
palette[i] = palette[i - 32768];
|
palette[i] = palette[i - 32768];
|
||||||
LibmGBA.BizSetPalette(_core, palette);
|
LibmGBA.BizSetPalette(Core, palette);
|
||||||
|
|
||||||
_settings = o;
|
_settings = o;
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -14,7 +14,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBA
|
||||||
{
|
{
|
||||||
IntPtr p = IntPtr.Zero;
|
IntPtr p = IntPtr.Zero;
|
||||||
int size = 0;
|
int size = 0;
|
||||||
if (!LibmGBA.BizStartGetState(_core, ref p, ref size))
|
if (!LibmGBA.BizStartGetState(Core, ref p, ref size))
|
||||||
{
|
{
|
||||||
throw new InvalidOperationException("Core failed to save!");
|
throw new InvalidOperationException("Core failed to save!");
|
||||||
}
|
}
|
||||||
|
@ -55,7 +55,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBA
|
||||||
}
|
}
|
||||||
|
|
||||||
reader.Read(_savebuff, 0, length);
|
reader.Read(_savebuff, 0, length);
|
||||||
if (!LibmGBA.BizPutState(_core, _savebuff, length))
|
if (!LibmGBA.BizPutState(Core, _savebuff, length))
|
||||||
{
|
{
|
||||||
throw new InvalidOperationException("Core rejected the savestate!");
|
throw new InvalidOperationException("Core rejected the savestate!");
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,8 +38,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBA
|
||||||
|
|
||||||
var skipBios = !DeterministicEmulation && _syncSettings.SkipBios;
|
var skipBios = !DeterministicEmulation && _syncSettings.SkipBios;
|
||||||
|
|
||||||
_core = LibmGBA.BizCreate(bios, file, file.Length, GetOverrideInfo(game), skipBios);
|
Core = LibmGBA.BizCreate(bios, file, file.Length, GetOverrideInfo(game), skipBios);
|
||||||
if (_core == IntPtr.Zero)
|
if (Core == IntPtr.Zero)
|
||||||
{
|
{
|
||||||
throw new InvalidOperationException($"{nameof(LibmGBA.BizCreate)}() returned NULL! Bad BIOS? and/or ROM?");
|
throw new InvalidOperationException($"{nameof(LibmGBA.BizCreate)}() returned NULL! Bad BIOS? and/or ROM?");
|
||||||
}
|
}
|
||||||
|
@ -60,10 +60,11 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBA
|
||||||
};
|
};
|
||||||
_tracecb = new LibmGBA.TraceCallback((msg) => _tracer.Put(_traceInfo(msg)));
|
_tracecb = new LibmGBA.TraceCallback((msg) => _tracer.Put(_traceInfo(msg)));
|
||||||
ser.Register(_tracer);
|
ser.Register(_tracer);
|
||||||
|
MemoryCallbacks = new MGBAMemoryCallbackSystem(this);
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
LibmGBA.BizDestroy(_core);
|
LibmGBA.BizDestroy(Core);
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -104,7 +105,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBA
|
||||||
Frame++;
|
Frame++;
|
||||||
if (controller.IsPressed("Power"))
|
if (controller.IsPressed("Power"))
|
||||||
{
|
{
|
||||||
LibmGBA.BizReset(_core);
|
LibmGBA.BizReset(Core);
|
||||||
|
|
||||||
// BizReset caused memorydomain pointers to change.
|
// BizReset caused memorydomain pointers to change.
|
||||||
WireMemoryDomainPointers();
|
WireMemoryDomainPointers();
|
||||||
|
@ -113,7 +114,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBA
|
||||||
LibmGBA.BizSetTraceCallback(_tracer.Enabled ? _tracecb : null);
|
LibmGBA.BizSetTraceCallback(_tracer.Enabled ? _tracecb : null);
|
||||||
|
|
||||||
IsLagFrame = LibmGBA.BizAdvance(
|
IsLagFrame = LibmGBA.BizAdvance(
|
||||||
_core,
|
Core,
|
||||||
VBANext.GetButtons(controller),
|
VBANext.GetButtons(controller),
|
||||||
render ? _videobuff : _dummyvideobuff,
|
render ? _videobuff : _dummyvideobuff,
|
||||||
ref _nsamp,
|
ref _nsamp,
|
||||||
|
@ -150,10 +151,10 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBA
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
if (_core != IntPtr.Zero)
|
if (Core != IntPtr.Zero)
|
||||||
{
|
{
|
||||||
LibmGBA.BizDestroy(_core);
|
LibmGBA.BizDestroy(Core);
|
||||||
_core = IntPtr.Zero;
|
Core = IntPtr.Zero;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -169,7 +170,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBA
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly byte[] _saveScratch = new byte[262144];
|
private readonly byte[] _saveScratch = new byte[262144];
|
||||||
private IntPtr _core;
|
internal IntPtr Core;
|
||||||
|
|
||||||
private static LibmGBA.OverrideInfo GetOverrideInfo(GameInfo game)
|
private static LibmGBA.OverrideInfo GetOverrideInfo(GameInfo game)
|
||||||
{
|
{
|
||||||
|
|
|
@ -0,0 +1,141 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using BizHawk.Emulation.Common;
|
||||||
|
|
||||||
|
namespace BizHawk.Emulation.Cores.Nintendo.GBA
|
||||||
|
{
|
||||||
|
public class MGBAMemoryCallbackSystem : IMemoryCallbackSystem
|
||||||
|
{
|
||||||
|
private readonly MGBAHawk _mgba;
|
||||||
|
|
||||||
|
public MGBAMemoryCallbackSystem(MGBAHawk mgba)
|
||||||
|
{
|
||||||
|
_mgba = mgba;
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly List<CallbackContainer> _callbacks = new List<CallbackContainer>();
|
||||||
|
|
||||||
|
public string[] AvailableScopes { get; } = { "System Bus" };
|
||||||
|
public bool ExecuteCallbacksAvailable => false;
|
||||||
|
|
||||||
|
public bool HasReads => _callbacks.Any(c => c.Callback.Type == MemoryCallbackType.Read);
|
||||||
|
public bool HasWrites => _callbacks.Any(c => c.Callback.Type == MemoryCallbackType.Write);
|
||||||
|
public bool HasExecutes => _callbacks.Any(c => c.Callback.Type == MemoryCallbackType.Execute);
|
||||||
|
|
||||||
|
public bool HasReadsForScope(string scope) =>
|
||||||
|
_callbacks.Any(c => c.Callback.Scope == scope
|
||||||
|
&& c.Callback.Type == MemoryCallbackType.Read);
|
||||||
|
|
||||||
|
public bool HasWritesForScope(string scope) =>
|
||||||
|
_callbacks.Any(c => c.Callback.Scope == scope
|
||||||
|
&& c.Callback.Type == MemoryCallbackType.Write);
|
||||||
|
|
||||||
|
public bool HasExecutesForScope(string scope) =>
|
||||||
|
_callbacks.Any(c => c.Callback.Scope == scope
|
||||||
|
&& c.Callback.Type == MemoryCallbackType.Execute);
|
||||||
|
|
||||||
|
public void Add(IMemoryCallback callback)
|
||||||
|
{
|
||||||
|
if (!AvailableScopes.Contains(callback.Scope))
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException($"{callback.Scope} is not currently supported for callbacks");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!callback.Address.HasValue)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException("Wildcard callbacks (no address specified) not currently implemented.");
|
||||||
|
}
|
||||||
|
|
||||||
|
var container = new CallbackContainer(callback);
|
||||||
|
|
||||||
|
if (container.Callback.Type == MemoryCallbackType.Execute)
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LibmGBA.BizSetMemCallback(container.CallDelegate);
|
||||||
|
container.ID = LibmGBA.BizSetWatchpoint(_mgba.Core, callback.Address.Value, container.WatchPointType);
|
||||||
|
}
|
||||||
|
|
||||||
|
_callbacks.Add(container);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Remove(MemoryCallbackDelegate action)
|
||||||
|
{
|
||||||
|
var cbToRemove = _callbacks.Single(container => container.Callback.Callback == action);
|
||||||
|
|
||||||
|
if (LibmGBA.BizClearWatchpoint(_mgba.Core, cbToRemove.ID))
|
||||||
|
{
|
||||||
|
_callbacks.Remove(cbToRemove);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RemoveAll(IEnumerable<MemoryCallbackDelegate> actions)
|
||||||
|
{
|
||||||
|
foreach (var action in actions)
|
||||||
|
{
|
||||||
|
Remove(action);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Clear()
|
||||||
|
{
|
||||||
|
foreach (var cb in _callbacks)
|
||||||
|
{
|
||||||
|
if (LibmGBA.BizClearWatchpoint(_mgba.Core, cb.ID))
|
||||||
|
{
|
||||||
|
_callbacks.Remove(cb);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerator<IMemoryCallback> GetEnumerator() => _callbacks.Select(c => c.Callback).GetEnumerator();
|
||||||
|
IEnumerator IEnumerable.GetEnumerator() => _callbacks.Select(c => c.Callback).GetEnumerator();
|
||||||
|
|
||||||
|
public void CallMemoryCallbacks(uint addr, uint value, uint flags, string scope)
|
||||||
|
{
|
||||||
|
// Not a thing in this implementation
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class CallbackContainer
|
||||||
|
{
|
||||||
|
public CallbackContainer(IMemoryCallback callBack)
|
||||||
|
{
|
||||||
|
Callback = callBack;
|
||||||
|
CallDelegate = Call;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IMemoryCallback Callback { get; }
|
||||||
|
|
||||||
|
// the core returns this when setting a wp and needs it to clear that wp
|
||||||
|
public int ID { get; set; }
|
||||||
|
|
||||||
|
public LibmGBA.mWatchpointType WatchPointType
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
switch (Callback.Type)
|
||||||
|
{
|
||||||
|
default:
|
||||||
|
case MemoryCallbackType.Read:
|
||||||
|
return LibmGBA.mWatchpointType.WATCHPOINT_READ;
|
||||||
|
case MemoryCallbackType.Write:
|
||||||
|
return LibmGBA.mWatchpointType.WATCHPOINT_WRITE;
|
||||||
|
case MemoryCallbackType.Execute:
|
||||||
|
throw new NotImplementedException("Executes not implemented yet");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public LibmGBA.MemCallback CallDelegate;
|
||||||
|
|
||||||
|
void Call(uint addr, LibmGBA.mWatchpointType type, uint oldValue, uint newValue)
|
||||||
|
{
|
||||||
|
Callback.Callback?.Invoke(addr, newValue, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue