814f75142e
* Implemented in IR the managed methods of the Saturating region ... ... of the SoftFallback class (the SatQ ones). The need to natively manage the Fpcr and Fpsr system registers is still a fact. Contributes to https://github.com/Ryujinx/Ryujinx/issues/2917 ; I will open another PR to implement in Intrinsics-branchless the methods of the Saturation region as well (the SatXXXToXXX ones). All instructions involved have been tested locally in both release and debug modes, in both lowcq and highcq. * Ptc.InternalVersion = 3665 * Addressed PR feedback. * Implemented in IR the managed methods of the ShlReg region of the SoftFallback class. It also includes the last two SatQ ones (following up on https://github.com/Ryujinx/Ryujinx/pull/3665). All instructions involved have been tested locally in both release and debug modes, in both lowcq and highcq. * Fpsr and Fpcr freed. Handling/isolation of Fpsr and Fpcr via register for IR and via memory for Tests and Threads, with synchronization to context exchanges (explicit for SoftFloat); without having to call managed methods. Thanks to the inlining work of the previous two PRs and others in this. Tests performed locally in both release and debug modes, in both lowcq and highcq, with FastFP to true and false (explicit FP tests included). Tested with the title Tony Hawk's PS. Depends on shlreg. * Update InstEmitSimdHelper.cs * De-magic Masks. Remove the Stride and Len flags; Fpsr.NZCV are A32 only, then moved to Fpscr: this leads to emitting less IR in reference to Get/Set Fpsr/Fpcr/Fpscr methods in reference to Mrs/Msr (A64) and Vmrs/Vmsr (A32) instructions. * Addressed PR feedback.
164 lines
No EOL
4.9 KiB
C#
164 lines
No EOL
4.9 KiB
C#
using ARMeilleure.Memory;
|
|
using System;
|
|
|
|
namespace ARMeilleure.State
|
|
{
|
|
public class ExecutionContext
|
|
{
|
|
private const int MinCountForCheck = 4000;
|
|
|
|
private NativeContext _nativeContext;
|
|
|
|
internal IntPtr NativeContextPtr => _nativeContext.BasePtr;
|
|
|
|
private bool _interrupted;
|
|
|
|
private readonly ICounter _counter;
|
|
|
|
public ulong Pc => _nativeContext.GetPc();
|
|
|
|
public uint CtrEl0 => 0x8444c004;
|
|
public uint DczidEl0 => 0x00000004;
|
|
|
|
public ulong CntfrqEl0 => _counter.Frequency;
|
|
public ulong CntpctEl0 => _counter.Counter;
|
|
|
|
// CNTVCT_EL0 = CNTPCT_EL0 - CNTVOFF_EL2
|
|
// Since EL2 isn't implemented, CNTVOFF_EL2 = 0
|
|
public ulong CntvctEl0 => CntpctEl0;
|
|
|
|
public long TpidrEl0 { get; set; }
|
|
public long TpidrroEl0 { get; set; }
|
|
|
|
public uint Pstate
|
|
{
|
|
get => _nativeContext.GetPstate();
|
|
set => _nativeContext.SetPstate(value);
|
|
}
|
|
|
|
public FPSR Fpsr
|
|
{
|
|
get => (FPSR)_nativeContext.GetFPState((uint)FPSR.Mask);
|
|
set => _nativeContext.SetFPState((uint)value, (uint)FPSR.Mask);
|
|
}
|
|
|
|
public FPCR Fpcr
|
|
{
|
|
get => (FPCR)_nativeContext.GetFPState((uint)FPCR.Mask);
|
|
set => _nativeContext.SetFPState((uint)value, (uint)FPCR.Mask);
|
|
}
|
|
public FPCR StandardFpcrValue => (Fpcr & (FPCR.Ahp)) | FPCR.Dn | FPCR.Fz;
|
|
|
|
public FPSCR Fpscr
|
|
{
|
|
get => (FPSCR)_nativeContext.GetFPState((uint)FPSCR.Mask);
|
|
set => _nativeContext.SetFPState((uint)value, (uint)FPSCR.Mask);
|
|
}
|
|
|
|
public bool IsAarch32 { get; set; }
|
|
|
|
internal ExecutionMode ExecutionMode
|
|
{
|
|
get
|
|
{
|
|
if (IsAarch32)
|
|
{
|
|
return GetPstateFlag(PState.TFlag)
|
|
? 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,
|
|
ExceptionCallbackNoArgs interruptCallback = null,
|
|
ExceptionCallback breakCallback = null,
|
|
ExceptionCallback supervisorCallback = null,
|
|
ExceptionCallback undefinedCallback = null)
|
|
{
|
|
_nativeContext = new NativeContext(allocator);
|
|
_counter = counter;
|
|
_interruptCallback = interruptCallback;
|
|
_breakCallback = breakCallback;
|
|
_supervisorCallback = supervisorCallback;
|
|
_undefinedCallback = 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);
|
|
|
|
public bool GetPstateFlag(PState flag) => _nativeContext.GetPstateFlag(flag);
|
|
public void SetPstateFlag(PState flag, bool value) => _nativeContext.SetPstateFlag(flag, value);
|
|
|
|
public bool GetFPstateFlag(FPState flag) => _nativeContext.GetFPStateFlag(flag);
|
|
public void SetFPstateFlag(FPState flag, bool value) => _nativeContext.SetFPStateFlag(flag, 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();
|
|
}
|
|
}
|
|
} |