[mGBA] don't try to read watchpoint type for execute callbacks

This commit is contained in:
CasualPokePlayer 2022-05-01 11:06:36 -07:00 committed by GitHub
parent f7ead5f592
commit cd8f5b4203
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 167 additions and 167 deletions

View File

@ -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"),
}; };
} }
} }
} }
} }