From c619596e077e65778c28b9ac879cbd0fbc3650e0 Mon Sep 17 00:00:00 2001 From: gdkchan Date: Sun, 11 Nov 2018 14:38:26 -0300 Subject: [PATCH] Allow the cpu to read/write from the correct memory locations for accesses crossing a page boundary --- ...moryException.cs => VmmAccessException.cs} | 2 +- ChocolArm64/Memory/MemoryManager.cs | 118 +++++++++++--- Ryujinx.HLE/{Memory => }/DeviceMemory.cs | 6 +- Ryujinx.HLE/HOS/Font/SharedFontManager.cs | 2 +- Ryujinx.HLE/HOS/Kernel/KMemoryManager.cs | 3 - .../HOS/Services/Nv/NvMap/NvMapIoctl.cs | 5 +- Ryujinx.HLE/Memory/ArenaAllocator.cs | 150 ------------------ Ryujinx.HLE/Switch.cs | 1 - 8 files changed, 99 insertions(+), 188 deletions(-) rename ChocolArm64/Exceptions/{VmmOutOfMemoryException.cs => VmmAccessException.cs} (71%) rename Ryujinx.HLE/{Memory => }/DeviceMemory.cs (95%) delete mode 100644 Ryujinx.HLE/Memory/ArenaAllocator.cs diff --git a/ChocolArm64/Exceptions/VmmOutOfMemoryException.cs b/ChocolArm64/Exceptions/VmmAccessException.cs similarity index 71% rename from ChocolArm64/Exceptions/VmmOutOfMemoryException.cs rename to ChocolArm64/Exceptions/VmmAccessException.cs index d6ddf75227..ff86276035 100644 --- a/ChocolArm64/Exceptions/VmmOutOfMemoryException.cs +++ b/ChocolArm64/Exceptions/VmmAccessException.cs @@ -4,7 +4,7 @@ namespace ChocolArm64.Exceptions { public class VmmAccessException : Exception { - private const string ExMsg = "Memory region at 0x{0} with size 0x{1} is not contiguous!"; + private const string ExMsg = "Memory region at 0x{0:X16} with size 0x{1:X16} is not contiguous!"; public VmmAccessException() { } diff --git a/ChocolArm64/Memory/MemoryManager.cs b/ChocolArm64/Memory/MemoryManager.cs index 21c0cb91fd..2109346b42 100644 --- a/ChocolArm64/Memory/MemoryManager.cs +++ b/ChocolArm64/Memory/MemoryManager.cs @@ -1,5 +1,6 @@ using ChocolArm64.Events; using ChocolArm64.Exceptions; +using ChocolArm64.Instructions; using ChocolArm64.State; using System; using System.Collections.Concurrent; @@ -197,17 +198,42 @@ namespace ChocolArm64.Memory public ushort ReadUInt16(long position) { - return *((ushort*)Translate(position)); + if ((position & 1) == 0) + { + return *((ushort*)Translate(position)); + } + else + { + return (ushort)(ReadByte(position + 0) << 0 | + ReadByte(position + 1) << 8); + } } public uint ReadUInt32(long position) { - return *((uint*)Translate(position)); + if ((position & 3) == 0) + { + return *((uint*)Translate(position)); + } + else + { + return (uint)(ReadUInt16(position + 0) << 0 | + ReadUInt16(position + 2) << 16); + } } public ulong ReadUInt64(long position) { - return *((ulong*)Translate(position)); + if ((position & 7) == 0) + { + return *((ulong*)Translate(position)); + } + else + { + return (ulong)ReadUInt32(position + 0) << 0 | + (ulong)ReadUInt32(position + 4) << 32; + } + } public Vector128 ReadVector8(long position) @@ -218,59 +244,80 @@ namespace ChocolArm64.Memory } else { - throw new PlatformNotSupportedException(); + Vector128 value = VectorHelper.VectorSingleZero(); + + value = VectorHelper.VectorInsertInt(ReadByte(position), value, 0, 0); + + return value; } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public Vector128 ReadVector16(long position) { - if (Sse2.IsSupported) + if (Sse2.IsSupported && (position & 1) == 0) { return Sse.StaticCast(Sse2.Insert(Sse2.SetZeroVector128(), ReadUInt16(position), 0)); } else { - throw new PlatformNotSupportedException(); + Vector128 value = VectorHelper.VectorSingleZero(); + + value = VectorHelper.VectorInsertInt(ReadUInt16(position), value, 0, 1); + + return value; } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public Vector128 ReadVector32(long position) { - if (Sse.IsSupported) + if (Sse.IsSupported && (position & 3) == 0) { return Sse.LoadScalarVector128((float*)Translate(position)); } else { - throw new PlatformNotSupportedException(); + Vector128 value = VectorHelper.VectorSingleZero(); + + value = VectorHelper.VectorInsertInt(ReadUInt32(position), value, 0, 2); + + return value; } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public Vector128 ReadVector64(long position) { - if (Sse2.IsSupported) + if (Sse2.IsSupported && (position & 7) == 0) { return Sse.StaticCast(Sse2.LoadScalarVector128((double*)Translate(position))); } else { - throw new PlatformNotSupportedException(); + Vector128 value = VectorHelper.VectorSingleZero(); + + value = VectorHelper.VectorInsertInt(ReadUInt64(position), value, 0, 3); + + return value; } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public Vector128 ReadVector128(long position) { - if (Sse.IsSupported) + if (Sse.IsSupported && (position & 15) == 0) { return Sse.LoadVector128((float*)Translate(position)); } else { - throw new PlatformNotSupportedException(); + Vector128 value = VectorHelper.VectorSingleZero(); + + value = VectorHelper.VectorInsertInt(ReadUInt64(position + 0), value, 0, 3); + value = VectorHelper.VectorInsertInt(ReadUInt64(position + 8), value, 1, 3); + + return value; } } @@ -347,17 +394,41 @@ namespace ChocolArm64.Memory public void WriteUInt16(long position, ushort value) { - *((ushort*)TranslateWrite(position)) = value; + if ((position & 1) == 0) + { + *((ushort*)TranslateWrite(position)) = value; + } + else + { + WriteByte(position + 0, (byte)(value >> 0)); + WriteByte(position + 1, (byte)(value >> 8)); + } } public void WriteUInt32(long position, uint value) { - *((uint*)TranslateWrite(position)) = value; + if ((position & 3) == 0) + { + *((uint*)TranslateWrite(position)) = value; + } + else + { + WriteUInt16(position + 0, (ushort)(value >> 0)); + WriteUInt16(position + 2, (ushort)(value >> 16)); + } } public void WriteUInt64(long position, ulong value) { - *((ulong*)TranslateWrite(position)) = value; + if ((position & 7) == 0) + { + *((ulong*)TranslateWrite(position)) = value; + } + else + { + WriteUInt32(position + 0, (uint)(value >> 0)); + WriteUInt32(position + 4, (uint)(value >> 32)); + } } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -373,7 +444,7 @@ namespace ChocolArm64.Memory } else { - throw new PlatformNotSupportedException(); + WriteByte(position, (byte)VectorHelper.VectorExtractIntZx(value, 0, 0)); } } @@ -386,46 +457,47 @@ namespace ChocolArm64.Memory } else { - throw new PlatformNotSupportedException(); + WriteUInt16(position, (ushort)VectorHelper.VectorExtractIntZx(value, 0, 1)); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public void WriteVector32(long position, Vector128 value) { - if (Sse.IsSupported) + if (Sse.IsSupported && (position & 3) == 0) { Sse.StoreScalar((float*)TranslateWrite(position), value); } else { - throw new PlatformNotSupportedException(); + WriteUInt32(position, (uint)VectorHelper.VectorExtractIntZx(value, 0, 2)); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public void WriteVector64(long position, Vector128 value) { - if (Sse2.IsSupported) + if (Sse2.IsSupported && (position & 7) == 0) { Sse2.StoreScalar((double*)TranslateWrite(position), Sse.StaticCast(value)); } else { - throw new PlatformNotSupportedException(); + WriteUInt64(position, VectorHelper.VectorExtractIntZx(value, 0, 3)); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public void WriteVector128(long position, Vector128 value) { - if (Sse.IsSupported) + if (Sse.IsSupported && (position & 15) == 0) { Sse.Store((float*)TranslateWrite(position), value); } else { - throw new PlatformNotSupportedException(); + WriteUInt64(position + 0, VectorHelper.VectorExtractIntZx(value, 0, 3)); + WriteUInt64(position + 8, VectorHelper.VectorExtractIntZx(value, 1, 3)); } } diff --git a/Ryujinx.HLE/Memory/DeviceMemory.cs b/Ryujinx.HLE/DeviceMemory.cs similarity index 95% rename from Ryujinx.HLE/Memory/DeviceMemory.cs rename to Ryujinx.HLE/DeviceMemory.cs index 3c5f2e5f78..edc7091197 100644 --- a/Ryujinx.HLE/Memory/DeviceMemory.cs +++ b/Ryujinx.HLE/DeviceMemory.cs @@ -1,22 +1,18 @@ using System; using System.Runtime.InteropServices; -namespace Ryujinx.HLE.Memory +namespace Ryujinx.HLE { class DeviceMemory : IDisposable { public const long RamSize = 4L * 1024 * 1024 * 1024; - public ArenaAllocator Allocator { get; private set; } - public IntPtr RamPointer { get; private set; } private unsafe byte* RamPtr; public unsafe DeviceMemory() { - Allocator = new ArenaAllocator(RamSize); - RamPointer = Marshal.AllocHGlobal(new IntPtr(RamSize)); RamPtr = (byte*)RamPointer; diff --git a/Ryujinx.HLE/HOS/Font/SharedFontManager.cs b/Ryujinx.HLE/HOS/Font/SharedFontManager.cs index 313db34571..55adf46a5c 100644 --- a/Ryujinx.HLE/HOS/Font/SharedFontManager.cs +++ b/Ryujinx.HLE/HOS/Font/SharedFontManager.cs @@ -1,4 +1,4 @@ -using LibHac; +using LibHac; using Ryujinx.HLE.FileSystem; using Ryujinx.HLE.FileSystem.Content; using Ryujinx.HLE.Resource; diff --git a/Ryujinx.HLE/HOS/Kernel/KMemoryManager.cs b/Ryujinx.HLE/HOS/Kernel/KMemoryManager.cs index 2589203fdc..9cb03eefea 100644 --- a/Ryujinx.HLE/HOS/Kernel/KMemoryManager.cs +++ b/Ryujinx.HLE/HOS/Kernel/KMemoryManager.cs @@ -1,6 +1,5 @@ using ChocolArm64.Memory; using Ryujinx.Common; -using Ryujinx.HLE.Memory; using System; using System.Collections.Generic; @@ -18,8 +17,6 @@ namespace Ryujinx.HLE.HOS.Kernel private MemoryManager CpuMemory; - private ArenaAllocator Allocator; - private Horizon System; public long AddrSpaceStart { get; private set; } diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvMap/NvMapIoctl.cs b/Ryujinx.HLE/HOS/Services/Nv/NvMap/NvMapIoctl.cs index 090c52fcd7..adc523e501 100644 --- a/Ryujinx.HLE/HOS/Services/Nv/NvMap/NvMapIoctl.cs +++ b/Ryujinx.HLE/HOS/Services/Nv/NvMap/NvMapIoctl.cs @@ -131,10 +131,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvMap //When the address is zero, we need to allocate //our own backing memory for the NvMap. //TODO: Is this allocation inside the transfer memory? - if (!Context.Device.Memory.Allocator.TryAllocate((uint)Size, out Address)) - { - Result = NvResult.OutOfMemory; - } + Result = NvResult.OutOfMemory; } if (Result == NvResult.Success) diff --git a/Ryujinx.HLE/Memory/ArenaAllocator.cs b/Ryujinx.HLE/Memory/ArenaAllocator.cs deleted file mode 100644 index 9bcb7873e0..0000000000 --- a/Ryujinx.HLE/Memory/ArenaAllocator.cs +++ /dev/null @@ -1,150 +0,0 @@ -using System.Collections.Generic; - -namespace Ryujinx.HLE.Memory -{ - class ArenaAllocator - { - private class Region - { - public long Position { get; set; } - public long Size { get; set; } - - public Region(long Position, long Size) - { - this.Position = Position; - this.Size = Size; - } - } - - private LinkedList FreeRegions; - - public long TotalAvailableSize { get; private set; } - public long TotalUsedSize { get; private set; } - - public ArenaAllocator(long ArenaSize) - { - TotalAvailableSize = ArenaSize; - - FreeRegions = new LinkedList(); - - FreeRegions.AddFirst(new Region(0, ArenaSize)); - } - - public bool TryAllocate(long Size, out long Position) - { - LinkedListNode Node = FreeRegions.First; - - while (Node != null) - { - Region Rg = Node.Value; - - if ((ulong)Rg.Size >= (ulong)Size) - { - Position = Rg.Position; - - Rg.Position += Size; - Rg.Size -= Size; - - if (Rg.Size == 0) - { - //Region is empty, just remove it. - FreeRegions.Remove(Node); - } - else if (Node.Previous != null) - { - //Re-sort based on size (smaller first). - Node = Node.Previous; - - FreeRegions.Remove(Node.Next); - - while (Node != null && (ulong)Node.Value.Size > (ulong)Rg.Size) - { - Node = Node.Previous; - } - - if (Node != null) - { - FreeRegions.AddAfter(Node, Rg); - } - else - { - FreeRegions.AddFirst(Rg); - } - } - - TotalUsedSize += Size; - - return true; - } - - Node = Node.Next; - } - - Position = 0; - - return false; - } - - public void Free(long Position, long Size) - { - long End = Position + Size; - - Region NewRg = new Region(Position, Size); - - LinkedListNode Node = FreeRegions.First; - LinkedListNode PrevSz = null; - - while (Node != null) - { - LinkedListNode NextNode = Node.Next; - - Region Rg = Node.Value; - - long RgEnd = Rg.Position + Rg.Size; - - if (Rg.Position == End) - { - //Current region position matches the end of the freed region, - //just merge the two and remove the current region from the list. - NewRg.Size += Rg.Size; - - FreeRegions.Remove(Node); - } - else if (RgEnd == Position) - { - //End of the current region matches the position of the freed region, - //just merge the two and remove the current region from the list. - NewRg.Position = Rg.Position; - NewRg.Size += Rg.Size; - - FreeRegions.Remove(Node); - } - else - { - if (PrevSz == null) - { - PrevSz = Node; - } - else if ((ulong)Rg.Size < (ulong)NewRg.Size && - (ulong)Rg.Size > (ulong)PrevSz.Value.Size) - { - PrevSz = Node; - } - } - - Node = NextNode; - } - - if (PrevSz != null && (ulong)PrevSz.Value.Size < (ulong)Size) - { - FreeRegions.AddAfter(PrevSz, NewRg); - } - else - { - FreeRegions.AddFirst(NewRg); - } - - TotalUsedSize -= Size; - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/Switch.cs b/Ryujinx.HLE/Switch.cs index ddcc6fddec..5b3b36d0f7 100644 --- a/Ryujinx.HLE/Switch.cs +++ b/Ryujinx.HLE/Switch.cs @@ -4,7 +4,6 @@ using Ryujinx.Graphics.Gal; using Ryujinx.HLE.FileSystem; using Ryujinx.HLE.HOS; using Ryujinx.HLE.Input; -using Ryujinx.HLE.Memory; using System; using System.Threading;