[mGBA] don't try to read watchpoint type for execute callbacks
This commit is contained in:
parent
f7ead5f592
commit
cd8f5b4203
|
@ -1,79 +1,79 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using BizHawk.Emulation.Common;
|
using BizHawk.Emulation.Common;
|
||||||
|
|
||||||
namespace BizHawk.Emulation.Cores.Nintendo.GBA
|
namespace BizHawk.Emulation.Cores.Nintendo.GBA
|
||||||
{
|
{
|
||||||
public class MGBAMemoryCallbackSystem : IMemoryCallbackSystem
|
public class MGBAMemoryCallbackSystem : IMemoryCallbackSystem
|
||||||
{
|
{
|
||||||
private readonly MGBAHawk _mgba;
|
private readonly MGBAHawk _mgba;
|
||||||
private readonly LibmGBA.MemCallback _readWriteCallback;
|
private readonly LibmGBA.MemCallback _readWriteCallback;
|
||||||
private readonly LibmGBA.ExecCallback _executeCallback;
|
private readonly LibmGBA.ExecCallback _executeCallback;
|
||||||
private readonly List<CallbackContainer> _callbacks = new();
|
private readonly List<CallbackContainer> _callbacks = new();
|
||||||
|
|
||||||
public MGBAMemoryCallbackSystem(MGBAHawk mgba)
|
public MGBAMemoryCallbackSystem(MGBAHawk mgba)
|
||||||
{
|
{
|
||||||
_mgba = mgba;
|
_mgba = mgba;
|
||||||
_readWriteCallback = RunReadWriteCallback;
|
_readWriteCallback = RunReadWriteCallback;
|
||||||
_executeCallback = RunExecCallback;
|
_executeCallback = RunExecCallback;
|
||||||
}
|
}
|
||||||
|
|
||||||
public string[] AvailableScopes { get; } = { "System Bus" };
|
public string[] AvailableScopes { get; } = { "System Bus" };
|
||||||
public bool ExecuteCallbacksAvailable => true;
|
public bool ExecuteCallbacksAvailable => true;
|
||||||
|
|
||||||
public bool HasReads => _callbacks.Any(c => c.Callback.Type == MemoryCallbackType.Read);
|
public bool HasReads => _callbacks.Any(c => c.Callback.Type == MemoryCallbackType.Read);
|
||||||
public bool HasWrites => _callbacks.Any(c => c.Callback.Type == MemoryCallbackType.Write);
|
public bool HasWrites => _callbacks.Any(c => c.Callback.Type == MemoryCallbackType.Write);
|
||||||
public bool HasExecutes => _callbacks.Any(c => c.Callback.Type == MemoryCallbackType.Execute);
|
public bool HasExecutes => _callbacks.Any(c => c.Callback.Type == MemoryCallbackType.Execute);
|
||||||
|
|
||||||
public bool HasReadsForScope(string scope) =>
|
public bool HasReadsForScope(string scope) =>
|
||||||
_callbacks.Any(c => c.Callback.Scope == scope
|
_callbacks.Any(c => c.Callback.Scope == scope
|
||||||
&& c.Callback.Type == MemoryCallbackType.Read);
|
&& c.Callback.Type == MemoryCallbackType.Read);
|
||||||
|
|
||||||
public bool HasWritesForScope(string scope) =>
|
public bool HasWritesForScope(string scope) =>
|
||||||
_callbacks.Any(c => c.Callback.Scope == scope
|
_callbacks.Any(c => c.Callback.Scope == scope
|
||||||
&& c.Callback.Type == MemoryCallbackType.Write);
|
&& c.Callback.Type == MemoryCallbackType.Write);
|
||||||
|
|
||||||
public bool HasExecutesForScope(string scope) =>
|
public bool HasExecutesForScope(string scope) =>
|
||||||
_callbacks.Any(c => c.Callback.Scope == scope
|
_callbacks.Any(c => c.Callback.Scope == scope
|
||||||
&& c.Callback.Type == MemoryCallbackType.Execute);
|
&& c.Callback.Type == MemoryCallbackType.Execute);
|
||||||
|
|
||||||
public void Add(IMemoryCallback callback)
|
public void Add(IMemoryCallback callback)
|
||||||
{
|
{
|
||||||
if (!AvailableScopes.Contains(callback.Scope))
|
if (!AvailableScopes.Contains(callback.Scope))
|
||||||
{
|
{
|
||||||
throw new InvalidOperationException($"{callback.Scope} is not currently supported for callbacks");
|
throw new InvalidOperationException($"{callback.Scope} is not currently supported for callbacks");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!callback.Address.HasValue)
|
if (!callback.Address.HasValue)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException("Wildcard callbacks (no address specified) not currently implemented.");
|
throw new NotImplementedException("Wildcard callbacks (no address specified) not currently implemented.");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (callback.AddressMask != 0xFFFFFFFF)
|
if (callback.AddressMask != 0xFFFFFFFF)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException("Non 0xFFFFFFFF address masks are not currently implemented.");
|
throw new NotImplementedException("Non 0xFFFFFFFF address masks are not currently implemented.");
|
||||||
}
|
}
|
||||||
|
|
||||||
var container = new CallbackContainer(callback);
|
var container = new CallbackContainer(callback);
|
||||||
|
|
||||||
if (container.Callback.Type == MemoryCallbackType.Execute)
|
if (container.Callback.Type == MemoryCallbackType.Execute)
|
||||||
{
|
{
|
||||||
MGBAHawk.ZZHacky.BizSetExecCallback(_mgba.Core, _executeCallback);
|
MGBAHawk.ZZHacky.BizSetExecCallback(_mgba.Core, _executeCallback);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
container.ID = MGBAHawk.ZZHacky.BizSetWatchpoint(_mgba.Core, callback.Address.Value, container.WatchPointType);
|
container.ID = MGBAHawk.ZZHacky.BizSetWatchpoint(_mgba.Core, callback.Address.Value, container.WatchPointType);
|
||||||
MGBAHawk.ZZHacky.BizSetMemCallback(_mgba.Core, _readWriteCallback);
|
MGBAHawk.ZZHacky.BizSetMemCallback(_mgba.Core, _readWriteCallback);
|
||||||
}
|
}
|
||||||
|
|
||||||
_callbacks.Add(container);
|
_callbacks.Add(container);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Remove(CallbackContainer cb)
|
private void Remove(CallbackContainer cb)
|
||||||
{
|
{
|
||||||
if (cb.Callback.Type == MemoryCallbackType.Execute)
|
if (cb.Callback.Type == MemoryCallbackType.Execute)
|
||||||
{
|
{
|
||||||
_callbacks.Remove(cb);
|
_callbacks.Remove(cb);
|
||||||
|
|
||||||
|
@ -81,8 +81,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBA
|
||||||
{
|
{
|
||||||
MGBAHawk.ZZHacky.BizSetExecCallback(_mgba.Core, null);
|
MGBAHawk.ZZHacky.BizSetExecCallback(_mgba.Core, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (!MGBAHawk.ZZHacky.BizClearWatchpoint(_mgba.Core, cb.ID))
|
if (!MGBAHawk.ZZHacky.BizClearWatchpoint(_mgba.Core, cb.ID))
|
||||||
{
|
{
|
||||||
|
@ -95,107 +95,107 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBA
|
||||||
{
|
{
|
||||||
MGBAHawk.ZZHacky.BizSetMemCallback(_mgba.Core, null);
|
MGBAHawk.ZZHacky.BizSetMemCallback(_mgba.Core, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Remove(MemoryCallbackDelegate action)
|
public void Remove(MemoryCallbackDelegate action)
|
||||||
{
|
{
|
||||||
var cbToRemove = _callbacks.SingleOrDefault(c => c.Callback.Callback == action);
|
var cbToRemove = _callbacks.SingleOrDefault(c => c.Callback.Callback == action);
|
||||||
if (cbToRemove == null)
|
if (cbToRemove == null)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Remove(cbToRemove);
|
Remove(cbToRemove);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void RemoveAll(IEnumerable<MemoryCallbackDelegate> actions)
|
public void RemoveAll(IEnumerable<MemoryCallbackDelegate> actions)
|
||||||
{
|
{
|
||||||
foreach (var action in actions)
|
foreach (var action in actions)
|
||||||
{
|
{
|
||||||
Remove(action);
|
Remove(action);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Clear()
|
public void Clear()
|
||||||
{
|
{
|
||||||
foreach (var cb in _callbacks)
|
foreach (var cb in _callbacks)
|
||||||
{
|
{
|
||||||
Remove(cb);
|
Remove(cb);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerator<IMemoryCallback> GetEnumerator() => _callbacks.Select(c => c.Callback).GetEnumerator();
|
public IEnumerator<IMemoryCallback> GetEnumerator() => _callbacks.Select(c => c.Callback).GetEnumerator();
|
||||||
|
|
||||||
IEnumerator IEnumerable.GetEnumerator()
|
IEnumerator IEnumerable.GetEnumerator()
|
||||||
=> GetEnumerator();
|
=> GetEnumerator();
|
||||||
|
|
||||||
public void CallMemoryCallbacks(uint addr, uint value, uint flags, string scope)
|
public void CallMemoryCallbacks(uint addr, uint value, uint flags, string scope)
|
||||||
{
|
{
|
||||||
// Not a thing in this implementation
|
// Not a thing in this implementation
|
||||||
}
|
}
|
||||||
|
|
||||||
private void RunReadWriteCallback(uint addr, LibmGBA.mWatchpointType type, uint oldValue, uint newValue)
|
private void RunReadWriteCallback(uint addr, LibmGBA.mWatchpointType type, uint oldValue, uint newValue)
|
||||||
{
|
{
|
||||||
var flags = type switch
|
var flags = type switch
|
||||||
{
|
{
|
||||||
LibmGBA.mWatchpointType.WATCHPOINT_READ => MemoryCallbackFlags.AccessRead,
|
LibmGBA.mWatchpointType.WATCHPOINT_READ => MemoryCallbackFlags.AccessRead,
|
||||||
LibmGBA.mWatchpointType.WATCHPOINT_WRITE => MemoryCallbackFlags.AccessWrite,
|
LibmGBA.mWatchpointType.WATCHPOINT_WRITE => MemoryCallbackFlags.AccessWrite,
|
||||||
_ => throw new InvalidOperationException("Invalid watchpoint type"),
|
_ => throw new InvalidOperationException("Invalid watchpoint type"),
|
||||||
};
|
};
|
||||||
|
|
||||||
foreach (var cb in _callbacks)
|
foreach (var cb in _callbacks)
|
||||||
{
|
{
|
||||||
if (cb.WatchPointType == type && cb.Callback.Address == addr)
|
if (cb.Callback.Type != MemoryCallbackType.Execute && cb.WatchPointType == type && cb.Callback.Address == addr)
|
||||||
{
|
{
|
||||||
cb.Callback.Callback?.Invoke(addr, newValue, (uint)flags);
|
cb.Callback.Callback?.Invoke(addr, newValue, (uint)flags);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void RunExecCallback(uint pc)
|
private void RunExecCallback(uint pc)
|
||||||
{
|
{
|
||||||
foreach (var cb in _callbacks)
|
foreach (var cb in _callbacks)
|
||||||
{
|
{
|
||||||
if (cb.Callback.Type == MemoryCallbackType.Execute && cb.Callback.Address == pc)
|
if (cb.Callback.Type == MemoryCallbackType.Execute && cb.Callback.Address == pc)
|
||||||
{
|
{
|
||||||
cb.Callback.Callback?.Invoke(pc, 0, (uint)MemoryCallbackFlags.AccessExecute);
|
cb.Callback.Callback?.Invoke(pc, 0, (uint)MemoryCallbackFlags.AccessExecute);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private MemoryCallbackDelegate DebugCallback = null;
|
private MemoryCallbackDelegate DebugCallback = null;
|
||||||
|
|
||||||
private bool DebugCallbackExecuted = false;
|
private bool DebugCallbackExecuted = false;
|
||||||
|
|
||||||
public void Debug2805()
|
public void Debug2805()
|
||||||
{
|
{
|
||||||
DebugCallback = (_, _, _) =>
|
DebugCallback = (_, _, _) =>
|
||||||
{
|
{
|
||||||
Console.WriteLine(DebugCallbackExecuted ? "subsequent call" : "first call");
|
Console.WriteLine(DebugCallbackExecuted ? "subsequent call" : "first call");
|
||||||
Remove(DebugCallback);
|
Remove(DebugCallback);
|
||||||
DebugCallbackExecuted = true;
|
DebugCallbackExecuted = true;
|
||||||
};
|
};
|
||||||
Add(new MemoryCallback("System Bus", MemoryCallbackType.Write, "Plugin Hook", DebugCallback, 0x020096E0, null));
|
Add(new MemoryCallback("System Bus", MemoryCallbackType.Write, "Plugin Hook", DebugCallback, 0x020096E0, null));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class CallbackContainer
|
internal class CallbackContainer
|
||||||
{
|
{
|
||||||
public CallbackContainer(IMemoryCallback callBack)
|
public CallbackContainer(IMemoryCallback callBack)
|
||||||
{
|
{
|
||||||
Callback = callBack;
|
Callback = callBack;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IMemoryCallback Callback { get; }
|
public IMemoryCallback Callback { get; }
|
||||||
|
|
||||||
// the core returns this when setting a wp and needs it to clear that wp
|
// the core returns this when setting a wp and needs it to clear that wp
|
||||||
public int ID { get; set; }
|
public int ID { get; set; }
|
||||||
|
|
||||||
public LibmGBA.mWatchpointType WatchPointType
|
public LibmGBA.mWatchpointType WatchPointType
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
return Callback.Type switch
|
return Callback.Type switch
|
||||||
{
|
{
|
||||||
MemoryCallbackType.Read => LibmGBA.mWatchpointType.WATCHPOINT_READ,
|
MemoryCallbackType.Read => LibmGBA.mWatchpointType.WATCHPOINT_READ,
|
||||||
|
@ -203,7 +203,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBA
|
||||||
MemoryCallbackType.Execute => throw new NotImplementedException("Executes can not be used from watch points."),
|
MemoryCallbackType.Execute => throw new NotImplementedException("Executes can not be used from watch points."),
|
||||||
_ => throw new InvalidOperationException("Invalid callback type"),
|
_ => throw new InvalidOperationException("Invalid callback type"),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue