Allow the cpu to read/write from the correct memory locations for accesses crossing a page boundary

This commit is contained in:
gdkchan 2018-11-11 14:38:26 -03:00
commit c619596e07
8 changed files with 99 additions and 188 deletions

View file

@ -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() { }

View file

@ -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));
}
}

View file

@ -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;

View file

@ -1,4 +1,4 @@
using LibHac;
using LibHac;
using Ryujinx.HLE.FileSystem;
using Ryujinx.HLE.FileSystem.Content;
using Ryujinx.HLE.Resource;

View file

@ -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; }

View file

@ -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)

View file

@ -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;
}
}
}

View file

@ -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;