Move MemoryCallbackSystem from CoreComm to IDebuggable and refactor accordingly, Lua - tell the user when memory callbacks are not available for a given core
This commit is contained in:
parent
11a8a009c5
commit
0b84beec88
|
@ -124,6 +124,11 @@ namespace BizHawk.Client.Common
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void LogMemoryCallbacksNotImplemented()
|
||||||
|
{
|
||||||
|
Log(string.Format("{0} does not implement memory callbacks"));
|
||||||
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
[LuaMethodAttributes(
|
[LuaMethodAttributes(
|
||||||
|
@ -196,10 +201,19 @@ namespace BizHawk.Client.Common
|
||||||
)]
|
)]
|
||||||
public string OnMemoryExecute(LuaFunction luaf, uint address, string name = null)
|
public string OnMemoryExecute(LuaFunction luaf, uint address, string name = null)
|
||||||
{
|
{
|
||||||
var nlf = new NamedLuaFunction(luaf, "OnMemoryExecute", LogOutputCallback, CurrentThread, name);
|
if (Global.Emulator.MemoryCallbacksAvailable())
|
||||||
_luaFunctions.Add(nlf);
|
{
|
||||||
Global.CoreComm.MemoryCallbackSystem.AddExecute(nlf.Callback, address);
|
var nlf = new NamedLuaFunction(luaf, "OnMemoryExecute", LogOutputCallback, CurrentThread, name);
|
||||||
return nlf.Guid.ToString();
|
_luaFunctions.Add(nlf);
|
||||||
|
|
||||||
|
Global.Emulator.AsDebuggable().MemoryCallbacks.AddExecute(nlf.Callback, address);
|
||||||
|
return nlf.Guid.ToString();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LogMemoryCallbacksNotImplemented();
|
||||||
|
return Guid.Empty.ToString();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[LuaMethodAttributes(
|
[LuaMethodAttributes(
|
||||||
|
@ -208,10 +222,18 @@ namespace BizHawk.Client.Common
|
||||||
)]
|
)]
|
||||||
public string OnMemoryRead(LuaFunction luaf, uint? address = null, string name = null)
|
public string OnMemoryRead(LuaFunction luaf, uint? address = null, string name = null)
|
||||||
{
|
{
|
||||||
var nlf = new NamedLuaFunction(luaf, "OnMemoryRead", LogOutputCallback, CurrentThread, name);
|
if (Global.Emulator.MemoryCallbacksAvailable())
|
||||||
_luaFunctions.Add(nlf);
|
{
|
||||||
Global.CoreComm.MemoryCallbackSystem.AddRead(nlf.Callback, address);
|
var nlf = new NamedLuaFunction(luaf, "OnMemoryRead", LogOutputCallback, CurrentThread, name);
|
||||||
return nlf.Guid.ToString();
|
_luaFunctions.Add(nlf);
|
||||||
|
Global.Emulator.AsDebuggable().MemoryCallbacks.AddRead(nlf.Callback, address);
|
||||||
|
return nlf.Guid.ToString();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LogMemoryCallbacksNotImplemented();
|
||||||
|
return Guid.Empty.ToString();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[LuaMethodAttributes(
|
[LuaMethodAttributes(
|
||||||
|
@ -220,10 +242,18 @@ namespace BizHawk.Client.Common
|
||||||
)]
|
)]
|
||||||
public string OnMemoryWrite(LuaFunction luaf, uint? address = null, string name = null)
|
public string OnMemoryWrite(LuaFunction luaf, uint? address = null, string name = null)
|
||||||
{
|
{
|
||||||
var nlf = new NamedLuaFunction(luaf, "OnMemoryWrite", LogOutputCallback, CurrentThread, name);
|
if (Global.Emulator.MemoryCallbacksAvailable())
|
||||||
_luaFunctions.Add(nlf);
|
{
|
||||||
Global.CoreComm.MemoryCallbackSystem.AddWrite(nlf.Callback, address);
|
var nlf = new NamedLuaFunction(luaf, "OnMemoryWrite", LogOutputCallback, CurrentThread, name);
|
||||||
return nlf.Guid.ToString();
|
_luaFunctions.Add(nlf);
|
||||||
|
Global.Emulator.AsDebuggable().MemoryCallbacks.AddWrite(nlf.Callback, address);
|
||||||
|
return nlf.Guid.ToString();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LogMemoryCallbacksNotImplemented();
|
||||||
|
return Guid.Empty.ToString();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[LuaMethodAttributes(
|
[LuaMethodAttributes(
|
||||||
|
|
|
@ -23,7 +23,11 @@ namespace BizHawk.Client.Common
|
||||||
Global.Emulator.AsInputPollable().InputCallbacks.Remove(function.Callback);
|
Global.Emulator.AsInputPollable().InputCallbacks.Remove(function.Callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
Global.Emulator.CoreComm.MemoryCallbackSystem.Remove(function.Callback);
|
if (Global.Emulator.CanDebug())
|
||||||
|
{
|
||||||
|
Global.Emulator.AsDebuggable().MemoryCallbacks.Remove(function.Callback);
|
||||||
|
}
|
||||||
|
|
||||||
return base.Remove(function);
|
return base.Remove(function);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,7 +38,11 @@ namespace BizHawk.Client.Common
|
||||||
Global.Emulator.AsInputPollable().InputCallbacks.RemoveAll(this.Select(x => x.Callback));
|
Global.Emulator.AsInputPollable().InputCallbacks.RemoveAll(this.Select(x => x.Callback));
|
||||||
}
|
}
|
||||||
|
|
||||||
Global.Emulator.CoreComm.MemoryCallbackSystem.RemoveAll(this.Select(x => x.Callback));
|
if (Global.Emulator.CanDebug())
|
||||||
|
{
|
||||||
|
Global.Emulator.AsDebuggable().MemoryCallbacks.RemoveAll(this.Select(x => x.Callback));
|
||||||
|
}
|
||||||
|
|
||||||
Clear();
|
Clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -394,7 +394,7 @@ namespace BizHawk.Client.EmuHawk
|
||||||
var b = new AddBreakpointDialog();
|
var b = new AddBreakpointDialog();
|
||||||
if (b.ShowDialog() == DialogResult.OK)
|
if (b.ShowDialog() == DialogResult.OK)
|
||||||
{
|
{
|
||||||
Breakpoints.Add(b.Address, b.BreakType);
|
Breakpoints.Add(_core, b.Address, b.BreakType);
|
||||||
}
|
}
|
||||||
|
|
||||||
BreakpointView.ItemCount = Breakpoints.Count;
|
BreakpointView.ItemCount = Breakpoints.Count;
|
||||||
|
@ -446,18 +446,21 @@ namespace BizHawk.Client.EmuHawk
|
||||||
{
|
{
|
||||||
public Action Callback { get; set; }
|
public Action Callback { get; set; }
|
||||||
|
|
||||||
public void Add(uint address, BreakpointType type)
|
public void Add(Atari2600 core, uint address, BreakpointType type)
|
||||||
{
|
{
|
||||||
Add(new AtariBreakpoint(Callback, address, type));
|
Add(new AtariBreakpoint(core, Callback, address, type));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class AtariBreakpoint
|
public class AtariBreakpoint
|
||||||
{
|
{
|
||||||
private bool _active;
|
private bool _active;
|
||||||
|
private readonly Atari2600 _core;
|
||||||
|
|
||||||
public AtariBreakpoint(Action callBack, uint address, BreakpointType type, bool enabled = true)
|
public AtariBreakpoint(Atari2600 core, Action callBack, uint address, BreakpointType type, bool enabled = true)
|
||||||
{
|
{
|
||||||
|
_core = core;
|
||||||
|
|
||||||
Callback = callBack;
|
Callback = callBack;
|
||||||
Address = address;
|
Address = address;
|
||||||
Active = enabled;
|
Active = enabled;
|
||||||
|
@ -500,20 +503,20 @@ namespace BizHawk.Client.EmuHawk
|
||||||
switch (Type)
|
switch (Type)
|
||||||
{
|
{
|
||||||
case BreakpointType.Read:
|
case BreakpointType.Read:
|
||||||
Global.CoreComm.MemoryCallbackSystem.AddRead(Callback, Address);
|
_core.MemoryCallbacks.AddRead(Callback, Address);
|
||||||
break;
|
break;
|
||||||
case BreakpointType.Write:
|
case BreakpointType.Write:
|
||||||
Global.CoreComm.MemoryCallbackSystem.AddWrite(Callback, Address);
|
_core.MemoryCallbacks.AddWrite(Callback, Address);
|
||||||
break;
|
break;
|
||||||
case BreakpointType.Execute:
|
case BreakpointType.Execute:
|
||||||
Global.CoreComm.MemoryCallbackSystem.AddExecute(Callback, Address);
|
_core.MemoryCallbacks.AddExecute(Callback, Address);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void RemoveCallback()
|
private void RemoveCallback()
|
||||||
{
|
{
|
||||||
Global.CoreComm.MemoryCallbackSystem.Remove(Callback);
|
_core.MemoryCallbacks.Remove(Callback);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,122 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace BizHawk.Emulation.Common
|
||||||
|
{
|
||||||
|
public class MemoryCallbackSystem : IMemoryCallbackSystem
|
||||||
|
{
|
||||||
|
private readonly List<Action> _reads = new List<Action>();
|
||||||
|
private readonly List<uint?> _readAddrs = new List<uint?>();
|
||||||
|
|
||||||
|
private readonly List<Action> _writes = new List<Action>();
|
||||||
|
private readonly List<uint?> _writeAddrs = new List<uint?>();
|
||||||
|
|
||||||
|
private readonly List<Action> _executes = new List<Action>();
|
||||||
|
private readonly List<uint> _execAddrs = new List<uint>();
|
||||||
|
|
||||||
|
public void AddRead(Action function, uint? addr)
|
||||||
|
{
|
||||||
|
_reads.Add(function);
|
||||||
|
_readAddrs.Add(addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddWrite(Action function, uint? addr)
|
||||||
|
{
|
||||||
|
_writes.Add(function);
|
||||||
|
_writeAddrs.Add(addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddExecute(Action function, uint addr)
|
||||||
|
{
|
||||||
|
_executes.Add(function);
|
||||||
|
_execAddrs.Add(addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void CallRead(uint addr)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < _reads.Count; i++)
|
||||||
|
{
|
||||||
|
if (!_readAddrs[i].HasValue || _readAddrs[i].Value == addr)
|
||||||
|
{
|
||||||
|
_reads[i]();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void CallWrite(uint addr)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < _writes.Count; i++)
|
||||||
|
{
|
||||||
|
if (!_writeAddrs[i].HasValue || _writeAddrs[i] == addr)
|
||||||
|
{
|
||||||
|
_writes[i]();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void CallExecute(uint addr)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < _executes.Count; i++)
|
||||||
|
{
|
||||||
|
if (_execAddrs[i] == addr)
|
||||||
|
{
|
||||||
|
_executes[i]();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool HasReads { get { return _reads.Any(); } }
|
||||||
|
public bool HasWrites { get { return _writes.Any(); } }
|
||||||
|
public bool HasExecutes { get { return _executes.Any(); } }
|
||||||
|
|
||||||
|
public void Remove(Action action)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < _reads.Count; i++)
|
||||||
|
{
|
||||||
|
if (_reads[i] == action)
|
||||||
|
{
|
||||||
|
_reads.Remove(_reads[i]);
|
||||||
|
_readAddrs.Remove(_readAddrs[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < _writes.Count; i++)
|
||||||
|
{
|
||||||
|
if (_writes[i] == action)
|
||||||
|
{
|
||||||
|
_writes.Remove(_writes[i]);
|
||||||
|
_writeAddrs.Remove(_writeAddrs[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < _executes.Count; i++)
|
||||||
|
{
|
||||||
|
if (_executes[i] == action)
|
||||||
|
{
|
||||||
|
_executes.Remove(_executes[i]);
|
||||||
|
_execAddrs.Remove(_execAddrs[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RemoveAll(IEnumerable<Action> actions)
|
||||||
|
{
|
||||||
|
foreach (var action in actions)
|
||||||
|
{
|
||||||
|
Remove(action);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Clear()
|
||||||
|
{
|
||||||
|
_reads.Clear();
|
||||||
|
_readAddrs.Clear();
|
||||||
|
_writes.Clear();
|
||||||
|
_writes.Clear();
|
||||||
|
_executes.Clear();
|
||||||
|
_execAddrs.Clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -52,6 +52,7 @@
|
||||||
<Compile Include="Base Implementations\BasicServiceProvider.cs" />
|
<Compile Include="Base Implementations\BasicServiceProvider.cs" />
|
||||||
<Compile Include="Base Implementations\ControllerDefinition.cs" />
|
<Compile Include="Base Implementations\ControllerDefinition.cs" />
|
||||||
<Compile Include="Base Implementations\InputCallbackSystem.cs" />
|
<Compile Include="Base Implementations\InputCallbackSystem.cs" />
|
||||||
|
<Compile Include="Base Implementations\MemoryCallbackSystem.cs" />
|
||||||
<Compile Include="Base Implementations\NullController.cs" />
|
<Compile Include="Base Implementations\NullController.cs" />
|
||||||
<Compile Include="Base Implementations\NullEmulator.cs" />
|
<Compile Include="Base Implementations\NullEmulator.cs" />
|
||||||
<Compile Include="Base Implementations\NullSound.cs" />
|
<Compile Include="Base Implementations\NullSound.cs" />
|
||||||
|
@ -72,6 +73,7 @@
|
||||||
<Compile Include="Interfaces\IEmulatorService.cs" />
|
<Compile Include="Interfaces\IEmulatorService.cs" />
|
||||||
<Compile Include="Interfaces\IInputCallbackSystem.cs" />
|
<Compile Include="Interfaces\IInputCallbackSystem.cs" />
|
||||||
<Compile Include="Interfaces\IInputPollable.cs" />
|
<Compile Include="Interfaces\IInputPollable.cs" />
|
||||||
|
<Compile Include="Interfaces\IMemoryCallbackSystem.cs" />
|
||||||
<Compile Include="Interfaces\IMemoryDomains.cs" />
|
<Compile Include="Interfaces\IMemoryDomains.cs" />
|
||||||
<Compile Include="Interfaces\ISaveRam.cs" />
|
<Compile Include="Interfaces\ISaveRam.cs" />
|
||||||
<Compile Include="Interfaces\IEmulatorServiceProvider.cs" />
|
<Compile Include="Interfaces\IEmulatorServiceProvider.cs" />
|
||||||
|
|
|
@ -7,9 +7,13 @@ namespace BizHawk.Emulation.Common
|
||||||
{
|
{
|
||||||
public class CoreComm
|
public class CoreComm
|
||||||
{
|
{
|
||||||
public ICoreFileProvider CoreFileProvider;
|
public CoreComm(Action<string> ShowMessage, Action<string> NotifyMessage)
|
||||||
|
{
|
||||||
|
this.ShowMessage = ShowMessage;
|
||||||
|
this.Notify = NotifyMessage;
|
||||||
|
}
|
||||||
|
|
||||||
public MemoryCallbackSystem MemoryCallbackSystem = new MemoryCallbackSystem();
|
public ICoreFileProvider CoreFileProvider;
|
||||||
|
|
||||||
public double VsyncRate
|
public double VsyncRate
|
||||||
{
|
{
|
||||||
|
@ -47,129 +51,8 @@ namespace BizHawk.Emulation.Common
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Action<string> Notify { get; private set; }
|
public Action<string> Notify { get; private set; }
|
||||||
|
|
||||||
public CoreComm(Action<string> ShowMessage, Action<string> NotifyMessage)
|
|
||||||
{
|
|
||||||
this.ShowMessage = ShowMessage;
|
|
||||||
this.Notify = NotifyMessage;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Func<object> RequestGLContext;
|
public Func<object> RequestGLContext;
|
||||||
public Action<object> ActivateGLContext;
|
public Action<object> ActivateGLContext;
|
||||||
public Action DeactivateGLContext; //this shouldnt be necessary.. frontend should be changing context before it does anything.. but for now..
|
public Action DeactivateGLContext; //this shouldnt be necessary.. frontend should be changing context before it does anything.. but for now..
|
||||||
}
|
}
|
||||||
|
|
||||||
public class MemoryCallbackSystem
|
|
||||||
{
|
|
||||||
private readonly List<Action> _reads = new List<Action>();
|
|
||||||
private readonly List<uint?> _readAddrs = new List<uint?>();
|
|
||||||
|
|
||||||
private readonly List<Action> _writes = new List<Action>();
|
|
||||||
private readonly List<uint?> _writeAddrs = new List<uint?>();
|
|
||||||
|
|
||||||
private readonly List<Action> _executes = new List<Action>();
|
|
||||||
private readonly List<uint> _execAddrs = new List<uint>();
|
|
||||||
|
|
||||||
public void AddRead(Action function, uint? addr)
|
|
||||||
{
|
|
||||||
_reads.Add(function);
|
|
||||||
_readAddrs.Add(addr);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AddWrite(Action function, uint? addr)
|
|
||||||
{
|
|
||||||
_writes.Add(function);
|
|
||||||
_writeAddrs.Add(addr);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AddExecute(Action function, uint addr)
|
|
||||||
{
|
|
||||||
_executes.Add(function);
|
|
||||||
_execAddrs.Add(addr);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void CallRead(uint addr)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < _reads.Count; i++)
|
|
||||||
{
|
|
||||||
if (!_readAddrs[i].HasValue || _readAddrs[i].Value == addr)
|
|
||||||
{
|
|
||||||
_reads[i]();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void CallWrite(uint addr)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < _writes.Count; i++)
|
|
||||||
{
|
|
||||||
if (!_writeAddrs[i].HasValue || _writeAddrs[i] == addr)
|
|
||||||
{
|
|
||||||
_writes[i]();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void CallExecute(uint addr)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < _executes.Count; i++)
|
|
||||||
{
|
|
||||||
if (_execAddrs[i] == addr)
|
|
||||||
{
|
|
||||||
_executes[i]();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool HasReads { get { return _reads.Any(); } }
|
|
||||||
public bool HasWrites { get { return _writes.Any(); } }
|
|
||||||
public bool HasExecutes { get { return _executes.Any(); } }
|
|
||||||
|
|
||||||
public void Remove(Action action)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < _reads.Count; i++)
|
|
||||||
{
|
|
||||||
if (_reads[i] == action)
|
|
||||||
{
|
|
||||||
_reads.Remove(_reads[i]);
|
|
||||||
_readAddrs.Remove(_readAddrs[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < _writes.Count; i++)
|
|
||||||
{
|
|
||||||
if (_writes[i] == action)
|
|
||||||
{
|
|
||||||
_writes.Remove(_writes[i]);
|
|
||||||
_writeAddrs.Remove(_writeAddrs[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < _executes.Count; i++)
|
|
||||||
{
|
|
||||||
if (_executes[i] == action)
|
|
||||||
{
|
|
||||||
_executes.Remove(_executes[i]);
|
|
||||||
_execAddrs.Remove(_execAddrs[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void RemoveAll(IEnumerable<Action> actions)
|
|
||||||
{
|
|
||||||
foreach (var action in actions)
|
|
||||||
{
|
|
||||||
Remove(action);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Clear()
|
|
||||||
{
|
|
||||||
_reads.Clear();
|
|
||||||
_readAddrs.Clear();
|
|
||||||
_writes.Clear();
|
|
||||||
_writes.Clear();
|
|
||||||
_executes.Clear();
|
|
||||||
_execAddrs.Clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -77,26 +77,6 @@ namespace BizHawk.Emulation.Common.IEmulatorExtensions
|
||||||
return (IInputPollable)core.ServiceProvider.GetService<IInputPollable>();
|
return (IInputPollable)core.ServiceProvider.GetService<IInputPollable>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool CpuTraceAvailable(this IEmulator core)
|
|
||||||
{
|
|
||||||
// TODO: this is a pretty ugly way to handle this
|
|
||||||
var debuggable = (IDebuggable)core.ServiceProvider.GetService<IDebuggable>();
|
|
||||||
if (debuggable != null)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var tracer = debuggable.Tracer;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
catch(NotImplementedException)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool CanDebug(this IEmulator core)
|
public static bool CanDebug(this IEmulator core)
|
||||||
{
|
{
|
||||||
if (core == null)
|
if (core == null)
|
||||||
|
@ -112,6 +92,56 @@ namespace BizHawk.Emulation.Common.IEmulatorExtensions
|
||||||
return (IDebuggable)core.ServiceProvider.GetService<IDebuggable>();
|
return (IDebuggable)core.ServiceProvider.GetService<IDebuggable>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static bool CpuTraceAvailable(this IEmulator core)
|
||||||
|
{
|
||||||
|
if (core == null)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: this is a pretty ugly way to handle this
|
||||||
|
var debuggable = (IDebuggable)core.ServiceProvider.GetService<IDebuggable>();
|
||||||
|
if (debuggable != null)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var tracer = debuggable.Tracer;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch (NotImplementedException)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool MemoryCallbacksAvailable(this IEmulator core)
|
||||||
|
{
|
||||||
|
if (core == null)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: this is a pretty ugly way to handle this
|
||||||
|
var debuggable = (IDebuggable)core.ServiceProvider.GetService<IDebuggable>();
|
||||||
|
if (debuggable != null)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var tracer = debuggable.MemoryCallbacks;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch (NotImplementedException)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: a better place for these
|
// TODO: a better place for these
|
||||||
public static bool IsImplemented(this MethodInfo info)
|
public static bool IsImplemented(this MethodInfo info)
|
||||||
{
|
{
|
||||||
|
|
|
@ -18,5 +18,7 @@ namespace BizHawk.Emulation.Common
|
||||||
void SetCpuRegister(string register, int value);
|
void SetCpuRegister(string register, int value);
|
||||||
|
|
||||||
ITracer Tracer { get; }
|
ITracer Tracer { get; }
|
||||||
|
|
||||||
|
IMemoryCallbackSystem MemoryCallbacks { get; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,70 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace BizHawk.Emulation.Common
|
||||||
|
{
|
||||||
|
public interface IMemoryCallbackSystem
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Returns whether or not there are currently any read hooks
|
||||||
|
/// </summary>
|
||||||
|
bool HasReads { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns whether or not there are currently any write hooks
|
||||||
|
/// </summary>
|
||||||
|
bool HasWrites { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns whether or not there are currently any execute hooks
|
||||||
|
/// </summary>
|
||||||
|
bool HasExecutes { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds a Read callback for the given address
|
||||||
|
/// If no address is specified the callback will be hooked to all addresses
|
||||||
|
/// </summary>
|
||||||
|
void AddRead(Action function, uint? addr);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds a Write callback for the given address
|
||||||
|
/// If no address is specified the callback will be hooked to all addresses
|
||||||
|
/// </summary>
|
||||||
|
void AddWrite(Action function, uint? addr);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds an Execute callback for the given address
|
||||||
|
/// </summary>
|
||||||
|
void AddExecute(Action function, uint addr);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Executes all Read callbacks for the given addr
|
||||||
|
/// </summary>
|
||||||
|
void CallRead(uint addr);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Executes all Write callbacks for the given addr
|
||||||
|
/// </summary>
|
||||||
|
void CallWrite(uint addr);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Executes all Execute callbacks for the given addr
|
||||||
|
/// </summary>
|
||||||
|
void CallExecute(uint addr);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Removes the given callback from the list
|
||||||
|
/// </summary>
|
||||||
|
void Remove(Action action);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Removes the given callbacks from the list
|
||||||
|
/// </summary>
|
||||||
|
void RemoveAll(IEnumerable<Action> actions);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Removes all read,write, and execute callbacks
|
||||||
|
/// </summary>
|
||||||
|
void Clear();
|
||||||
|
}
|
||||||
|
}
|
|
@ -59,7 +59,7 @@ namespace BizHawk.Emulation.Cores.Components.H6280
|
||||||
LagIFlag = FlagI;
|
LagIFlag = FlagI;
|
||||||
|
|
||||||
if (Debug) Logger(State());
|
if (Debug) Logger(State());
|
||||||
CoreComm.MemoryCallbackSystem.CallExecute(PC);
|
Core.MemoryCallbacks.CallExecute(PC);
|
||||||
if (CDLLoggingActive) CDLOpcode();
|
if (CDLLoggingActive) CDLOpcode();
|
||||||
|
|
||||||
byte opcode = ReadMemory(PC++);
|
byte opcode = ReadMemory(PC++);
|
||||||
|
|
|
@ -9,10 +9,10 @@ namespace BizHawk.Emulation.Cores.Components.H6280
|
||||||
{
|
{
|
||||||
public sealed partial class HuC6280
|
public sealed partial class HuC6280
|
||||||
{
|
{
|
||||||
public HuC6280(CoreComm comm)
|
public HuC6280(IDebuggable core)
|
||||||
{
|
{
|
||||||
Reset();
|
Reset();
|
||||||
CoreComm = comm;
|
Core = core;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Reset()
|
public void Reset()
|
||||||
|
@ -224,7 +224,7 @@ namespace BizHawk.Emulation.Cores.Components.H6280
|
||||||
public Action<int, byte> WriteVDC;
|
public Action<int, byte> WriteVDC;
|
||||||
public Action<int> ThinkAction = delegate { };
|
public Action<int> ThinkAction = delegate { };
|
||||||
|
|
||||||
public CoreComm CoreComm;
|
public IDebuggable Core;
|
||||||
|
|
||||||
public byte ReadMemory(ushort address)
|
public byte ReadMemory(ushort address)
|
||||||
{
|
{
|
||||||
|
|
|
@ -125,5 +125,7 @@ namespace BizHawk.Emulation.Cores.Calculators
|
||||||
[FeatureNotImplemented]
|
[FeatureNotImplemented]
|
||||||
get { throw new NotImplementedException(); }
|
get { throw new NotImplementedException(); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public IMemoryCallbackSystem MemoryCallbacks { get; private set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,6 +54,7 @@ namespace BizHawk.Emulation.Cores.Calculators
|
||||||
{
|
{
|
||||||
ServiceProvider = new BasicServiceProvider(this);
|
ServiceProvider = new BasicServiceProvider(this);
|
||||||
InputCallbacks = new InputCallbackSystem();
|
InputCallbacks = new InputCallbackSystem();
|
||||||
|
MemoryCallbacks = new MemoryCallbackSystem();
|
||||||
PutSettings((TI83Settings)Settings ?? new TI83Settings());
|
PutSettings((TI83Settings)Settings ?? new TI83Settings());
|
||||||
|
|
||||||
CoreComm = comm;
|
CoreComm = comm;
|
||||||
|
@ -93,7 +94,7 @@ namespace BizHawk.Emulation.Cores.Calculators
|
||||||
ret = rom[romPage * 0x4000 + addr - 0x4000]; //other rom page
|
ret = rom[romPage * 0x4000 + addr - 0x4000]; //other rom page
|
||||||
else ret = ram[addr - 0x8000];
|
else ret = ram[addr - 0x8000];
|
||||||
|
|
||||||
CoreComm.MemoryCallbackSystem.CallRead(addr);
|
MemoryCallbacks.CallRead(addr);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -106,7 +107,7 @@ namespace BizHawk.Emulation.Cores.Calculators
|
||||||
return; //other rom page
|
return; //other rom page
|
||||||
else ram[addr - 0x8000] = value;
|
else ram[addr - 0x8000] = value;
|
||||||
|
|
||||||
CoreComm.MemoryCallbackSystem.CallWrite(addr);
|
MemoryCallbacks.CallWrite(addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void WriteHardware(ushort addr, byte value)
|
public void WriteHardware(ushort addr, byte value)
|
||||||
|
|
|
@ -132,6 +132,12 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64
|
||||||
[FeatureNotImplemented]
|
[FeatureNotImplemented]
|
||||||
get { throw new NotImplementedException(); }
|
get { throw new NotImplementedException(); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public IMemoryCallbackSystem MemoryCallbacks
|
||||||
|
{
|
||||||
|
[FeatureNotImplemented]
|
||||||
|
get { throw new NotImplementedException(); }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static public class C64Util
|
static public class C64Util
|
||||||
|
|
|
@ -108,7 +108,7 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
|
||||||
|
|
||||||
_mapper.Bit13 = addr.Bit(13);
|
_mapper.Bit13 = addr.Bit(13);
|
||||||
var temp = _mapper.ReadMemory((ushort)(addr & 0x1FFF));
|
var temp = _mapper.ReadMemory((ushort)(addr & 0x1FFF));
|
||||||
CoreComm.MemoryCallbackSystem.CallRead(addr);
|
MemoryCallbacks.CallRead(addr);
|
||||||
|
|
||||||
return temp;
|
return temp;
|
||||||
}
|
}
|
||||||
|
@ -130,7 +130,7 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
|
||||||
|
|
||||||
_mapper.WriteMemory((ushort)(addr & 0x1FFF), value);
|
_mapper.WriteMemory((ushort)(addr & 0x1FFF), value);
|
||||||
|
|
||||||
CoreComm.MemoryCallbackSystem.CallWrite(addr);
|
MemoryCallbacks.CallWrite(addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void PokeMemory(ushort addr, byte value)
|
public void PokeMemory(ushort addr, byte value)
|
||||||
|
@ -140,7 +140,7 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
|
||||||
|
|
||||||
public void ExecFetch(ushort addr)
|
public void ExecFetch(ushort addr)
|
||||||
{
|
{
|
||||||
CoreComm.MemoryCallbackSystem.CallExecute(addr);
|
MemoryCallbacks.CallExecute(addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static MapperBase SetMultiCartMapper(int romLength, int gameTotal)
|
private static MapperBase SetMultiCartMapper(int romLength, int gameTotal)
|
||||||
|
|
|
@ -57,5 +57,7 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
|
||||||
}
|
}
|
||||||
|
|
||||||
public ITracer Tracer { get; private set; }
|
public ITracer Tracer { get; private set; }
|
||||||
|
|
||||||
|
public IMemoryCallbackSystem MemoryCallbacks { get; private set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,9 +24,11 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
|
||||||
[CoreConstructor("A26")]
|
[CoreConstructor("A26")]
|
||||||
public Atari2600(CoreComm comm, GameInfo game, byte[] rom, object settings, object syncSettings)
|
public Atari2600(CoreComm comm, GameInfo game, byte[] rom, object settings, object syncSettings)
|
||||||
{
|
{
|
||||||
Tracer = new TraceBuffer();
|
|
||||||
ServiceProvider = new BasicServiceProvider(this);
|
ServiceProvider = new BasicServiceProvider(this);
|
||||||
|
Tracer = new TraceBuffer();
|
||||||
|
MemoryCallbacks = new MemoryCallbackSystem();
|
||||||
InputCallbacks = new InputCallbackSystem();
|
InputCallbacks = new InputCallbackSystem();
|
||||||
|
|
||||||
Ram = new byte[128];
|
Ram = new byte[128];
|
||||||
CoreComm = comm;
|
CoreComm = comm;
|
||||||
Settings = (A2600Settings)settings ?? new A2600Settings();
|
Settings = (A2600Settings)settings ?? new A2600Settings();
|
||||||
|
|
|
@ -59,5 +59,11 @@ namespace BizHawk.Emulation.Cores.Atari.Atari7800
|
||||||
[FeatureNotImplemented]
|
[FeatureNotImplemented]
|
||||||
get { throw new NotImplementedException(); }
|
get { throw new NotImplementedException(); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public IMemoryCallbackSystem MemoryCallbacks
|
||||||
|
{
|
||||||
|
[FeatureNotImplemented]
|
||||||
|
get { throw new NotImplementedException(); }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -72,6 +72,12 @@ namespace BizHawk.Emulation.Cores.ColecoVision
|
||||||
get { throw new NotImplementedException(); }
|
get { throw new NotImplementedException(); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public IMemoryCallbackSystem MemoryCallbacks
|
||||||
|
{
|
||||||
|
[FeatureNotImplemented]
|
||||||
|
get { throw new NotImplementedException(); }
|
||||||
|
}
|
||||||
|
|
||||||
public MemoryDomainList MemoryDomains { get { return memoryDomains; } }
|
public MemoryDomainList MemoryDomains { get { return memoryDomains; } }
|
||||||
MemoryDomainList memoryDomains;
|
MemoryDomainList memoryDomains;
|
||||||
const ushort RamSizeMask = 0x03FF;
|
const ushort RamSizeMask = 0x03FF;
|
||||||
|
|
|
@ -164,8 +164,6 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CoreComm.MemoryCallbackSystem.CallRead(addr);
|
|
||||||
|
|
||||||
if (cart != null)
|
if (cart != null)
|
||||||
{
|
{
|
||||||
return (ushort)cart;
|
return (ushort)cart;
|
||||||
|
@ -356,8 +354,6 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CoreComm.MemoryCallbackSystem.CallWrite(addr);
|
|
||||||
|
|
||||||
return (cart || stic || psg);
|
return (cart || stic || psg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,6 +32,12 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBA
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public IMemoryCallbackSystem MemoryCallbacks
|
||||||
|
{
|
||||||
|
[FeatureNotImplemented]
|
||||||
|
get { throw new NotImplementedException(); }
|
||||||
|
}
|
||||||
|
|
||||||
public static readonly ControllerDefinition GBAController =
|
public static readonly ControllerDefinition GBAController =
|
||||||
new ControllerDefinition
|
new ControllerDefinition
|
||||||
{
|
{
|
||||||
|
|
|
@ -24,6 +24,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBA
|
||||||
{
|
{
|
||||||
ServiceProvider = new BasicServiceProvider(this);
|
ServiceProvider = new BasicServiceProvider(this);
|
||||||
CoreComm = comm;
|
CoreComm = comm;
|
||||||
|
MemoryCallbacks = new MemoryCallbackSystem();
|
||||||
|
|
||||||
byte[] biosfile = CoreComm.CoreFileProvider.GetFirmware("GBA", "Bios", true, "GBA bios file is mandatory.");
|
byte[] biosfile = CoreComm.CoreFileProvider.GetFirmware("GBA", "Bios", true, "GBA bios file is mandatory.");
|
||||||
if (file.Length > 32 * 1024 * 1024)
|
if (file.Length > 32 * 1024 * 1024)
|
||||||
throw new ArgumentException("ROM is too big to be a GBA ROM!");
|
throw new ArgumentException("ROM is too big to be a GBA ROM!");
|
||||||
|
@ -119,6 +121,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBA
|
||||||
|
|
||||||
public ITracer Tracer { get; private set; }
|
public ITracer Tracer { get; private set; }
|
||||||
|
|
||||||
|
public IMemoryCallbackSystem MemoryCallbacks { get; private set; }
|
||||||
|
|
||||||
public string SystemId { get { return "GBA"; } }
|
public string SystemId { get { return "GBA"; } }
|
||||||
|
|
||||||
public bool DeterministicEmulation { get; private set; }
|
public bool DeterministicEmulation { get; private set; }
|
||||||
|
@ -283,9 +287,9 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBA
|
||||||
void InitCallbacks()
|
void InitCallbacks()
|
||||||
{
|
{
|
||||||
padcb = new LibVBANext.StandardCallback(() => InputCallbacks.Call());
|
padcb = new LibVBANext.StandardCallback(() => InputCallbacks.Call());
|
||||||
fetchcb = new LibVBANext.AddressCallback((addr) => CoreComm.MemoryCallbackSystem.CallExecute(addr));
|
fetchcb = new LibVBANext.AddressCallback((addr) => MemoryCallbacks.CallExecute(addr));
|
||||||
readcb = new LibVBANext.AddressCallback((addr) => CoreComm.MemoryCallbackSystem.CallRead(addr));
|
readcb = new LibVBANext.AddressCallback((addr) => MemoryCallbacks.CallRead(addr));
|
||||||
writecb = new LibVBANext.AddressCallback((addr) => CoreComm.MemoryCallbackSystem.CallWrite(addr));
|
writecb = new LibVBANext.AddressCallback((addr) => MemoryCallbacks.CallWrite(addr));
|
||||||
tracecb = new LibVBANext.TraceCallback((addr, opcode) => Tracer.Put(Trace(addr, opcode)));
|
tracecb = new LibVBANext.TraceCallback((addr, opcode) => Tracer.Put(Trace(addr, opcode)));
|
||||||
_inputCallbacks.ActiveChanged += SyncPadCallback;
|
_inputCallbacks.ActiveChanged += SyncPadCallback;
|
||||||
}
|
}
|
||||||
|
@ -304,9 +308,9 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBA
|
||||||
void SyncCallbacks()
|
void SyncCallbacks()
|
||||||
{
|
{
|
||||||
//LibVBANext.SetPadCallback(Core, InputCallbacks.Any() ? padcb : null);
|
//LibVBANext.SetPadCallback(Core, InputCallbacks.Any() ? padcb : null);
|
||||||
LibVBANext.SetFetchCallback(Core, CoreComm.MemoryCallbackSystem.HasExecutes ? fetchcb : null);
|
LibVBANext.SetFetchCallback(Core, MemoryCallbacks.HasExecutes ? fetchcb : null);
|
||||||
LibVBANext.SetReadCallback(Core, CoreComm.MemoryCallbackSystem.HasReads ? readcb : null);
|
LibVBANext.SetReadCallback(Core, MemoryCallbacks.HasReads ? readcb : null);
|
||||||
LibVBANext.SetWriteCallback(Core, CoreComm.MemoryCallbackSystem.HasWrites ? writecb : null);
|
LibVBANext.SetWriteCallback(Core, MemoryCallbacks.HasWrites ? writecb : null);
|
||||||
LibVBANext.SetTraceCallback(Core, Tracer.Enabled ? tracecb : null);
|
LibVBANext.SetTraceCallback(Core, Tracer.Enabled ? tracecb : null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -140,6 +140,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
|
||||||
{
|
{
|
||||||
ServiceProvider = new BasicServiceProvider(this);
|
ServiceProvider = new BasicServiceProvider(this);
|
||||||
Tracer = new TraceBuffer();
|
Tracer = new TraceBuffer();
|
||||||
|
MemoryCallbacks = new MemoryCallbackSystem();
|
||||||
CoreComm = comm;
|
CoreComm = comm;
|
||||||
|
|
||||||
comm.VsyncNum = 262144;
|
comm.VsyncNum = 262144;
|
||||||
|
@ -276,6 +277,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
|
||||||
|
|
||||||
public ITracer Tracer { get; private set; }
|
public ITracer Tracer { get; private set; }
|
||||||
|
|
||||||
|
public IMemoryCallbackSystem MemoryCallbacks { get; private set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// true if the emulator is currently emulating CGB
|
/// true if the emulator is currently emulating CGB
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -643,7 +646,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
|
||||||
|
|
||||||
void RefreshMemoryCallbacks()
|
void RefreshMemoryCallbacks()
|
||||||
{
|
{
|
||||||
var mcs = CoreComm.MemoryCallbackSystem;
|
var mcs = MemoryCallbacks;
|
||||||
|
|
||||||
// we RefreshMemoryCallbacks() after the triggers in case the trigger turns itself off at that point
|
// we RefreshMemoryCallbacks() after the triggers in case the trigger turns itself off at that point
|
||||||
|
|
||||||
|
|
|
@ -93,6 +93,12 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
|
||||||
get { throw new NotImplementedException(); }
|
get { throw new NotImplementedException(); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public IMemoryCallbackSystem MemoryCallbacks
|
||||||
|
{
|
||||||
|
[FeatureNotImplemented]
|
||||||
|
get { throw new NotImplementedException(); }
|
||||||
|
}
|
||||||
|
|
||||||
public IVideoProvider VideoProvider { get { return this; } }
|
public IVideoProvider VideoProvider { get { return this; } }
|
||||||
public ISoundProvider SoundProvider { get { return null; } }
|
public ISoundProvider SoundProvider { get { return null; } }
|
||||||
public ISyncSoundProvider SyncSoundProvider { get { return this; } }
|
public ISyncSoundProvider SyncSoundProvider { get { return this; } }
|
||||||
|
|
|
@ -67,5 +67,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.N64
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public IMemoryCallbackSystem MemoryCallbacks { get; private set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,6 +52,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.N64
|
||||||
public N64(CoreComm comm, GameInfo game, byte[] file, object settings, object syncSettings)
|
public N64(CoreComm comm, GameInfo game, byte[] file, object settings, object syncSettings)
|
||||||
{
|
{
|
||||||
ServiceProvider = new BasicServiceProvider(this);
|
ServiceProvider = new BasicServiceProvider(this);
|
||||||
|
MemoryCallbacks = new MemoryCallbackSystem();
|
||||||
|
|
||||||
int SaveType = 0;
|
int SaveType = 0;
|
||||||
if (game.OptionValue("SaveType") == "EEPROM_16K")
|
if (game.OptionValue("SaveType") == "EEPROM_16K")
|
||||||
|
@ -399,7 +400,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.N64
|
||||||
|
|
||||||
private void RefreshMemoryCallbacks()
|
private void RefreshMemoryCallbacks()
|
||||||
{
|
{
|
||||||
var mcs = CoreComm.MemoryCallbackSystem;
|
var mcs = MemoryCallbacks;
|
||||||
|
|
||||||
// we RefreshMemoryCallbacks() after the triggers in case the trigger turns itself off at that point
|
// we RefreshMemoryCallbacks() after the triggers in case the trigger turns itself off at that point
|
||||||
if (mcs.HasReads)
|
if (mcs.HasReads)
|
||||||
|
|
|
@ -534,7 +534,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
|
||||||
|
|
||||||
public void ExecFetch(ushort addr)
|
public void ExecFetch(ushort addr)
|
||||||
{
|
{
|
||||||
CoreComm.MemoryCallbackSystem.CallExecute(addr);
|
MemoryCallbacks.CallExecute(addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte ReadMemory(ushort addr)
|
public byte ReadMemory(ushort addr)
|
||||||
|
@ -579,7 +579,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
|
||||||
ret = sysbus_watch[addr].ApplyGameGenie(ret);
|
ret = sysbus_watch[addr].ApplyGameGenie(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
CoreComm.MemoryCallbackSystem.CallRead(addr);
|
MemoryCallbacks.CallRead(addr);
|
||||||
|
|
||||||
DB = ret;
|
DB = ret;
|
||||||
|
|
||||||
|
@ -633,7 +633,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
|
||||||
board.WritePRG(addr - 0x8000, value);
|
board.WritePRG(addr - 0x8000, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
CoreComm.MemoryCallbackSystem.CallWrite(addr);
|
MemoryCallbacks.CallWrite(addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,6 +40,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
|
||||||
this.ControllerSettings = this.SyncSettings.Controls;
|
this.ControllerSettings = this.SyncSettings.Controls;
|
||||||
CoreComm = comm;
|
CoreComm = comm;
|
||||||
Tracer = new TraceBuffer();
|
Tracer = new TraceBuffer();
|
||||||
|
MemoryCallbacks = new MemoryCallbackSystem();
|
||||||
BootGodDB.Initialize();
|
BootGodDB.Initialize();
|
||||||
videoProvider = new MyVideoProvider(this);
|
videoProvider = new MyVideoProvider(this);
|
||||||
Init(game, rom, fdsbios);
|
Init(game, rom, fdsbios);
|
||||||
|
@ -926,6 +927,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
|
||||||
}
|
}
|
||||||
|
|
||||||
public ITracer Tracer { get; private set; }
|
public ITracer Tracer { get; private set; }
|
||||||
|
public IMemoryCallbackSystem MemoryCallbacks { get; private set; }
|
||||||
|
|
||||||
NESSettings Settings = new NESSettings();
|
NESSettings Settings = new NESSettings();
|
||||||
NESSyncSettings SyncSettings = new NESSyncSettings();
|
NESSyncSettings SyncSettings = new NESSyncSettings();
|
||||||
|
|
|
@ -402,6 +402,12 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.QuickNES
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public IMemoryCallbackSystem MemoryCallbacks
|
||||||
|
{
|
||||||
|
[FeatureNotImplemented]
|
||||||
|
get { throw new NotImplementedException(); }
|
||||||
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
public IInputCallbackSystem InputCallbacks { [FeatureNotImplemented]get { throw new NotImplementedException(); } }
|
public IInputCallbackSystem InputCallbacks { [FeatureNotImplemented]get { throw new NotImplementedException(); } }
|
||||||
|
|
|
@ -35,6 +35,9 @@ namespace BizHawk.Emulation.Cores.Nintendo.SNES
|
||||||
public LibsnesCore(GameInfo game, byte[] romData, bool deterministicEmulation, byte[] xmlData, CoreComm comm, object Settings, object SyncSettings)
|
public LibsnesCore(GameInfo game, byte[] romData, bool deterministicEmulation, byte[] xmlData, CoreComm comm, object Settings, object SyncSettings)
|
||||||
{
|
{
|
||||||
ServiceProvider = new BasicServiceProvider(this);
|
ServiceProvider = new BasicServiceProvider(this);
|
||||||
|
MemoryCallbacks = new MemoryCallbackSystem();
|
||||||
|
Tracer = new TraceBuffer();
|
||||||
|
|
||||||
_game = game;
|
_game = game;
|
||||||
CoreComm = comm;
|
CoreComm = comm;
|
||||||
byte[] sgbRomData = null;
|
byte[] sgbRomData = null;
|
||||||
|
@ -146,8 +149,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.SNES
|
||||||
CoreComm.VsyncDen = 4 * 341 * 312;
|
CoreComm.VsyncDen = 4 * 341 * 312;
|
||||||
}
|
}
|
||||||
|
|
||||||
Tracer = new TraceBuffer();
|
|
||||||
|
|
||||||
api.CMD_power();
|
api.CMD_power();
|
||||||
|
|
||||||
SetupMemoryDomains(romData, sgbRomData);
|
SetupMemoryDomains(romData, sgbRomData);
|
||||||
|
@ -250,6 +251,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.SNES
|
||||||
public IInputCallbackSystem InputCallbacks { [FeatureNotImplemented]get { return _inputCallbacks; } }
|
public IInputCallbackSystem InputCallbacks { [FeatureNotImplemented]get { return _inputCallbacks; } }
|
||||||
|
|
||||||
public ITracer Tracer { get; private set; }
|
public ITracer Tracer { get; private set; }
|
||||||
|
public IMemoryCallbackSystem MemoryCallbacks { get; private set; }
|
||||||
|
|
||||||
[FeatureNotImplemented]
|
[FeatureNotImplemented]
|
||||||
public void SetCpuRegister(string register, int value)
|
public void SetCpuRegister(string register, int value)
|
||||||
|
@ -385,7 +387,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.SNES
|
||||||
|
|
||||||
void ReadHook(uint addr)
|
void ReadHook(uint addr)
|
||||||
{
|
{
|
||||||
CoreComm.MemoryCallbackSystem.CallRead(addr);
|
MemoryCallbacks.CallRead(addr);
|
||||||
//we RefreshMemoryCallbacks() after the trigger in case the trigger turns itself off at that point
|
//we RefreshMemoryCallbacks() after the trigger in case the trigger turns itself off at that point
|
||||||
//EDIT: for now, theres some IPC re-entrancy problem
|
//EDIT: for now, theres some IPC re-entrancy problem
|
||||||
//RefreshMemoryCallbacks();
|
//RefreshMemoryCallbacks();
|
||||||
|
@ -393,7 +395,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.SNES
|
||||||
}
|
}
|
||||||
void ExecHook(uint addr)
|
void ExecHook(uint addr)
|
||||||
{
|
{
|
||||||
CoreComm.MemoryCallbackSystem.CallExecute(addr);
|
MemoryCallbacks.CallExecute(addr);
|
||||||
//we RefreshMemoryCallbacks() after the trigger in case the trigger turns itself off at that point
|
//we RefreshMemoryCallbacks() after the trigger in case the trigger turns itself off at that point
|
||||||
//EDIT: for now, theres some IPC re-entrancy problem
|
//EDIT: for now, theres some IPC re-entrancy problem
|
||||||
//RefreshMemoryCallbacks();
|
//RefreshMemoryCallbacks();
|
||||||
|
@ -401,7 +403,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.SNES
|
||||||
}
|
}
|
||||||
void WriteHook(uint addr, byte val)
|
void WriteHook(uint addr, byte val)
|
||||||
{
|
{
|
||||||
CoreComm.MemoryCallbackSystem.CallWrite(addr);
|
MemoryCallbacks.CallWrite(addr);
|
||||||
//we RefreshMemoryCallbacks() after the trigger in case the trigger turns itself off at that point
|
//we RefreshMemoryCallbacks() after the trigger in case the trigger turns itself off at that point
|
||||||
//EDIT: for now, theres some IPC re-entrancy problem
|
//EDIT: for now, theres some IPC re-entrancy problem
|
||||||
//RefreshMemoryCallbacks();
|
//RefreshMemoryCallbacks();
|
||||||
|
@ -649,7 +651,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.SNES
|
||||||
|
|
||||||
void RefreshMemoryCallbacks(bool suppress)
|
void RefreshMemoryCallbacks(bool suppress)
|
||||||
{
|
{
|
||||||
var mcs = CoreComm.MemoryCallbackSystem;
|
var mcs = MemoryCallbacks;
|
||||||
api.QUERY_set_state_hook_exec(!suppress && mcs.HasExecutes);
|
api.QUERY_set_state_hook_exec(!suppress && mcs.HasExecutes);
|
||||||
api.QUERY_set_state_hook_read(!suppress && mcs.HasReads);
|
api.QUERY_set_state_hook_read(!suppress && mcs.HasReads);
|
||||||
api.QUERY_set_state_hook_write(!suppress && mcs.HasWrites);
|
api.QUERY_set_state_hook_write(!suppress && mcs.HasWrites);
|
||||||
|
|
|
@ -70,6 +70,7 @@ namespace BizHawk.Emulation.Cores.PCEngine
|
||||||
{
|
{
|
||||||
ServiceProvider = new BasicServiceProvider(this);
|
ServiceProvider = new BasicServiceProvider(this);
|
||||||
Tracer = new TraceBuffer();
|
Tracer = new TraceBuffer();
|
||||||
|
MemoryCallbacks = new MemoryCallbackSystem();
|
||||||
CoreComm = comm;
|
CoreComm = comm;
|
||||||
|
|
||||||
switch (game.System)
|
switch (game.System)
|
||||||
|
@ -94,11 +95,13 @@ namespace BizHawk.Emulation.Cores.PCEngine
|
||||||
public string BoardName { get { return null; } }
|
public string BoardName { get { return null; } }
|
||||||
|
|
||||||
public ITracer Tracer { get; private set; }
|
public ITracer Tracer { get; private set; }
|
||||||
|
public IMemoryCallbackSystem MemoryCallbacks { get; private set; }
|
||||||
|
|
||||||
public PCEngine(CoreComm comm, GameInfo game, Disc disc, object Settings, object syncSettings)
|
public PCEngine(CoreComm comm, GameInfo game, Disc disc, object Settings, object syncSettings)
|
||||||
{
|
{
|
||||||
CoreComm = comm;
|
CoreComm = comm;
|
||||||
Tracer = new TraceBuffer();
|
Tracer = new TraceBuffer();
|
||||||
|
MemoryCallbacks = new MemoryCallbackSystem();
|
||||||
CoreComm.UsesDriveLed = true;
|
CoreComm.UsesDriveLed = true;
|
||||||
systemid = "PCECD";
|
systemid = "PCECD";
|
||||||
Type = NecSystemType.TurboCD;
|
Type = NecSystemType.TurboCD;
|
||||||
|
@ -152,7 +155,7 @@ namespace BizHawk.Emulation.Cores.PCEngine
|
||||||
void Init(GameInfo game, byte[] rom)
|
void Init(GameInfo game, byte[] rom)
|
||||||
{
|
{
|
||||||
Controller = NullController.GetNullController();
|
Controller = NullController.GetNullController();
|
||||||
Cpu = new HuC6280(CoreComm);
|
Cpu = new HuC6280(this);
|
||||||
VCE = new VCE();
|
VCE = new VCE();
|
||||||
VDC1 = new VDC(this, Cpu, VCE);
|
VDC1 = new VDC(this, Cpu, VCE);
|
||||||
PSG = new HuC6280PSG();
|
PSG = new HuC6280PSG();
|
||||||
|
|
|
@ -48,6 +48,12 @@ namespace BizHawk.Emulation.Cores.Sega.Genesis
|
||||||
[FeatureNotImplemented]
|
[FeatureNotImplemented]
|
||||||
public IInputCallbackSystem InputCallbacks { get { throw new NotImplementedException(); } }
|
public IInputCallbackSystem InputCallbacks { get { throw new NotImplementedException(); } }
|
||||||
|
|
||||||
|
public IMemoryCallbackSystem MemoryCallbacks
|
||||||
|
{
|
||||||
|
[FeatureNotImplemented]
|
||||||
|
get { throw new NotImplementedException(); }
|
||||||
|
}
|
||||||
|
|
||||||
public void ResetCounters()
|
public void ResetCounters()
|
||||||
{
|
{
|
||||||
Frame = 0;
|
Frame = 0;
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
else
|
else
|
||||||
ret = SystemRam[address & RamSizeMask];
|
ret = SystemRam[address & RamSizeMask];
|
||||||
|
|
||||||
CoreComm.MemoryCallbackSystem.CallRead(address);
|
MemoryCallbacks.CallRead(address);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,7 +27,7 @@
|
||||||
else if (address >= 0xC000)
|
else if (address >= 0xC000)
|
||||||
SystemRam[address & RamSizeMask] = value;
|
SystemRam[address & RamSizeMask] = value;
|
||||||
|
|
||||||
CoreComm.MemoryCallbackSystem.CallWrite((uint)address);
|
MemoryCallbacks.CallWrite((uint)address);
|
||||||
}
|
}
|
||||||
|
|
||||||
void InitExt2kMapper(int size)
|
void InitExt2kMapper(int size)
|
||||||
|
|
|
@ -53,7 +53,7 @@
|
||||||
ret = SystemRam[address & RamSizeMask];
|
ret = SystemRam[address & RamSizeMask];
|
||||||
}
|
}
|
||||||
|
|
||||||
CoreComm.MemoryCallbackSystem.CallRead(address);
|
MemoryCallbacks.CallRead(address);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -91,7 +91,7 @@
|
||||||
else if (address == 0xFFFF) RomBank2 = (byte)(value % RomBanks);
|
else if (address == 0xFFFF) RomBank2 = (byte)(value % RomBanks);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
CoreComm.MemoryCallbackSystem.CallWrite((uint)address);
|
MemoryCallbacks.CallWrite((uint)address);
|
||||||
}
|
}
|
||||||
|
|
||||||
void InitSegaMapper()
|
void InitSegaMapper()
|
||||||
|
|
|
@ -81,6 +81,7 @@ namespace BizHawk.Emulation.Cores.Sega.MasterSystem
|
||||||
|
|
||||||
private readonly InputCallbackSystem _inputCallbacks = new InputCallbackSystem();
|
private readonly InputCallbackSystem _inputCallbacks = new InputCallbackSystem();
|
||||||
public IInputCallbackSystem InputCallbacks { get { return _inputCallbacks; } }
|
public IInputCallbackSystem InputCallbacks { get { return _inputCallbacks; } }
|
||||||
|
public IMemoryCallbackSystem MemoryCallbacks { get; private set; }
|
||||||
|
|
||||||
byte Port01 = 0xFF;
|
byte Port01 = 0xFF;
|
||||||
byte Port02 = 0xFF;
|
byte Port02 = 0xFF;
|
||||||
|
@ -100,6 +101,7 @@ namespace BizHawk.Emulation.Cores.Sega.MasterSystem
|
||||||
Settings = (SMSSettings)settings ?? new SMSSettings();
|
Settings = (SMSSettings)settings ?? new SMSSettings();
|
||||||
SyncSettings = (SMSSyncSettings)syncSettings ?? new SMSSyncSettings();
|
SyncSettings = (SMSSyncSettings)syncSettings ?? new SMSSyncSettings();
|
||||||
CoreComm = comm;
|
CoreComm = comm;
|
||||||
|
MemoryCallbacks = new MemoryCallbackSystem();
|
||||||
|
|
||||||
IsGameGear = game.System == "GG";
|
IsGameGear = game.System == "GG";
|
||||||
IsSG1000 = game.System == "SG";
|
IsSG1000 = game.System == "SG";
|
||||||
|
|
|
@ -397,6 +397,9 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private readonly MemoryCallbackSystem _memoryCallbacks = new MemoryCallbackSystem();
|
||||||
|
public IMemoryCallbackSystem MemoryCallbacks { get { return _memoryCallbacks; } }
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
// TODO: use render and rendersound
|
// TODO: use render and rendersound
|
||||||
|
@ -660,17 +663,17 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx
|
||||||
|
|
||||||
void InitMemCallbacks()
|
void InitMemCallbacks()
|
||||||
{
|
{
|
||||||
ExecCallback = new LibGPGX.mem_cb(a => CoreComm.MemoryCallbackSystem.CallExecute(a));
|
ExecCallback = new LibGPGX.mem_cb(a => MemoryCallbacks.CallExecute(a));
|
||||||
ReadCallback = new LibGPGX.mem_cb(a => CoreComm.MemoryCallbackSystem.CallRead(a));
|
ReadCallback = new LibGPGX.mem_cb(a => MemoryCallbacks.CallRead(a));
|
||||||
WriteCallback = new LibGPGX.mem_cb(a => CoreComm.MemoryCallbackSystem.CallWrite(a));
|
WriteCallback = new LibGPGX.mem_cb(a => MemoryCallbacks.CallWrite(a));
|
||||||
}
|
}
|
||||||
|
|
||||||
void RefreshMemCallbacks()
|
void RefreshMemCallbacks()
|
||||||
{
|
{
|
||||||
LibGPGX.gpgx_set_mem_callback(
|
LibGPGX.gpgx_set_mem_callback(
|
||||||
CoreComm.MemoryCallbackSystem.HasReads ? ReadCallback : null,
|
MemoryCallbacks.HasReads ? ReadCallback : null,
|
||||||
CoreComm.MemoryCallbackSystem.HasWrites ? WriteCallback : null,
|
MemoryCallbacks.HasWrites ? WriteCallback : null,
|
||||||
CoreComm.MemoryCallbackSystem.HasExecutes ? ExecCallback : null);
|
MemoryCallbacks.HasExecutes ? ExecCallback : null);
|
||||||
}
|
}
|
||||||
|
|
||||||
void KillMemCallbacks()
|
void KillMemCallbacks()
|
||||||
|
|
|
@ -90,6 +90,7 @@ namespace BizHawk.Emulation.Cores.WonderSwan
|
||||||
public WonderSwan(CoreComm comm, byte[] file, bool deterministic, object Settings, object SyncSettings)
|
public WonderSwan(CoreComm comm, byte[] file, bool deterministic, object Settings, object SyncSettings)
|
||||||
{
|
{
|
||||||
ServiceProvider = new BasicServiceProvider(this);
|
ServiceProvider = new BasicServiceProvider(this);
|
||||||
|
MemoryCallbacks = new MemoryCallbackSystem();
|
||||||
CoreComm = comm;
|
CoreComm = comm;
|
||||||
_Settings = (Settings)Settings ?? new Settings();
|
_Settings = (Settings)Settings ?? new Settings();
|
||||||
_SyncSettings = (SyncSettings)SyncSettings ?? new SyncSettings();
|
_SyncSettings = (SyncSettings)SyncSettings ?? new SyncSettings();
|
||||||
|
@ -141,6 +142,8 @@ namespace BizHawk.Emulation.Cores.WonderSwan
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public IMemoryCallbackSystem MemoryCallbacks { get; private set; }
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
if (Core != IntPtr.Zero)
|
if (Core != IntPtr.Zero)
|
||||||
|
@ -353,15 +356,15 @@ namespace BizHawk.Emulation.Cores.WonderSwan
|
||||||
|
|
||||||
void ReadCallback(uint addr)
|
void ReadCallback(uint addr)
|
||||||
{
|
{
|
||||||
CoreComm.MemoryCallbackSystem.CallRead(addr);
|
MemoryCallbacks.CallRead(addr);
|
||||||
}
|
}
|
||||||
void WriteCallback(uint addr)
|
void WriteCallback(uint addr)
|
||||||
{
|
{
|
||||||
CoreComm.MemoryCallbackSystem.CallWrite(addr);
|
MemoryCallbacks.CallWrite(addr);
|
||||||
}
|
}
|
||||||
void ExecCallback(uint addr)
|
void ExecCallback(uint addr)
|
||||||
{
|
{
|
||||||
CoreComm.MemoryCallbackSystem.CallExecute(addr);
|
MemoryCallbacks.CallExecute(addr);
|
||||||
}
|
}
|
||||||
void ButtonCallback()
|
void ButtonCallback()
|
||||||
{
|
{
|
||||||
|
@ -391,9 +394,9 @@ namespace BizHawk.Emulation.Cores.WonderSwan
|
||||||
void SetMemoryCallbacks()
|
void SetMemoryCallbacks()
|
||||||
{
|
{
|
||||||
BizSwan.bizswan_setmemorycallbacks(Core,
|
BizSwan.bizswan_setmemorycallbacks(Core,
|
||||||
CoreComm.MemoryCallbackSystem.HasReads ? ReadCallbackD : null,
|
MemoryCallbacks.HasReads ? ReadCallbackD : null,
|
||||||
CoreComm.MemoryCallbackSystem.HasWrites ? WriteCallbackD : null,
|
MemoryCallbacks.HasWrites ? WriteCallbackD : null,
|
||||||
CoreComm.MemoryCallbackSystem.HasExecutes ? ExecCallbackD : null);
|
MemoryCallbacks.HasExecutes ? ExecCallbackD : null);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
Loading…
Reference in New Issue