fix #3230, also cleanup this code and fix other bugs with it
This commit is contained in:
parent
ebb0282860
commit
b39631b248
|
@ -9,16 +9,17 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBA
|
|||
public class MGBAMemoryCallbackSystem : IMemoryCallbackSystem
|
||||
{
|
||||
private readonly MGBAHawk _mgba;
|
||||
private LibmGBA.ExecCallback _executeCallback;
|
||||
private readonly Dictionary<uint, IMemoryCallback> _execPcs = new Dictionary<uint, IMemoryCallback> { [0] = null };
|
||||
private readonly LibmGBA.MemCallback _readWriteCallback;
|
||||
private readonly LibmGBA.ExecCallback _executeCallback;
|
||||
private readonly List<CallbackContainer> _callbacks = new();
|
||||
|
||||
public MGBAMemoryCallbackSystem(MGBAHawk mgba)
|
||||
{
|
||||
_mgba = mgba;
|
||||
_readWriteCallback = RunReadWriteCallback;
|
||||
_executeCallback = RunExecCallback;
|
||||
}
|
||||
|
||||
private readonly List<CallbackContainer> _callbacks = new List<CallbackContainer>();
|
||||
|
||||
public string[] AvailableScopes { get; } = { "System Bus" };
|
||||
public bool ExecuteCallbacksAvailable => true;
|
||||
|
||||
|
@ -50,18 +51,21 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBA
|
|||
throw new NotImplementedException("Wildcard callbacks (no address specified) not currently implemented.");
|
||||
}
|
||||
|
||||
if (callback.AddressMask != 0xFFFFFFFF)
|
||||
{
|
||||
throw new NotImplementedException("Non 0xFFFFFFFF address masks are not currently implemented.");
|
||||
}
|
||||
|
||||
var container = new CallbackContainer(callback);
|
||||
|
||||
if (container.Callback.Type == MemoryCallbackType.Execute)
|
||||
{
|
||||
_executeCallback = RunExecCallback;
|
||||
_execPcs[callback.Address.Value] = callback;
|
||||
MGBAHawk.ZZHacky.BizSetExecCallback(_mgba.Core, _executeCallback);
|
||||
}
|
||||
else
|
||||
{
|
||||
MGBAHawk.ZZHacky.BizSetMemCallback(_mgba.Core, container.CallDelegate);
|
||||
container.ID = MGBAHawk.ZZHacky.BizSetWatchpoint(_mgba.Core, callback.Address.Value, container.WatchPointType);
|
||||
MGBAHawk.ZZHacky.BizSetMemCallback(_mgba.Core, _readWriteCallback);
|
||||
}
|
||||
|
||||
_callbacks.Add(container);
|
||||
|
@ -69,27 +73,40 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBA
|
|||
|
||||
private void Remove(CallbackContainer cb)
|
||||
{
|
||||
if (MGBAHawk.ZZHacky.BizClearWatchpoint(_mgba.Core, cb.ID)) _callbacks.Remove(cb);
|
||||
if (cb.Callback.Type == MemoryCallbackType.Execute)
|
||||
{
|
||||
_callbacks.Remove(cb);
|
||||
|
||||
if (!HasExecutes)
|
||||
{
|
||||
MGBAHawk.ZZHacky.BizSetExecCallback(_mgba.Core, null);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!MGBAHawk.ZZHacky.BizClearWatchpoint(_mgba.Core, cb.ID))
|
||||
{
|
||||
throw new InvalidOperationException("Unable to clear watchpoint???");
|
||||
}
|
||||
|
||||
_callbacks.Remove(cb);
|
||||
|
||||
if (!HasReads && !HasWrites)
|
||||
{
|
||||
MGBAHawk.ZZHacky.BizSetMemCallback(_mgba.Core, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Remove(MemoryCallbackDelegate action)
|
||||
{
|
||||
var cbToRemove = _callbacks.SingleOrDefault(container => container.Callback.Callback == action);
|
||||
if (cbToRemove == null) return;
|
||||
var cbToRemove = _callbacks.SingleOrDefault(c => c.Callback.Callback == action);
|
||||
if (cbToRemove == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (cbToRemove.Callback.Type is MemoryCallbackType.Execute)
|
||||
{
|
||||
_callbacks.Remove(cbToRemove);
|
||||
if (!_callbacks.Any(cb => cb.Callback.Type is MemoryCallbackType.Execute))
|
||||
{
|
||||
_executeCallback = null;
|
||||
MGBAHawk.ZZHacky.BizSetExecCallback(_mgba.Core, null);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Remove(cbToRemove);
|
||||
}
|
||||
Remove(cbToRemove);
|
||||
}
|
||||
|
||||
public void RemoveAll(IEnumerable<MemoryCallbackDelegate> actions)
|
||||
|
@ -102,7 +119,10 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBA
|
|||
|
||||
public void Clear()
|
||||
{
|
||||
foreach (var cb in _callbacks) Remove(cb);
|
||||
foreach (var cb in _callbacks)
|
||||
{
|
||||
Remove(cb);
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerator<IMemoryCallback> GetEnumerator() => _callbacks.Select(c => c.Callback).GetEnumerator();
|
||||
|
@ -115,11 +135,32 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBA
|
|||
// Not a thing in this implementation
|
||||
}
|
||||
|
||||
private void RunReadWriteCallback(uint addr, LibmGBA.mWatchpointType type, uint oldValue, uint newValue)
|
||||
{
|
||||
var flags = type switch
|
||||
{
|
||||
LibmGBA.mWatchpointType.WATCHPOINT_READ => MemoryCallbackFlags.AccessRead,
|
||||
LibmGBA.mWatchpointType.WATCHPOINT_WRITE => MemoryCallbackFlags.AccessWrite,
|
||||
_ => throw new InvalidOperationException("Invalid watchpoint type"),
|
||||
};
|
||||
|
||||
foreach (var cb in _callbacks)
|
||||
{
|
||||
if (cb.WatchPointType == type && cb.Callback.Address == addr)
|
||||
{
|
||||
cb.Callback.Callback?.Invoke(addr, newValue, (uint)flags);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void RunExecCallback(uint pc)
|
||||
{
|
||||
if (_execPcs.TryGetValue(pc, out var callback))
|
||||
{
|
||||
callback?.Callback?.Invoke(pc, 0, 0);
|
||||
foreach (var cb in _callbacks)
|
||||
{
|
||||
if (cb.Callback.Address == pc)
|
||||
{
|
||||
cb.Callback.Callback?.Invoke(pc, 0, (uint)MemoryCallbackFlags.AccessExecute);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -144,36 +185,25 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBA
|
|||
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 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 can not be used from watch points.");
|
||||
}
|
||||
return Callback.Type switch
|
||||
{
|
||||
MemoryCallbackType.Read => LibmGBA.mWatchpointType.WATCHPOINT_READ,
|
||||
MemoryCallbackType.Write => LibmGBA.mWatchpointType.WATCHPOINT_WRITE,
|
||||
MemoryCallbackType.Execute => throw new NotImplementedException("Executes can not be used from watch points."),
|
||||
_ => throw new InvalidOperationException("Invalid callback type"),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public LibmGBA.MemCallback CallDelegate;
|
||||
|
||||
private void Call(uint addr, LibmGBA.mWatchpointType type, uint oldValue, uint newValue)
|
||||
{
|
||||
Callback.Callback?.Invoke(addr, newValue, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue