Allow the cpu to read/write from the correct memory locations for accesses crossing a page boundary
This commit is contained in:
parent
aa16232977
commit
c619596e07
8 changed files with 99 additions and 188 deletions
|
@ -4,7 +4,7 @@ namespace ChocolArm64.Exceptions
|
||||||
{
|
{
|
||||||
public class VmmAccessException : Exception
|
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() { }
|
public VmmAccessException() { }
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
using ChocolArm64.Events;
|
using ChocolArm64.Events;
|
||||||
using ChocolArm64.Exceptions;
|
using ChocolArm64.Exceptions;
|
||||||
|
using ChocolArm64.Instructions;
|
||||||
using ChocolArm64.State;
|
using ChocolArm64.State;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
|
@ -197,17 +198,42 @@ namespace ChocolArm64.Memory
|
||||||
|
|
||||||
public ushort ReadUInt16(long position)
|
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)
|
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)
|
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<float> ReadVector8(long position)
|
public Vector128<float> ReadVector8(long position)
|
||||||
|
@ -218,59 +244,80 @@ namespace ChocolArm64.Memory
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
throw new PlatformNotSupportedException();
|
Vector128<float> value = VectorHelper.VectorSingleZero();
|
||||||
|
|
||||||
|
value = VectorHelper.VectorInsertInt(ReadByte(position), value, 0, 0);
|
||||||
|
|
||||||
|
return value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public Vector128<float> ReadVector16(long position)
|
public Vector128<float> ReadVector16(long position)
|
||||||
{
|
{
|
||||||
if (Sse2.IsSupported)
|
if (Sse2.IsSupported && (position & 1) == 0)
|
||||||
{
|
{
|
||||||
return Sse.StaticCast<ushort, float>(Sse2.Insert(Sse2.SetZeroVector128<ushort>(), ReadUInt16(position), 0));
|
return Sse.StaticCast<ushort, float>(Sse2.Insert(Sse2.SetZeroVector128<ushort>(), ReadUInt16(position), 0));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
throw new PlatformNotSupportedException();
|
Vector128<float> value = VectorHelper.VectorSingleZero();
|
||||||
|
|
||||||
|
value = VectorHelper.VectorInsertInt(ReadUInt16(position), value, 0, 1);
|
||||||
|
|
||||||
|
return value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public Vector128<float> ReadVector32(long position)
|
public Vector128<float> ReadVector32(long position)
|
||||||
{
|
{
|
||||||
if (Sse.IsSupported)
|
if (Sse.IsSupported && (position & 3) == 0)
|
||||||
{
|
{
|
||||||
return Sse.LoadScalarVector128((float*)Translate(position));
|
return Sse.LoadScalarVector128((float*)Translate(position));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
throw new PlatformNotSupportedException();
|
Vector128<float> value = VectorHelper.VectorSingleZero();
|
||||||
|
|
||||||
|
value = VectorHelper.VectorInsertInt(ReadUInt32(position), value, 0, 2);
|
||||||
|
|
||||||
|
return value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public Vector128<float> ReadVector64(long position)
|
public Vector128<float> ReadVector64(long position)
|
||||||
{
|
{
|
||||||
if (Sse2.IsSupported)
|
if (Sse2.IsSupported && (position & 7) == 0)
|
||||||
{
|
{
|
||||||
return Sse.StaticCast<double, float>(Sse2.LoadScalarVector128((double*)Translate(position)));
|
return Sse.StaticCast<double, float>(Sse2.LoadScalarVector128((double*)Translate(position)));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
throw new PlatformNotSupportedException();
|
Vector128<float> value = VectorHelper.VectorSingleZero();
|
||||||
|
|
||||||
|
value = VectorHelper.VectorInsertInt(ReadUInt64(position), value, 0, 3);
|
||||||
|
|
||||||
|
return value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public Vector128<float> ReadVector128(long position)
|
public Vector128<float> ReadVector128(long position)
|
||||||
{
|
{
|
||||||
if (Sse.IsSupported)
|
if (Sse.IsSupported && (position & 15) == 0)
|
||||||
{
|
{
|
||||||
return Sse.LoadVector128((float*)Translate(position));
|
return Sse.LoadVector128((float*)Translate(position));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
throw new PlatformNotSupportedException();
|
Vector128<float> 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)
|
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)
|
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)
|
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)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
@ -373,7 +444,7 @@ namespace ChocolArm64.Memory
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
throw new PlatformNotSupportedException();
|
WriteByte(position, (byte)VectorHelper.VectorExtractIntZx(value, 0, 0));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -386,46 +457,47 @@ namespace ChocolArm64.Memory
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
throw new PlatformNotSupportedException();
|
WriteUInt16(position, (ushort)VectorHelper.VectorExtractIntZx(value, 0, 1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public void WriteVector32(long position, Vector128<float> value)
|
public void WriteVector32(long position, Vector128<float> value)
|
||||||
{
|
{
|
||||||
if (Sse.IsSupported)
|
if (Sse.IsSupported && (position & 3) == 0)
|
||||||
{
|
{
|
||||||
Sse.StoreScalar((float*)TranslateWrite(position), value);
|
Sse.StoreScalar((float*)TranslateWrite(position), value);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
throw new PlatformNotSupportedException();
|
WriteUInt32(position, (uint)VectorHelper.VectorExtractIntZx(value, 0, 2));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public void WriteVector64(long position, Vector128<float> value)
|
public void WriteVector64(long position, Vector128<float> value)
|
||||||
{
|
{
|
||||||
if (Sse2.IsSupported)
|
if (Sse2.IsSupported && (position & 7) == 0)
|
||||||
{
|
{
|
||||||
Sse2.StoreScalar((double*)TranslateWrite(position), Sse.StaticCast<float, double>(value));
|
Sse2.StoreScalar((double*)TranslateWrite(position), Sse.StaticCast<float, double>(value));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
throw new PlatformNotSupportedException();
|
WriteUInt64(position, VectorHelper.VectorExtractIntZx(value, 0, 3));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public void WriteVector128(long position, Vector128<float> value)
|
public void WriteVector128(long position, Vector128<float> value)
|
||||||
{
|
{
|
||||||
if (Sse.IsSupported)
|
if (Sse.IsSupported && (position & 15) == 0)
|
||||||
{
|
{
|
||||||
Sse.Store((float*)TranslateWrite(position), value);
|
Sse.Store((float*)TranslateWrite(position), value);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
throw new PlatformNotSupportedException();
|
WriteUInt64(position + 0, VectorHelper.VectorExtractIntZx(value, 0, 3));
|
||||||
|
WriteUInt64(position + 8, VectorHelper.VectorExtractIntZx(value, 1, 3));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,22 +1,18 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
namespace Ryujinx.HLE.Memory
|
namespace Ryujinx.HLE
|
||||||
{
|
{
|
||||||
class DeviceMemory : IDisposable
|
class DeviceMemory : IDisposable
|
||||||
{
|
{
|
||||||
public const long RamSize = 4L * 1024 * 1024 * 1024;
|
public const long RamSize = 4L * 1024 * 1024 * 1024;
|
||||||
|
|
||||||
public ArenaAllocator Allocator { get; private set; }
|
|
||||||
|
|
||||||
public IntPtr RamPointer { get; private set; }
|
public IntPtr RamPointer { get; private set; }
|
||||||
|
|
||||||
private unsafe byte* RamPtr;
|
private unsafe byte* RamPtr;
|
||||||
|
|
||||||
public unsafe DeviceMemory()
|
public unsafe DeviceMemory()
|
||||||
{
|
{
|
||||||
Allocator = new ArenaAllocator(RamSize);
|
|
||||||
|
|
||||||
RamPointer = Marshal.AllocHGlobal(new IntPtr(RamSize));
|
RamPointer = Marshal.AllocHGlobal(new IntPtr(RamSize));
|
||||||
|
|
||||||
RamPtr = (byte*)RamPointer;
|
RamPtr = (byte*)RamPointer;
|
|
@ -1,4 +1,4 @@
|
||||||
using LibHac;
|
using LibHac;
|
||||||
using Ryujinx.HLE.FileSystem;
|
using Ryujinx.HLE.FileSystem;
|
||||||
using Ryujinx.HLE.FileSystem.Content;
|
using Ryujinx.HLE.FileSystem.Content;
|
||||||
using Ryujinx.HLE.Resource;
|
using Ryujinx.HLE.Resource;
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
using ChocolArm64.Memory;
|
using ChocolArm64.Memory;
|
||||||
using Ryujinx.Common;
|
using Ryujinx.Common;
|
||||||
using Ryujinx.HLE.Memory;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
@ -18,8 +17,6 @@ namespace Ryujinx.HLE.HOS.Kernel
|
||||||
|
|
||||||
private MemoryManager CpuMemory;
|
private MemoryManager CpuMemory;
|
||||||
|
|
||||||
private ArenaAllocator Allocator;
|
|
||||||
|
|
||||||
private Horizon System;
|
private Horizon System;
|
||||||
|
|
||||||
public long AddrSpaceStart { get; private set; }
|
public long AddrSpaceStart { get; private set; }
|
||||||
|
|
|
@ -131,10 +131,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvMap
|
||||||
//When the address is zero, we need to allocate
|
//When the address is zero, we need to allocate
|
||||||
//our own backing memory for the NvMap.
|
//our own backing memory for the NvMap.
|
||||||
//TODO: Is this allocation inside the transfer memory?
|
//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)
|
if (Result == NvResult.Success)
|
||||||
|
|
|
@ -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<Region> FreeRegions;
|
|
||||||
|
|
||||||
public long TotalAvailableSize { get; private set; }
|
|
||||||
public long TotalUsedSize { get; private set; }
|
|
||||||
|
|
||||||
public ArenaAllocator(long ArenaSize)
|
|
||||||
{
|
|
||||||
TotalAvailableSize = ArenaSize;
|
|
||||||
|
|
||||||
FreeRegions = new LinkedList<Region>();
|
|
||||||
|
|
||||||
FreeRegions.AddFirst(new Region(0, ArenaSize));
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool TryAllocate(long Size, out long Position)
|
|
||||||
{
|
|
||||||
LinkedListNode<Region> 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<Region> Node = FreeRegions.First;
|
|
||||||
LinkedListNode<Region> PrevSz = null;
|
|
||||||
|
|
||||||
while (Node != null)
|
|
||||||
{
|
|
||||||
LinkedListNode<Region> 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -4,7 +4,6 @@ using Ryujinx.Graphics.Gal;
|
||||||
using Ryujinx.HLE.FileSystem;
|
using Ryujinx.HLE.FileSystem;
|
||||||
using Ryujinx.HLE.HOS;
|
using Ryujinx.HLE.HOS;
|
||||||
using Ryujinx.HLE.Input;
|
using Ryujinx.HLE.Input;
|
||||||
using Ryujinx.HLE.Memory;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue