Implement a new physical memory manager and replace DeviceMemory (#856)
* Implement a new physical memory manager and replace DeviceMemory * Proper generic constraints * Fix debug build * Add memory tests * New CPU memory manager and general code cleanup * Remove host memory management from CPU project, use Ryujinx.Memory instead * Fix tests * Document exceptions on MemoryBlock * Fix leak on unix memory allocation * Proper disposal of some objects on tests * Fix JitCache not being set as initialized * GetRef without checks for 8-bits and 16-bits CAS * Add MemoryBlock destructor * Throw in separate method to improve codegen * Address PR feedback * QueryModified improvements * Fix memory write tracking not marking all pages as modified in some cases * Simplify MarkRegionAsModified * Remove XML doc for ghost param * Add back optimization to avoid useless buffer updates * Add Ryujinx.Cpu project, move MemoryManager there and remove MemoryBlockWrapper * Some nits * Do not perform address translation when size is 0 * Address PR feedback and format NativeInterface class * Remove ghost parameter description * Update Ryujinx.Cpu to .NET Core 3.1 * Address PR feedback * Fix build * Return a well defined value for GetPhysicalAddress with invalid VA, and do not return unmapped ranges as modified * Typo
This commit is contained in:
parent
1758424208
commit
f77694e4f7
126 changed files with 2176 additions and 2092 deletions
|
@ -3,6 +3,7 @@ using ARMeilleure.State;
|
|||
using ARMeilleure.Translation;
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading;
|
||||
|
||||
namespace ARMeilleure.Instructions
|
||||
{
|
||||
|
@ -12,18 +13,18 @@ namespace ARMeilleure.Instructions
|
|||
|
||||
private class ThreadContext
|
||||
{
|
||||
public ExecutionContext Context { get; }
|
||||
public MemoryManager Memory { get; }
|
||||
public Translator Translator { get; }
|
||||
public State.ExecutionContext Context { get; }
|
||||
public IMemoryManager Memory { get; }
|
||||
public Translator Translator { get; }
|
||||
|
||||
public ulong ExclusiveAddress { get; set; }
|
||||
public ulong ExclusiveValueLow { get; set; }
|
||||
public ulong ExclusiveAddress { get; set; }
|
||||
public ulong ExclusiveValueLow { get; set; }
|
||||
public ulong ExclusiveValueHigh { get; set; }
|
||||
|
||||
public ThreadContext(ExecutionContext context, MemoryManager memory, Translator translator)
|
||||
public ThreadContext(State.ExecutionContext context, IMemoryManager memory, Translator translator)
|
||||
{
|
||||
Context = context;
|
||||
Memory = memory;
|
||||
Context = context;
|
||||
Memory = memory;
|
||||
Translator = translator;
|
||||
|
||||
ExclusiveAddress = ulong.MaxValue;
|
||||
|
@ -33,7 +34,7 @@ namespace ARMeilleure.Instructions
|
|||
[ThreadStatic]
|
||||
private static ThreadContext _context;
|
||||
|
||||
public static void RegisterThread(ExecutionContext context, MemoryManager memory, Translator translator)
|
||||
public static void RegisterThread(State.ExecutionContext context, IMemoryManager memory, Translator translator)
|
||||
{
|
||||
_context = new ThreadContext(context, memory, translator);
|
||||
}
|
||||
|
@ -70,7 +71,7 @@ namespace ARMeilleure.Instructions
|
|||
Statistics.ResumeTimer();
|
||||
}
|
||||
|
||||
#region "System registers"
|
||||
#region "System registers"
|
||||
public static ulong GetCtrEl0()
|
||||
{
|
||||
return (ulong)GetContext().CtrEl0;
|
||||
|
@ -93,7 +94,8 @@ namespace ARMeilleure.Instructions
|
|||
|
||||
public static uint GetFpscr()
|
||||
{
|
||||
ExecutionContext context = GetContext();
|
||||
var context = GetContext();
|
||||
|
||||
uint result = (uint)(context.Fpsr & FPSR.A32Mask) | (uint)(context.Fpcr & FPCR.A32Mask);
|
||||
|
||||
result |= context.GetFPstateFlag(FPState.NFlag) ? (1u << 31) : 0;
|
||||
|
@ -146,7 +148,7 @@ namespace ARMeilleure.Instructions
|
|||
|
||||
public static void SetFpscr(uint value)
|
||||
{
|
||||
ExecutionContext context = GetContext();
|
||||
var context = GetContext();
|
||||
|
||||
context.SetFPstateFlag(FPState.NFlag, (value & (1u << 31)) != 0);
|
||||
context.SetFPstateFlag(FPState.ZFlag, (value & (1u << 30)) != 0);
|
||||
|
@ -171,37 +173,37 @@ namespace ARMeilleure.Instructions
|
|||
#region "Read"
|
||||
public static byte ReadByte(ulong address)
|
||||
{
|
||||
return GetMemoryManager().ReadByte((long)address);
|
||||
return GetMemoryManager().Read<byte>(address);
|
||||
}
|
||||
|
||||
public static ushort ReadUInt16(ulong address)
|
||||
{
|
||||
return GetMemoryManager().ReadUInt16((long)address);
|
||||
return GetMemoryManager().Read<ushort>(address);
|
||||
}
|
||||
|
||||
public static uint ReadUInt32(ulong address)
|
||||
{
|
||||
return GetMemoryManager().ReadUInt32((long)address);
|
||||
return GetMemoryManager().Read<uint>(address);
|
||||
}
|
||||
|
||||
public static ulong ReadUInt64(ulong address)
|
||||
{
|
||||
return GetMemoryManager().ReadUInt64((long)address);
|
||||
return GetMemoryManager().Read<ulong>(address);
|
||||
}
|
||||
|
||||
public static V128 ReadVector128(ulong address)
|
||||
{
|
||||
return GetMemoryManager().ReadVector128((long)address);
|
||||
return GetMemoryManager().Read<V128>(address);
|
||||
}
|
||||
#endregion
|
||||
#endregion
|
||||
|
||||
#region "Read exclusive"
|
||||
#region "Read exclusive"
|
||||
public static byte ReadByteExclusive(ulong address)
|
||||
{
|
||||
byte value = _context.Memory.ReadByte((long)address);
|
||||
byte value = _context.Memory.Read<byte>(address);
|
||||
|
||||
_context.ExclusiveAddress = GetMaskedExclusiveAddress(address);
|
||||
_context.ExclusiveValueLow = value;
|
||||
_context.ExclusiveAddress = GetMaskedExclusiveAddress(address);
|
||||
_context.ExclusiveValueLow = value;
|
||||
_context.ExclusiveValueHigh = 0;
|
||||
|
||||
return value;
|
||||
|
@ -209,10 +211,10 @@ namespace ARMeilleure.Instructions
|
|||
|
||||
public static ushort ReadUInt16Exclusive(ulong address)
|
||||
{
|
||||
ushort value = _context.Memory.ReadUInt16((long)address);
|
||||
ushort value = _context.Memory.Read<ushort>(address);
|
||||
|
||||
_context.ExclusiveAddress = GetMaskedExclusiveAddress(address);
|
||||
_context.ExclusiveValueLow = value;
|
||||
_context.ExclusiveAddress = GetMaskedExclusiveAddress(address);
|
||||
_context.ExclusiveValueLow = value;
|
||||
_context.ExclusiveValueHigh = 0;
|
||||
|
||||
return value;
|
||||
|
@ -220,10 +222,10 @@ namespace ARMeilleure.Instructions
|
|||
|
||||
public static uint ReadUInt32Exclusive(ulong address)
|
||||
{
|
||||
uint value = _context.Memory.ReadUInt32((long)address);
|
||||
uint value = _context.Memory.Read<uint>(address);
|
||||
|
||||
_context.ExclusiveAddress = GetMaskedExclusiveAddress(address);
|
||||
_context.ExclusiveValueLow = value;
|
||||
_context.ExclusiveAddress = GetMaskedExclusiveAddress(address);
|
||||
_context.ExclusiveValueLow = value;
|
||||
_context.ExclusiveValueHigh = 0;
|
||||
|
||||
return value;
|
||||
|
@ -231,10 +233,10 @@ namespace ARMeilleure.Instructions
|
|||
|
||||
public static ulong ReadUInt64Exclusive(ulong address)
|
||||
{
|
||||
ulong value = _context.Memory.ReadUInt64((long)address);
|
||||
ulong value = _context.Memory.Read<ulong>(address);
|
||||
|
||||
_context.ExclusiveAddress = GetMaskedExclusiveAddress(address);
|
||||
_context.ExclusiveValueLow = value;
|
||||
_context.ExclusiveAddress = GetMaskedExclusiveAddress(address);
|
||||
_context.ExclusiveValueLow = value;
|
||||
_context.ExclusiveValueHigh = 0;
|
||||
|
||||
return value;
|
||||
|
@ -242,54 +244,60 @@ namespace ARMeilleure.Instructions
|
|||
|
||||
public static V128 ReadVector128Exclusive(ulong address)
|
||||
{
|
||||
V128 value = _context.Memory.AtomicLoadInt128((long)address);
|
||||
V128 value = MemoryManagerPal.AtomicLoad128(ref _context.Memory.GetRef<V128>(address));
|
||||
|
||||
_context.ExclusiveAddress = GetMaskedExclusiveAddress(address);
|
||||
_context.ExclusiveValueLow = value.Extract<ulong>(0);
|
||||
_context.ExclusiveAddress = GetMaskedExclusiveAddress(address);
|
||||
_context.ExclusiveValueLow = value.Extract<ulong>(0);
|
||||
_context.ExclusiveValueHigh = value.Extract<ulong>(1);
|
||||
|
||||
return value;
|
||||
}
|
||||
#endregion
|
||||
#endregion
|
||||
|
||||
#region "Write"
|
||||
#region "Write"
|
||||
public static void WriteByte(ulong address, byte value)
|
||||
{
|
||||
GetMemoryManager().WriteByte((long)address, value);
|
||||
GetMemoryManager().Write(address, value);
|
||||
}
|
||||
|
||||
public static void WriteUInt16(ulong address, ushort value)
|
||||
{
|
||||
GetMemoryManager().WriteUInt16((long)address, value);
|
||||
GetMemoryManager().Write(address, value);
|
||||
}
|
||||
|
||||
public static void WriteUInt32(ulong address, uint value)
|
||||
{
|
||||
GetMemoryManager().WriteUInt32((long)address, value);
|
||||
GetMemoryManager().Write(address, value);
|
||||
}
|
||||
|
||||
public static void WriteUInt64(ulong address, ulong value)
|
||||
{
|
||||
GetMemoryManager().WriteUInt64((long)address, value);
|
||||
GetMemoryManager().Write(address, value);
|
||||
}
|
||||
|
||||
public static void WriteVector128(ulong address, V128 value)
|
||||
{
|
||||
GetMemoryManager().WriteVector128((long)address, value);
|
||||
GetMemoryManager().Write(address, value);
|
||||
}
|
||||
#endregion
|
||||
#endregion
|
||||
|
||||
#region "Write exclusive"
|
||||
#region "Write exclusive"
|
||||
public static int WriteByteExclusive(ulong address, byte value)
|
||||
{
|
||||
bool success = _context.ExclusiveAddress == GetMaskedExclusiveAddress(address);
|
||||
|
||||
if (success)
|
||||
{
|
||||
success = _context.Memory.AtomicCompareExchangeByte(
|
||||
(long)address,
|
||||
(byte)_context.ExclusiveValueLow,
|
||||
(byte)value);
|
||||
ref int valueRef = ref _context.Memory.GetRefNoChecks<int>(address);
|
||||
|
||||
int currentValue = valueRef;
|
||||
|
||||
byte expected = (byte)_context.ExclusiveValueLow;
|
||||
|
||||
int expected32 = (currentValue & ~byte.MaxValue) | expected;
|
||||
int desired32 = (currentValue & ~byte.MaxValue) | value;
|
||||
|
||||
success = Interlocked.CompareExchange(ref valueRef, desired32, expected32) == expected32;
|
||||
|
||||
if (success)
|
||||
{
|
||||
|
@ -306,10 +314,16 @@ namespace ARMeilleure.Instructions
|
|||
|
||||
if (success)
|
||||
{
|
||||
success = _context.Memory.AtomicCompareExchangeInt16(
|
||||
(long)address,
|
||||
(short)_context.ExclusiveValueLow,
|
||||
(short)value);
|
||||
ref int valueRef = ref _context.Memory.GetRefNoChecks<int>(address);
|
||||
|
||||
int currentValue = valueRef;
|
||||
|
||||
ushort expected = (ushort)_context.ExclusiveValueLow;
|
||||
|
||||
int expected32 = (currentValue & ~ushort.MaxValue) | expected;
|
||||
int desired32 = (currentValue & ~ushort.MaxValue) | value;
|
||||
|
||||
success = Interlocked.CompareExchange(ref valueRef, desired32, expected32) == expected32;
|
||||
|
||||
if (success)
|
||||
{
|
||||
|
@ -326,10 +340,9 @@ namespace ARMeilleure.Instructions
|
|||
|
||||
if (success)
|
||||
{
|
||||
success = _context.Memory.AtomicCompareExchangeInt32(
|
||||
(long)address,
|
||||
(int)_context.ExclusiveValueLow,
|
||||
(int)value);
|
||||
ref int valueRef = ref _context.Memory.GetRef<int>(address);
|
||||
|
||||
success = Interlocked.CompareExchange(ref valueRef, (int)value, (int)_context.ExclusiveValueLow) == (int)_context.ExclusiveValueLow;
|
||||
|
||||
if (success)
|
||||
{
|
||||
|
@ -346,10 +359,9 @@ namespace ARMeilleure.Instructions
|
|||
|
||||
if (success)
|
||||
{
|
||||
success = _context.Memory.AtomicCompareExchangeInt64(
|
||||
(long)address,
|
||||
(long)_context.ExclusiveValueLow,
|
||||
(long)value);
|
||||
ref long valueRef = ref _context.Memory.GetRef<long>(address);
|
||||
|
||||
success = Interlocked.CompareExchange(ref valueRef, (long)value, (long)_context.ExclusiveValueLow) == (long)_context.ExclusiveValueLow;
|
||||
|
||||
if (success)
|
||||
{
|
||||
|
@ -368,7 +380,9 @@ namespace ARMeilleure.Instructions
|
|||
{
|
||||
V128 expected = new V128(_context.ExclusiveValueLow, _context.ExclusiveValueHigh);
|
||||
|
||||
success = _context.Memory.AtomicCompareExchangeInt128((long)address, expected, value);
|
||||
ref V128 location = ref _context.Memory.GetRef<V128>(address);
|
||||
|
||||
success = MemoryManagerPal.CompareAndSwap128(ref location, expected, value) == expected;
|
||||
|
||||
if (success)
|
||||
{
|
||||
|
@ -378,7 +392,7 @@ namespace ARMeilleure.Instructions
|
|||
|
||||
return success ? 0 : 1;
|
||||
}
|
||||
#endregion
|
||||
#endregion
|
||||
|
||||
private static ulong GetMaskedExclusiveAddress(ulong address)
|
||||
{
|
||||
|
@ -412,7 +426,8 @@ namespace ARMeilleure.Instructions
|
|||
{
|
||||
Statistics.PauseTimer();
|
||||
|
||||
ExecutionContext context = GetContext();
|
||||
var context = GetContext();
|
||||
|
||||
context.CheckInterrupt();
|
||||
|
||||
Statistics.ResumeTimer();
|
||||
|
@ -420,12 +435,12 @@ namespace ARMeilleure.Instructions
|
|||
return context.Running;
|
||||
}
|
||||
|
||||
public static ExecutionContext GetContext()
|
||||
public static State.ExecutionContext GetContext()
|
||||
{
|
||||
return _context.Context;
|
||||
}
|
||||
|
||||
public static MemoryManager GetMemoryManager()
|
||||
public static IMemoryManager GetMemoryManager()
|
||||
{
|
||||
return _context.Memory;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue