mirror of
https://git.743378673.xyz/MeloNX/MeloNX.git
synced 2025-07-31 08:37:10 +02:00
Implement a new JIT for Arm devices
This commit is contained in:
parent
9864675a0b
commit
597710a522
127 changed files with 42538 additions and 25 deletions
148
src/Ryujinx.Cpu/LightningJit/State/ExecutionContext.cs
Normal file
148
src/Ryujinx.Cpu/LightningJit/State/ExecutionContext.cs
Normal file
|
@ -0,0 +1,148 @@
|
|||
using ARMeilleure.Memory;
|
||||
using ARMeilleure.State;
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.Cpu.LightningJit.State
|
||||
{
|
||||
public class ExecutionContext : IExecutionContext
|
||||
{
|
||||
private const int MinCountForCheck = 4000;
|
||||
|
||||
private readonly NativeContext _nativeContext;
|
||||
|
||||
internal IntPtr NativeContextPtr => _nativeContext.BasePtr;
|
||||
|
||||
private bool _interrupted;
|
||||
|
||||
private readonly ICounter _counter;
|
||||
|
||||
public ulong Pc => _nativeContext.GetPc();
|
||||
|
||||
public ulong CntfrqEl0 => _counter.Frequency;
|
||||
public ulong CntpctEl0 => _counter.Counter;
|
||||
|
||||
public long TpidrEl0
|
||||
{
|
||||
get => _nativeContext.GetTpidrEl0();
|
||||
set => _nativeContext.SetTpidrEl0(value);
|
||||
}
|
||||
|
||||
public long TpidrroEl0
|
||||
{
|
||||
get => _nativeContext.GetTpidrroEl0();
|
||||
set => _nativeContext.SetTpidrroEl0(value);
|
||||
}
|
||||
|
||||
public uint Pstate
|
||||
{
|
||||
get => _nativeContext.GetPstate();
|
||||
set => _nativeContext.SetPstate(value);
|
||||
}
|
||||
|
||||
public uint Fpsr
|
||||
{
|
||||
get => _nativeContext.GetFPState((uint)FPSR.Mask);
|
||||
set => _nativeContext.SetFPState(value, (uint)FPSR.Mask);
|
||||
}
|
||||
|
||||
public uint Fpcr
|
||||
{
|
||||
get => _nativeContext.GetFPState((uint)FPCR.Mask);
|
||||
set => _nativeContext.SetFPState(value, (uint)FPCR.Mask);
|
||||
}
|
||||
|
||||
public bool IsAarch32 { get; set; }
|
||||
|
||||
internal ExecutionMode ExecutionMode
|
||||
{
|
||||
get
|
||||
{
|
||||
if (IsAarch32)
|
||||
{
|
||||
return (Pstate & (1u << 5)) != 0
|
||||
? ExecutionMode.Aarch32Thumb
|
||||
: ExecutionMode.Aarch32Arm;
|
||||
}
|
||||
else
|
||||
{
|
||||
return ExecutionMode.Aarch64;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool Running
|
||||
{
|
||||
get => _nativeContext.GetRunning();
|
||||
private set => _nativeContext.SetRunning(value);
|
||||
}
|
||||
|
||||
private readonly ExceptionCallbackNoArgs _interruptCallback;
|
||||
private readonly ExceptionCallback _breakCallback;
|
||||
private readonly ExceptionCallback _supervisorCallback;
|
||||
private readonly ExceptionCallback _undefinedCallback;
|
||||
|
||||
public ExecutionContext(IJitMemoryAllocator allocator, ICounter counter, ExceptionCallbacks exceptionCallbacks)
|
||||
{
|
||||
_nativeContext = new NativeContext(allocator);
|
||||
_counter = counter;
|
||||
_interruptCallback = exceptionCallbacks.InterruptCallback;
|
||||
_breakCallback = exceptionCallbacks.BreakCallback;
|
||||
_supervisorCallback = exceptionCallbacks.SupervisorCallback;
|
||||
_undefinedCallback = exceptionCallbacks.UndefinedCallback;
|
||||
|
||||
Running = true;
|
||||
|
||||
_nativeContext.SetCounter(MinCountForCheck);
|
||||
}
|
||||
|
||||
public ulong GetX(int index) => _nativeContext.GetX(index);
|
||||
public void SetX(int index, ulong value) => _nativeContext.SetX(index, value);
|
||||
|
||||
public V128 GetV(int index) => _nativeContext.GetV(index);
|
||||
public void SetV(int index, V128 value) => _nativeContext.SetV(index, value);
|
||||
|
||||
internal void CheckInterrupt()
|
||||
{
|
||||
if (_interrupted)
|
||||
{
|
||||
_interrupted = false;
|
||||
|
||||
_interruptCallback?.Invoke(this);
|
||||
}
|
||||
|
||||
_nativeContext.SetCounter(MinCountForCheck);
|
||||
}
|
||||
|
||||
public void RequestInterrupt()
|
||||
{
|
||||
_interrupted = true;
|
||||
}
|
||||
|
||||
internal void OnBreak(ulong address, int imm)
|
||||
{
|
||||
_breakCallback?.Invoke(this, address, imm);
|
||||
}
|
||||
|
||||
internal void OnSupervisorCall(ulong address, int imm)
|
||||
{
|
||||
_supervisorCallback?.Invoke(this, address, imm);
|
||||
}
|
||||
|
||||
internal void OnUndefined(ulong address, int opCode)
|
||||
{
|
||||
_undefinedCallback?.Invoke(this, address, opCode);
|
||||
}
|
||||
|
||||
public void StopRunning()
|
||||
{
|
||||
Running = false;
|
||||
|
||||
_nativeContext.SetCounter(0);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_nativeContext.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
9
src/Ryujinx.Cpu/LightningJit/State/ExecutionMode.cs
Normal file
9
src/Ryujinx.Cpu/LightningJit/State/ExecutionMode.cs
Normal file
|
@ -0,0 +1,9 @@
|
|||
namespace Ryujinx.Cpu.LightningJit.State
|
||||
{
|
||||
enum ExecutionMode
|
||||
{
|
||||
Aarch32Arm = 0,
|
||||
Aarch32Thumb = 1,
|
||||
Aarch64 = 2,
|
||||
}
|
||||
}
|
173
src/Ryujinx.Cpu/LightningJit/State/NativeContext.cs
Normal file
173
src/Ryujinx.Cpu/LightningJit/State/NativeContext.cs
Normal file
|
@ -0,0 +1,173 @@
|
|||
using ARMeilleure.Memory;
|
||||
using ARMeilleure.State;
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Ryujinx.Cpu.LightningJit.State
|
||||
{
|
||||
class NativeContext : IDisposable
|
||||
{
|
||||
private unsafe struct NativeCtxStorage
|
||||
{
|
||||
public fixed ulong X[32];
|
||||
public fixed ulong V[64];
|
||||
public uint Flags;
|
||||
public uint FpFlags;
|
||||
public long TpidrEl0;
|
||||
public long TpidrroEl0;
|
||||
public int Counter;
|
||||
public uint HostFpFlags;
|
||||
public ulong DispatchAddress;
|
||||
public int Running;
|
||||
}
|
||||
|
||||
private static NativeCtxStorage _dummyStorage = new();
|
||||
|
||||
private readonly IJitMemoryBlock _block;
|
||||
|
||||
public IntPtr BasePtr => _block.Pointer;
|
||||
|
||||
public NativeContext(IJitMemoryAllocator allocator)
|
||||
{
|
||||
_block = allocator.Allocate((ulong)Unsafe.SizeOf<NativeCtxStorage>());
|
||||
}
|
||||
|
||||
public ulong GetPc()
|
||||
{
|
||||
// TODO: More precise tracking of PC value.
|
||||
return GetStorage().DispatchAddress;
|
||||
}
|
||||
|
||||
public unsafe ulong GetX(int index)
|
||||
{
|
||||
if ((uint)index >= 32)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(index));
|
||||
}
|
||||
|
||||
return GetStorage().X[index];
|
||||
}
|
||||
|
||||
public unsafe void SetX(int index, ulong value)
|
||||
{
|
||||
if ((uint)index >= 32)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(index));
|
||||
}
|
||||
|
||||
GetStorage().X[index] = value;
|
||||
}
|
||||
|
||||
public unsafe V128 GetV(int index)
|
||||
{
|
||||
if ((uint)index >= 32)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(index));
|
||||
}
|
||||
|
||||
return new V128(GetStorage().V[index * 2 + 0], GetStorage().V[index * 2 + 1]);
|
||||
}
|
||||
|
||||
public unsafe void SetV(int index, V128 value)
|
||||
{
|
||||
if ((uint)index >= 32)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(index));
|
||||
}
|
||||
|
||||
GetStorage().V[index * 2 + 0] = value.Extract<ulong>(0);
|
||||
GetStorage().V[index * 2 + 1] = value.Extract<ulong>(1);
|
||||
}
|
||||
|
||||
public unsafe uint GetPstate()
|
||||
{
|
||||
return GetStorage().Flags;
|
||||
}
|
||||
|
||||
public unsafe void SetPstate(uint value)
|
||||
{
|
||||
GetStorage().Flags = value;
|
||||
}
|
||||
|
||||
public unsafe uint GetFPState(uint mask = uint.MaxValue)
|
||||
{
|
||||
return GetStorage().FpFlags & mask;
|
||||
}
|
||||
|
||||
public unsafe void SetFPState(uint value, uint mask = uint.MaxValue)
|
||||
{
|
||||
GetStorage().FpFlags = (value & mask) | (GetStorage().FpFlags & ~mask);
|
||||
}
|
||||
|
||||
public long GetTpidrEl0() => GetStorage().TpidrEl0;
|
||||
public void SetTpidrEl0(long value) => GetStorage().TpidrEl0 = value;
|
||||
|
||||
public long GetTpidrroEl0() => GetStorage().TpidrroEl0;
|
||||
public void SetTpidrroEl0(long value) => GetStorage().TpidrroEl0 = value;
|
||||
|
||||
public int GetCounter() => GetStorage().Counter;
|
||||
public void SetCounter(int value) => GetStorage().Counter = value;
|
||||
|
||||
public bool GetRunning() => GetStorage().Running != 0;
|
||||
public void SetRunning(bool value) => GetStorage().Running = value ? 1 : 0;
|
||||
|
||||
public unsafe static int GetXOffset()
|
||||
{
|
||||
return StorageOffset(ref _dummyStorage, ref _dummyStorage.X[0]);
|
||||
}
|
||||
|
||||
public unsafe static int GetVOffset()
|
||||
{
|
||||
return StorageOffset(ref _dummyStorage, ref _dummyStorage.V[0]);
|
||||
}
|
||||
|
||||
public static int GetFlagsOffset()
|
||||
{
|
||||
return StorageOffset(ref _dummyStorage, ref _dummyStorage.Flags);
|
||||
}
|
||||
|
||||
public static int GetFpFlagsOffset()
|
||||
{
|
||||
return StorageOffset(ref _dummyStorage, ref _dummyStorage.FpFlags);
|
||||
}
|
||||
|
||||
public static int GetTpidrEl0Offset()
|
||||
{
|
||||
return StorageOffset(ref _dummyStorage, ref _dummyStorage.TpidrEl0);
|
||||
}
|
||||
|
||||
public static int GetTpidrroEl0Offset()
|
||||
{
|
||||
return StorageOffset(ref _dummyStorage, ref _dummyStorage.TpidrroEl0);
|
||||
}
|
||||
|
||||
public static int GetCounterOffset()
|
||||
{
|
||||
return StorageOffset(ref _dummyStorage, ref _dummyStorage.Counter);
|
||||
}
|
||||
|
||||
public static int GetHostFpFlagsOffset()
|
||||
{
|
||||
return StorageOffset(ref _dummyStorage, ref _dummyStorage.HostFpFlags);
|
||||
}
|
||||
|
||||
public static int GetDispatchAddressOffset()
|
||||
{
|
||||
return StorageOffset(ref _dummyStorage, ref _dummyStorage.DispatchAddress);
|
||||
}
|
||||
|
||||
public static int GetRunningOffset()
|
||||
{
|
||||
return StorageOffset(ref _dummyStorage, ref _dummyStorage.Running);
|
||||
}
|
||||
|
||||
private static int StorageOffset<T>(ref NativeCtxStorage storage, ref T target)
|
||||
{
|
||||
return (int)Unsafe.ByteOffset(ref Unsafe.As<NativeCtxStorage, T>(ref storage), ref target);
|
||||
}
|
||||
|
||||
private unsafe ref NativeCtxStorage GetStorage() => ref Unsafe.AsRef<NativeCtxStorage>((void*)_block.Pointer);
|
||||
|
||||
public void Dispose() => _block.Dispose();
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue