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
|
||||
{
|
||||
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() { }
|
||||
|
|
@ -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<float> ReadVector8(long position)
|
||||
|
@ -218,59 +244,80 @@ namespace ChocolArm64.Memory
|
|||
}
|
||||
else
|
||||
{
|
||||
throw new PlatformNotSupportedException();
|
||||
Vector128<float> value = VectorHelper.VectorSingleZero();
|
||||
|
||||
value = VectorHelper.VectorInsertInt(ReadByte(position), value, 0, 0);
|
||||
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
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));
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new PlatformNotSupportedException();
|
||||
Vector128<float> value = VectorHelper.VectorSingleZero();
|
||||
|
||||
value = VectorHelper.VectorInsertInt(ReadUInt16(position), value, 0, 1);
|
||||
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public Vector128<float> ReadVector32(long position)
|
||||
{
|
||||
if (Sse.IsSupported)
|
||||
if (Sse.IsSupported && (position & 3) == 0)
|
||||
{
|
||||
return Sse.LoadScalarVector128((float*)Translate(position));
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new PlatformNotSupportedException();
|
||||
Vector128<float> value = VectorHelper.VectorSingleZero();
|
||||
|
||||
value = VectorHelper.VectorInsertInt(ReadUInt32(position), value, 0, 2);
|
||||
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
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)));
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new PlatformNotSupportedException();
|
||||
Vector128<float> value = VectorHelper.VectorSingleZero();
|
||||
|
||||
value = VectorHelper.VectorInsertInt(ReadUInt64(position), value, 0, 3);
|
||||
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public Vector128<float> ReadVector128(long position)
|
||||
{
|
||||
if (Sse.IsSupported)
|
||||
if (Sse.IsSupported && (position & 15) == 0)
|
||||
{
|
||||
return Sse.LoadVector128((float*)Translate(position));
|
||||
}
|
||||
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)
|
||||
{
|
||||
*((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<float> 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<float> value)
|
||||
{
|
||||
if (Sse2.IsSupported)
|
||||
if (Sse2.IsSupported && (position & 7) == 0)
|
||||
{
|
||||
Sse2.StoreScalar((double*)TranslateWrite(position), Sse.StaticCast<float, double>(value));
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new PlatformNotSupportedException();
|
||||
WriteUInt64(position, VectorHelper.VectorExtractIntZx(value, 0, 3));
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void WriteVector128(long position, Vector128<float> 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));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
|
@ -1,4 +1,4 @@
|
|||
using LibHac;
|
||||
using LibHac;
|
||||
using Ryujinx.HLE.FileSystem;
|
||||
using Ryujinx.HLE.FileSystem.Content;
|
||||
using Ryujinx.HLE.Resource;
|
||||
|
|
|
@ -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; }
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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.HOS;
|
||||
using Ryujinx.HLE.Input;
|
||||
using Ryujinx.HLE.Memory;
|
||||
using System;
|
||||
using System.Threading;
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue