diff options
Diffstat (limited to 'src/Ryujinx.Cpu/LightningJit/State')
| -rw-r--r-- | src/Ryujinx.Cpu/LightningJit/State/ExecutionContext.cs | 153 | ||||
| -rw-r--r-- | src/Ryujinx.Cpu/LightningJit/State/ExecutionMode.cs | 9 | ||||
| -rw-r--r-- | src/Ryujinx.Cpu/LightningJit/State/NativeContext.cs | 173 |
3 files changed, 335 insertions, 0 deletions
diff --git a/src/Ryujinx.Cpu/LightningJit/State/ExecutionContext.cs b/src/Ryujinx.Cpu/LightningJit/State/ExecutionContext.cs new file mode 100644 index 00000000..facb9142 --- /dev/null +++ b/src/Ryujinx.Cpu/LightningJit/State/ExecutionContext.cs @@ -0,0 +1,153 @@ +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); + } + + protected virtual void Dispose(bool disposing) + { + _nativeContext.Dispose(); + } + + public void Dispose() + { + Dispose(disposing: true); + GC.SuppressFinalize(this); + } + } +} diff --git a/src/Ryujinx.Cpu/LightningJit/State/ExecutionMode.cs b/src/Ryujinx.Cpu/LightningJit/State/ExecutionMode.cs new file mode 100644 index 00000000..0602bc9a --- /dev/null +++ b/src/Ryujinx.Cpu/LightningJit/State/ExecutionMode.cs @@ -0,0 +1,9 @@ +namespace Ryujinx.Cpu.LightningJit.State +{ + enum ExecutionMode + { + Aarch32Arm = 0, + Aarch32Thumb = 1, + Aarch64 = 2, + } +} diff --git a/src/Ryujinx.Cpu/LightningJit/State/NativeContext.cs b/src/Ryujinx.Cpu/LightningJit/State/NativeContext.cs new file mode 100644 index 00000000..fdb8793d --- /dev/null +++ b/src/Ryujinx.Cpu/LightningJit/State/NativeContext.cs @@ -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(); + } +} |
