diff --git a/BizHawk.Client.Common/Api/Classes/MemApi.cs b/BizHawk.Client.Common/Api/Classes/MemApi.cs index 3dd1b524ac..05b1cb73e4 100644 --- a/BizHawk.Client.Common/Api/Classes/MemApi.cs +++ b/BizHawk.Client.Common/Api/Classes/MemApi.cs @@ -1,22 +1,24 @@ using System; using System.Collections.Generic; +using System.Security.Cryptography; +using BizHawk.Common.BufferExtensions; using BizHawk.Emulation.Common; using BizHawk.Emulation.Common.IEmulatorExtensions; -using BizHawk.Common.BufferExtensions; namespace BizHawk.Client.Common { - public sealed class MemApi : MemApiBase, IMem + public sealed class MemApi : IMem { - private MemoryDomain _currentMemoryDomain; - private bool _isBigEndian; - public MemApi() - : base() - { - } + [RequiredService] + private IEmulator Emulator { get; set; } - protected override MemoryDomain Domain + [OptionalService] + private IMemoryDomains MemoryDomainCore { get; set; } + + private MemoryDomain _currentMemoryDomain; + + private MemoryDomain Domain { get { @@ -38,6 +40,151 @@ namespace BizHawk.Client.Common } } + private bool _isBigEndian; + + private IMemoryDomains DomainList + { + get + { + if (MemoryDomainCore != null) + { + return MemoryDomainCore; + } + + var error = $"Error: {Emulator.Attributes().CoreName} does not implement memory domains"; + Console.WriteLine(error); + throw new NotImplementedException(error); + } + } + + private string VerifyMemoryDomain(string domain) + { + try + { + if (DomainList[domain] == null) + { + Console.WriteLine($"Unable to find domain: {domain}, falling back to current"); + return Domain.Name; + } + + return domain; + } + catch // Just in case + { + Console.WriteLine($"Unable to find domain: {domain}, falling back to current"); + } + + return Domain.Name; + } + + private uint ReadUnsignedByte(long addr, string domain = null) + { + var d = string.IsNullOrEmpty(domain) ? Domain : DomainList[VerifyMemoryDomain(domain)]; + if (addr < d.Size) + { + return d.PeekByte(addr); + } + + Console.WriteLine($"Warning: attempted read of {addr} outside the memory size of {d.Size}"); + return 0; + } + + private void WriteUnsignedByte(long addr, uint v, string domain = null) + { + var d = string.IsNullOrEmpty(domain) ? Domain : DomainList[VerifyMemoryDomain(domain)]; + if (d.CanPoke()) + { + if (addr < d.Size) + { + d.PokeByte(addr, (byte)v); + } + else + { + Console.WriteLine($"Warning: attempted write to {addr} outside the memory size of {d.Size}"); + } + } + else + { + Console.WriteLine($"Error: the domain {d.Name} is not writable"); + } + } + + private static int U2S(uint u, int size) + { + var s = (int)u; + s <<= 8 * (4 - size); + s >>= 8 * (4 - size); + return s; + } + + #region Endian Handling + + private uint ReadUnsignedLittle(long addr, int size, string domain = null) + { + uint v = 0; + for (var i = 0; i < size; ++i) + { + v |= ReadUnsignedByte(addr + i, domain) << (8 * i); + } + + return v; + } + + private uint ReadUnsignedBig(long addr, int size, string domain = null) + { + uint v = 0; + for (var i = 0; i < size; ++i) + { + v |= ReadUnsignedByte(addr + i, domain) << (8 * (size - 1 - i)); + } + + return v; + } + + private void WriteUnsignedLittle(long addr, uint v, int size, string domain = null) + { + for (var i = 0; i < size; ++i) + { + WriteUnsignedByte(addr + i, (v >> (8 * i)) & 0xFF, domain); + } + } + + private void WriteUnsignedBig(long addr, uint v, int size, string domain = null) + { + for (var i = 0; i < size; ++i) + { + WriteUnsignedByte(addr + i, (v >> (8 * (size - 1 - i))) & 0xFF, domain); + } + } + + private int ReadSigned(long addr, int size, string domain = null) + { + return _isBigEndian + ? U2S(ReadUnsignedBig(addr, size, domain), size) + : U2S(ReadUnsignedLittle(addr, size, domain), size); + } + + private uint ReadUnsigned(long addr, int size, string domain = null) + { + return _isBigEndian + ? ReadUnsignedBig(addr, size, domain) + : ReadUnsignedLittle(addr, size, domain); + } + + private void WriteSigned(long addr, int value, int size, string domain = null) + { + if (_isBigEndian) WriteUnsignedBig(addr, (uint)value, size, domain); + else WriteUnsignedLittle(addr, (uint)value, size, domain); + } + + private void WriteUnsigned(long addr, uint value, int size, string domain = null) + { + if (_isBigEndian) WriteUnsignedBig(addr, value, size, domain); + else WriteUnsignedLittle(addr, value, size, domain); + } + + #endregion + #region Unique Library Methods public void SetBigEndian(bool enabled = true) @@ -122,42 +269,12 @@ namespace BizHawk.Client.Common data[i] = d.PeekByte(addr + i); } - using var hasher = System.Security.Cryptography.SHA256.Create(); + using var hasher = SHA256.Create(); return hasher.ComputeHash(data).BytesToHexString(); } #endregion - #region Endian Handling - - private int ReadSigned(long addr, int size, string domain = null) - { - return _isBigEndian - ? ReadSignedBig(addr, size, domain) - : ReadSignedLittle(addr, size, domain); - } - - private uint ReadUnsigned(long addr, int size, string domain = null) - { - return _isBigEndian - ? ReadUnsignedBig(addr, size, domain) - : ReadUnsignedLittle(addr, size, domain); - } - - private void WriteSigned(long addr, int value, int size, string domain = null) - { - if (_isBigEndian) WriteSignedBig(addr, value, size, domain); - else WriteSignedLittle(addr, value, size, domain); - } - - private void WriteUnsigned(long addr, uint value, int size, string domain = null) - { - if (_isBigEndian) WriteUnsignedBig(addr, value, size, domain); - else WriteUnsignedLittle(addr, value, size, domain); - } - - #endregion - #region Common Special and Legacy Methods public uint ReadByte(long addr, string domain = null) @@ -170,24 +287,83 @@ namespace BizHawk.Client.Common WriteUnsignedByte(addr, value, domain); } - public new List ReadByteRange(long addr, int length, string domain = null) + public List ReadByteRange(long addr, int length, string domain = null) { - return base.ReadByteRange(addr, length, domain); + var d = string.IsNullOrEmpty(domain) ? Domain : DomainList[VerifyMemoryDomain(domain)]; + var lastAddr = length + addr; + var list = new List(); + for (; addr <= lastAddr; addr++) + { + if (addr < d.Size) + list.Add(d.PeekByte(addr)); + else { + Console.WriteLine($"Warning: Attempted read {addr} outside memory domain size of {d.Size} in {nameof(ReadByteRange)}()"); + list.Add(0); + } + } + + return list; } - public new void WriteByteRange(long addr, List memoryblock, string domain = null) + public void WriteByteRange(long addr, List memoryblock, string domain = null) { - base.WriteByteRange(addr, memoryblock, domain); + var d = string.IsNullOrEmpty(domain) ? Domain : DomainList[VerifyMemoryDomain(domain)]; + if (d.CanPoke()) + { + foreach (var m in memoryblock) + { + if (addr < d.Size) + { + d.PokeByte(addr++, m); + } + else + { + Console.WriteLine($"Warning: Attempted write {addr} outside memory domain size of {d.Size} in {nameof(WriteByteRange)}()"); + } + } + } + else + { + Console.WriteLine($"Error: the domain {d.Name} is not writable"); + } } public float ReadFloat(long addr, string domain = null) { - return base.ReadFloat(addr, _isBigEndian, domain); + var d = string.IsNullOrEmpty(domain) ? Domain : DomainList[VerifyMemoryDomain(domain)]; + if (addr < d.Size) + { + var val = d.PeekUint(addr, _isBigEndian); + var bytes = BitConverter.GetBytes(val); + return BitConverter.ToSingle(bytes, 0); + } + + Console.WriteLine($"Warning: Attempted read {addr} outside memory size of {d.Size}"); + + return 0; } public void WriteFloat(long addr, double value, string domain = null) { - base.WriteFloat(addr, value, _isBigEndian, domain); + var d = string.IsNullOrEmpty(domain) ? Domain : DomainList[VerifyMemoryDomain(domain)]; + if (d.CanPoke()) + { + if (addr < d.Size) + { + var dv = (float)value; + var bytes = BitConverter.GetBytes(dv); + var v = BitConverter.ToUInt32(bytes, 0); + d.PokeUint(addr, v, _isBigEndian); + } + else + { + Console.WriteLine($"Warning: Attempted write {addr} outside memory size of {d.Size}"); + } + } + else + { + Console.WriteLine($"Error: the domain {Domain.Name} is not writable"); + } } #endregion @@ -217,6 +393,7 @@ namespace BizHawk.Client.Common #endregion #region 2 Byte + public int ReadS16(long addr, string domain = null) { return (short)ReadSigned(addr, 2, domain); @@ -285,4 +462,4 @@ namespace BizHawk.Client.Common #endregion } -} \ No newline at end of file +} diff --git a/BizHawk.Client.Common/Api/Classes/MemApiBase.cs b/BizHawk.Client.Common/Api/Classes/MemApiBase.cs deleted file mode 100644 index ca05d34ac5..0000000000 --- a/BizHawk.Client.Common/Api/Classes/MemApiBase.cs +++ /dev/null @@ -1,240 +0,0 @@ -using System; -using System.Collections.Generic; -using BizHawk.Emulation.Common; -using BizHawk.Emulation.Common.IEmulatorExtensions; - -namespace BizHawk.Client.Common -{ - /// - /// Base class for the Memory and MainMemory plugin libraries - /// - public abstract class MemApiBase : IExternalApi - { - [RequiredService] - protected IEmulator Emulator { get; set; } - - [OptionalService] - protected IMemoryDomains MemoryDomainCore { get; set; } - - protected abstract MemoryDomain Domain { get; } - - protected MemApiBase() - { } - - protected IMemoryDomains DomainList - { - get - { - if (MemoryDomainCore != null) - { - return MemoryDomainCore; - } - - var error = $"Error: {Emulator.Attributes().CoreName} does not implement memory domains"; - Console.WriteLine(error); - throw new NotImplementedException(error); - } - } - - public string VerifyMemoryDomain(string domain) - { - try - { - if (DomainList[domain] == null) - { - Console.WriteLine($"Unable to find domain: {domain}, falling back to current"); - return Domain.Name; - } - - return domain; - } - catch // Just in case - { - Console.WriteLine($"Unable to find domain: {domain}, falling back to current"); - } - - return Domain.Name; - } - - protected uint ReadUnsignedByte(long addr, string domain = null) - { - var d = string.IsNullOrEmpty(domain) ? Domain : DomainList[VerifyMemoryDomain(domain)]; - if (addr < d.Size) - { - return d.PeekByte(addr); - } - - Console.WriteLine($"Warning: attempted read of {addr} outside the memory size of {d.Size}"); - return 0; - } - - protected void WriteUnsignedByte(long addr, uint v, string domain = null) - { - var d = string.IsNullOrEmpty(domain) ? Domain : DomainList[VerifyMemoryDomain(domain)]; - if (d.CanPoke()) - { - if (addr < d.Size) - { - d.PokeByte(addr, (byte)v); - } - else - { - Console.WriteLine($"Warning: attempted write to {addr} outside the memory size of {d.Size}"); - } - } - else - { - Console.WriteLine($"Error: the domain {d.Name} is not writable"); - } - } - - protected static int U2S(uint u, int size) - { - var s = (int)u; - s <<= 8 * (4 - size); - s >>= 8 * (4 - size); - return s; - } - - protected int ReadSignedLittle(long addr, int size, string domain = null) - { - return U2S(ReadUnsignedLittle(addr, size, domain), size); - } - - protected uint ReadUnsignedLittle(long addr, int size, string domain = null) - { - uint v = 0; - for (var i = 0; i < size; ++i) - { - v |= ReadUnsignedByte(addr + i, domain) << (8 * i); - } - - return v; - } - - protected int ReadSignedBig(long addr, int size, string domain = null) - { - return U2S(ReadUnsignedBig(addr, size, domain), size); - } - - protected uint ReadUnsignedBig(long addr, int size, string domain = null) - { - uint v = 0; - for (var i = 0; i < size; ++i) - { - v |= ReadUnsignedByte(addr + i, domain) << (8 * (size - 1 - i)); - } - - return v; - } - - protected void WriteSignedLittle(long addr, int v, int size, string domain = null) - { - WriteUnsignedLittle(addr, (uint)v, size, domain); - } - - protected void WriteUnsignedLittle(long addr, uint v, int size, string domain = null) - { - for (var i = 0; i < size; ++i) - { - WriteUnsignedByte(addr + i, (v >> (8 * i)) & 0xFF, domain); - } - } - - protected void WriteSignedBig(long addr, int v, int size, string domain = null) - { - WriteUnsignedBig(addr, (uint)v, size, domain); - } - - protected void WriteUnsignedBig(long addr, uint v, int size, string domain = null) - { - for (var i = 0; i < size; ++i) - { - WriteUnsignedByte(addr + i, (v >> (8 * (size - 1 - i))) & 0xFF, domain); - } - } - - #region public Library implementations - - protected List ReadByteRange(long addr, int length, string domain = null) - { - var d = string.IsNullOrEmpty(domain) ? Domain : DomainList[VerifyMemoryDomain(domain)]; - var lastAddr = length + addr; - var list = new List(); - for (; addr <= lastAddr; addr++) - { - if (addr < d.Size) - list.Add(d.PeekByte(addr)); - else { - Console.WriteLine($"Warning: Attempted read {addr} outside memory domain size of {d.Size} in {nameof(ReadByteRange)}()"); - list.Add(0); - } - } - - return list; - } - - protected void WriteByteRange(long addr, List memoryblock, string domain = null) - { - var d = string.IsNullOrEmpty(domain) ? Domain : DomainList[VerifyMemoryDomain(domain)]; - if (d.CanPoke()) - { - foreach (var m in memoryblock) - { - if (addr < d.Size) - { - d.PokeByte(addr++, m); - } - else - { - Console.WriteLine($"Warning: Attempted write {addr} outside memory domain size of {d.Size} in {nameof(WriteByteRange)}()"); - } - } - } - else - { - Console.WriteLine($"Error: the domain {d.Name} is not writable"); - } - } - - protected float ReadFloat(long addr, bool bigEndian, string domain = null) - { - var d = string.IsNullOrEmpty(domain) ? Domain : DomainList[VerifyMemoryDomain(domain)]; - if (addr < d.Size) - { - var val = d.PeekUint(addr, bigEndian); - var bytes = BitConverter.GetBytes(val); - return BitConverter.ToSingle(bytes, 0); - } - - Console.WriteLine($"Warning: Attempted read {addr} outside memory size of {d.Size}"); - - return 0; - } - - protected void WriteFloat(long addr, double value, bool bigEndian, string domain = null) - { - var d = string.IsNullOrEmpty(domain) ? Domain : DomainList[VerifyMemoryDomain(domain)]; - if (d.CanPoke()) - { - if (addr < d.Size) - { - var dv = (float)value; - var bytes = BitConverter.GetBytes(dv); - var v = BitConverter.ToUInt32(bytes, 0); - d.PokeUint(addr, v, bigEndian); - } - else - { - Console.WriteLine($"Warning: Attempted write {addr} outside memory size of {d.Size}"); - } - } - else - { - Console.WriteLine($"Error: the domain {Domain.Name} is not writable"); - } - } - - #endregion - } -} diff --git a/BizHawk.Client.Common/BizHawk.Client.Common.csproj b/BizHawk.Client.Common/BizHawk.Client.Common.csproj index a5520b09f3..502d535d1d 100644 --- a/BizHawk.Client.Common/BizHawk.Client.Common.csproj +++ b/BizHawk.Client.Common/BizHawk.Client.Common.csproj @@ -87,7 +87,6 @@ -