211 lines
4.3 KiB
C#
211 lines
4.3 KiB
C#
using System;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Text;
|
|
|
|
namespace BizHawk.Emulation.Common
|
|
{
|
|
public class MemoryCallbackSystem : IMemoryCallbackSystem
|
|
{
|
|
public MemoryCallbackSystem()
|
|
{
|
|
ExecuteCallbacksAvailable = true;
|
|
}
|
|
|
|
private readonly List<IMemoryCallback> Reads = new List<IMemoryCallback>();
|
|
private readonly List<IMemoryCallback> Writes = new List<IMemoryCallback>();
|
|
private readonly List<IMemoryCallback> Execs = new List<IMemoryCallback>();
|
|
|
|
bool empty = true;
|
|
|
|
private bool _hasReads = false;
|
|
private bool _hasWrites = false;
|
|
private bool _hasExecutes = false;
|
|
|
|
public bool ExecuteCallbacksAvailable { get; set; }
|
|
|
|
public void Add(IMemoryCallback callback)
|
|
{
|
|
switch (callback.Type)
|
|
{
|
|
case MemoryCallbackType.Execute:
|
|
Execs.Add(callback);
|
|
_hasExecutes = true;
|
|
break;
|
|
case MemoryCallbackType.Read:
|
|
Reads.Add(callback);
|
|
_hasReads = true;
|
|
break;
|
|
case MemoryCallbackType.Write:
|
|
Writes.Add(callback);
|
|
_hasWrites = true;
|
|
break;
|
|
}
|
|
if (empty)
|
|
Changes();
|
|
empty = false;
|
|
}
|
|
|
|
private static void Call(List<IMemoryCallback> cbs, uint addr)
|
|
{
|
|
for (int i = 0; i < cbs.Count; i++)
|
|
{
|
|
if (!cbs[i].Address.HasValue || cbs[i].Address == addr)
|
|
cbs[i].Callback();
|
|
}
|
|
}
|
|
|
|
public void CallReads(uint addr)
|
|
{
|
|
if (_hasReads)
|
|
{
|
|
Call(Reads, addr);
|
|
}
|
|
}
|
|
|
|
public void CallWrites(uint addr)
|
|
{
|
|
if (_hasWrites)
|
|
{
|
|
Call(Writes, addr);
|
|
}
|
|
}
|
|
|
|
public void CallExecutes(uint addr)
|
|
{
|
|
if (_hasExecutes)
|
|
{
|
|
Call(Execs, addr);
|
|
}
|
|
}
|
|
|
|
public bool HasReads
|
|
{
|
|
get { return _hasReads; }
|
|
}
|
|
|
|
public bool HasWrites
|
|
{
|
|
get { return _hasWrites; }
|
|
}
|
|
|
|
public bool HasExecutes
|
|
{
|
|
get { return _hasExecutes; }
|
|
}
|
|
|
|
private void UpdateHasVariables()
|
|
{
|
|
_hasReads = Reads.Count > 0;
|
|
_hasWrites = Reads.Count > 0;
|
|
_hasExecutes = Reads.Count > 0;
|
|
}
|
|
|
|
private int RemoveInternal(Action action)
|
|
{
|
|
int ret = 0;
|
|
ret += Reads.RemoveAll(imc => imc.Callback == action);
|
|
ret += Writes.RemoveAll(imc => imc.Callback == action);
|
|
ret += Execs.RemoveAll(imc => imc.Callback == action);
|
|
|
|
UpdateHasVariables();
|
|
|
|
return ret;
|
|
}
|
|
|
|
public void Remove(Action action)
|
|
{
|
|
if (RemoveInternal(action) > 0)
|
|
{
|
|
bool newEmpty = !HasReads && !HasWrites && !HasExecutes;
|
|
if (newEmpty != empty)
|
|
Changes();
|
|
empty = newEmpty;
|
|
}
|
|
}
|
|
|
|
public void RemoveAll(IEnumerable<Action> actions)
|
|
{
|
|
bool changed = false;
|
|
foreach (var action in actions)
|
|
{
|
|
changed |= RemoveInternal(action) > 0;
|
|
}
|
|
if (changed)
|
|
{
|
|
bool newEmpty = !HasReads && !HasWrites && !HasExecutes;
|
|
if (newEmpty != empty)
|
|
Changes();
|
|
empty = newEmpty;
|
|
}
|
|
|
|
UpdateHasVariables();
|
|
}
|
|
|
|
public void Clear()
|
|
{
|
|
Reads.Clear();
|
|
Writes.Clear();
|
|
Execs.Clear();
|
|
if (!empty)
|
|
Changes();
|
|
empty = true;
|
|
|
|
UpdateHasVariables();
|
|
}
|
|
|
|
public delegate void ActiveChangedEventHandler();
|
|
public event ActiveChangedEventHandler ActiveChanged;
|
|
|
|
private void Changes()
|
|
{
|
|
if (ActiveChanged != null)
|
|
{
|
|
ActiveChanged();
|
|
}
|
|
}
|
|
|
|
public IEnumerator<IMemoryCallback> GetEnumerator()
|
|
{
|
|
foreach (var imc in Reads)
|
|
yield return imc;
|
|
foreach (var imc in Writes)
|
|
yield return imc;
|
|
foreach (var imc in Execs)
|
|
yield return imc;
|
|
}
|
|
|
|
IEnumerator IEnumerable.GetEnumerator()
|
|
{
|
|
foreach (var imc in Reads)
|
|
yield return imc;
|
|
foreach (var imc in Writes)
|
|
yield return imc;
|
|
foreach (var imc in Execs)
|
|
yield return imc;
|
|
}
|
|
}
|
|
|
|
public class MemoryCallback : IMemoryCallback
|
|
{
|
|
public MemoryCallback(MemoryCallbackType type, string name, Action callback, uint? address)
|
|
{
|
|
if (type == MemoryCallbackType.Execute && !address.HasValue)
|
|
{
|
|
throw new InvalidOperationException("When assigning an execute callback, an address must be specified");
|
|
}
|
|
|
|
Type = type;
|
|
Name = name;
|
|
Callback = callback;
|
|
Address = address;
|
|
}
|
|
|
|
public MemoryCallbackType Type { get; private set; }
|
|
public string Name { get; private set; }
|
|
public Action Callback { get; private set; }
|
|
public uint? Address { get; private set; }
|
|
}
|
|
}
|