mGBA update, various cleanups and some reorg
This commit is contained in:
parent
f6503adfb8
commit
f3ee3e7956
|
@ -14,7 +14,7 @@
|
|||
[submodule "mgba"]
|
||||
path = submodules/mgba
|
||||
url = https://github.com/TASEmulators/mgba.git
|
||||
branch = bizhawk-0.10
|
||||
branch = bizhawk-0.11
|
||||
[submodule "waterbox/melon/melonDS"]
|
||||
path = waterbox/melon/melonDS
|
||||
url = https://github.com/TASEmulators/melonDS.git
|
||||
|
|
Binary file not shown.
Binary file not shown.
|
@ -1,4 +1,5 @@
|
|||
using System;
|
||||
|
||||
using BizHawk.Emulation.Common;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Nintendo.GBA
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
using BizHawk.BizInvoke;
|
||||
using BizHawk.Emulation.Common;
|
||||
|
||||
|
@ -8,7 +9,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBA
|
|||
public abstract class LibmGBA
|
||||
{
|
||||
[Flags]
|
||||
public enum Buttons : int
|
||||
public enum Buttons : ushort
|
||||
{
|
||||
A = 1,
|
||||
B = 2,
|
||||
|
@ -91,7 +92,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBA
|
|||
CHB = 32
|
||||
}
|
||||
|
||||
public enum mWatchpointType
|
||||
public enum mWatchpointType : int
|
||||
{
|
||||
WATCHPOINT_WRITE = 1,
|
||||
WATCHPOINT_READ = 2,
|
||||
|
@ -100,16 +101,19 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBA
|
|||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public class OverrideInfo
|
||||
public struct OverrideInfo
|
||||
{
|
||||
public SaveType Savetype;
|
||||
public Hardware Hardware;
|
||||
public uint IdleLoop = IDLE_LOOP_NONE;
|
||||
public const uint IDLE_LOOP_NONE = unchecked((uint)0xffffffff);
|
||||
public uint IdleLoop;
|
||||
public bool VbaBugCompat;
|
||||
public bool DetectPokemonRomHacks;
|
||||
|
||||
public const uint IDLE_LOOP_NONE = 0xffffffffu;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public class MemoryAreas
|
||||
public struct MemoryAreas
|
||||
{
|
||||
public IntPtr bios;
|
||||
public IntPtr wram;
|
||||
|
@ -122,29 +126,29 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBA
|
|||
public IntPtr sram;
|
||||
}
|
||||
|
||||
[BizImport(cc, Compatibility = true)]
|
||||
[BizImport(cc)]
|
||||
public abstract void BizDestroy(IntPtr ctx);
|
||||
|
||||
[BizImport(cc, Compatibility = true)]
|
||||
public abstract IntPtr BizCreate(byte[] bios, byte[] data, int length, [In]OverrideInfo dbinfo, bool skipBios);
|
||||
[BizImport(cc)]
|
||||
public abstract IntPtr BizCreate(byte[] bios, byte[] data, int length, ref OverrideInfo overrides, bool skipBios);
|
||||
|
||||
[BizImport(cc, Compatibility = true)]
|
||||
[BizImport(cc)]
|
||||
public abstract void BizReset(IntPtr ctx);
|
||||
|
||||
[BizImport(cc, Compatibility = true)]
|
||||
[BizImport(cc)]
|
||||
public abstract bool BizAdvance(IntPtr ctx, Buttons keys, int[] vbuff, ref int nsamp, short[] sbuff,
|
||||
long time, short gyrox, short gyroy, short gyroz, byte luma);
|
||||
|
||||
[BizImport(cc, Compatibility = true)]
|
||||
[BizImport(cc)]
|
||||
public abstract void BizSetPalette(IntPtr ctx, int[] palette);
|
||||
|
||||
[BizImport(cc, Compatibility = true)]
|
||||
public abstract void BizGetMemoryAreas(IntPtr ctx, [Out]MemoryAreas dst);
|
||||
[BizImport(cc)]
|
||||
public abstract void BizGetMemoryAreas(IntPtr ctx, out MemoryAreas dst);
|
||||
|
||||
[BizImport(cc, Compatibility = true)]
|
||||
[BizImport(cc)]
|
||||
public abstract int BizGetSaveRam(IntPtr ctx, byte[] dest, int maxsize);
|
||||
|
||||
[BizImport(cc, Compatibility = true)]
|
||||
[BizImport(cc)]
|
||||
public abstract void BizPutSaveRam(IntPtr ctx, byte[] src, int size);
|
||||
|
||||
/// <summary>
|
||||
|
@ -153,8 +157,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBA
|
|||
/// <param name="p">private parameter to be passed to BizFinishGetState</param>
|
||||
/// <param name="size">size of buffer to be allocated for BizFinishGetState</param>
|
||||
/// <returns>if false, operation failed and BizFinishGetState should not be called</returns>
|
||||
[BizImport(cc, Compatibility = true)]
|
||||
public abstract bool BizStartGetState(IntPtr ctx, ref IntPtr p, ref int size);
|
||||
[BizImport(cc)]
|
||||
public abstract bool BizStartGetState(IntPtr ctx, out IntPtr p, out int size);
|
||||
|
||||
/// <summary>
|
||||
/// finish a savestate operation. if StartGetState returned true, this must be called else memory leaks
|
||||
|
@ -162,57 +166,61 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBA
|
|||
/// <param name="p">returned by BizStartGetState</param>
|
||||
/// <param name="dest">buffer of length size</param>
|
||||
/// <param name="size">returned by BizStartGetState</param>
|
||||
[BizImport(cc, Compatibility = true)]
|
||||
[BizImport(cc)]
|
||||
public abstract void BizFinishGetState(IntPtr p, byte[] dest, int size);
|
||||
|
||||
[BizImport(cc, Compatibility = true)]
|
||||
[BizImport(cc)]
|
||||
public abstract bool BizPutState(IntPtr ctx, byte[] src, int size);
|
||||
|
||||
[BizImport(cc, Compatibility = true)]
|
||||
[BizImport(cc)]
|
||||
public abstract void BizSetLayerMask(IntPtr ctx, Layers mask);
|
||||
|
||||
[BizImport(cc, Compatibility = true)]
|
||||
[BizImport(cc)]
|
||||
public abstract void BizSetSoundMask(IntPtr ctx, Sounds mask);
|
||||
|
||||
[BizImport(cc, Compatibility = true)]
|
||||
[BizImport(cc)]
|
||||
public abstract void BizGetRegisters(IntPtr ctx, int[] dest);
|
||||
|
||||
[BizImport(cc, Compatibility = true)]
|
||||
[BizImport(cc)]
|
||||
public abstract void BizSetRegister(IntPtr ctx, int index, int value);
|
||||
|
||||
[BizImport(cc, Compatibility = true)]
|
||||
[BizImport(cc)]
|
||||
public abstract ulong BizGetGlobalTime(IntPtr ctx);
|
||||
|
||||
[BizImport(cc, Compatibility = true)]
|
||||
[BizImport(cc)]
|
||||
public abstract void BizWriteBus(IntPtr ctx, uint addr, byte val);
|
||||
|
||||
[BizImport(cc, Compatibility = true)]
|
||||
[BizImport(cc)]
|
||||
public abstract byte BizReadBus(IntPtr ctx, uint addr);
|
||||
|
||||
[UnmanagedFunctionPointer(cc)]
|
||||
public delegate void InputCallback();
|
||||
[BizImport(cc, Compatibility = true)]
|
||||
|
||||
[BizImport(cc)]
|
||||
public abstract void BizSetInputCallback(IntPtr ctx, InputCallback cb);
|
||||
|
||||
[UnmanagedFunctionPointer(cc)]
|
||||
public delegate void TraceCallback(string msg);
|
||||
[BizImport(cc, Compatibility = true)]
|
||||
|
||||
[BizImport(cc)]
|
||||
public abstract void BizSetTraceCallback(IntPtr ctx, TraceCallback cb);
|
||||
|
||||
[UnmanagedFunctionPointer(cc)]
|
||||
public delegate void MemCallback(uint addr, mWatchpointType type, uint oldValue, uint newValue);
|
||||
[BizImport(cc, Compatibility = true)]
|
||||
|
||||
[BizImport(cc)]
|
||||
public abstract void BizSetMemCallback(IntPtr ctx, MemCallback cb);
|
||||
|
||||
[UnmanagedFunctionPointer(cc)]
|
||||
public delegate void ExecCallback(uint pc);
|
||||
[BizImport(cc, Compatibility = true)]
|
||||
|
||||
[BizImport(cc)]
|
||||
public abstract void BizSetExecCallback(IntPtr ctx, ExecCallback cb);
|
||||
|
||||
[BizImport(cc, Compatibility = true)]
|
||||
public abstract int BizSetWatchpoint(IntPtr ctx, uint addr, mWatchpointType type);
|
||||
[BizImport(cc)]
|
||||
public abstract long BizSetWatchpoint(IntPtr ctx, uint addr, mWatchpointType type);
|
||||
|
||||
[BizImport(cc, Compatibility = true)]
|
||||
public abstract bool BizClearWatchpoint(IntPtr ctx, int id);
|
||||
[BizImport(cc)]
|
||||
public abstract bool BizClearWatchpoint(IntPtr ctx, long id);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using BizHawk.Emulation.Common;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Nintendo.GBA
|
||||
|
@ -13,7 +14,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBA
|
|||
var ret = new Dictionary<string, RegisterValue>();
|
||||
for (var i = 0; i < RegisterNames.Length; i++)
|
||||
{
|
||||
ret[RegisterNames[i]] = new RegisterValue(values[i]);
|
||||
ret[RegisterNames[i]] = new(values[i]);
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
@ -41,7 +42,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBA
|
|||
"R15" => 15,
|
||||
"CPSR" => 16,
|
||||
"SPSR" => 17,
|
||||
_=> -1
|
||||
_ => -1
|
||||
};
|
||||
|
||||
if (index != -1)
|
||||
|
@ -50,7 +51,9 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBA
|
|||
}
|
||||
}
|
||||
|
||||
public IMemoryCallbackSystem MemoryCallbacks { get; }
|
||||
private readonly MGBAMemoryCallbackSystem _memoryCallbacks;
|
||||
|
||||
public IMemoryCallbackSystem MemoryCallbacks => _memoryCallbacks;
|
||||
|
||||
public bool CanStep(StepType type) => false;
|
||||
|
||||
|
|
|
@ -0,0 +1,81 @@
|
|||
using System;
|
||||
|
||||
using BizHawk.Common;
|
||||
using BizHawk.Emulation.Common;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Nintendo.GBA
|
||||
{
|
||||
public partial class MGBAHawk : IEmulator
|
||||
{
|
||||
public IEmulatorServiceProvider ServiceProvider { get; }
|
||||
|
||||
public ControllerDefinition ControllerDefinition => GBAController;
|
||||
|
||||
public bool FrameAdvance(IController controller, bool render, bool renderSound = true)
|
||||
{
|
||||
if (controller.IsPressed("Power"))
|
||||
{
|
||||
LibmGBA.BizReset(Core);
|
||||
|
||||
// BizReset caused memorydomain pointers to change.
|
||||
WireMemoryDomainPointers();
|
||||
}
|
||||
|
||||
LibmGBA.BizSetTraceCallback(Core, Tracer.IsEnabled() ? _tracecb : null);
|
||||
|
||||
IsLagFrame = LibmGBA.BizAdvance(
|
||||
Core,
|
||||
LibmGBA.GetButtons(controller),
|
||||
render ? _videobuff : _dummyvideobuff,
|
||||
ref _nsamp,
|
||||
renderSound ? _soundbuff : _dummysoundbuff,
|
||||
RTCTime(),
|
||||
(short)controller.AxisValue("Tilt X"),
|
||||
(short)controller.AxisValue("Tilt Y"),
|
||||
(short)controller.AxisValue("Tilt Z"),
|
||||
(byte)(255 - controller.AxisValue("Light Sensor")));
|
||||
|
||||
if (IsLagFrame)
|
||||
{
|
||||
LagCount++;
|
||||
}
|
||||
|
||||
// this should be called in hblank on the appropriate line, but until we implement that, just do it here
|
||||
_scanlinecb?.Invoke();
|
||||
|
||||
Frame++;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public int Frame { get; private set; }
|
||||
|
||||
public string SystemId => VSystemID.Raw.GBA;
|
||||
|
||||
public bool DeterministicEmulation { get; }
|
||||
|
||||
public void ResetCounters()
|
||||
{
|
||||
Frame = 0;
|
||||
LagCount = 0;
|
||||
IsLagFrame = false;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (Core != IntPtr.Zero)
|
||||
{
|
||||
LibmGBA.BizDestroy(Core);
|
||||
Core = IntPtr.Zero;
|
||||
_memoryCallbacks.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
public static readonly ControllerDefinition GBAController = new ControllerDefinition("GBA Controller")
|
||||
{
|
||||
BoolButtons = { "Up", "Down", "Left", "Right", "Start", "Select", "B", "A", "L", "R", "Power" }
|
||||
}.AddXYZTriple("Tilt {0}", (-32767).RangeTo(32767), 0)
|
||||
.AddAxis("Light Sensor", 0.RangeTo(255), 0)
|
||||
.MakeImmutable();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
using System;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Nintendo.GBA
|
||||
{
|
||||
public partial class MGBAHawk : IGBAGPUViewable
|
||||
{
|
||||
public GBAGPUMemoryAreas GetMemoryAreas()
|
||||
=> _gpumem;
|
||||
|
||||
public void SetScanlineCallback(Action callback, int scanline)
|
||||
=> _scanlinecb = callback;
|
||||
|
||||
private Action _scanlinecb;
|
||||
|
||||
private GBAGPUMemoryAreas _gpumem;
|
||||
}
|
||||
}
|
|
@ -7,12 +7,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBA
|
|||
private readonly LibmGBA.InputCallback InputCallback;
|
||||
public int LagCount { get; set; }
|
||||
public bool IsLagFrame { get; set; }
|
||||
private void InputCb()
|
||||
{
|
||||
// most things are already handled in the core, this is just for event.oninputpoll
|
||||
InputCallbacks.Call();
|
||||
}
|
||||
private InputCallbackSystem _inputCallbacks = new InputCallbackSystem();
|
||||
public IInputCallbackSystem InputCallbacks => _inputCallbacks;
|
||||
public IInputCallbackSystem InputCallbacks { get; } = new InputCallbackSystem();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,23 +21,24 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBA
|
|||
|
||||
private void CreateMemoryDomains(int romsize)
|
||||
{
|
||||
var le = MemoryDomain.Endian.Little;
|
||||
const MemoryDomain.Endian le = MemoryDomain.Endian.Little;
|
||||
|
||||
var mm = new List<MemoryDomain>();
|
||||
mm.Add(_iwram = new MemoryDomainIntPtr("IWRAM", le, IntPtr.Zero, 32 * 1024, true, 4));
|
||||
mm.Add(_ewram = new MemoryDomainIntPtr("EWRAM", le, IntPtr.Zero, 256 * 1024, true, 4));
|
||||
mm.Add(_bios = new MemoryDomainIntPtr("BIOS", le, IntPtr.Zero, 16 * 1024, false, 4));
|
||||
mm.Add(_palram = new MemoryDomainIntPtr("PALRAM", le, IntPtr.Zero, 1024, true, 4));
|
||||
mm.Add(_vram = new MemoryDomainIntPtr("VRAM", le, IntPtr.Zero, 96 * 1024, true, 4));
|
||||
mm.Add(_oam = new MemoryDomainIntPtr("OAM", le, IntPtr.Zero, 1024, true, 4));
|
||||
mm.Add(_rom = new MemoryDomainIntPtr("ROM", le, IntPtr.Zero, romsize, true, 4));
|
||||
// 128 KB is the max size for GBA savedata
|
||||
// mGBA does not know a game's save type (and as a result actual savedata size) on startup.
|
||||
// Instead, BizHawk's savedata buffer will be accessed directly for a consistent interface.
|
||||
mm.Add(_sram = new MemoryDomainIntPtr("SRAM", le, IntPtr.Zero, 128 * 1024, true, 4));
|
||||
mm.Add(_cwram = new MemoryDomainDelegate("Combined WRAM", (256 + 32) * 1024, le, null, null, 4));
|
||||
var mm = new List<MemoryDomain>
|
||||
{
|
||||
(_iwram = new MemoryDomainIntPtr("IWRAM", le, IntPtr.Zero, 32 * 1024, true, 4)),
|
||||
(_ewram = new MemoryDomainIntPtr("EWRAM", le, IntPtr.Zero, 256 * 1024, true, 4)),
|
||||
(_bios = new MemoryDomainIntPtr("BIOS", le, IntPtr.Zero, 16 * 1024, false, 4)),
|
||||
(_palram = new MemoryDomainIntPtr("PALRAM", le, IntPtr.Zero, 1024, true, 4)),
|
||||
(_vram = new MemoryDomainIntPtr("VRAM", le, IntPtr.Zero, 96 * 1024, true, 4)),
|
||||
(_oam = new MemoryDomainIntPtr("OAM", le, IntPtr.Zero, 1024, true, 4)),
|
||||
(_rom = new MemoryDomainIntPtr("ROM", le, IntPtr.Zero, romsize, true, 4)),
|
||||
// 128 KB is the max size for GBA savedata
|
||||
// mGBA does not know a game's save type (and as a result actual savedata size) on startup.
|
||||
// Instead, BizHawk's savedata buffer will be accessed directly for a consistent interface.
|
||||
(_sram = new MemoryDomainIntPtr("SRAM", le, IntPtr.Zero, 128 * 1024, true, 4)),
|
||||
(_cwram = new MemoryDomainDelegate("Combined WRAM", (256 + 32) * 1024, le, null, null, 4)),
|
||||
|
||||
mm.Add(new MemoryDomainDelegate("System Bus", 0x10000000, le,
|
||||
new MemoryDomainDelegate("System Bus", 0x10000000, le,
|
||||
addr =>
|
||||
{
|
||||
var a = (uint)addr;
|
||||
|
@ -49,16 +50,16 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBA
|
|||
var a = (uint)addr;
|
||||
if (a >= 0x10000000) throw new ArgumentOutOfRangeException(paramName: nameof(addr), a, message: "address out of range");
|
||||
LibmGBA.BizWriteBus(Core, a, val);
|
||||
}, 4));
|
||||
}, 4)
|
||||
};
|
||||
|
||||
_memoryDomains = new MemoryDomainList(mm);
|
||||
_memoryDomains = new(mm);
|
||||
WireMemoryDomainPointers();
|
||||
}
|
||||
|
||||
private void WireMemoryDomainPointers()
|
||||
{
|
||||
var s = new LibmGBA.MemoryAreas();
|
||||
LibmGBA.BizGetMemoryAreas(Core, s);
|
||||
LibmGBA.BizGetMemoryAreas(Core, out var s);
|
||||
|
||||
_iwram.Data = s.iwram;
|
||||
_ewram.Data = s.wram;
|
||||
|
@ -96,7 +97,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBA
|
|||
}
|
||||
};
|
||||
|
||||
_gpumem = new GBAGPUMemoryAreas
|
||||
_gpumem = new()
|
||||
{
|
||||
mmio = s.mmio,
|
||||
oam = s.oam,
|
||||
|
|
|
@ -1,13 +1,15 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
using BizHawk.Emulation.Common;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Nintendo.GBA
|
||||
{
|
||||
public partial class MGBAHawk : ISaveRam
|
||||
{
|
||||
private readonly byte[] _saveScratch = new byte[262144];
|
||||
|
||||
public byte[] CloneSaveRam()
|
||||
{
|
||||
int len = LibmGBA.BizGetSaveRam(Core, _saveScratch, _saveScratch.Length);
|
||||
|
@ -16,6 +18,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBA
|
|||
throw new InvalidOperationException("Save buffer not long enough");
|
||||
}
|
||||
|
||||
len = TruncateRTCIfUsingDeterministicTime(len);
|
||||
|
||||
if (len == 0)
|
||||
{
|
||||
return null;
|
||||
|
@ -26,14 +30,16 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBA
|
|||
return ret;
|
||||
}
|
||||
|
||||
private static readonly byte[] _legacyHeader = Encoding.ASCII.GetBytes("GBABATT\0");
|
||||
|
||||
public void StoreSaveRam(byte[] data)
|
||||
{
|
||||
if (data.Take(8).SequenceEqual(Encoding.ASCII.GetBytes("GBABATT\0")))
|
||||
if (data.AsSpan().Slice(0, 8).SequenceEqual(_legacyHeader))
|
||||
{
|
||||
data = LegacyFix(data);
|
||||
}
|
||||
|
||||
LibmGBA.BizPutSaveRam(Core, data, data.Length);
|
||||
LibmGBA.BizPutSaveRam(Core, data, TruncateRTCIfUsingDeterministicTime(data.Length));
|
||||
}
|
||||
|
||||
public bool SaveRamModified => LibmGBA.BizGetSaveRam(Core, _saveScratch, _saveScratch.Length) > 0;
|
||||
|
@ -61,5 +67,9 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBA
|
|||
// well, isn't this a sticky situation!
|
||||
return flash; // woops
|
||||
}
|
||||
|
||||
// probably don't want RTC data in the save if a user is not using real time
|
||||
private int TruncateRTCIfUsingDeterministicTime(int len)
|
||||
=> (!DeterministicEmulation && _syncSettings.RTCUseRealTime) ? len : len & ~0xff;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
using BizHawk.Common;
|
||||
using BizHawk.Emulation.Common;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using BizHawk.Emulation.Cores.Nintendo.Gameboy;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Nintendo.GBA
|
||||
|
@ -11,9 +11,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBA
|
|||
public partial class MGBAHawk : ISettable<MGBAHawk.Settings, MGBAHawk.SyncSettings>
|
||||
{
|
||||
public Settings GetSettings()
|
||||
{
|
||||
return _settings.Clone();
|
||||
}
|
||||
=> _settings.Clone();
|
||||
|
||||
public PutSettingsDirtyBits PutSettings(Settings o)
|
||||
{
|
||||
|
@ -35,17 +33,17 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBA
|
|||
LibmGBA.BizSetSoundMask(Core, smask);
|
||||
|
||||
var palette = new int[65536];
|
||||
GBColors.ColorType c = GBColors.ColorType.vivid;
|
||||
switch (o.ColorType)
|
||||
var c = o.ColorType switch
|
||||
{
|
||||
case Settings.ColorTypes.SameBoy: c = GBColors.ColorType.sameboy; break;
|
||||
case Settings.ColorTypes.Gambatte: c = GBColors.ColorType.gambatte; break;
|
||||
case Settings.ColorTypes.Vivid: c = GBColors.ColorType.vivid; break;
|
||||
case Settings.ColorTypes.VbaVivid: c = GBColors.ColorType.vbavivid; break;
|
||||
case Settings.ColorTypes.VbaGbNew: c = GBColors.ColorType.vbagbnew; break;
|
||||
case Settings.ColorTypes.VbaGbOld: c = GBColors.ColorType.vbabgbold; break;
|
||||
case Settings.ColorTypes.BizhawkGba: c = GBColors.ColorType.gba; break;
|
||||
}
|
||||
Settings.ColorTypes.SameBoy => GBColors.ColorType.sameboy,
|
||||
Settings.ColorTypes.Gambatte => GBColors.ColorType.gambatte,
|
||||
Settings.ColorTypes.Vivid => GBColors.ColorType.vivid,
|
||||
Settings.ColorTypes.VbaVivid => GBColors.ColorType.vbavivid,
|
||||
Settings.ColorTypes.VbaGbNew => GBColors.ColorType.vbagbnew,
|
||||
Settings.ColorTypes.VbaGbOld => GBColors.ColorType.vbabgbold,
|
||||
Settings.ColorTypes.BizhawkGba => GBColors.ColorType.gba,
|
||||
_ => GBColors.ColorType.vivid,
|
||||
};
|
||||
GBColors.GetLut(c, palette, agb: true);
|
||||
for (var i = 32768; i < 65536; i++)
|
||||
palette[i] = palette[i - 32768];
|
||||
|
@ -126,21 +124,15 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBA
|
|||
[TypeConverter(typeof(DescribableEnumConverter))]
|
||||
public ColorTypes ColorType { get; set; }
|
||||
|
||||
public Settings Clone()
|
||||
{
|
||||
return (Settings)MemberwiseClone();
|
||||
}
|
||||
|
||||
public Settings()
|
||||
{
|
||||
SettingsUtil.SetDefaultValues(this);
|
||||
}
|
||||
=> SettingsUtil.SetDefaultValues(this);
|
||||
|
||||
public Settings Clone()
|
||||
=> (Settings)MemberwiseClone();
|
||||
}
|
||||
|
||||
public SyncSettings GetSyncSettings()
|
||||
{
|
||||
return _syncSettings.Clone();
|
||||
}
|
||||
=> _syncSettings.Clone();
|
||||
|
||||
public PutSettingsDirtyBits PutSyncSettings(SyncSettings o)
|
||||
{
|
||||
|
@ -210,20 +202,24 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBA
|
|||
[DefaultValue(false)]
|
||||
public bool OverrideGbPlayerDetect { get; set; }
|
||||
|
||||
public SyncSettings()
|
||||
{
|
||||
SettingsUtil.SetDefaultValues(this);
|
||||
}
|
||||
[DisplayName("VBA Bug Compatibility Mode")]
|
||||
[Description("Enables a compatibility mode for buggy Pokemon romhacks which rely on VBA bugs. Generally you don't need to enable yourself as Pokemon romhack detection will enable this itself.")]
|
||||
[DefaultValue(false)]
|
||||
public bool OverrideVbaBugCompat { get; set; }
|
||||
|
||||
public static bool NeedsReboot(SyncSettings x, SyncSettings y)
|
||||
{
|
||||
return !DeepEquality.DeepEquals(x, y);
|
||||
}
|
||||
[DisplayName("Detect Pokemon Romhacks")]
|
||||
[Description("Detects Pokemon romhacks and enables compatibility options due to their generally buggy nature. Will override other override settings.")]
|
||||
[DefaultValue(true)]
|
||||
public bool OverridePokemonRomhackDetect { get; set; }
|
||||
|
||||
public SyncSettings()
|
||||
=> SettingsUtil.SetDefaultValues(this);
|
||||
|
||||
public SyncSettings Clone()
|
||||
{
|
||||
return (SyncSettings)MemberwiseClone();
|
||||
}
|
||||
=> (SyncSettings)MemberwiseClone();
|
||||
|
||||
public static bool NeedsReboot(SyncSettings x, SyncSettings y)
|
||||
=> !DeepEquality.DeepEquals(x, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using System;
|
||||
|
||||
using BizHawk.Emulation.Common;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Nintendo.GBA
|
||||
|
|
|
@ -7,18 +7,16 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBA
|
|||
{
|
||||
public partial class MGBAHawk : IStatable
|
||||
{
|
||||
private byte[] _savebuff = new byte[0];
|
||||
private byte[] _savebuff = Array.Empty<byte>();
|
||||
|
||||
public void SaveStateBinary(BinaryWriter writer)
|
||||
{
|
||||
IntPtr p = IntPtr.Zero;
|
||||
int size = 0;
|
||||
if (!LibmGBA.BizStartGetState(Core, ref p, ref size))
|
||||
if (!LibmGBA.BizStartGetState(Core, out var p, out var size))
|
||||
{
|
||||
throw new InvalidOperationException("Core failed to save!");
|
||||
}
|
||||
|
||||
if (size != _savebuff.Length)
|
||||
if (size > _savebuff.Length)
|
||||
{
|
||||
_savebuff = new byte[size];
|
||||
}
|
||||
|
@ -37,7 +35,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBA
|
|||
public void LoadStateBinary(BinaryReader reader)
|
||||
{
|
||||
int length = reader.ReadInt32();
|
||||
if (length != _savebuff.Length)
|
||||
if (length > _savebuff.Length)
|
||||
{
|
||||
_savebuff = new byte[length];
|
||||
}
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
using System.Text;
|
||||
|
||||
using BizHawk.Emulation.Common;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Nintendo.GBA
|
||||
{
|
||||
public partial class MGBAHawk
|
||||
{
|
||||
private ITraceable Tracer { get; }
|
||||
|
||||
private readonly LibmGBA.TraceCallback _tracecb;
|
||||
|
||||
private void MakeTrace(string msg)
|
||||
{
|
||||
var disasm = msg.Split('|')[1];
|
||||
var split = disasm.Split(':');
|
||||
var machineCode = split[0].PadLeft(8);
|
||||
var instruction = split[1].Trim();
|
||||
var regs = GetCpuFlagsAndRegisters();
|
||||
var wordSize = (regs["CPSR"].Value & 32) == 0 ? 4UL : 2UL;
|
||||
var pc = regs["R15"].Value - wordSize * 2;
|
||||
var sb = new StringBuilder();
|
||||
|
||||
for (var i = 0; i < RegisterNames.Length; i++)
|
||||
{
|
||||
sb.Append($" { RegisterNames[i] }:{ regs[RegisterNames[i]].Value:X8}");
|
||||
}
|
||||
|
||||
Tracer.Put(new(
|
||||
disassembly: $"{pc:X8}: { machineCode } { instruction }".PadRight(50),
|
||||
registerInfo: sb.ToString()));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,10 +4,10 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBA
|
|||
{
|
||||
public partial class MGBAHawk : IVideoProvider
|
||||
{
|
||||
public int[] GetVideoBuffer()
|
||||
{
|
||||
return _videobuff;
|
||||
}
|
||||
private readonly int[] _videobuff = new int[240 * 160];
|
||||
private readonly int[] _dummyvideobuff = new int[240 * 160];
|
||||
|
||||
public int[] GetVideoBuffer() => _videobuff;
|
||||
|
||||
public int VirtualWidth => 240;
|
||||
public int VirtualHeight => 160;
|
||||
|
@ -17,13 +17,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBA
|
|||
|
||||
public int BackgroundColor => unchecked((int)0xff000000);
|
||||
|
||||
|
||||
public int VsyncNumerator => 262144;
|
||||
|
||||
public int VsyncDenominator => 4389;
|
||||
|
||||
private readonly int[] _videobuff = new int[240 * 160];
|
||||
|
||||
private readonly int[] _dummyvideobuff = new int[240 * 160];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,19 +1,16 @@
|
|||
using System;
|
||||
using System.Text;
|
||||
|
||||
using BizHawk.BizInvoke;
|
||||
using BizHawk.Common;
|
||||
using BizHawk.Emulation.Common;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Nintendo.GBA
|
||||
{
|
||||
[PortedCore(CoreNames.Mgba, "endrift", "0.9.1", "https://mgba.io/")]
|
||||
[PortedCore(CoreNames.Mgba, "endrift", "0.10", "https://mgba.io/")]
|
||||
[ServiceNotApplicable(new[] { typeof(IDriveLight), typeof(IRegionable) })]
|
||||
public partial class MGBAHawk : IEmulator, IVideoProvider, ISoundProvider, IGBAGPUViewable,
|
||||
ISaveRam, IStatable, IInputPollable, ISettable<MGBAHawk.Settings, MGBAHawk.SyncSettings>,
|
||||
IDebuggable
|
||||
public partial class MGBAHawk
|
||||
{
|
||||
private static readonly LibmGBA LibmGBA;
|
||||
public static LibmGBA ZZHacky => LibmGBA;
|
||||
|
||||
static MGBAHawk()
|
||||
{
|
||||
|
@ -22,24 +19,29 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBA
|
|||
LibmGBA = BizInvoker.GetInvoker<LibmGBA>(resolver, CallingConventionAdapters.Native);
|
||||
}
|
||||
|
||||
[CoreConstructor(VSystemID.Raw.GBA)]
|
||||
public MGBAHawk(byte[] file, CoreComm comm, SyncSettings syncSettings, Settings settings, bool deterministic, GameInfo game)
|
||||
{
|
||||
_syncSettings = syncSettings ?? new SyncSettings();
|
||||
_settings = settings ?? new Settings();
|
||||
private IntPtr Core;
|
||||
|
||||
var bios = comm.CoreFileProvider.GetFirmware(new("GBA", "Bios"));
|
||||
[CoreConstructor(VSystemID.Raw.GBA)]
|
||||
public MGBAHawk(CoreLoadParameters<Settings, SyncSettings> lp)
|
||||
{
|
||||
_syncSettings = lp.SyncSettings ?? new();
|
||||
_settings = lp.Settings ?? new();
|
||||
|
||||
var bios = lp.Comm.CoreFileProvider.GetFirmware(new("GBA", "Bios"));
|
||||
if (bios is { Length: not 0x4000 }) throw new InvalidOperationException("BIOS must be exactly 16384 bytes!");
|
||||
if (deterministic && bios is null) throw new MissingFirmwareException("A BIOS is required for deterministic recordings!");
|
||||
DeterministicEmulation = deterministic
|
||||
if (lp.DeterministicEmulationRequested && bios is null) throw new MissingFirmwareException("A BIOS is required for deterministic recordings!");
|
||||
DeterministicEmulation = lp.DeterministicEmulationRequested
|
||||
|| (bios is not null && !_syncSettings.RTCUseRealTime); // in this case, the core is deterministic even though it wasn't asked to be
|
||||
var rom = lp.Roms[0].FileData;
|
||||
var overrides = GetOverrideInfo(_syncSettings);
|
||||
|
||||
Core = LibmGBA.BizCreate(
|
||||
bios,
|
||||
file,
|
||||
file.Length,
|
||||
GetOverrideInfo(_syncSettings),
|
||||
rom,
|
||||
rom.Length,
|
||||
ref overrides,
|
||||
skipBios: _syncSettings.SkipBios);
|
||||
|
||||
if (Core == IntPtr.Zero)
|
||||
{
|
||||
throw new InvalidOperationException($"{nameof(LibmGBA.BizCreate)}() returned NULL! Bad BIOS? and/or ROM?");
|
||||
|
@ -47,7 +49,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBA
|
|||
|
||||
try
|
||||
{
|
||||
CreateMemoryDomains(file.Length);
|
||||
CreateMemoryDomains(rom.Length);
|
||||
var ser = new BasicServiceProvider(this);
|
||||
ser.Register<IDisassemblable>(new ArmV4Disassembler());
|
||||
ser.Register<IMemoryDomains>(_memoryDomains);
|
||||
|
@ -57,9 +59,9 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBA
|
|||
|
||||
const string TRACE_HEADER = "ARM7: PC, machine code, mnemonic, operands, registers";
|
||||
Tracer = new TraceBuffer(TRACE_HEADER);
|
||||
_tracecb = msg => Tracer.Put(_traceInfo(msg));
|
||||
_tracecb = MakeTrace;
|
||||
ser.Register(Tracer);
|
||||
MemoryCallbacks = new MGBAMemoryCallbackSystem(this);
|
||||
_memoryCallbacks = new(LibmGBA, Core);
|
||||
}
|
||||
catch
|
||||
{
|
||||
|
@ -67,117 +69,20 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBA
|
|||
throw;
|
||||
}
|
||||
|
||||
InputCallback = new LibmGBA.InputCallback(InputCb);
|
||||
// most things are already handled in the core, this is just for event.oninputpoll
|
||||
InputCallback = InputCallbacks.Call;
|
||||
LibmGBA.BizSetInputCallback(Core, InputCallback);
|
||||
}
|
||||
|
||||
public IEmulatorServiceProvider ServiceProvider { get; }
|
||||
|
||||
public ControllerDefinition ControllerDefinition => GBAController;
|
||||
|
||||
private ITraceable Tracer { get; }
|
||||
|
||||
private LibmGBA.TraceCallback _tracecb { get; set; }
|
||||
|
||||
private TraceInfo _traceInfo(string msg)
|
||||
{
|
||||
var disasm = msg.Split('|')[1];
|
||||
var split = disasm.Split(':');
|
||||
var machineCode = split[0].PadLeft(8);
|
||||
var instruction = split[1].Trim();
|
||||
var regs = GetCpuFlagsAndRegisters();
|
||||
var wordSize = (regs["CPSR"].Value & 32) == 0 ? 4UL : 2UL;
|
||||
var pc = regs["R15"].Value - wordSize * 2;
|
||||
var sb = new StringBuilder();
|
||||
|
||||
for (var i = 0; i < RegisterNames.Length; i++)
|
||||
{
|
||||
sb.Append($" { RegisterNames[i] }:{ regs[RegisterNames[i]].Value:X8}");
|
||||
}
|
||||
|
||||
return new(
|
||||
disassembly: $"{pc:X8}: { machineCode } { instruction }".PadRight(50),
|
||||
registerInfo: sb.ToString());
|
||||
}
|
||||
|
||||
public bool FrameAdvance(IController controller, bool render, bool renderSound = true)
|
||||
{
|
||||
if (controller.IsPressed("Power"))
|
||||
{
|
||||
LibmGBA.BizReset(Core);
|
||||
|
||||
// BizReset caused memorydomain pointers to change.
|
||||
WireMemoryDomainPointers();
|
||||
}
|
||||
|
||||
LibmGBA.BizSetTraceCallback(Core, Tracer.IsEnabled() ? _tracecb : null);
|
||||
|
||||
IsLagFrame = LibmGBA.BizAdvance(
|
||||
Core,
|
||||
LibmGBA.GetButtons(controller),
|
||||
render ? _videobuff : _dummyvideobuff,
|
||||
ref _nsamp,
|
||||
renderSound ? _soundbuff : _dummysoundbuff,
|
||||
RTCTime(),
|
||||
(short)controller.AxisValue("Tilt X"),
|
||||
(short)controller.AxisValue("Tilt Y"),
|
||||
(short)controller.AxisValue("Tilt Z"),
|
||||
(byte)(255 - controller.AxisValue("Light Sensor")));
|
||||
|
||||
if (IsLagFrame)
|
||||
{
|
||||
LagCount++;
|
||||
}
|
||||
|
||||
// this should be called in hblank on the appropriate line, but until we implement that, just do it here
|
||||
_scanlinecb?.Invoke();
|
||||
|
||||
Frame++;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public int Frame { get; private set; }
|
||||
|
||||
public string SystemId => VSystemID.Raw.GBA;
|
||||
|
||||
public bool DeterministicEmulation { get; }
|
||||
|
||||
public void ResetCounters()
|
||||
{
|
||||
Frame = 0;
|
||||
LagCount = 0;
|
||||
IsLagFrame = false;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (Core != IntPtr.Zero)
|
||||
{
|
||||
LibmGBA.BizDestroy(Core);
|
||||
Core = IntPtr.Zero;
|
||||
}
|
||||
}
|
||||
|
||||
public GBAGPUMemoryAreas GetMemoryAreas()
|
||||
{
|
||||
return _gpumem;
|
||||
}
|
||||
|
||||
public void SetScanlineCallback(Action callback, int scanline)
|
||||
{
|
||||
_scanlinecb = callback;
|
||||
}
|
||||
|
||||
private readonly byte[] _saveScratch = new byte[262144];
|
||||
internal IntPtr Core;
|
||||
|
||||
private static LibmGBA.OverrideInfo GetOverrideInfo(SyncSettings syncSettings)
|
||||
{
|
||||
var ret = new LibmGBA.OverrideInfo
|
||||
{
|
||||
Savetype = syncSettings.OverrideSaveType,
|
||||
Hardware = LibmGBA.Hardware.None
|
||||
Hardware = LibmGBA.Hardware.None,
|
||||
IdleLoop = LibmGBA.OverrideInfo.IDLE_LOOP_NONE,
|
||||
VbaBugCompat = syncSettings.OverrideVbaBugCompat,
|
||||
DetectPokemonRomHacks = syncSettings.OverridePokemonRomhackDetect
|
||||
};
|
||||
|
||||
if (syncSettings.OverrideRtc is SyncSettings.HardwareSelection.Autodetect)
|
||||
|
@ -233,27 +138,18 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBA
|
|||
return ret;
|
||||
}
|
||||
|
||||
private Action _scanlinecb;
|
||||
|
||||
private GBAGPUMemoryAreas _gpumem;
|
||||
private static readonly DateTime _epoch = new(1970, 1, 1);
|
||||
|
||||
private long RTCTime()
|
||||
{
|
||||
if (!DeterministicEmulation && _syncSettings.RTCUseRealTime)
|
||||
{
|
||||
return (long)DateTime.Now.Subtract(new DateTime(1970, 1, 1)).TotalSeconds;
|
||||
return (long)DateTime.Now.Subtract(_epoch).TotalSeconds;
|
||||
}
|
||||
|
||||
long baseTime = (long)_syncSettings.RTCInitialTime.Subtract(new DateTime(1970, 1, 1)).TotalSeconds;
|
||||
long baseTime = (long)_syncSettings.RTCInitialTime.Subtract(_epoch).TotalSeconds;
|
||||
long increment = Frame * 4389L >> 18;
|
||||
return baseTime + increment;
|
||||
}
|
||||
|
||||
public static readonly ControllerDefinition GBAController = new ControllerDefinition("GBA Controller")
|
||||
{
|
||||
BoolButtons = { "Up", "Down", "Left", "Right", "Start", "Select", "B", "A", "L", "R", "Power" }
|
||||
}.AddXYZTriple("Tilt {0}", (-32767).RangeTo(32767), 0)
|
||||
.AddAxis("Light Sensor", 0.RangeTo(255), 0)
|
||||
.MakeImmutable();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,13 +2,15 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
using BizHawk.Emulation.Common;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Nintendo.GBA
|
||||
{
|
||||
public class MGBAMemoryCallbackSystem : IMemoryCallbackSystem
|
||||
public class MGBAMemoryCallbackSystem : IMemoryCallbackSystem, IDisposable
|
||||
{
|
||||
private readonly MGBAHawk _mgba;
|
||||
private LibmGBA _mgba;
|
||||
private IntPtr _core;
|
||||
private readonly LibmGBA.MemCallback _readWriteCallback;
|
||||
private readonly LibmGBA.ExecCallback _executeCallback;
|
||||
private readonly Dictionary<uint, MemoryCallbackDelegate> _readCallbacks = new();
|
||||
|
@ -16,9 +18,10 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBA
|
|||
private readonly Dictionary<uint, MemoryCallbackDelegate> _execCallbacks = new();
|
||||
private readonly List<CallbackContainer> _callbacks = new();
|
||||
|
||||
public MGBAMemoryCallbackSystem(MGBAHawk mgba)
|
||||
public MGBAMemoryCallbackSystem(LibmGBA mgba, IntPtr core)
|
||||
{
|
||||
_mgba = mgba;
|
||||
_core = core;
|
||||
_readWriteCallback = RunReadWriteCallback;
|
||||
_executeCallback = RunExecCallback;
|
||||
}
|
||||
|
@ -63,12 +66,12 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBA
|
|||
|
||||
if (container.Callback.Type == MemoryCallbackType.Execute)
|
||||
{
|
||||
MGBAHawk.ZZHacky.BizSetExecCallback(_mgba.Core, _executeCallback);
|
||||
_mgba.BizSetExecCallback(_core, _executeCallback);
|
||||
}
|
||||
else
|
||||
{
|
||||
container.ID = MGBAHawk.ZZHacky.BizSetWatchpoint(_mgba.Core, callback.Address.Value, container.WatchPointType);
|
||||
MGBAHawk.ZZHacky.BizSetMemCallback(_mgba.Core, _readWriteCallback);
|
||||
container.ID = _mgba.BizSetWatchpoint(_core, callback.Address.Value, container.WatchPointType);
|
||||
_mgba.BizSetMemCallback(_core, _readWriteCallback);
|
||||
}
|
||||
|
||||
var cbDict = container.Callback.Type switch
|
||||
|
@ -101,12 +104,12 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBA
|
|||
|
||||
if (!HasExecutes)
|
||||
{
|
||||
MGBAHawk.ZZHacky.BizSetExecCallback(_mgba.Core, null);
|
||||
_mgba.BizSetExecCallback(_core, null);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!MGBAHawk.ZZHacky.BizClearWatchpoint(_mgba.Core, cb.ID))
|
||||
if (!_mgba.BizClearWatchpoint(_core, cb.ID))
|
||||
{
|
||||
throw new InvalidOperationException("Unable to clear watchpoint???");
|
||||
}
|
||||
|
@ -126,7 +129,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBA
|
|||
|
||||
if (!HasReads && !HasWrites)
|
||||
{
|
||||
MGBAHawk.ZZHacky.BizSetMemCallback(_mgba.Core, null);
|
||||
_mgba.BizSetMemCallback(_core, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -196,31 +199,37 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBA
|
|||
cb?.Invoke(pc, 0, (uint)MemoryCallbackFlags.AccessExecute);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal class CallbackContainer
|
||||
{
|
||||
public CallbackContainer(IMemoryCallback callBack)
|
||||
public void Dispose()
|
||||
{
|
||||
Callback = callBack;
|
||||
_mgba = null;
|
||||
_core = IntPtr.Zero;
|
||||
}
|
||||
|
||||
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
|
||||
private class CallbackContainer
|
||||
{
|
||||
get
|
||||
public CallbackContainer(IMemoryCallback callBack)
|
||||
{
|
||||
return Callback.Type switch
|
||||
Callback = callBack;
|
||||
}
|
||||
|
||||
public IMemoryCallback Callback { get; }
|
||||
|
||||
// the core returns this when setting a wp and needs it to clear that wp
|
||||
public long ID { get; set; }
|
||||
|
||||
public LibmGBA.mWatchpointType WatchPointType
|
||||
{
|
||||
get
|
||||
{
|
||||
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"),
|
||||
};
|
||||
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"),
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 707a6f8fbd07a64911667914d295c8b055e9cce3
|
||||
Subproject commit f59c9650fd141fd68a9b3f51f7860bb3791aa193
|
Loading…
Reference in New Issue