Compare commits
1 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
0c87bf9ea4 |
@@ -33,13 +33,13 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
switch (GetPackedId(op))
|
switch (GetPackedId(op))
|
||||||
{
|
{
|
||||||
case 0b11_011_0000_0000_001: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetCtrEl0)); break;
|
case 0b11_011_0000_0000_001: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetCtrEl0)); break;
|
||||||
case 0b11_011_0000_0000_111: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetDczidEl0)); break;
|
case 0b11_011_0000_0000_111: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetDczidEl0)); break;
|
||||||
case 0b11_011_0100_0010_000: EmitGetNzcv(context); return;
|
case 0b11_011_0100_0010_000: EmitGetNzcv(context); return;
|
||||||
case 0b11_011_0100_0100_000: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetFpcr)); break;
|
case 0b11_011_0100_0100_000: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetFpcr)); break;
|
||||||
case 0b11_011_0100_0100_001: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetFpsr)); break;
|
case 0b11_011_0100_0100_001: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetFpsr)); break;
|
||||||
case 0b11_011_1101_0000_010: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetTpidrEl0)); break;
|
case 0b11_011_1101_0000_010: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetTpidrEl0)); break;
|
||||||
case 0b11_011_1101_0000_011: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetTpidr)); break;
|
case 0b11_011_1101_0000_011: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetTpidrroEl0)); break;
|
||||||
case 0b11_011_1110_0000_000: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetCntfrqEl0)); break;
|
case 0b11_011_1110_0000_000: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetCntfrqEl0)); break;
|
||||||
case 0b11_011_1110_0000_001: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetCntpctEl0)); break;
|
case 0b11_011_1110_0000_001: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetCntpctEl0)); break;
|
||||||
case 0b11_011_1110_0000_010: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetCntvctEl0)); break;
|
case 0b11_011_1110_0000_010: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetCntvctEl0)); break;
|
||||||
|
@@ -107,14 +107,14 @@ namespace ARMeilleure.Instructions
|
|||||||
return (uint)GetContext().TpidrEl0;
|
return (uint)GetContext().TpidrEl0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ulong GetTpidr()
|
public static ulong GetTpidrroEl0()
|
||||||
{
|
{
|
||||||
return (ulong)GetContext().Tpidr;
|
return (ulong)GetContext().TpidrroEl0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static uint GetTpidr32()
|
public static uint GetTpidr32()
|
||||||
{
|
{
|
||||||
return (uint)GetContext().Tpidr;
|
return (uint)GetContext().TpidrroEl0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ulong GetCntfrqEl0()
|
public static ulong GetCntfrqEl0()
|
||||||
|
5
ARMeilleure/State/ExceptionCallback.cs
Normal file
5
ARMeilleure/State/ExceptionCallback.cs
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
namespace ARMeilleure.State
|
||||||
|
{
|
||||||
|
public delegate void ExceptionCallbackNoArgs(ExecutionContext context);
|
||||||
|
public delegate void ExceptionCallback(ExecutionContext context, ulong address, int id);
|
||||||
|
}
|
@@ -1,6 +1,5 @@
|
|||||||
using ARMeilleure.Memory;
|
using ARMeilleure.Memory;
|
||||||
using System;
|
using System;
|
||||||
using System.Diagnostics;
|
|
||||||
|
|
||||||
namespace ARMeilleure.State
|
namespace ARMeilleure.State
|
||||||
{
|
{
|
||||||
@@ -14,34 +13,22 @@ namespace ARMeilleure.State
|
|||||||
|
|
||||||
private bool _interrupted;
|
private bool _interrupted;
|
||||||
|
|
||||||
private static Stopwatch _tickCounter;
|
private readonly ICounter _counter;
|
||||||
|
|
||||||
private static double _hostTickFreq;
|
public ulong Pc => _nativeContext.GetPc();
|
||||||
|
|
||||||
public uint CtrEl0 => 0x8444c004;
|
public uint CtrEl0 => 0x8444c004;
|
||||||
public uint DczidEl0 => 0x00000004;
|
public uint DczidEl0 => 0x00000004;
|
||||||
|
|
||||||
public ulong CntfrqEl0 { get; set; }
|
public ulong CntfrqEl0 => _counter.Frequency;
|
||||||
public ulong CntpctEl0
|
public ulong CntpctEl0 => _counter.Counter;
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
double ticks = _tickCounter.ElapsedTicks * _hostTickFreq;
|
|
||||||
|
|
||||||
return (ulong)(ticks * CntfrqEl0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// CNTVCT_EL0 = CNTPCT_EL0 - CNTVOFF_EL2
|
// CNTVCT_EL0 = CNTPCT_EL0 - CNTVOFF_EL2
|
||||||
// Since EL2 isn't implemented, CNTVOFF_EL2 = 0
|
// Since EL2 isn't implemented, CNTVOFF_EL2 = 0
|
||||||
public ulong CntvctEl0 => CntpctEl0;
|
public ulong CntvctEl0 => CntpctEl0;
|
||||||
|
|
||||||
public static TimeSpan ElapsedTime => _tickCounter.Elapsed;
|
|
||||||
public static long ElapsedTicks => _tickCounter.ElapsedTicks;
|
|
||||||
public static double TickFrequency => _hostTickFreq;
|
|
||||||
|
|
||||||
public long TpidrEl0 { get; set; }
|
public long TpidrEl0 { get; set; }
|
||||||
public long Tpidr { get; set; }
|
public long TpidrroEl0 { get; set; }
|
||||||
|
|
||||||
public uint Pstate
|
public uint Pstate
|
||||||
{
|
{
|
||||||
@@ -78,35 +65,38 @@ namespace ARMeilleure.State
|
|||||||
private set => _nativeContext.SetRunning(value);
|
private set => _nativeContext.SetRunning(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public event EventHandler<EventArgs> Interrupt;
|
private readonly ExceptionCallbackNoArgs _interruptCallback;
|
||||||
public event EventHandler<InstExceptionEventArgs> Break;
|
private readonly ExceptionCallback _breakCallback;
|
||||||
public event EventHandler<InstExceptionEventArgs> SupervisorCall;
|
private readonly ExceptionCallback _supervisorCallback;
|
||||||
public event EventHandler<InstUndefinedEventArgs> Undefined;
|
private readonly ExceptionCallback _undefinedCallback;
|
||||||
|
|
||||||
static ExecutionContext()
|
public ExecutionContext(
|
||||||
{
|
IJitMemoryAllocator allocator,
|
||||||
_hostTickFreq = 1.0 / Stopwatch.Frequency;
|
ICounter counter,
|
||||||
|
ExceptionCallbackNoArgs interruptCallback = null,
|
||||||
_tickCounter = new Stopwatch();
|
ExceptionCallback breakCallback = null,
|
||||||
_tickCounter.Start();
|
ExceptionCallback supervisorCallback = null,
|
||||||
}
|
ExceptionCallback undefinedCallback = null)
|
||||||
|
|
||||||
public ExecutionContext(IJitMemoryAllocator allocator)
|
|
||||||
{
|
{
|
||||||
_nativeContext = new NativeContext(allocator);
|
_nativeContext = new NativeContext(allocator);
|
||||||
|
_counter = counter;
|
||||||
|
_interruptCallback = interruptCallback;
|
||||||
|
_breakCallback = breakCallback;
|
||||||
|
_supervisorCallback = supervisorCallback;
|
||||||
|
_undefinedCallback = undefinedCallback;
|
||||||
|
|
||||||
Running = true;
|
Running = true;
|
||||||
|
|
||||||
_nativeContext.SetCounter(MinCountForCheck);
|
_nativeContext.SetCounter(MinCountForCheck);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ulong GetX(int index) => _nativeContext.GetX(index);
|
public ulong GetX(int index) => _nativeContext.GetX(index);
|
||||||
public void SetX(int index, ulong value) => _nativeContext.SetX(index, value);
|
public void SetX(int index, ulong value) => _nativeContext.SetX(index, value);
|
||||||
|
|
||||||
public V128 GetV(int index) => _nativeContext.GetV(index);
|
public V128 GetV(int index) => _nativeContext.GetV(index);
|
||||||
public void SetV(int index, V128 value) => _nativeContext.SetV(index, value);
|
public void SetV(int index, V128 value) => _nativeContext.SetV(index, value);
|
||||||
|
|
||||||
public bool GetPstateFlag(PState flag) => _nativeContext.GetPstateFlag(flag);
|
public bool GetPstateFlag(PState flag) => _nativeContext.GetPstateFlag(flag);
|
||||||
public void SetPstateFlag(PState flag, bool value) => _nativeContext.SetPstateFlag(flag, value);
|
public void SetPstateFlag(PState flag, bool value) => _nativeContext.SetPstateFlag(flag, value);
|
||||||
|
|
||||||
public bool GetFPstateFlag(FPState flag) => _nativeContext.GetFPStateFlag(flag);
|
public bool GetFPstateFlag(FPState flag) => _nativeContext.GetFPStateFlag(flag);
|
||||||
@@ -118,7 +108,7 @@ namespace ARMeilleure.State
|
|||||||
{
|
{
|
||||||
_interrupted = false;
|
_interrupted = false;
|
||||||
|
|
||||||
Interrupt?.Invoke(this, EventArgs.Empty);
|
_interruptCallback?.Invoke(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
_nativeContext.SetCounter(MinCountForCheck);
|
_nativeContext.SetCounter(MinCountForCheck);
|
||||||
@@ -131,17 +121,17 @@ namespace ARMeilleure.State
|
|||||||
|
|
||||||
internal void OnBreak(ulong address, int imm)
|
internal void OnBreak(ulong address, int imm)
|
||||||
{
|
{
|
||||||
Break?.Invoke(this, new InstExceptionEventArgs(address, imm));
|
_breakCallback?.Invoke(this, address, imm);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void OnSupervisorCall(ulong address, int imm)
|
internal void OnSupervisorCall(ulong address, int imm)
|
||||||
{
|
{
|
||||||
SupervisorCall?.Invoke(this, new InstExceptionEventArgs(address, imm));
|
_supervisorCallback?.Invoke(this, address, imm);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void OnUndefined(ulong address, int opCode)
|
internal void OnUndefined(ulong address, int opCode)
|
||||||
{
|
{
|
||||||
Undefined?.Invoke(this, new InstUndefinedEventArgs(address, opCode));
|
_undefinedCallback?.Invoke(this, address, opCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void StopRunning()
|
public void StopRunning()
|
||||||
@@ -151,16 +141,6 @@ namespace ARMeilleure.State
|
|||||||
_nativeContext.SetCounter(0);
|
_nativeContext.SetCounter(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void SuspendCounter()
|
|
||||||
{
|
|
||||||
_tickCounter.Stop();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void ResumeCounter()
|
|
||||||
{
|
|
||||||
_tickCounter.Start();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
_nativeContext.Dispose();
|
_nativeContext.Dispose();
|
||||||
|
18
ARMeilleure/State/ICounter.cs
Normal file
18
ARMeilleure/State/ICounter.cs
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
namespace ARMeilleure.State
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// CPU Counter interface.
|
||||||
|
/// </summary>
|
||||||
|
public interface ICounter
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Counter frequency in Hertz.
|
||||||
|
/// </summary>
|
||||||
|
ulong Frequency { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Current counter value.
|
||||||
|
/// </summary>
|
||||||
|
ulong Counter { get; }
|
||||||
|
}
|
||||||
|
}
|
@@ -1,16 +0,0 @@
|
|||||||
using System;
|
|
||||||
|
|
||||||
namespace ARMeilleure.State
|
|
||||||
{
|
|
||||||
public class InstExceptionEventArgs : EventArgs
|
|
||||||
{
|
|
||||||
public ulong Address { get; }
|
|
||||||
public int Id { get; }
|
|
||||||
|
|
||||||
public InstExceptionEventArgs(ulong address, int id)
|
|
||||||
{
|
|
||||||
Address = address;
|
|
||||||
Id = id;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,16 +0,0 @@
|
|||||||
using System;
|
|
||||||
|
|
||||||
namespace ARMeilleure.State
|
|
||||||
{
|
|
||||||
public class InstUndefinedEventArgs : EventArgs
|
|
||||||
{
|
|
||||||
public ulong Address { get; }
|
|
||||||
public int OpCode { get; }
|
|
||||||
|
|
||||||
public InstUndefinedEventArgs(ulong address, int opCode)
|
|
||||||
{
|
|
||||||
Address = address;
|
|
||||||
OpCode = opCode;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -34,6 +34,12 @@ namespace ARMeilleure.State
|
|||||||
GetStorage().ExclusiveAddress = ulong.MaxValue;
|
GetStorage().ExclusiveAddress = ulong.MaxValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ulong GetPc()
|
||||||
|
{
|
||||||
|
// TODO: More precise tracking of PC value.
|
||||||
|
return GetStorage().DispatchAddress;
|
||||||
|
}
|
||||||
|
|
||||||
public unsafe ulong GetX(int index)
|
public unsafe ulong GetX(int index)
|
||||||
{
|
{
|
||||||
if ((uint)index >= RegisterConsts.IntRegsCount)
|
if ((uint)index >= RegisterConsts.IntRegsCount)
|
||||||
|
@@ -115,7 +115,7 @@ namespace ARMeilleure.Translation
|
|||||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetFpsr)));
|
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetFpsr)));
|
||||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetFunctionAddress)));
|
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetFunctionAddress)));
|
||||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.InvalidateCacheLine)));
|
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.InvalidateCacheLine)));
|
||||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetTpidr)));
|
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetTpidrroEl0)));
|
||||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetTpidr32))); // A32 only.
|
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetTpidr32))); // A32 only.
|
||||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetTpidrEl0)));
|
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetTpidrEl0)));
|
||||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetTpidrEl032))); // A32 only.
|
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetTpidrEl032))); // A32 only.
|
||||||
|
@@ -27,7 +27,7 @@ namespace ARMeilleure.Translation.PTC
|
|||||||
private const string OuterHeaderMagicString = "PTCohd\0\0";
|
private const string OuterHeaderMagicString = "PTCohd\0\0";
|
||||||
private const string InnerHeaderMagicString = "PTCihd\0\0";
|
private const string InnerHeaderMagicString = "PTCihd\0\0";
|
||||||
|
|
||||||
private const uint InternalVersion = 3267; //! To be incremented manually for each change to the ARMeilleure project.
|
private const uint InternalVersion = 3362; //! To be incremented manually for each change to the ARMeilleure project.
|
||||||
|
|
||||||
private const string ActualDir = "0";
|
private const string ActualDir = "0";
|
||||||
private const string BackupDir = "1";
|
private const string BackupDir = "1";
|
||||||
|
@@ -523,9 +523,7 @@ namespace Ryujinx.Audio.Renderer.Server
|
|||||||
|
|
||||||
private ulong GetSystemTicks()
|
private ulong GetSystemTicks()
|
||||||
{
|
{
|
||||||
double ticks = ARMeilleure.State.ExecutionContext.ElapsedTicks * ARMeilleure.State.ExecutionContext.TickFrequency;
|
return (ulong)(_manager.TickSource.ElapsedSeconds * Constants.TargetTimerFrequency);
|
||||||
|
|
||||||
return (ulong)(ticks * Constants.TargetTimerFrequency);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private uint ComputeVoiceDrop(CommandBuffer commandBuffer, long voicesEstimatedTime, long deltaTimeDsp)
|
private uint ComputeVoiceDrop(CommandBuffer commandBuffer, long voicesEstimatedTime, long deltaTimeDsp)
|
||||||
|
@@ -19,6 +19,7 @@ using Ryujinx.Audio.Integration;
|
|||||||
using Ryujinx.Audio.Renderer.Dsp;
|
using Ryujinx.Audio.Renderer.Dsp;
|
||||||
using Ryujinx.Audio.Renderer.Parameter;
|
using Ryujinx.Audio.Renderer.Parameter;
|
||||||
using Ryujinx.Common.Logging;
|
using Ryujinx.Common.Logging;
|
||||||
|
using Ryujinx.Cpu;
|
||||||
using Ryujinx.Memory;
|
using Ryujinx.Memory;
|
||||||
using System;
|
using System;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
@@ -77,6 +78,11 @@ namespace Ryujinx.Audio.Renderer.Server
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private IHardwareDeviceDriver _deviceDriver;
|
private IHardwareDeviceDriver _deviceDriver;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Tick source used to measure elapsed time.
|
||||||
|
/// </summary>
|
||||||
|
public ITickSource TickSource { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The <see cref="AudioProcessor"/> instance associated to this manager.
|
/// The <see cref="AudioProcessor"/> instance associated to this manager.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -90,9 +96,11 @@ namespace Ryujinx.Audio.Renderer.Server
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Create a new <see cref="AudioRendererManager"/>.
|
/// Create a new <see cref="AudioRendererManager"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public AudioRendererManager()
|
/// <param name="tickSource">Tick source used to measure elapsed time.</param>
|
||||||
|
public AudioRendererManager(ITickSource tickSource)
|
||||||
{
|
{
|
||||||
Processor = new AudioProcessor();
|
Processor = new AudioProcessor();
|
||||||
|
TickSource = tickSource;
|
||||||
_sessionIds = new int[Constants.AudioRendererSessionCountMax];
|
_sessionIds = new int[Constants.AudioRendererSessionCountMax];
|
||||||
_sessions = new AudioRenderSystem[Constants.AudioRendererSessionCountMax];
|
_sessions = new AudioRenderSystem[Constants.AudioRendererSessionCountMax];
|
||||||
_activeSessionCount = 0;
|
_activeSessionCount = 0;
|
||||||
|
64
Ryujinx.Cpu/ExceptionCallbacks.cs
Normal file
64
Ryujinx.Cpu/ExceptionCallbacks.cs
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
namespace Ryujinx.Cpu
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Exception callback without any additional arguments.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="context">Context for the thread where the exception was triggered</param>
|
||||||
|
public delegate void ExceptionCallbackNoArgs(IExecutionContext context);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Exception callback.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="context">Context for the thread where the exception was triggered</param>
|
||||||
|
/// <param name="address">Address of the instruction that caused the exception</param>
|
||||||
|
/// <param name="imm">Immediate value of the instruction that caused the exception, or for undefined instruction, the instruction itself</param>
|
||||||
|
public delegate void ExceptionCallback(IExecutionContext context, ulong address, int imm);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Stores handlers for the various CPU exceptions.
|
||||||
|
/// </summary>
|
||||||
|
public struct ExceptionCallbacks
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Handler for CPU interrupts triggered using <see cref="IExecutionContext.RequestInterrupt"/>.
|
||||||
|
/// </summary>
|
||||||
|
public readonly ExceptionCallbackNoArgs InterruptCallback;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Handler for CPU software interrupts caused by the Arm BRK instruction.
|
||||||
|
/// </summary>
|
||||||
|
public readonly ExceptionCallback BreakCallback;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Handler for CPU software interrupts caused by the Arm SVC instruction.
|
||||||
|
/// </summary>
|
||||||
|
public readonly ExceptionCallback SupervisorCallback;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Handler for CPU software interrupts caused by any undefined Arm instruction.
|
||||||
|
/// </summary>
|
||||||
|
public readonly ExceptionCallback UndefinedCallback;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new exception callbacks structure.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// All handlers are optional, and if null, the CPU will just continue executing as if nothing happened.
|
||||||
|
/// </remarks>
|
||||||
|
/// <param name="interruptCallback">Handler for CPU interrupts triggered using <see cref="IExecutionContext.RequestInterrupt"/></param>
|
||||||
|
/// <param name="breakCallback">Handler for CPU software interrupts caused by the Arm BRK instruction</param>
|
||||||
|
/// <param name="supervisorCallback">Handler for CPU software interrupts caused by the Arm SVC instruction</param>
|
||||||
|
/// <param name="undefinedCallback">Handler for CPU software interrupts caused by any undefined Arm instruction</param>
|
||||||
|
public ExceptionCallbacks(
|
||||||
|
ExceptionCallbackNoArgs interruptCallback = null,
|
||||||
|
ExceptionCallback breakCallback = null,
|
||||||
|
ExceptionCallback supervisorCallback = null,
|
||||||
|
ExceptionCallback undefinedCallback = null)
|
||||||
|
{
|
||||||
|
InterruptCallback = interruptCallback;
|
||||||
|
BreakCallback = breakCallback;
|
||||||
|
SupervisorCallback = supervisorCallback;
|
||||||
|
UndefinedCallback = undefinedCallback;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
39
Ryujinx.Cpu/ICpuContext.cs
Normal file
39
Ryujinx.Cpu/ICpuContext.cs
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
namespace Ryujinx.Cpu
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// CPU context interface.
|
||||||
|
/// </summary>
|
||||||
|
public interface ICpuContext
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new execution context that will store thread CPU register state when executing guest code.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="exceptionCallbacks">Optional functions to be called when the CPU receives an interrupt</param>
|
||||||
|
/// <returns>Execution context</returns>
|
||||||
|
IExecutionContext CreateExecutionContext(ExceptionCallbacks exceptionCallbacks);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Starts executing code at a specified entry point address.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// This function only returns when the execution is stopped, by calling <see cref="IExecutionContext.StopRunning"/>.
|
||||||
|
/// </remarks>
|
||||||
|
/// <param name="context">Execution context to be used for this run</param>
|
||||||
|
/// <param name="address">Entry point address</param>
|
||||||
|
void Execute(IExecutionContext context, ulong address);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Invalidates the instruction cache for a given memory region.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// This should be called if code is modified to make the CPU emulator aware of the modifications,
|
||||||
|
/// otherwise it might run stale code which will lead to errors and crashes.
|
||||||
|
/// Calling this function is not necessary if the code memory was modified by guest code,
|
||||||
|
/// as the expectation is that it will do it on its own using the appropriate cache invalidation instructions,
|
||||||
|
/// except on Arm32 where those instructions can't be used in unprivileged mode.
|
||||||
|
/// </remarks>
|
||||||
|
/// <param name="address">Address of the region to be invalidated</param>
|
||||||
|
/// <param name="size">Size of the region to be invalidated</param>
|
||||||
|
void InvalidateCacheRegion(ulong address, ulong size);
|
||||||
|
}
|
||||||
|
}
|
18
Ryujinx.Cpu/ICpuEngine.cs
Normal file
18
Ryujinx.Cpu/ICpuEngine.cs
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
using ARMeilleure.Memory;
|
||||||
|
|
||||||
|
namespace Ryujinx.Cpu
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// CPU execution engine interface.
|
||||||
|
/// </summary>
|
||||||
|
public interface ICpuEngine
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new CPU context that can be used to run code for multiple threads sharing an address space.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="memoryManager">Memory manager for the address space of the context</param>
|
||||||
|
/// <param name="for64Bit">Indicates if the context will be used to run 64-bit or 32-bit Arm code</param>
|
||||||
|
/// <returns>CPU context</returns>
|
||||||
|
ICpuContext CreateCpuContext(IMemoryManager memoryManager, bool for64Bit);
|
||||||
|
}
|
||||||
|
}
|
112
Ryujinx.Cpu/IExecutionContext.cs
Normal file
112
Ryujinx.Cpu/IExecutionContext.cs
Normal file
@@ -0,0 +1,112 @@
|
|||||||
|
using ARMeilleure.State;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Ryujinx.Cpu
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// CPU register state interface.
|
||||||
|
/// </summary>
|
||||||
|
public interface IExecutionContext : IDisposable
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Current Program Counter.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// In some implementations, this value might not be accurate and might not point to the last instruction executed.
|
||||||
|
/// </remarks>
|
||||||
|
ulong Pc { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Thread ID Register (EL0).
|
||||||
|
/// </summary>
|
||||||
|
long TpidrEl0 { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Thread ID Register (read-only) (EL0).
|
||||||
|
/// </summary>
|
||||||
|
long TpidrroEl0 { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Processor State register.
|
||||||
|
/// </summary>
|
||||||
|
uint Pstate { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Floating-point Control Register.
|
||||||
|
/// </summary>
|
||||||
|
uint Fpcr { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Floating-point Status Register.
|
||||||
|
/// </summary>
|
||||||
|
uint Fpsr { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Indicates whenever the CPU is running 64-bit (AArch64 mode) or 32-bit (AArch32 mode) code.
|
||||||
|
/// </summary>
|
||||||
|
bool IsAarch32 { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Indicates whenever the CPU is still running code.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Even if this is false, the guest code might be still exiting.
|
||||||
|
/// One must not assume that the code is no longer running from this property alone.
|
||||||
|
/// </remarks>
|
||||||
|
bool Running { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the value of a general purpose register.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// The special <paramref name="index"/> of 31 can be used to access the SP (Stack Pointer) register.
|
||||||
|
/// </remarks>
|
||||||
|
/// <param name="index">Index of the register, in the range 0-31 (inclusive)</param>
|
||||||
|
/// <returns>The register value</returns>
|
||||||
|
ulong GetX(int index);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the value of a general purpose register.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// The special <paramref name="index"/> of 31 can be used to access the SP (Stack Pointer) register.
|
||||||
|
/// </remarks>
|
||||||
|
/// <param name="index">Index of the register, in the range 0-31 (inclusive)</param>
|
||||||
|
/// <param name="value">Value to be set</param>
|
||||||
|
void SetX(int index, ulong value);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the value of a FP/SIMD register.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="index">Index of the register, in the range 0-31 (inclusive)</param>
|
||||||
|
/// <returns>The register value</returns>
|
||||||
|
V128 GetV(int index);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the value of a FP/SIMD register.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="index">Index of the register, in the range 0-31 (inclusive)</param>
|
||||||
|
/// <param name="value">Value to be set</param>
|
||||||
|
void SetV(int index, V128 value);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Requests the thread to stop running temporarily and call <see cref="ExceptionCallbacks.InterruptCallback"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// The thread might not pause immediately.
|
||||||
|
/// One must not assume that guest code is no longer being executed by the thread after calling this function.
|
||||||
|
/// </remarks>
|
||||||
|
void RequestInterrupt();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Requests the thread to stop running guest code and return as soon as possible.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// The thread might not stop immediately.
|
||||||
|
/// One must not assume that guest code is no longer being executed by the thread after calling this function.
|
||||||
|
/// After a thread has been stopped, it can't be restarted with the same <see cref="IExecutionContext"/>.
|
||||||
|
/// If you only need to pause the thread temporarily, use <see cref="RequestInterrupt"/> instead.
|
||||||
|
/// </remarks>
|
||||||
|
void StopRunning();
|
||||||
|
}
|
||||||
|
}
|
31
Ryujinx.Cpu/ITickSource.cs
Normal file
31
Ryujinx.Cpu/ITickSource.cs
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
using ARMeilleure.State;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Ryujinx.Cpu
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Tick source interface.
|
||||||
|
/// </summary>
|
||||||
|
public interface ITickSource : ICounter
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Time elapsed since the counter was created.
|
||||||
|
/// </summary>
|
||||||
|
TimeSpan ElapsedTime { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Time elapsed since the counter was created, in seconds.
|
||||||
|
/// </summary>
|
||||||
|
double ElapsedSeconds { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Stops counting.
|
||||||
|
/// </summary>
|
||||||
|
void Suspend();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Resumes counting after a call to <see cref="Suspend"/>.
|
||||||
|
/// </summary>
|
||||||
|
void Resume();
|
||||||
|
}
|
||||||
|
}
|
41
Ryujinx.Cpu/Jit/JitCpuContext.cs
Normal file
41
Ryujinx.Cpu/Jit/JitCpuContext.cs
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
using ARMeilleure.Memory;
|
||||||
|
using ARMeilleure.Translation;
|
||||||
|
|
||||||
|
namespace Ryujinx.Cpu.Jit
|
||||||
|
{
|
||||||
|
class JitCpuContext : ICpuContext
|
||||||
|
{
|
||||||
|
private readonly ITickSource _tickSource;
|
||||||
|
private readonly Translator _translator;
|
||||||
|
|
||||||
|
public JitCpuContext(ITickSource tickSource, IMemoryManager memory, bool for64Bit)
|
||||||
|
{
|
||||||
|
_tickSource = tickSource;
|
||||||
|
_translator = new Translator(new JitMemoryAllocator(), memory, for64Bit);
|
||||||
|
memory.UnmapEvent += UnmapHandler;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UnmapHandler(ulong address, ulong size)
|
||||||
|
{
|
||||||
|
_translator.InvalidateJitCacheRegion(address, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public IExecutionContext CreateExecutionContext(ExceptionCallbacks exceptionCallbacks)
|
||||||
|
{
|
||||||
|
return new JitExecutionContext(new JitMemoryAllocator(), _tickSource, exceptionCallbacks);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public void Execute(IExecutionContext context, ulong address)
|
||||||
|
{
|
||||||
|
_translator.Execute(((JitExecutionContext)context).Impl, address);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public void InvalidateCacheRegion(ulong address, ulong size)
|
||||||
|
{
|
||||||
|
_translator.InvalidateJitCacheRegion(address, size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
20
Ryujinx.Cpu/Jit/JitEngine.cs
Normal file
20
Ryujinx.Cpu/Jit/JitEngine.cs
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
using ARMeilleure.Memory;
|
||||||
|
|
||||||
|
namespace Ryujinx.Cpu.Jit
|
||||||
|
{
|
||||||
|
public class JitEngine : ICpuEngine
|
||||||
|
{
|
||||||
|
private readonly ITickSource _tickSource;
|
||||||
|
|
||||||
|
public JitEngine(ITickSource tickSource)
|
||||||
|
{
|
||||||
|
_tickSource = tickSource;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public ICpuContext CreateCpuContext(IMemoryManager memoryManager, bool for64Bit)
|
||||||
|
{
|
||||||
|
return new JitCpuContext(_tickSource, memoryManager, for64Bit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
123
Ryujinx.Cpu/Jit/JitExecutionContext.cs
Normal file
123
Ryujinx.Cpu/Jit/JitExecutionContext.cs
Normal file
@@ -0,0 +1,123 @@
|
|||||||
|
using ARMeilleure.Memory;
|
||||||
|
using ARMeilleure.State;
|
||||||
|
|
||||||
|
namespace Ryujinx.Cpu.Jit
|
||||||
|
{
|
||||||
|
class JitExecutionContext : IExecutionContext
|
||||||
|
{
|
||||||
|
private readonly ExecutionContext _impl;
|
||||||
|
internal ExecutionContext Impl => _impl;
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public ulong Pc => _impl.Pc;
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public long TpidrEl0
|
||||||
|
{
|
||||||
|
get => _impl.TpidrEl0;
|
||||||
|
set => _impl.TpidrEl0 = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public long TpidrroEl0
|
||||||
|
{
|
||||||
|
get => _impl.TpidrroEl0;
|
||||||
|
set => _impl.TpidrroEl0 = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public uint Pstate
|
||||||
|
{
|
||||||
|
get => _impl.Pstate;
|
||||||
|
set => _impl.Pstate = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public uint Fpcr
|
||||||
|
{
|
||||||
|
get => (uint)_impl.Fpcr;
|
||||||
|
set => _impl.Fpcr = (FPCR)value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public uint Fpsr
|
||||||
|
{
|
||||||
|
get => (uint)_impl.Fpsr;
|
||||||
|
set => _impl.Fpsr = (FPSR)value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public bool IsAarch32
|
||||||
|
{
|
||||||
|
get => _impl.IsAarch32;
|
||||||
|
set => _impl.IsAarch32 = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public bool Running => _impl.Running;
|
||||||
|
|
||||||
|
private readonly ExceptionCallbacks _exceptionCallbacks;
|
||||||
|
|
||||||
|
public JitExecutionContext(IJitMemoryAllocator allocator, ICounter counter, ExceptionCallbacks exceptionCallbacks)
|
||||||
|
{
|
||||||
|
_impl = new ExecutionContext(
|
||||||
|
allocator,
|
||||||
|
counter,
|
||||||
|
InterruptHandler,
|
||||||
|
BreakHandler,
|
||||||
|
SupervisorCallHandler,
|
||||||
|
UndefinedHandler);
|
||||||
|
|
||||||
|
_exceptionCallbacks = exceptionCallbacks;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public ulong GetX(int index) => _impl.GetX(index);
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public void SetX(int index, ulong value) => _impl.SetX(index, value);
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public V128 GetV(int index) => _impl.GetV(index);
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public void SetV(int index, V128 value) => _impl.SetV(index, value);
|
||||||
|
|
||||||
|
private void InterruptHandler(ExecutionContext context)
|
||||||
|
{
|
||||||
|
_exceptionCallbacks.InterruptCallback?.Invoke(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void BreakHandler(ExecutionContext context, ulong address, int imm)
|
||||||
|
{
|
||||||
|
_exceptionCallbacks.BreakCallback?.Invoke(this, address, imm);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SupervisorCallHandler(ExecutionContext context, ulong address, int imm)
|
||||||
|
{
|
||||||
|
_exceptionCallbacks.SupervisorCallback?.Invoke(this, address, imm);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UndefinedHandler(ExecutionContext context, ulong address, int opCode)
|
||||||
|
{
|
||||||
|
_exceptionCallbacks.UndefinedCallback?.Invoke(this, address, opCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public void RequestInterrupt()
|
||||||
|
{
|
||||||
|
_impl.RequestInterrupt();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public void StopRunning()
|
||||||
|
{
|
||||||
|
_impl.StopRunning();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
_impl.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -1,9 +1,9 @@
|
|||||||
using ARMeilleure.Memory;
|
using ARMeilleure.Memory;
|
||||||
using Ryujinx.Memory;
|
using Ryujinx.Memory;
|
||||||
|
|
||||||
namespace Ryujinx.Cpu
|
namespace Ryujinx.Cpu.Jit
|
||||||
{
|
{
|
||||||
class JitMemoryAllocator : IJitMemoryAllocator
|
public class JitMemoryAllocator : IJitMemoryAllocator
|
||||||
{
|
{
|
||||||
public IJitMemoryBlock Allocate(ulong size) => new JitMemoryBlock(size, MemoryAllocationFlags.None);
|
public IJitMemoryBlock Allocate(ulong size) => new JitMemoryBlock(size, MemoryAllocationFlags.None);
|
||||||
public IJitMemoryBlock Reserve(ulong size) => new JitMemoryBlock(size, MemoryAllocationFlags.Reserve);
|
public IJitMemoryBlock Reserve(ulong size) => new JitMemoryBlock(size, MemoryAllocationFlags.Reserve);
|
@@ -2,9 +2,9 @@
|
|||||||
using Ryujinx.Memory;
|
using Ryujinx.Memory;
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace Ryujinx.Cpu
|
namespace Ryujinx.Cpu.Jit
|
||||||
{
|
{
|
||||||
class JitMemoryBlock : IJitMemoryBlock
|
public class JitMemoryBlock : IJitMemoryBlock
|
||||||
{
|
{
|
||||||
private readonly MemoryBlock _impl;
|
private readonly MemoryBlock _impl;
|
||||||
|
|
@@ -10,7 +10,7 @@ using System.Runtime.CompilerServices;
|
|||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
|
||||||
namespace Ryujinx.Cpu
|
namespace Ryujinx.Cpu.Jit
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents a CPU memory manager.
|
/// Represents a CPU memory manager.
|
@@ -8,12 +8,12 @@ using System.Collections.Generic;
|
|||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
|
||||||
namespace Ryujinx.Cpu
|
namespace Ryujinx.Cpu.Jit
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents a CPU memory manager which maps guest virtual memory directly onto a host virtual region.
|
/// Represents a CPU memory manager which maps guest virtual memory directly onto a host virtual region.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class MemoryManagerHostMapped : MemoryManagerBase, IMemoryManager, IVirtualMemoryManagerTracked, IWritableBlock
|
public sealed class MemoryManagerHostMapped : MemoryManagerBase, IMemoryManager, IVirtualMemoryManagerTracked, IWritableBlock
|
||||||
{
|
{
|
||||||
public const int PageBits = 12;
|
public const int PageBits = 12;
|
||||||
public const int PageSize = 1 << PageBits;
|
public const int PageSize = 1 << PageBits;
|
45
Ryujinx.Cpu/TickSource.cs
Normal file
45
Ryujinx.Cpu/TickSource.cs
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
using System;
|
||||||
|
using System.Diagnostics;
|
||||||
|
|
||||||
|
namespace Ryujinx.Cpu
|
||||||
|
{
|
||||||
|
public class TickSource : ITickSource
|
||||||
|
{
|
||||||
|
private static Stopwatch _tickCounter;
|
||||||
|
|
||||||
|
private static double _hostTickFreq;
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public ulong Frequency { get; }
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public ulong Counter => (ulong)(ElapsedSeconds * Frequency);
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public TimeSpan ElapsedTime => _tickCounter.Elapsed;
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public double ElapsedSeconds => _tickCounter.ElapsedTicks * _hostTickFreq;
|
||||||
|
|
||||||
|
public TickSource(ulong frequency)
|
||||||
|
{
|
||||||
|
Frequency = frequency;
|
||||||
|
_hostTickFreq = 1.0 / Stopwatch.Frequency;
|
||||||
|
|
||||||
|
_tickCounter = new Stopwatch();
|
||||||
|
_tickCounter.Start();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public void Suspend()
|
||||||
|
{
|
||||||
|
_tickCounter.Stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public void Resume()
|
||||||
|
{
|
||||||
|
_tickCounter.Start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -1,5 +1,4 @@
|
|||||||
using ARMeilleure.Memory;
|
using ARMeilleure.Memory;
|
||||||
using ARMeilleure.State;
|
|
||||||
using Ryujinx.Cpu;
|
using Ryujinx.Cpu;
|
||||||
using Ryujinx.Graphics.Gpu;
|
using Ryujinx.Graphics.Gpu;
|
||||||
using Ryujinx.HLE.HOS.Kernel.Process;
|
using Ryujinx.HLE.HOS.Kernel.Process;
|
||||||
@@ -11,12 +10,12 @@ namespace Ryujinx.HLE.HOS
|
|||||||
{
|
{
|
||||||
private readonly ulong _pid;
|
private readonly ulong _pid;
|
||||||
private readonly GpuContext _gpuContext;
|
private readonly GpuContext _gpuContext;
|
||||||
private readonly CpuContext _cpuContext;
|
private readonly ICpuContext _cpuContext;
|
||||||
private T _memoryManager;
|
private T _memoryManager;
|
||||||
|
|
||||||
public IVirtualMemoryManager AddressSpace => _memoryManager;
|
public IVirtualMemoryManager AddressSpace => _memoryManager;
|
||||||
|
|
||||||
public ArmProcessContext(ulong pid, GpuContext gpuContext, T memoryManager, bool for64Bit)
|
public ArmProcessContext(ulong pid, ICpuEngine cpuEngine, GpuContext gpuContext, T memoryManager, bool for64Bit)
|
||||||
{
|
{
|
||||||
if (memoryManager is IRefCounted rc)
|
if (memoryManager is IRefCounted rc)
|
||||||
{
|
{
|
||||||
@@ -27,11 +26,16 @@ namespace Ryujinx.HLE.HOS
|
|||||||
|
|
||||||
_pid = pid;
|
_pid = pid;
|
||||||
_gpuContext = gpuContext;
|
_gpuContext = gpuContext;
|
||||||
_cpuContext = new CpuContext(memoryManager, for64Bit);
|
_cpuContext = cpuEngine.CreateCpuContext(memoryManager, for64Bit);
|
||||||
_memoryManager = memoryManager;
|
_memoryManager = memoryManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Execute(ExecutionContext context, ulong codeAddress)
|
public IExecutionContext CreateExecutionContext(ExceptionCallbacks exceptionCallbacks)
|
||||||
|
{
|
||||||
|
return _cpuContext.CreateExecutionContext(exceptionCallbacks);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Execute(IExecutionContext context, ulong codeAddress)
|
||||||
{
|
{
|
||||||
_cpuContext.Execute(context, codeAddress);
|
_cpuContext.Execute(context, codeAddress);
|
||||||
}
|
}
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
using Ryujinx.Common.Configuration;
|
using Ryujinx.Common.Configuration;
|
||||||
using Ryujinx.Cpu;
|
using Ryujinx.Cpu;
|
||||||
|
using Ryujinx.Cpu.Jit;
|
||||||
using Ryujinx.Graphics.Gpu;
|
using Ryujinx.Graphics.Gpu;
|
||||||
using Ryujinx.HLE.HOS.Kernel;
|
using Ryujinx.HLE.HOS.Kernel;
|
||||||
using Ryujinx.HLE.HOS.Kernel.Process;
|
using Ryujinx.HLE.HOS.Kernel.Process;
|
||||||
@@ -10,10 +11,12 @@ namespace Ryujinx.HLE.HOS
|
|||||||
{
|
{
|
||||||
class ArmProcessContextFactory : IProcessContextFactory
|
class ArmProcessContextFactory : IProcessContextFactory
|
||||||
{
|
{
|
||||||
|
private readonly ICpuEngine _cpuEngine;
|
||||||
private readonly GpuContext _gpu;
|
private readonly GpuContext _gpu;
|
||||||
|
|
||||||
public ArmProcessContextFactory(GpuContext gpu)
|
public ArmProcessContextFactory(ICpuEngine cpuEngine, GpuContext gpu)
|
||||||
{
|
{
|
||||||
|
_cpuEngine = cpuEngine;
|
||||||
_gpu = gpu;
|
_gpu = gpu;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -29,12 +32,14 @@ namespace Ryujinx.HLE.HOS
|
|||||||
switch (mode)
|
switch (mode)
|
||||||
{
|
{
|
||||||
case MemoryManagerMode.SoftwarePageTable:
|
case MemoryManagerMode.SoftwarePageTable:
|
||||||
return new ArmProcessContext<MemoryManager>(pid, _gpu, new MemoryManager(context.Memory, addressSpaceSize, invalidAccessHandler), for64Bit);
|
var memoryManager = new MemoryManager(context.Memory, addressSpaceSize, invalidAccessHandler);
|
||||||
|
return new ArmProcessContext<MemoryManager>(pid, _cpuEngine, _gpu, memoryManager, for64Bit);
|
||||||
|
|
||||||
case MemoryManagerMode.HostMapped:
|
case MemoryManagerMode.HostMapped:
|
||||||
case MemoryManagerMode.HostMappedUnsafe:
|
case MemoryManagerMode.HostMappedUnsafe:
|
||||||
bool unsafeMode = mode == MemoryManagerMode.HostMappedUnsafe;
|
bool unsafeMode = mode == MemoryManagerMode.HostMappedUnsafe;
|
||||||
return new ArmProcessContext<MemoryManagerHostMapped>(pid, _gpu, new MemoryManagerHostMapped(context.Memory, addressSpaceSize, unsafeMode, invalidAccessHandler), for64Bit);
|
var memoryManagerHostMapped = new MemoryManagerHostMapped(context.Memory, addressSpaceSize, unsafeMode, invalidAccessHandler);
|
||||||
|
return new ArmProcessContext<MemoryManagerHostMapped>(pid, _cpuEngine, _gpu, memoryManagerHostMapped, for64Bit);
|
||||||
|
|
||||||
default:
|
default:
|
||||||
throw new ArgumentOutOfRangeException();
|
throw new ArgumentOutOfRangeException();
|
||||||
|
@@ -10,6 +10,8 @@ using Ryujinx.Audio.Integration;
|
|||||||
using Ryujinx.Audio.Output;
|
using Ryujinx.Audio.Output;
|
||||||
using Ryujinx.Audio.Renderer.Device;
|
using Ryujinx.Audio.Renderer.Device;
|
||||||
using Ryujinx.Audio.Renderer.Server;
|
using Ryujinx.Audio.Renderer.Server;
|
||||||
|
using Ryujinx.Cpu;
|
||||||
|
using Ryujinx.Cpu.Jit;
|
||||||
using Ryujinx.HLE.FileSystem;
|
using Ryujinx.HLE.FileSystem;
|
||||||
using Ryujinx.HLE.HOS.Kernel;
|
using Ryujinx.HLE.HOS.Kernel;
|
||||||
using Ryujinx.HLE.HOS.Kernel.Memory;
|
using Ryujinx.HLE.HOS.Kernel.Memory;
|
||||||
@@ -57,6 +59,9 @@ namespace Ryujinx.HLE.HOS
|
|||||||
|
|
||||||
internal Switch Device { get; private set; }
|
internal Switch Device { get; private set; }
|
||||||
|
|
||||||
|
internal ITickSource TickSource { get; }
|
||||||
|
internal ICpuEngine CpuEngine { get; }
|
||||||
|
|
||||||
internal SurfaceFlinger SurfaceFlinger { get; private set; }
|
internal SurfaceFlinger SurfaceFlinger { get; private set; }
|
||||||
internal AudioManager AudioManager { get; private set; }
|
internal AudioManager AudioManager { get; private set; }
|
||||||
internal AudioOutputManager AudioOutputManager { get; private set; }
|
internal AudioOutputManager AudioOutputManager { get; private set; }
|
||||||
@@ -121,7 +126,11 @@ namespace Ryujinx.HLE.HOS
|
|||||||
|
|
||||||
public Horizon(Switch device)
|
public Horizon(Switch device)
|
||||||
{
|
{
|
||||||
|
TickSource = new TickSource(KernelConstants.CounterFrequency);
|
||||||
|
CpuEngine = new JitEngine(TickSource);
|
||||||
|
|
||||||
KernelContext = new KernelContext(
|
KernelContext = new KernelContext(
|
||||||
|
TickSource,
|
||||||
device,
|
device,
|
||||||
device.Memory,
|
device.Memory,
|
||||||
device.Configuration.MemoryConfiguration.ToKernelMemorySize(),
|
device.Configuration.MemoryConfiguration.ToKernelMemorySize(),
|
||||||
@@ -215,40 +224,40 @@ namespace Ryujinx.HLE.HOS
|
|||||||
internalOffset = new TimeSpanType(-internalOffset.NanoSeconds);
|
internalOffset = new TimeSpanType(-internalOffset.NanoSeconds);
|
||||||
|
|
||||||
// First init the standard steady clock
|
// First init the standard steady clock
|
||||||
TimeServiceManager.Instance.SetupStandardSteadyClock(null, clockSourceId, systemTime, internalOffset, TimeSpanType.Zero, false);
|
TimeServiceManager.Instance.SetupStandardSteadyClock(TickSource, clockSourceId, systemTime, internalOffset, TimeSpanType.Zero, false);
|
||||||
TimeServiceManager.Instance.SetupStandardLocalSystemClock(null, new SystemClockContext(), systemTime.ToSeconds());
|
TimeServiceManager.Instance.SetupStandardLocalSystemClock(TickSource, new SystemClockContext(), systemTime.ToSeconds());
|
||||||
|
|
||||||
if (NxSettings.Settings.TryGetValue("time!standard_network_clock_sufficient_accuracy_minutes", out object standardNetworkClockSufficientAccuracyMinutes))
|
if (NxSettings.Settings.TryGetValue("time!standard_network_clock_sufficient_accuracy_minutes", out object standardNetworkClockSufficientAccuracyMinutes))
|
||||||
{
|
{
|
||||||
TimeSpanType standardNetworkClockSufficientAccuracy = new TimeSpanType((int)standardNetworkClockSufficientAccuracyMinutes * 60000000000);
|
TimeSpanType standardNetworkClockSufficientAccuracy = new TimeSpanType((int)standardNetworkClockSufficientAccuracyMinutes * 60000000000);
|
||||||
|
|
||||||
// The network system clock needs a valid system clock, as such we setup this system clock using the local system clock.
|
// The network system clock needs a valid system clock, as such we setup this system clock using the local system clock.
|
||||||
TimeServiceManager.Instance.StandardLocalSystemClock.GetClockContext(null, out SystemClockContext localSytemClockContext);
|
TimeServiceManager.Instance.StandardLocalSystemClock.GetClockContext(TickSource, out SystemClockContext localSytemClockContext);
|
||||||
TimeServiceManager.Instance.SetupStandardNetworkSystemClock(localSytemClockContext, standardNetworkClockSufficientAccuracy);
|
TimeServiceManager.Instance.SetupStandardNetworkSystemClock(localSytemClockContext, standardNetworkClockSufficientAccuracy);
|
||||||
}
|
}
|
||||||
|
|
||||||
TimeServiceManager.Instance.SetupStandardUserSystemClock(null, false, SteadyClockTimePoint.GetRandom());
|
TimeServiceManager.Instance.SetupStandardUserSystemClock(TickSource, false, SteadyClockTimePoint.GetRandom());
|
||||||
|
|
||||||
// FIXME: TimeZone should be init here but it's actually done in ContentManager
|
// FIXME: TimeZone should be init here but it's actually done in ContentManager
|
||||||
|
|
||||||
TimeServiceManager.Instance.SetupEphemeralNetworkSystemClock();
|
TimeServiceManager.Instance.SetupEphemeralNetworkSystemClock();
|
||||||
|
|
||||||
DatabaseImpl.Instance.InitializeDatabase(LibHacHorizonManager.SdbClient);
|
DatabaseImpl.Instance.InitializeDatabase(TickSource, LibHacHorizonManager.SdbClient);
|
||||||
|
|
||||||
HostSyncpoint = new NvHostSyncpt(device);
|
HostSyncpoint = new NvHostSyncpt(device);
|
||||||
|
|
||||||
SurfaceFlinger = new SurfaceFlinger(device);
|
SurfaceFlinger = new SurfaceFlinger(device);
|
||||||
|
|
||||||
InitializeAudioRenderer();
|
InitializeAudioRenderer(TickSource);
|
||||||
InitializeServices();
|
InitializeServices();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void InitializeAudioRenderer()
|
private void InitializeAudioRenderer(ITickSource tickSource)
|
||||||
{
|
{
|
||||||
AudioManager = new AudioManager();
|
AudioManager = new AudioManager();
|
||||||
AudioOutputManager = new AudioOutputManager();
|
AudioOutputManager = new AudioOutputManager();
|
||||||
AudioInputManager = new AudioInputManager();
|
AudioInputManager = new AudioInputManager();
|
||||||
AudioRendererManager = new AudioRendererManager();
|
AudioRendererManager = new AudioRendererManager(tickSource);
|
||||||
AudioRendererManager.SetVolume(Device.Configuration.AudioVolume);
|
AudioRendererManager.SetVolume(Device.Configuration.AudioVolume);
|
||||||
AudioDeviceSessionRegistry = new VirtualDeviceSessionRegistry();
|
AudioDeviceSessionRegistry = new VirtualDeviceSessionRegistry();
|
||||||
|
|
||||||
@@ -492,12 +501,12 @@ namespace Ryujinx.HLE.HOS
|
|||||||
if (pause && !IsPaused)
|
if (pause && !IsPaused)
|
||||||
{
|
{
|
||||||
Device.AudioDeviceDriver.GetPauseEvent().Reset();
|
Device.AudioDeviceDriver.GetPauseEvent().Reset();
|
||||||
ARMeilleure.State.ExecutionContext.SuspendCounter();
|
TickSource.Suspend();
|
||||||
}
|
}
|
||||||
else if (!pause && IsPaused)
|
else if (!pause && IsPaused)
|
||||||
{
|
{
|
||||||
Device.AudioDeviceDriver.GetPauseEvent().Set();
|
Device.AudioDeviceDriver.GetPauseEvent().Set();
|
||||||
ARMeilleure.State.ExecutionContext.ResumeCounter();
|
TickSource.Resume();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
IsPaused = pause;
|
IsPaused = pause;
|
||||||
|
@@ -12,5 +12,7 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||||||
public const ulong UserSlabHeapBase = DramMemoryMap.SlabHeapBase;
|
public const ulong UserSlabHeapBase = DramMemoryMap.SlabHeapBase;
|
||||||
public const ulong UserSlabHeapItemSize = KPageTableBase.PageSize;
|
public const ulong UserSlabHeapItemSize = KPageTableBase.PageSize;
|
||||||
public const ulong UserSlabHeapSize = 0x3de000;
|
public const ulong UserSlabHeapSize = 0x3de000;
|
||||||
|
|
||||||
|
public const ulong CounterFrequency = 19200000;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,4 +1,5 @@
|
|||||||
using Ryujinx.HLE.HOS.Kernel.Common;
|
using Ryujinx.Cpu;
|
||||||
|
using Ryujinx.HLE.HOS.Kernel.Common;
|
||||||
using Ryujinx.HLE.HOS.Kernel.Memory;
|
using Ryujinx.HLE.HOS.Kernel.Memory;
|
||||||
using Ryujinx.HLE.HOS.Kernel.Process;
|
using Ryujinx.HLE.HOS.Kernel.Process;
|
||||||
using Ryujinx.HLE.HOS.Kernel.SupervisorCall;
|
using Ryujinx.HLE.HOS.Kernel.SupervisorCall;
|
||||||
@@ -23,6 +24,7 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||||||
|
|
||||||
public Switch Device { get; }
|
public Switch Device { get; }
|
||||||
public MemoryBlock Memory { get; }
|
public MemoryBlock Memory { get; }
|
||||||
|
public ITickSource TickSource { get; }
|
||||||
public Syscall Syscall { get; }
|
public Syscall Syscall { get; }
|
||||||
public SyscallHandler SyscallHandler { get; }
|
public SyscallHandler SyscallHandler { get; }
|
||||||
|
|
||||||
@@ -52,11 +54,13 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||||||
private ulong _threadUid;
|
private ulong _threadUid;
|
||||||
|
|
||||||
public KernelContext(
|
public KernelContext(
|
||||||
|
ITickSource tickSource,
|
||||||
Switch device,
|
Switch device,
|
||||||
MemoryBlock memory,
|
MemoryBlock memory,
|
||||||
MemorySize memorySize,
|
MemorySize memorySize,
|
||||||
MemoryArrange memoryArrange)
|
MemoryArrange memoryArrange)
|
||||||
{
|
{
|
||||||
|
TickSource = tickSource;
|
||||||
Device = device;
|
Device = device;
|
||||||
Memory = memory;
|
Memory = memory;
|
||||||
|
|
||||||
|
@@ -115,7 +115,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
|||||||
|
|
||||||
string GetReg(int x)
|
string GetReg(int x)
|
||||||
{
|
{
|
||||||
var v = x == 32 ? (ulong)thread.LastPc : context.GetX(x);
|
var v = x == 32 ? context.Pc : context.GetX(x);
|
||||||
if (!AnalyzePointer(out PointerInfo info, v, thread))
|
if (!AnalyzePointer(out PointerInfo info, v, thread))
|
||||||
{
|
{
|
||||||
return $"0x{v:x16}";
|
return $"0x{v:x16}";
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
using ARMeilleure.State;
|
using Ryujinx.Cpu;
|
||||||
using Ryujinx.Memory;
|
using Ryujinx.Memory;
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
@@ -8,7 +8,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
|||||||
{
|
{
|
||||||
IVirtualMemoryManager AddressSpace { get; }
|
IVirtualMemoryManager AddressSpace { get; }
|
||||||
|
|
||||||
void Execute(ExecutionContext context, ulong codeAddress);
|
IExecutionContext CreateExecutionContext(ExceptionCallbacks exceptionCallbacks);
|
||||||
|
void Execute(IExecutionContext context, ulong codeAddress);
|
||||||
void InvalidateCacheRegion(ulong address, ulong size);
|
void InvalidateCacheRegion(ulong address, ulong size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,4 +1,3 @@
|
|||||||
using ARMeilleure.State;
|
|
||||||
using Ryujinx.Common;
|
using Ryujinx.Common;
|
||||||
using Ryujinx.Common.Logging;
|
using Ryujinx.Common.Logging;
|
||||||
using Ryujinx.Cpu;
|
using Ryujinx.Cpu;
|
||||||
@@ -744,14 +743,16 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SubscribeThreadEventHandlers(ARMeilleure.State.ExecutionContext context)
|
public IExecutionContext CreateExecutionContext()
|
||||||
{
|
{
|
||||||
context.Interrupt += InterruptHandler;
|
return Context?.CreateExecutionContext(new ExceptionCallbacks(
|
||||||
context.SupervisorCall += KernelContext.SyscallHandler.SvcCall;
|
InterruptHandler,
|
||||||
context.Undefined += UndefinedInstructionHandler;
|
null,
|
||||||
|
KernelContext.SyscallHandler.SvcCall,
|
||||||
|
UndefinedInstructionHandler));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void InterruptHandler(object sender, EventArgs e)
|
private void InterruptHandler(IExecutionContext context)
|
||||||
{
|
{
|
||||||
KThread currentThread = KernelStatic.GetCurrentThread();
|
KThread currentThread = KernelStatic.GetCurrentThread();
|
||||||
|
|
||||||
@@ -1093,12 +1094,12 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UndefinedInstructionHandler(object sender, InstUndefinedEventArgs e)
|
private void UndefinedInstructionHandler(IExecutionContext context, ulong address, int opCode)
|
||||||
{
|
{
|
||||||
KernelStatic.GetCurrentThread().PrintGuestStackTrace();
|
KernelStatic.GetCurrentThread().PrintGuestStackTrace();
|
||||||
KernelStatic.GetCurrentThread()?.PrintGuestRegisterPrintout();
|
KernelStatic.GetCurrentThread()?.PrintGuestRegisterPrintout();
|
||||||
|
|
||||||
throw new UndefinedInstructionException(e.Address, e.OpCode);
|
throw new UndefinedInstructionException(address, opCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void Destroy() => Context.Dispose();
|
protected override void Destroy() => Context.Dispose();
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
using ARMeilleure.State;
|
using Ryujinx.Cpu;
|
||||||
using Ryujinx.Memory;
|
using Ryujinx.Memory;
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
@@ -13,7 +13,12 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
|||||||
AddressSpace = asManager;
|
AddressSpace = asManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Execute(ExecutionContext context, ulong codeAddress)
|
public IExecutionContext CreateExecutionContext(ExceptionCallbacks exceptionCallbacks)
|
||||||
|
{
|
||||||
|
return new ProcessExecutionContext();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Execute(IExecutionContext context, ulong codeAddress)
|
||||||
{
|
{
|
||||||
throw new NotSupportedException();
|
throw new NotSupportedException();
|
||||||
}
|
}
|
||||||
|
44
Ryujinx.HLE/HOS/Kernel/Process/ProcessExecutionContext.cs
Normal file
44
Ryujinx.HLE/HOS/Kernel/Process/ProcessExecutionContext.cs
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
using ARMeilleure.State;
|
||||||
|
using Ryujinx.Cpu;
|
||||||
|
|
||||||
|
namespace Ryujinx.HLE.HOS.Kernel.Process
|
||||||
|
{
|
||||||
|
class ProcessExecutionContext : IExecutionContext
|
||||||
|
{
|
||||||
|
public ulong Pc => 0UL;
|
||||||
|
|
||||||
|
public ulong CntfrqEl0 { get => 0; set { } }
|
||||||
|
public ulong CntpctEl0 => 0UL;
|
||||||
|
|
||||||
|
public long TpidrEl0 { get => 0; set { } }
|
||||||
|
public long TpidrroEl0 { get => 0; set { } }
|
||||||
|
|
||||||
|
public uint Pstate { get => 0; set { } }
|
||||||
|
|
||||||
|
public uint Fpcr { get => 0; set { } }
|
||||||
|
public uint Fpsr { get => 0; set { } }
|
||||||
|
|
||||||
|
public bool IsAarch32 { get => false; set { } }
|
||||||
|
|
||||||
|
public bool Running { get; private set; } = true;
|
||||||
|
|
||||||
|
public ulong GetX(int index) => 0UL;
|
||||||
|
public void SetX(int index, ulong value) { }
|
||||||
|
|
||||||
|
public V128 GetV(int index) => default;
|
||||||
|
public void SetV(int index, V128 value) { }
|
||||||
|
|
||||||
|
public void RequestInterrupt()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public void StopRunning()
|
||||||
|
{
|
||||||
|
Running = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -1755,7 +1755,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
|||||||
|
|
||||||
public ulong GetSystemTick()
|
public ulong GetSystemTick()
|
||||||
{
|
{
|
||||||
return KernelStatic.GetCurrentThread().Context.CntpctEl0;
|
return _context.TickSource.Counter;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Break(ulong reason)
|
public void Break(ulong reason)
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
using ARMeilleure.State;
|
using Ryujinx.Cpu;
|
||||||
using Ryujinx.HLE.HOS.Kernel.Threading;
|
using Ryujinx.HLE.HOS.Kernel.Threading;
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
@@ -17,7 +17,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
|||||||
_syscall64 = new Syscall64(context.Syscall);
|
_syscall64 = new Syscall64(context.Syscall);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SvcCall(object sender, InstExceptionEventArgs e)
|
public void SvcCall(IExecutionContext context, ulong address, int id)
|
||||||
{
|
{
|
||||||
KThread currentThread = KernelStatic.GetCurrentThread();
|
KThread currentThread = KernelStatic.GetCurrentThread();
|
||||||
|
|
||||||
@@ -34,26 +34,24 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
|||||||
_context.CriticalSection.Leave();
|
_context.CriticalSection.Leave();
|
||||||
}
|
}
|
||||||
|
|
||||||
ExecutionContext context = (ExecutionContext)sender;
|
|
||||||
|
|
||||||
if (context.IsAarch32)
|
if (context.IsAarch32)
|
||||||
{
|
{
|
||||||
var svcFunc = SyscallTable.SvcTable32[e.Id];
|
var svcFunc = SyscallTable.SvcTable32[id];
|
||||||
|
|
||||||
if (svcFunc == null)
|
if (svcFunc == null)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException($"SVC 0x{e.Id:X4} is not implemented.");
|
throw new NotImplementedException($"SVC 0x{id:X4} is not implemented.");
|
||||||
}
|
}
|
||||||
|
|
||||||
svcFunc(_syscall32, context);
|
svcFunc(_syscall32, context);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var svcFunc = SyscallTable.SvcTable64[e.Id];
|
var svcFunc = SyscallTable.SvcTable64[id];
|
||||||
|
|
||||||
if (svcFunc == null)
|
if (svcFunc == null)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException($"SVC 0x{e.Id:X4} is not implemented.");
|
throw new NotImplementedException($"SVC 0x{id:X4} is not implemented.");
|
||||||
}
|
}
|
||||||
|
|
||||||
svcFunc(_syscall64, context);
|
svcFunc(_syscall64, context);
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
using ARMeilleure.State;
|
|
||||||
using Ryujinx.Common.Logging;
|
using Ryujinx.Common.Logging;
|
||||||
|
using Ryujinx.Cpu;
|
||||||
using Ryujinx.HLE.HOS.Kernel.Common;
|
using Ryujinx.HLE.HOS.Kernel.Common;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
@@ -14,13 +14,13 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
|||||||
private const int SvcFuncMaxArguments32 = 4;
|
private const int SvcFuncMaxArguments32 = 4;
|
||||||
private const int SvcMax = 0x80;
|
private const int SvcMax = 0x80;
|
||||||
|
|
||||||
public static Action<Syscall32, ExecutionContext>[] SvcTable32 { get; }
|
public static Action<Syscall32, IExecutionContext>[] SvcTable32 { get; }
|
||||||
public static Action<Syscall64, ExecutionContext>[] SvcTable64 { get; }
|
public static Action<Syscall64, IExecutionContext>[] SvcTable64 { get; }
|
||||||
|
|
||||||
static SyscallTable()
|
static SyscallTable()
|
||||||
{
|
{
|
||||||
SvcTable32 = new Action<Syscall32, ExecutionContext>[SvcMax];
|
SvcTable32 = new Action<Syscall32, IExecutionContext>[SvcMax];
|
||||||
SvcTable64 = new Action<Syscall64, ExecutionContext>[SvcMax];
|
SvcTable64 = new Action<Syscall64, IExecutionContext>[SvcMax];
|
||||||
|
|
||||||
Dictionary<int, string> svcFuncs64 = new Dictionary<int, string>
|
Dictionary<int, string> svcFuncs64 = new Dictionary<int, string>
|
||||||
{
|
{
|
||||||
@@ -182,9 +182,9 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Action<T, ExecutionContext> GenerateMethod<T>(string svcName, int registerCleanCount)
|
private static Action<T, IExecutionContext> GenerateMethod<T>(string svcName, int registerCleanCount)
|
||||||
{
|
{
|
||||||
Type[] argTypes = new Type[] { typeof(T), typeof(ExecutionContext) };
|
Type[] argTypes = new Type[] { typeof(T), typeof(IExecutionContext) };
|
||||||
|
|
||||||
DynamicMethod method = new DynamicMethod(svcName, null, argTypes);
|
DynamicMethod method = new DynamicMethod(svcName, null, argTypes);
|
||||||
|
|
||||||
@@ -292,9 +292,9 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
|||||||
generator.Emit(OpCodes.Ldarg_1);
|
generator.Emit(OpCodes.Ldarg_1);
|
||||||
generator.Emit(OpCodes.Ldc_I4, registerAttribute.Index);
|
generator.Emit(OpCodes.Ldc_I4, registerAttribute.Index);
|
||||||
|
|
||||||
MethodInfo info = typeof(ExecutionContext).GetMethod(nameof(ExecutionContext.GetX));
|
MethodInfo info = typeof(IExecutionContext).GetMethod(nameof(IExecutionContext.GetX));
|
||||||
|
|
||||||
generator.Emit(OpCodes.Call, info);
|
generator.Emit(OpCodes.Callvirt, info);
|
||||||
|
|
||||||
generator.Emit(OpCodes.Box, typeof(ulong));
|
generator.Emit(OpCodes.Box, typeof(ulong));
|
||||||
|
|
||||||
@@ -339,9 +339,9 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
|||||||
generator.Emit(OpCodes.Ldarg_1);
|
generator.Emit(OpCodes.Ldarg_1);
|
||||||
generator.Emit(OpCodes.Ldc_I4, registerAttribute.Index);
|
generator.Emit(OpCodes.Ldc_I4, registerAttribute.Index);
|
||||||
|
|
||||||
MethodInfo info = typeof(ExecutionContext).GetMethod(nameof(ExecutionContext.GetX));
|
MethodInfo info = typeof(IExecutionContext).GetMethod(nameof(IExecutionContext.GetX));
|
||||||
|
|
||||||
generator.Emit(OpCodes.Call, info);
|
generator.Emit(OpCodes.Callvirt, info);
|
||||||
|
|
||||||
ConvertToArgType(argType);
|
ConvertToArgType(argType);
|
||||||
|
|
||||||
@@ -355,9 +355,9 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
|||||||
generator.Emit(OpCodes.Ldarg_1);
|
generator.Emit(OpCodes.Ldarg_1);
|
||||||
generator.Emit(OpCodes.Ldc_I4, registerAttribute.Index);
|
generator.Emit(OpCodes.Ldc_I4, registerAttribute.Index);
|
||||||
|
|
||||||
MethodInfo info = typeof(ExecutionContext).GetMethod(nameof(ExecutionContext.GetX));
|
MethodInfo info = typeof(IExecutionContext).GetMethod(nameof(IExecutionContext.GetX));
|
||||||
|
|
||||||
generator.Emit(OpCodes.Call, info);
|
generator.Emit(OpCodes.Callvirt, info);
|
||||||
|
|
||||||
ConvertToArgType(argType);
|
ConvertToArgType(argType);
|
||||||
}
|
}
|
||||||
@@ -393,9 +393,9 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
|||||||
|
|
||||||
ConvertToFieldType(retType);
|
ConvertToFieldType(retType);
|
||||||
|
|
||||||
MethodInfo info = typeof(ExecutionContext).GetMethod(nameof(ExecutionContext.SetX));
|
MethodInfo info = typeof(IExecutionContext).GetMethod(nameof(IExecutionContext.SetX));
|
||||||
|
|
||||||
generator.Emit(OpCodes.Call, info);
|
generator.Emit(OpCodes.Callvirt, info);
|
||||||
|
|
||||||
registerInUse |= 1u << 0;
|
registerInUse |= 1u << 0;
|
||||||
}
|
}
|
||||||
@@ -415,9 +415,9 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
|||||||
|
|
||||||
ConvertToFieldType(local.LocalType);
|
ConvertToFieldType(local.LocalType);
|
||||||
|
|
||||||
MethodInfo info = typeof(ExecutionContext).GetMethod(nameof(ExecutionContext.SetX));
|
MethodInfo info = typeof(IExecutionContext).GetMethod(nameof(IExecutionContext.SetX));
|
||||||
|
|
||||||
generator.Emit(OpCodes.Call, info);
|
generator.Emit(OpCodes.Callvirt, info);
|
||||||
|
|
||||||
registerInUse |= 1u << attribute.Index;
|
registerInUse |= 1u << attribute.Index;
|
||||||
}
|
}
|
||||||
@@ -434,14 +434,14 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
|||||||
generator.Emit(OpCodes.Ldc_I4, i);
|
generator.Emit(OpCodes.Ldc_I4, i);
|
||||||
generator.Emit(OpCodes.Ldc_I8, 0L);
|
generator.Emit(OpCodes.Ldc_I8, 0L);
|
||||||
|
|
||||||
MethodInfo info = typeof(ExecutionContext).GetMethod(nameof(ExecutionContext.SetX));
|
MethodInfo info = typeof(IExecutionContext).GetMethod(nameof(IExecutionContext.SetX));
|
||||||
|
|
||||||
generator.Emit(OpCodes.Call, info);
|
generator.Emit(OpCodes.Callvirt, info);
|
||||||
}
|
}
|
||||||
|
|
||||||
generator.Emit(OpCodes.Ret);
|
generator.Emit(OpCodes.Ret);
|
||||||
|
|
||||||
return method.CreateDelegate<Action<T, ExecutionContext>>();
|
return method.CreateDelegate<Action<T, IExecutionContext>>();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void CheckIfTypeIsSupported(Type type, string svcName)
|
private static void CheckIfTypeIsSupported(Type type, string svcName)
|
||||||
|
@@ -23,7 +23,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
|
|||||||
|
|
||||||
public Thread HostThread { get; private set; }
|
public Thread HostThread { get; private set; }
|
||||||
|
|
||||||
public ARMeilleure.State.ExecutionContext Context { get; private set; }
|
public IExecutionContext Context { get; private set; }
|
||||||
|
|
||||||
public KThreadContext ThreadContext { get; private set; }
|
public KThreadContext ThreadContext { get; private set; }
|
||||||
|
|
||||||
@@ -115,9 +115,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
|
|||||||
|
|
||||||
public bool WaitingInArbitration { get; set; }
|
public bool WaitingInArbitration { get; set; }
|
||||||
|
|
||||||
public long LastPc { get; set; }
|
private object _activityOperationLock;
|
||||||
|
|
||||||
private object ActivityOperationLock = new object();
|
|
||||||
|
|
||||||
public KThread(KernelContext context) : base(context)
|
public KThread(KernelContext context) : base(context)
|
||||||
{
|
{
|
||||||
@@ -128,6 +126,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
|
|||||||
|
|
||||||
_mutexWaiters = new LinkedList<KThread>();
|
_mutexWaiters = new LinkedList<KThread>();
|
||||||
_pinnedWaiters = new LinkedList<KThread>();
|
_pinnedWaiters = new LinkedList<KThread>();
|
||||||
|
|
||||||
|
_activityOperationLock = new object();
|
||||||
}
|
}
|
||||||
|
|
||||||
public KernelResult Initialize(
|
public KernelResult Initialize(
|
||||||
@@ -192,7 +192,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
|
|||||||
|
|
||||||
HostThread = new Thread(ThreadStart);
|
HostThread = new Thread(ThreadStart);
|
||||||
|
|
||||||
Context = CpuContext.CreateExecutionContext();
|
Context = owner?.CreateExecutionContext() ?? new ProcessExecutionContext();
|
||||||
|
|
||||||
Context.IsAarch32 = !is64Bits;
|
Context.IsAarch32 = !is64Bits;
|
||||||
|
|
||||||
@@ -208,8 +208,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
|
|||||||
Context.SetX(13, (uint)stackTop);
|
Context.SetX(13, (uint)stackTop);
|
||||||
}
|
}
|
||||||
|
|
||||||
Context.CntfrqEl0 = 19200000;
|
Context.TpidrroEl0 = (long)_tlsAddress;
|
||||||
Context.Tpidr = (long)_tlsAddress;
|
|
||||||
|
|
||||||
ThreadUid = KernelContext.NewThreadUid();
|
ThreadUid = KernelContext.NewThreadUid();
|
||||||
|
|
||||||
@@ -221,7 +220,6 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
|
|||||||
|
|
||||||
if (owner != null)
|
if (owner != null)
|
||||||
{
|
{
|
||||||
owner.SubscribeThreadEventHandlers(Context);
|
|
||||||
owner.AddThread(this);
|
owner.AddThread(this);
|
||||||
|
|
||||||
if (owner.IsPaused)
|
if (owner.IsPaused)
|
||||||
@@ -538,7 +536,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
|
|||||||
|
|
||||||
public KernelResult SetActivity(bool pause)
|
public KernelResult SetActivity(bool pause)
|
||||||
{
|
{
|
||||||
lock (ActivityOperationLock)
|
lock (_activityOperationLock)
|
||||||
{
|
{
|
||||||
KernelResult result = KernelResult.Success;
|
KernelResult result = KernelResult.Success;
|
||||||
|
|
||||||
@@ -634,7 +632,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
|
|||||||
{
|
{
|
||||||
context = default;
|
context = default;
|
||||||
|
|
||||||
lock (ActivityOperationLock)
|
lock (_activityOperationLock)
|
||||||
{
|
{
|
||||||
KernelContext.CriticalSection.Enter();
|
KernelContext.CriticalSection.Enter();
|
||||||
|
|
||||||
@@ -656,7 +654,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
|
|||||||
return KernelResult.Success;
|
return KernelResult.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static uint GetPsr(ARMeilleure.State.ExecutionContext context)
|
private static uint GetPsr(IExecutionContext context)
|
||||||
{
|
{
|
||||||
return context.Pstate & 0xFF0FFE20;
|
return context.Pstate & 0xFF0FFE20;
|
||||||
}
|
}
|
||||||
@@ -683,9 +681,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
|
|||||||
context.Fp = Context.GetX(29);
|
context.Fp = Context.GetX(29);
|
||||||
context.Lr = Context.GetX(30);
|
context.Lr = Context.GetX(30);
|
||||||
context.Sp = Context.GetX(31);
|
context.Sp = Context.GetX(31);
|
||||||
context.Pc = (ulong)LastPc;
|
context.Pc = Context.Pc;
|
||||||
context.Pstate = GetPsr(Context);
|
context.Pstate = GetPsr(Context);
|
||||||
context.Tpidr = (ulong)Context.Tpidr;
|
context.Tpidr = (ulong)Context.TpidrroEl0;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -699,9 +697,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
|
|||||||
context.FpuRegisters[i] = Context.GetV(i);
|
context.FpuRegisters[i] = Context.GetV(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
context.Pc = (uint)LastPc;
|
context.Pc = (uint)Context.Pc;
|
||||||
context.Pstate = GetPsr(Context);
|
context.Pstate = GetPsr(Context);
|
||||||
context.Tpidr = (uint)Context.Tpidr;
|
context.Tpidr = (uint)Context.TpidrroEl0;
|
||||||
}
|
}
|
||||||
|
|
||||||
context.Fpcr = (uint)Context.Fpcr;
|
context.Fpcr = (uint)Context.Fpcr;
|
||||||
@@ -743,7 +741,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
|
|||||||
|
|
||||||
public KernelResult SetCoreAndAffinityMask(int newCore, ulong newAffinityMask)
|
public KernelResult SetCoreAndAffinityMask(int newCore, ulong newAffinityMask)
|
||||||
{
|
{
|
||||||
lock (ActivityOperationLock)
|
lock (_activityOperationLock)
|
||||||
{
|
{
|
||||||
KernelContext.CriticalSection.Enter();
|
KernelContext.CriticalSection.Enter();
|
||||||
|
|
||||||
|
@@ -101,7 +101,7 @@ namespace Ryujinx.HLE.HOS
|
|||||||
|
|
||||||
KProcess process = new KProcess(context);
|
KProcess process = new KProcess(context);
|
||||||
|
|
||||||
var processContextFactory = new ArmProcessContextFactory(context.Device.Gpu);
|
var processContextFactory = new ArmProcessContextFactory(context.Device.System.CpuEngine, context.Device.Gpu);
|
||||||
|
|
||||||
result = process.InitializeKip(
|
result = process.InitializeKip(
|
||||||
creationInfo,
|
creationInfo,
|
||||||
@@ -264,7 +264,7 @@ namespace Ryujinx.HLE.HOS
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
var processContextFactory = new ArmProcessContextFactory(context.Device.Gpu);
|
var processContextFactory = new ArmProcessContextFactory(context.Device.System.CpuEngine, context.Device.Gpu);
|
||||||
|
|
||||||
result = process.Initialize(
|
result = process.Initialize(
|
||||||
creationInfo,
|
creationInfo,
|
||||||
|
@@ -1,4 +1,5 @@
|
|||||||
using LibHac;
|
using LibHac;
|
||||||
|
using Ryujinx.Cpu;
|
||||||
using Ryujinx.HLE.HOS.Services.Mii.Types;
|
using Ryujinx.HLE.HOS.Services.Mii.Types;
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
@@ -27,7 +28,6 @@ namespace Ryujinx.HLE.HOS.Services.Mii
|
|||||||
|
|
||||||
public DatabaseImpl()
|
public DatabaseImpl()
|
||||||
{
|
{
|
||||||
_utilityImpl = new UtilityImpl();
|
|
||||||
_miiDatabase = new MiiDatabaseManager();
|
_miiDatabase = new MiiDatabaseManager();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -148,12 +148,13 @@ namespace Ryujinx.HLE.HOS.Services.Mii
|
|||||||
return GetDefault(flag, ref count, elements);
|
return GetDefault(flag, ref count, elements);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ResultCode InitializeDatabase(HorizonClient horizonClient)
|
public ResultCode InitializeDatabase(ITickSource tickSource, HorizonClient horizonClient)
|
||||||
{
|
{
|
||||||
|
_utilityImpl = new UtilityImpl(tickSource);
|
||||||
_miiDatabase.InitializeDatabase(horizonClient);
|
_miiDatabase.InitializeDatabase(horizonClient);
|
||||||
_miiDatabase.LoadFromFile(out _isBroken);
|
_miiDatabase.LoadFromFile(out _isBroken);
|
||||||
|
|
||||||
// Nintendo ignore any error code from before
|
// Nintendo ignores any error code from before.
|
||||||
return ResultCode.Success;
|
return ResultCode.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,4 +1,5 @@
|
|||||||
using Ryujinx.HLE.HOS.Services.Mii.Types;
|
using Ryujinx.Cpu;
|
||||||
|
using Ryujinx.HLE.HOS.Services.Mii.Types;
|
||||||
using Ryujinx.HLE.HOS.Services.Time;
|
using Ryujinx.HLE.HOS.Services.Time;
|
||||||
using Ryujinx.HLE.HOS.Services.Time.Clock;
|
using Ryujinx.HLE.HOS.Services.Time.Clock;
|
||||||
using System;
|
using System;
|
||||||
@@ -12,12 +13,12 @@ namespace Ryujinx.HLE.HOS.Services.Mii
|
|||||||
private uint _z;
|
private uint _z;
|
||||||
private uint _w;
|
private uint _w;
|
||||||
|
|
||||||
public UtilityImpl()
|
public UtilityImpl(ITickSource tickSource)
|
||||||
{
|
{
|
||||||
_x = 123456789;
|
_x = 123456789;
|
||||||
_y = 362436069;
|
_y = 362436069;
|
||||||
|
|
||||||
TimeSpanType time = TimeManager.Instance.TickBasedSteadyClock.GetCurrentRawTimePoint(null);
|
TimeSpanType time = TimeManager.Instance.TickBasedSteadyClock.GetCurrentRawTimePoint(tickSource);
|
||||||
|
|
||||||
_w = (uint)(time.NanoSeconds & uint.MaxValue);
|
_w = (uint)(time.NanoSeconds & uint.MaxValue);
|
||||||
_z = (uint)((time.NanoSeconds >> 32) & uint.MaxValue);
|
_z = (uint)((time.NanoSeconds >> 32) & uint.MaxValue);
|
||||||
|
@@ -688,7 +688,10 @@ namespace Ryujinx.HLE.HOS.Services.Nfc.Nfp
|
|||||||
{
|
{
|
||||||
if (context.Device.System.NfpDevices[i].State == NfpDeviceState.TagMounted)
|
if (context.Device.System.NfpDevices[i].State == NfpDeviceState.TagMounted)
|
||||||
{
|
{
|
||||||
RegisterInfo registerInfo = VirtualAmiibo.GetRegisterInfo(context.Device.System.NfpDevices[i].AmiiboId, context.Device.System.AccountManager.LastOpenedUser.Name);
|
RegisterInfo registerInfo = VirtualAmiibo.GetRegisterInfo(
|
||||||
|
context.Device.System.TickSource,
|
||||||
|
context.Device.System.NfpDevices[i].AmiiboId,
|
||||||
|
context.Device.System.AccountManager.LastOpenedUser.Name);
|
||||||
|
|
||||||
context.Memory.Write(outputPosition, registerInfo);
|
context.Memory.Write(outputPosition, registerInfo);
|
||||||
|
|
||||||
@@ -911,7 +914,7 @@ namespace Ryujinx.HLE.HOS.Services.Nfc.Nfp
|
|||||||
{
|
{
|
||||||
throw new ArgumentOutOfRangeException();
|
throw new ArgumentOutOfRangeException();
|
||||||
}
|
}
|
||||||
|
|
||||||
context.ResponseData.Write((uint)context.Device.System.NfpDevices[i].State);
|
context.ResponseData.Write((uint)context.Device.System.NfpDevices[i].State);
|
||||||
|
|
||||||
return ResultCode.Success;
|
return ResultCode.Success;
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
using Ryujinx.Common.Configuration;
|
using Ryujinx.Common.Configuration;
|
||||||
using Ryujinx.Common.Memory;
|
using Ryujinx.Common.Memory;
|
||||||
|
using Ryujinx.Cpu;
|
||||||
using Ryujinx.HLE.HOS.Services.Mii;
|
using Ryujinx.HLE.HOS.Services.Mii;
|
||||||
using Ryujinx.HLE.HOS.Services.Mii.Types;
|
using Ryujinx.HLE.HOS.Services.Mii.Types;
|
||||||
using Ryujinx.HLE.HOS.Services.Nfc.Nfp.NfpManager;
|
using Ryujinx.HLE.HOS.Services.Nfc.Nfp.NfpManager;
|
||||||
@@ -63,11 +64,11 @@ namespace Ryujinx.HLE.HOS.Services.Nfc.Nfp
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public static RegisterInfo GetRegisterInfo(string amiiboId, string nickname)
|
public static RegisterInfo GetRegisterInfo(ITickSource tickSource, string amiiboId, string nickname)
|
||||||
{
|
{
|
||||||
VirtualAmiiboFile amiiboFile = LoadAmiiboFile(amiiboId);
|
VirtualAmiiboFile amiiboFile = LoadAmiiboFile(amiiboId);
|
||||||
|
|
||||||
UtilityImpl utilityImpl = new UtilityImpl();
|
UtilityImpl utilityImpl = new UtilityImpl(tickSource);
|
||||||
CharInfo charInfo = new CharInfo();
|
CharInfo charInfo = new CharInfo();
|
||||||
|
|
||||||
charInfo.SetFromStoreData(StoreData.BuildDefault(utilityImpl, 0));
|
charInfo.SetFromStoreData(StoreData.BuildDefault(utilityImpl, 0));
|
||||||
|
@@ -6,7 +6,7 @@
|
|||||||
{
|
{
|
||||||
BufferQueueCore core = new BufferQueueCore(device, pid);
|
BufferQueueCore core = new BufferQueueCore(device, pid);
|
||||||
|
|
||||||
producer = new BufferQueueProducer(core);
|
producer = new BufferQueueProducer(core, device.System.TickSource);
|
||||||
consumer = new BufferQueueConsumer(core);
|
consumer = new BufferQueueConsumer(core);
|
||||||
|
|
||||||
return core;
|
return core;
|
||||||
|
@@ -1,5 +1,4 @@
|
|||||||
using Ryujinx.Common.Logging;
|
using Ryujinx.Common.Logging;
|
||||||
using Ryujinx.HLE.HOS.Kernel;
|
|
||||||
using Ryujinx.HLE.HOS.Kernel.Threading;
|
using Ryujinx.HLE.HOS.Kernel.Threading;
|
||||||
using Ryujinx.HLE.HOS.Services.SurfaceFlinger.Types;
|
using Ryujinx.HLE.HOS.Services.SurfaceFlinger.Types;
|
||||||
using System;
|
using System;
|
||||||
@@ -241,7 +240,7 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
|
|||||||
{
|
{
|
||||||
BufferSlot slot = Slots[item.Slot];
|
BufferSlot slot = Slots[item.Slot];
|
||||||
|
|
||||||
// TODO: Check this. On Android, this checks the "handle". I assume NvMapHandle is the handle, but it might not be.
|
// TODO: Check this. On Android, this checks the "handle". I assume NvMapHandle is the handle, but it might not be.
|
||||||
return !slot.GraphicBuffer.IsNull && slot.GraphicBuffer.Object.Buffer.Surfaces[0].NvMapHandle == item.GraphicBuffer.Object.Buffer.Surfaces[0].NvMapHandle;
|
return !slot.GraphicBuffer.IsNull && slot.GraphicBuffer.Object.Buffer.Surfaces[0].NvMapHandle == item.GraphicBuffer.Object.Buffer.Surfaces[0].NvMapHandle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,4 +1,5 @@
|
|||||||
using Ryujinx.Common.Logging;
|
using Ryujinx.Common.Logging;
|
||||||
|
using Ryujinx.Cpu;
|
||||||
using Ryujinx.HLE.HOS.Kernel.Threading;
|
using Ryujinx.HLE.HOS.Kernel.Threading;
|
||||||
using Ryujinx.HLE.HOS.Services.Settings;
|
using Ryujinx.HLE.HOS.Services.Settings;
|
||||||
using Ryujinx.HLE.HOS.Services.SurfaceFlinger.Types;
|
using Ryujinx.HLE.HOS.Services.SurfaceFlinger.Types;
|
||||||
@@ -12,6 +13,8 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
|
|||||||
{
|
{
|
||||||
public BufferQueueCore Core { get; }
|
public BufferQueueCore Core { get; }
|
||||||
|
|
||||||
|
private readonly ITickSource _tickSource;
|
||||||
|
|
||||||
private uint _stickyTransform;
|
private uint _stickyTransform;
|
||||||
|
|
||||||
private uint _nextCallbackTicket;
|
private uint _nextCallbackTicket;
|
||||||
@@ -20,9 +23,10 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
|
|||||||
|
|
||||||
private readonly object _callbackLock = new object();
|
private readonly object _callbackLock = new object();
|
||||||
|
|
||||||
public BufferQueueProducer(BufferQueueCore core)
|
public BufferQueueProducer(BufferQueueCore core, ITickSource tickSource)
|
||||||
{
|
{
|
||||||
Core = core;
|
Core = core;
|
||||||
|
_tickSource = tickSource;
|
||||||
|
|
||||||
_stickyTransform = 0;
|
_stickyTransform = 0;
|
||||||
_callbackTicket = 0;
|
_callbackTicket = 0;
|
||||||
@@ -179,8 +183,8 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
|
|||||||
GraphicBuffer graphicBuffer = Core.Slots[slot].GraphicBuffer.Object;
|
GraphicBuffer graphicBuffer = Core.Slots[slot].GraphicBuffer.Object;
|
||||||
|
|
||||||
if (Core.Slots[slot].GraphicBuffer.IsNull
|
if (Core.Slots[slot].GraphicBuffer.IsNull
|
||||||
|| graphicBuffer.Width != width
|
|| graphicBuffer.Width != width
|
||||||
|| graphicBuffer.Height != height
|
|| graphicBuffer.Height != height
|
||||||
|| graphicBuffer.Format != format
|
|| graphicBuffer.Format != format
|
||||||
|| (graphicBuffer.Usage & usage) != usage)
|
|| (graphicBuffer.Usage & usage) != usage)
|
||||||
{
|
{
|
||||||
@@ -193,7 +197,7 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Logger.Error?.Print(LogClass.SurfaceFlinger,
|
Logger.Error?.Print(LogClass.SurfaceFlinger,
|
||||||
$"Preallocated buffer mismatch - slot {slot}\n" +
|
$"Preallocated buffer mismatch - slot {slot}\n" +
|
||||||
$"available: Width = {graphicBuffer.Width} Height = {graphicBuffer.Height} Format = {graphicBuffer.Format} Usage = {graphicBuffer.Usage:x} " +
|
$"available: Width = {graphicBuffer.Width} Height = {graphicBuffer.Height} Format = {graphicBuffer.Format} Usage = {graphicBuffer.Usage:x} " +
|
||||||
$"requested: Width = {width} Height = {height} Format = {format} Usage = {usage:x}");
|
$"requested: Width = {width} Height = {height} Format = {format} Usage = {usage:x}");
|
||||||
@@ -388,7 +392,7 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
|
|||||||
Core.Slots[slot].BufferState = BufferState.Queued;
|
Core.Slots[slot].BufferState = BufferState.Queued;
|
||||||
Core.FrameCounter++;
|
Core.FrameCounter++;
|
||||||
Core.Slots[slot].FrameNumber = Core.FrameCounter;
|
Core.Slots[slot].FrameNumber = Core.FrameCounter;
|
||||||
Core.Slots[slot].QueueTime = TimeSpanType.FromTimeSpan(ARMeilleure.State.ExecutionContext.ElapsedTime);
|
Core.Slots[slot].QueueTime = TimeSpanType.FromTimeSpan(_tickSource.ElapsedTime);
|
||||||
Core.Slots[slot].PresentationTime = TimeSpanType.Zero;
|
Core.Slots[slot].PresentationTime = TimeSpanType.Zero;
|
||||||
|
|
||||||
item.AcquireCalled = Core.Slots[slot].AcquireCalled;
|
item.AcquireCalled = Core.Slots[slot].AcquireCalled;
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
using Ryujinx.HLE.HOS.Kernel.Threading;
|
using Ryujinx.Cpu;
|
||||||
|
|
||||||
namespace Ryujinx.HLE.HOS.Services.Time.Clock
|
namespace Ryujinx.HLE.HOS.Services.Time.Clock
|
||||||
{
|
{
|
||||||
@@ -11,14 +11,14 @@ namespace Ryujinx.HLE.HOS.Services.Time.Clock
|
|||||||
_standardNetworkClockSufficientAccuracy = new TimeSpanType(0);
|
_standardNetworkClockSufficientAccuracy = new TimeSpanType(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool IsStandardNetworkSystemClockAccuracySufficient(KThread thread)
|
public bool IsStandardNetworkSystemClockAccuracySufficient(ITickSource tickSource)
|
||||||
{
|
{
|
||||||
SteadyClockCore steadyClockCore = GetSteadyClockCore();
|
SteadyClockCore steadyClockCore = GetSteadyClockCore();
|
||||||
SteadyClockTimePoint currentTimePoint = steadyClockCore.GetCurrentTimePoint(thread);
|
SteadyClockTimePoint currentTimePoint = steadyClockCore.GetCurrentTimePoint(tickSource);
|
||||||
|
|
||||||
bool isStandardNetworkClockSufficientAccuracy = false;
|
bool isStandardNetworkClockSufficientAccuracy = false;
|
||||||
|
|
||||||
ResultCode result = GetClockContext(thread, out SystemClockContext context);
|
ResultCode result = GetClockContext(tickSource, out SystemClockContext context);
|
||||||
|
|
||||||
if (result == ResultCode.Success && context.SteadyTimePoint.GetSpanBetween(currentTimePoint, out long outSpan) == ResultCode.Success)
|
if (result == ResultCode.Success && context.SteadyTimePoint.GetSpanBetween(currentTimePoint, out long outSpan) == ResultCode.Success)
|
||||||
{
|
{
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
using Ryujinx.HLE.HOS.Kernel.Threading;
|
using Ryujinx.Cpu;
|
||||||
|
|
||||||
namespace Ryujinx.HLE.HOS.Services.Time.Clock
|
namespace Ryujinx.HLE.HOS.Services.Time.Clock
|
||||||
{
|
{
|
||||||
@@ -17,11 +17,11 @@ namespace Ryujinx.HLE.HOS.Services.Time.Clock
|
|||||||
_cachedRawTimePoint = TimeSpanType.Zero;
|
_cachedRawTimePoint = TimeSpanType.Zero;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override SteadyClockTimePoint GetTimePoint(KThread thread)
|
public override SteadyClockTimePoint GetTimePoint(ITickSource tickSource)
|
||||||
{
|
{
|
||||||
SteadyClockTimePoint result = new SteadyClockTimePoint
|
SteadyClockTimePoint result = new SteadyClockTimePoint
|
||||||
{
|
{
|
||||||
TimePoint = GetCurrentRawTimePoint(thread).ToSeconds(),
|
TimePoint = GetCurrentRawTimePoint(tickSource).ToSeconds(),
|
||||||
ClockSourceId = GetClockSourceId()
|
ClockSourceId = GetClockSourceId()
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -48,19 +48,9 @@ namespace Ryujinx.HLE.HOS.Services.Time.Clock
|
|||||||
_internalOffset = internalOffset;
|
_internalOffset = internalOffset;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override TimeSpanType GetCurrentRawTimePoint(KThread thread)
|
public override TimeSpanType GetCurrentRawTimePoint(ITickSource tickSource)
|
||||||
{
|
{
|
||||||
TimeSpanType ticksTimeSpan;
|
TimeSpanType ticksTimeSpan = TimeSpanType.FromTicks(tickSource.Counter, tickSource.Frequency);
|
||||||
|
|
||||||
// As this may be called before the guest code, we support passing a null thread to make this api usable.
|
|
||||||
if (thread == null)
|
|
||||||
{
|
|
||||||
ticksTimeSpan = TimeSpanType.FromSeconds(0);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ticksTimeSpan = TimeSpanType.FromTicks(thread.Context.CntpctEl0, thread.Context.CntfrqEl0);
|
|
||||||
}
|
|
||||||
|
|
||||||
TimeSpanType rawTimePoint = new TimeSpanType(_setupValue.NanoSeconds + ticksTimeSpan.NanoSeconds);
|
TimeSpanType rawTimePoint = new TimeSpanType(_setupValue.NanoSeconds + ticksTimeSpan.NanoSeconds);
|
||||||
|
|
||||||
|
@@ -1,4 +1,5 @@
|
|||||||
using Ryujinx.HLE.HOS.Kernel.Threading;
|
using Ryujinx.Cpu;
|
||||||
|
using Ryujinx.HLE.HOS.Kernel.Threading;
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace Ryujinx.HLE.HOS.Services.Time.Clock
|
namespace Ryujinx.HLE.HOS.Services.Time.Clock
|
||||||
@@ -26,15 +27,15 @@ namespace Ryujinx.HLE.HOS.Services.Time.Clock
|
|||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override ResultCode GetClockContext(KThread thread, out SystemClockContext context)
|
public override ResultCode GetClockContext(ITickSource tickSource, out SystemClockContext context)
|
||||||
{
|
{
|
||||||
ResultCode result = ApplyAutomaticCorrection(thread, false);
|
ResultCode result = ApplyAutomaticCorrection(tickSource, false);
|
||||||
|
|
||||||
context = new SystemClockContext();
|
context = new SystemClockContext();
|
||||||
|
|
||||||
if (result == ResultCode.Success)
|
if (result == ResultCode.Success)
|
||||||
{
|
{
|
||||||
return _localSystemClockCore.GetClockContext(thread, out context);
|
return _localSystemClockCore.GetClockContext(tickSource, out context);
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
@@ -45,13 +46,13 @@ namespace Ryujinx.HLE.HOS.Services.Time.Clock
|
|||||||
return ResultCode.NotImplemented;
|
return ResultCode.NotImplemented;
|
||||||
}
|
}
|
||||||
|
|
||||||
private ResultCode ApplyAutomaticCorrection(KThread thread, bool autoCorrectionEnabled)
|
private ResultCode ApplyAutomaticCorrection(ITickSource tickSource, bool autoCorrectionEnabled)
|
||||||
{
|
{
|
||||||
ResultCode result = ResultCode.Success;
|
ResultCode result = ResultCode.Success;
|
||||||
|
|
||||||
if (_autoCorrectionEnabled != autoCorrectionEnabled && _networkSystemClockCore.IsClockSetup(thread))
|
if (_autoCorrectionEnabled != autoCorrectionEnabled && _networkSystemClockCore.IsClockSetup(tickSource))
|
||||||
{
|
{
|
||||||
result = _networkSystemClockCore.GetClockContext(thread, out SystemClockContext context);
|
result = _networkSystemClockCore.GetClockContext(tickSource, out SystemClockContext context);
|
||||||
|
|
||||||
if (result == ResultCode.Success)
|
if (result == ResultCode.Success)
|
||||||
{
|
{
|
||||||
@@ -67,9 +68,9 @@ namespace Ryujinx.HLE.HOS.Services.Time.Clock
|
|||||||
_autoCorrectionEvent = new KEvent(system.KernelContext);
|
_autoCorrectionEvent = new KEvent(system.KernelContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ResultCode SetAutomaticCorrectionEnabled(KThread thread, bool autoCorrectionEnabled)
|
public ResultCode SetAutomaticCorrectionEnabled(ITickSource tickSource, bool autoCorrectionEnabled)
|
||||||
{
|
{
|
||||||
ResultCode result = ApplyAutomaticCorrection(thread, autoCorrectionEnabled);
|
ResultCode result = ApplyAutomaticCorrection(tickSource, autoCorrectionEnabled);
|
||||||
|
|
||||||
if (result == ResultCode.Success)
|
if (result == ResultCode.Success)
|
||||||
{
|
{
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
using Ryujinx.HLE.HOS.Kernel.Threading;
|
using Ryujinx.Cpu;
|
||||||
using Ryujinx.HLE.Utilities;
|
using Ryujinx.HLE.Utilities;
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
@@ -63,21 +63,21 @@ namespace Ryujinx.HLE.HOS.Services.Time.Clock
|
|||||||
|
|
||||||
public virtual void SetInternalOffset(TimeSpanType internalOffset) {}
|
public virtual void SetInternalOffset(TimeSpanType internalOffset) {}
|
||||||
|
|
||||||
public virtual SteadyClockTimePoint GetTimePoint(KThread thread)
|
public virtual SteadyClockTimePoint GetTimePoint(ITickSource tickSource)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual TimeSpanType GetCurrentRawTimePoint(KThread thread)
|
public virtual TimeSpanType GetCurrentRawTimePoint(ITickSource tickSource)
|
||||||
{
|
{
|
||||||
SteadyClockTimePoint timePoint = GetTimePoint(thread);
|
SteadyClockTimePoint timePoint = GetTimePoint(tickSource);
|
||||||
|
|
||||||
return TimeSpanType.FromSeconds(timePoint.TimePoint);
|
return TimeSpanType.FromSeconds(timePoint.TimePoint);
|
||||||
}
|
}
|
||||||
|
|
||||||
public SteadyClockTimePoint GetCurrentTimePoint(KThread thread)
|
public SteadyClockTimePoint GetCurrentTimePoint(ITickSource tickSource)
|
||||||
{
|
{
|
||||||
SteadyClockTimePoint result = GetTimePoint(thread);
|
SteadyClockTimePoint result = GetTimePoint(tickSource);
|
||||||
|
|
||||||
result.TimePoint += GetTestOffset().ToSeconds();
|
result.TimePoint += GetTestOffset().ToSeconds();
|
||||||
result.TimePoint += GetInternalOffset().ToSeconds();
|
result.TimePoint += GetInternalOffset().ToSeconds();
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
using System;
|
using Ryujinx.Cpu;
|
||||||
using Ryujinx.HLE.HOS.Kernel.Threading;
|
using Ryujinx.HLE.HOS.Kernel.Threading;
|
||||||
|
|
||||||
namespace Ryujinx.HLE.HOS.Services.Time.Clock
|
namespace Ryujinx.HLE.HOS.Services.Time.Clock
|
||||||
@@ -25,13 +25,13 @@ namespace Ryujinx.HLE.HOS.Services.Time.Clock
|
|||||||
return _steadyClockCore;
|
return _steadyClockCore;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ResultCode GetCurrentTime(KThread thread, out long posixTime)
|
public ResultCode GetCurrentTime(ITickSource tickSource, out long posixTime)
|
||||||
{
|
{
|
||||||
posixTime = 0;
|
posixTime = 0;
|
||||||
|
|
||||||
SteadyClockTimePoint currentTimePoint = _steadyClockCore.GetCurrentTimePoint(thread);
|
SteadyClockTimePoint currentTimePoint = _steadyClockCore.GetCurrentTimePoint(tickSource);
|
||||||
|
|
||||||
ResultCode result = GetClockContext(thread, out SystemClockContext clockContext);
|
ResultCode result = GetClockContext(tickSource, out SystemClockContext clockContext);
|
||||||
|
|
||||||
if (result == ResultCode.Success)
|
if (result == ResultCode.Success)
|
||||||
{
|
{
|
||||||
@@ -48,9 +48,9 @@ namespace Ryujinx.HLE.HOS.Services.Time.Clock
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ResultCode SetCurrentTime(KThread thread, long posixTime)
|
public ResultCode SetCurrentTime(ITickSource tickSource, long posixTime)
|
||||||
{
|
{
|
||||||
SteadyClockTimePoint currentTimePoint = _steadyClockCore.GetCurrentTimePoint(thread);
|
SteadyClockTimePoint currentTimePoint = _steadyClockCore.GetCurrentTimePoint(tickSource);
|
||||||
|
|
||||||
SystemClockContext clockContext = new SystemClockContext()
|
SystemClockContext clockContext = new SystemClockContext()
|
||||||
{
|
{
|
||||||
@@ -68,7 +68,7 @@ namespace Ryujinx.HLE.HOS.Services.Time.Clock
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual ResultCode GetClockContext(KThread thread, out SystemClockContext context)
|
public virtual ResultCode GetClockContext(ITickSource tickSource, out SystemClockContext context)
|
||||||
{
|
{
|
||||||
context = _context;
|
context = _context;
|
||||||
|
|
||||||
@@ -127,13 +127,13 @@ namespace Ryujinx.HLE.HOS.Services.Time.Clock
|
|||||||
_isInitialized = true;
|
_isInitialized = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool IsClockSetup(KThread thread)
|
public bool IsClockSetup(ITickSource tickSource)
|
||||||
{
|
{
|
||||||
ResultCode result = GetClockContext(thread, out SystemClockContext context);
|
ResultCode result = GetClockContext(tickSource, out SystemClockContext context);
|
||||||
|
|
||||||
if (result == ResultCode.Success)
|
if (result == ResultCode.Success)
|
||||||
{
|
{
|
||||||
SteadyClockTimePoint steadyClockTimePoint = _steadyClockCore.GetCurrentTimePoint(thread);
|
SteadyClockTimePoint steadyClockTimePoint = _steadyClockCore.GetCurrentTimePoint(tickSource);
|
||||||
|
|
||||||
return steadyClockTimePoint.ClockSourceId == context.SteadyTimePoint.ClockSourceId;
|
return steadyClockTimePoint.ClockSourceId == context.SteadyTimePoint.ClockSourceId;
|
||||||
}
|
}
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
using Ryujinx.HLE.HOS.Kernel.Threading;
|
using Ryujinx.Cpu;
|
||||||
|
|
||||||
namespace Ryujinx.HLE.HOS.Services.Time.Clock
|
namespace Ryujinx.HLE.HOS.Services.Time.Clock
|
||||||
{
|
{
|
||||||
@@ -6,7 +6,7 @@ namespace Ryujinx.HLE.HOS.Services.Time.Clock
|
|||||||
{
|
{
|
||||||
public TickBasedSteadyClockCore() {}
|
public TickBasedSteadyClockCore() {}
|
||||||
|
|
||||||
public override SteadyClockTimePoint GetTimePoint(KThread thread)
|
public override SteadyClockTimePoint GetTimePoint(ITickSource tickSource)
|
||||||
{
|
{
|
||||||
SteadyClockTimePoint result = new SteadyClockTimePoint
|
SteadyClockTimePoint result = new SteadyClockTimePoint
|
||||||
{
|
{
|
||||||
@@ -14,17 +14,7 @@ namespace Ryujinx.HLE.HOS.Services.Time.Clock
|
|||||||
ClockSourceId = GetClockSourceId()
|
ClockSourceId = GetClockSourceId()
|
||||||
};
|
};
|
||||||
|
|
||||||
TimeSpanType ticksTimeSpan;
|
TimeSpanType ticksTimeSpan = TimeSpanType.FromTicks(tickSource.Counter, tickSource.Frequency);
|
||||||
|
|
||||||
// As this may be called before the guest code, we support passing a null thread to make this api usable.
|
|
||||||
if (thread == null)
|
|
||||||
{
|
|
||||||
ticksTimeSpan = TimeSpanType.FromSeconds(0);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ticksTimeSpan = TimeSpanType.FromTicks(thread.Context.CntpctEl0, thread.Context.CntfrqEl0);
|
|
||||||
}
|
|
||||||
|
|
||||||
result.TimePoint = ticksTimeSpan.ToSeconds();
|
result.TimePoint = ticksTimeSpan.ToSeconds();
|
||||||
|
|
||||||
|
@@ -2,7 +2,6 @@ using Ryujinx.Common;
|
|||||||
using Ryujinx.Cpu;
|
using Ryujinx.Cpu;
|
||||||
using Ryujinx.HLE.HOS.Ipc;
|
using Ryujinx.HLE.HOS.Ipc;
|
||||||
using Ryujinx.HLE.HOS.Kernel.Common;
|
using Ryujinx.HLE.HOS.Kernel.Common;
|
||||||
using Ryujinx.HLE.HOS.Kernel.Threading;
|
|
||||||
using Ryujinx.HLE.HOS.Services.Time.Clock;
|
using Ryujinx.HLE.HOS.Services.Time.Clock;
|
||||||
using Ryujinx.HLE.HOS.Services.Time.StaticService;
|
using Ryujinx.HLE.HOS.Services.Time.StaticService;
|
||||||
using Ryujinx.HLE.HOS.Services.Time.TimeZone;
|
using Ryujinx.HLE.HOS.Services.Time.TimeZone;
|
||||||
@@ -163,13 +162,15 @@ namespace Ryujinx.HLE.HOS.Services.Time
|
|||||||
|
|
||||||
bool autoCorrectionEnabled = context.RequestData.ReadBoolean();
|
bool autoCorrectionEnabled = context.RequestData.ReadBoolean();
|
||||||
|
|
||||||
ResultCode result = userClock.SetAutomaticCorrectionEnabled(context.Thread, autoCorrectionEnabled);
|
ITickSource tickSource = context.Device.System.TickSource;
|
||||||
|
|
||||||
|
ResultCode result = userClock.SetAutomaticCorrectionEnabled(tickSource, autoCorrectionEnabled);
|
||||||
|
|
||||||
if (result == ResultCode.Success)
|
if (result == ResultCode.Success)
|
||||||
{
|
{
|
||||||
_timeManager.SharedMemory.SetAutomaticCorrectionEnabled(autoCorrectionEnabled);
|
_timeManager.SharedMemory.SetAutomaticCorrectionEnabled(autoCorrectionEnabled);
|
||||||
|
|
||||||
SteadyClockTimePoint currentTimePoint = userClock.GetSteadyClockCore().GetCurrentTimePoint(context.Thread);
|
SteadyClockTimePoint currentTimePoint = userClock.GetSteadyClockCore().GetCurrentTimePoint(tickSource);
|
||||||
|
|
||||||
userClock.SetAutomaticCorrectionUpdatedTime(currentTimePoint);
|
userClock.SetAutomaticCorrectionUpdatedTime(currentTimePoint);
|
||||||
userClock.SignalAutomaticCorrectionEvent();
|
userClock.SignalAutomaticCorrectionEvent();
|
||||||
@@ -190,7 +191,9 @@ namespace Ryujinx.HLE.HOS.Services.Time
|
|||||||
// IsStandardNetworkSystemClockAccuracySufficient() -> bool
|
// IsStandardNetworkSystemClockAccuracySufficient() -> bool
|
||||||
public ResultCode IsStandardNetworkSystemClockAccuracySufficient(ServiceCtx context)
|
public ResultCode IsStandardNetworkSystemClockAccuracySufficient(ServiceCtx context)
|
||||||
{
|
{
|
||||||
context.ResponseData.Write(_timeManager.StandardNetworkSystemClock.IsStandardNetworkSystemClockAccuracySufficient(context.Thread));
|
ITickSource tickSource = context.Device.System.TickSource;
|
||||||
|
|
||||||
|
context.ResponseData.Write(_timeManager.StandardNetworkSystemClock.IsStandardNetworkSystemClockAccuracySufficient(tickSource));
|
||||||
|
|
||||||
return ResultCode.Success;
|
return ResultCode.Success;
|
||||||
}
|
}
|
||||||
@@ -222,14 +225,16 @@ namespace Ryujinx.HLE.HOS.Services.Time
|
|||||||
return ResultCode.UninitializedClock;
|
return ResultCode.UninitializedClock;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ITickSource tickSource = context.Device.System.TickSource;
|
||||||
|
|
||||||
SystemClockContext otherContext = context.RequestData.ReadStruct<SystemClockContext>();
|
SystemClockContext otherContext = context.RequestData.ReadStruct<SystemClockContext>();
|
||||||
SteadyClockTimePoint currentTimePoint = steadyClock.GetCurrentTimePoint(context.Thread);
|
SteadyClockTimePoint currentTimePoint = steadyClock.GetCurrentTimePoint(tickSource);
|
||||||
|
|
||||||
ResultCode result = ResultCode.TimeMismatch;
|
ResultCode result = ResultCode.TimeMismatch;
|
||||||
|
|
||||||
if (currentTimePoint.ClockSourceId == otherContext.SteadyTimePoint.ClockSourceId)
|
if (currentTimePoint.ClockSourceId == otherContext.SteadyTimePoint.ClockSourceId)
|
||||||
{
|
{
|
||||||
TimeSpanType ticksTimeSpan = TimeSpanType.FromTicks(context.Thread.Context.CntpctEl0, context.Thread.Context.CntfrqEl0);
|
TimeSpanType ticksTimeSpan = TimeSpanType.FromTicks(tickSource.Counter, tickSource.Frequency);
|
||||||
long baseTimePoint = otherContext.Offset + currentTimePoint.TimePoint - ticksTimeSpan.ToSeconds();
|
long baseTimePoint = otherContext.Offset + currentTimePoint.TimePoint - ticksTimeSpan.ToSeconds();
|
||||||
|
|
||||||
context.ResponseData.Write(baseTimePoint);
|
context.ResponseData.Write(baseTimePoint);
|
||||||
@@ -248,15 +253,17 @@ namespace Ryujinx.HLE.HOS.Services.Time
|
|||||||
|
|
||||||
context.Response.PtrBuff[0] = context.Response.PtrBuff[0].WithSize((uint)Marshal.SizeOf<ClockSnapshot>());
|
context.Response.PtrBuff[0] = context.Response.PtrBuff[0].WithSize((uint)Marshal.SizeOf<ClockSnapshot>());
|
||||||
|
|
||||||
ResultCode result = _timeManager.StandardUserSystemClock.GetClockContext(context.Thread, out SystemClockContext userContext);
|
ITickSource tickSource = context.Device.System.TickSource;
|
||||||
|
|
||||||
|
ResultCode result = _timeManager.StandardUserSystemClock.GetClockContext(tickSource, out SystemClockContext userContext);
|
||||||
|
|
||||||
if (result == ResultCode.Success)
|
if (result == ResultCode.Success)
|
||||||
{
|
{
|
||||||
result = _timeManager.StandardNetworkSystemClock.GetClockContext(context.Thread, out SystemClockContext networkContext);
|
result = _timeManager.StandardNetworkSystemClock.GetClockContext(tickSource, out SystemClockContext networkContext);
|
||||||
|
|
||||||
if (result == ResultCode.Success)
|
if (result == ResultCode.Success)
|
||||||
{
|
{
|
||||||
result = GetClockSnapshotFromSystemClockContextInternal(context.Thread, userContext, networkContext, type, out ClockSnapshot clockSnapshot);
|
result = GetClockSnapshotFromSystemClockContextInternal(tickSource, userContext, networkContext, type, out ClockSnapshot clockSnapshot);
|
||||||
|
|
||||||
if (result == ResultCode.Success)
|
if (result == ResultCode.Success)
|
||||||
{
|
{
|
||||||
@@ -281,7 +288,9 @@ namespace Ryujinx.HLE.HOS.Services.Time
|
|||||||
SystemClockContext userContext = context.RequestData.ReadStruct<SystemClockContext>();
|
SystemClockContext userContext = context.RequestData.ReadStruct<SystemClockContext>();
|
||||||
SystemClockContext networkContext = context.RequestData.ReadStruct<SystemClockContext>();
|
SystemClockContext networkContext = context.RequestData.ReadStruct<SystemClockContext>();
|
||||||
|
|
||||||
ResultCode result = GetClockSnapshotFromSystemClockContextInternal(context.Thread, userContext, networkContext, type, out ClockSnapshot clockSnapshot);
|
ITickSource tickSource = context.Device.System.TickSource;
|
||||||
|
|
||||||
|
ResultCode result = GetClockSnapshotFromSystemClockContextInternal(tickSource, userContext, networkContext, type, out ClockSnapshot clockSnapshot);
|
||||||
|
|
||||||
if (result == ResultCode.Success)
|
if (result == ResultCode.Success)
|
||||||
{
|
{
|
||||||
@@ -344,12 +353,12 @@ namespace Ryujinx.HLE.HOS.Services.Time
|
|||||||
return resultCode;
|
return resultCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
private ResultCode GetClockSnapshotFromSystemClockContextInternal(KThread thread, SystemClockContext userContext, SystemClockContext networkContext, byte type, out ClockSnapshot clockSnapshot)
|
private ResultCode GetClockSnapshotFromSystemClockContextInternal(ITickSource tickSource, SystemClockContext userContext, SystemClockContext networkContext, byte type, out ClockSnapshot clockSnapshot)
|
||||||
{
|
{
|
||||||
clockSnapshot = new ClockSnapshot();
|
clockSnapshot = new ClockSnapshot();
|
||||||
|
|
||||||
SteadyClockCore steadyClockCore = _timeManager.StandardSteadyClock;
|
SteadyClockCore steadyClockCore = _timeManager.StandardSteadyClock;
|
||||||
SteadyClockTimePoint currentTimePoint = steadyClockCore.GetCurrentTimePoint(thread);
|
SteadyClockTimePoint currentTimePoint = steadyClockCore.GetCurrentTimePoint(tickSource);
|
||||||
|
|
||||||
clockSnapshot.IsAutomaticCorrectionEnabled = _timeManager.StandardUserSystemClock.IsAutomaticCorrectionEnabled();
|
clockSnapshot.IsAutomaticCorrectionEnabled = _timeManager.StandardUserSystemClock.IsAutomaticCorrectionEnabled();
|
||||||
clockSnapshot.UserContext = userContext;
|
clockSnapshot.UserContext = userContext;
|
||||||
|
@@ -1,4 +1,5 @@
|
|||||||
using Ryujinx.Common;
|
using Ryujinx.Common;
|
||||||
|
using Ryujinx.Cpu;
|
||||||
using Ryujinx.HLE.Exceptions;
|
using Ryujinx.HLE.Exceptions;
|
||||||
using Ryujinx.HLE.HOS.Ipc;
|
using Ryujinx.HLE.HOS.Ipc;
|
||||||
using Ryujinx.HLE.HOS.Kernel.Common;
|
using Ryujinx.HLE.HOS.Kernel.Common;
|
||||||
@@ -6,7 +7,6 @@ using Ryujinx.HLE.HOS.Services.Time.Clock;
|
|||||||
using Ryujinx.HLE.Utilities;
|
using Ryujinx.HLE.Utilities;
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace Ryujinx.HLE.HOS.Services.Time
|
namespace Ryujinx.HLE.HOS.Services.Time
|
||||||
{
|
{
|
||||||
@@ -68,7 +68,9 @@ namespace Ryujinx.HLE.HOS.Services.Time
|
|||||||
TimeSpanType testOffset = context.RequestData.ReadStruct<TimeSpanType>();
|
TimeSpanType testOffset = context.RequestData.ReadStruct<TimeSpanType>();
|
||||||
bool isRtcResetDetected = context.RequestData.ReadBoolean();
|
bool isRtcResetDetected = context.RequestData.ReadBoolean();
|
||||||
|
|
||||||
_timeManager.SetupStandardSteadyClock(context.Thread, clockSourceId, setupValue, internalOffset, testOffset, isRtcResetDetected);
|
ITickSource tickSource = context.Device.System.TickSource;
|
||||||
|
|
||||||
|
_timeManager.SetupStandardSteadyClock(tickSource, clockSourceId, setupValue, internalOffset, testOffset, isRtcResetDetected);
|
||||||
|
|
||||||
return ResultCode.Success;
|
return ResultCode.Success;
|
||||||
}
|
}
|
||||||
@@ -80,7 +82,9 @@ namespace Ryujinx.HLE.HOS.Services.Time
|
|||||||
SystemClockContext clockContext = context.RequestData.ReadStruct<SystemClockContext>();
|
SystemClockContext clockContext = context.RequestData.ReadStruct<SystemClockContext>();
|
||||||
long posixTime = context.RequestData.ReadInt64();
|
long posixTime = context.RequestData.ReadInt64();
|
||||||
|
|
||||||
_timeManager.SetupStandardLocalSystemClock(context.Thread, clockContext, posixTime);
|
ITickSource tickSource = context.Device.System.TickSource;
|
||||||
|
|
||||||
|
_timeManager.SetupStandardLocalSystemClock(tickSource, clockContext, posixTime);
|
||||||
|
|
||||||
return ResultCode.Success;
|
return ResultCode.Success;
|
||||||
}
|
}
|
||||||
@@ -107,7 +111,9 @@ namespace Ryujinx.HLE.HOS.Services.Time
|
|||||||
|
|
||||||
SteadyClockTimePoint steadyClockTimePoint = context.RequestData.ReadStruct<SteadyClockTimePoint>();
|
SteadyClockTimePoint steadyClockTimePoint = context.RequestData.ReadStruct<SteadyClockTimePoint>();
|
||||||
|
|
||||||
_timeManager.SetupStandardUserSystemClock(context.Thread, isAutomaticCorrectionEnabled, steadyClockTimePoint);
|
ITickSource tickSource = context.Device.System.TickSource;
|
||||||
|
|
||||||
|
_timeManager.SetupStandardUserSystemClock(tickSource, isAutomaticCorrectionEnabled, steadyClockTimePoint);
|
||||||
|
|
||||||
return ResultCode.Success;
|
return ResultCode.Success;
|
||||||
}
|
}
|
||||||
@@ -191,7 +197,9 @@ namespace Ryujinx.HLE.HOS.Services.Time
|
|||||||
{
|
{
|
||||||
TimeSpanType rtcOffset = context.RequestData.ReadStruct<TimeSpanType>();
|
TimeSpanType rtcOffset = context.RequestData.ReadStruct<TimeSpanType>();
|
||||||
|
|
||||||
_timeManager.SetStandardSteadyClockRtcOffset(context.Thread, rtcOffset);
|
ITickSource tickSource = context.Device.System.TickSource;
|
||||||
|
|
||||||
|
_timeManager.SetStandardSteadyClockRtcOffset(tickSource, rtcOffset);
|
||||||
|
|
||||||
return ResultCode.Success;
|
return ResultCode.Success;
|
||||||
}
|
}
|
||||||
|
@@ -1,4 +1,5 @@
|
|||||||
using Ryujinx.Common;
|
using Ryujinx.Common;
|
||||||
|
using Ryujinx.Cpu;
|
||||||
using Ryujinx.HLE.HOS.Services.Time.Clock;
|
using Ryujinx.HLE.HOS.Services.Time.Clock;
|
||||||
|
|
||||||
namespace Ryujinx.HLE.HOS.Services.Time.StaticService
|
namespace Ryujinx.HLE.HOS.Services.Time.StaticService
|
||||||
@@ -25,7 +26,9 @@ namespace Ryujinx.HLE.HOS.Services.Time.StaticService
|
|||||||
return ResultCode.UninitializedClock;
|
return ResultCode.UninitializedClock;
|
||||||
}
|
}
|
||||||
|
|
||||||
SteadyClockTimePoint currentTimePoint = _steadyClock.GetCurrentTimePoint(context.Thread);
|
ITickSource tickSource = context.Device.System.TickSource;
|
||||||
|
|
||||||
|
SteadyClockTimePoint currentTimePoint = _steadyClock.GetCurrentTimePoint(tickSource);
|
||||||
|
|
||||||
context.ResponseData.WriteStruct(currentTimePoint);
|
context.ResponseData.WriteStruct(currentTimePoint);
|
||||||
|
|
||||||
|
@@ -1,4 +1,5 @@
|
|||||||
using Ryujinx.Common;
|
using Ryujinx.Common;
|
||||||
|
using Ryujinx.Cpu;
|
||||||
using Ryujinx.HLE.HOS.Ipc;
|
using Ryujinx.HLE.HOS.Ipc;
|
||||||
using Ryujinx.HLE.HOS.Kernel.Common;
|
using Ryujinx.HLE.HOS.Kernel.Common;
|
||||||
using Ryujinx.HLE.HOS.Kernel.Threading;
|
using Ryujinx.HLE.HOS.Kernel.Threading;
|
||||||
@@ -31,7 +32,9 @@ namespace Ryujinx.HLE.HOS.Services.Time.StaticService
|
|||||||
return ResultCode.UninitializedClock;
|
return ResultCode.UninitializedClock;
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultCode result = _clockCore.GetCurrentTime(context.Thread, out long posixTime);
|
ITickSource tickSource = context.Device.System.TickSource;
|
||||||
|
|
||||||
|
ResultCode result = _clockCore.GetCurrentTime(tickSource, out long posixTime);
|
||||||
|
|
||||||
if (result == ResultCode.Success)
|
if (result == ResultCode.Success)
|
||||||
{
|
{
|
||||||
@@ -57,7 +60,9 @@ namespace Ryujinx.HLE.HOS.Services.Time.StaticService
|
|||||||
|
|
||||||
long posixTime = context.RequestData.ReadInt64();
|
long posixTime = context.RequestData.ReadInt64();
|
||||||
|
|
||||||
return _clockCore.SetCurrentTime(context.Thread, posixTime);
|
ITickSource tickSource = context.Device.System.TickSource;
|
||||||
|
|
||||||
|
return _clockCore.SetCurrentTime(tickSource, posixTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
[CommandHipc(2)]
|
[CommandHipc(2)]
|
||||||
@@ -69,7 +74,9 @@ namespace Ryujinx.HLE.HOS.Services.Time.StaticService
|
|||||||
return ResultCode.UninitializedClock;
|
return ResultCode.UninitializedClock;
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultCode result = _clockCore.GetClockContext(context.Thread, out SystemClockContext clockContext);
|
ITickSource tickSource = context.Device.System.TickSource;
|
||||||
|
|
||||||
|
ResultCode result = _clockCore.GetClockContext(tickSource, out SystemClockContext clockContext);
|
||||||
|
|
||||||
if (result == ResultCode.Success)
|
if (result == ResultCode.Success)
|
||||||
{
|
{
|
||||||
|
@@ -7,7 +7,6 @@ using Ryujinx.HLE.Utilities;
|
|||||||
using System;
|
using System;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace Ryujinx.HLE.HOS.Services.Time.StaticService
|
namespace Ryujinx.HLE.HOS.Services.Time.StaticService
|
||||||
{
|
{
|
||||||
@@ -44,7 +43,7 @@ namespace Ryujinx.HLE.HOS.Services.Time.StaticService
|
|||||||
{
|
{
|
||||||
return ResultCode.PermissionDenied;
|
return ResultCode.PermissionDenied;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ResultCode.NotImplemented;
|
return ResultCode.NotImplemented;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,11 +1,10 @@
|
|||||||
using System;
|
using Ryujinx.Cpu;
|
||||||
using System.IO;
|
|
||||||
using Ryujinx.HLE.Exceptions;
|
using Ryujinx.HLE.Exceptions;
|
||||||
using Ryujinx.HLE.HOS.Kernel.Memory;
|
using Ryujinx.HLE.HOS.Kernel.Memory;
|
||||||
using Ryujinx.HLE.HOS.Kernel.Threading;
|
|
||||||
using Ryujinx.HLE.HOS.Services.Time.Clock;
|
using Ryujinx.HLE.HOS.Services.Time.Clock;
|
||||||
using Ryujinx.HLE.HOS.Services.Time.TimeZone;
|
using Ryujinx.HLE.HOS.Services.Time.TimeZone;
|
||||||
using Ryujinx.HLE.Utilities;
|
using Ryujinx.HLE.Utilities;
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
namespace Ryujinx.HLE.HOS.Services.Time
|
namespace Ryujinx.HLE.HOS.Services.Time
|
||||||
{
|
{
|
||||||
@@ -68,14 +67,13 @@ namespace Ryujinx.HLE.HOS.Services.Time
|
|||||||
TimeZone.Initialize(this, device);
|
TimeZone.Initialize(this, device);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void SetupStandardSteadyClock(ITickSource tickSource, UInt128 clockSourceId, TimeSpanType setupValue, TimeSpanType internalOffset, TimeSpanType testOffset, bool isRtcResetDetected)
|
||||||
public void SetupStandardSteadyClock(KThread thread, UInt128 clockSourceId, TimeSpanType setupValue, TimeSpanType internalOffset, TimeSpanType testOffset, bool isRtcResetDetected)
|
|
||||||
{
|
{
|
||||||
SetupInternalStandardSteadyClock(clockSourceId, setupValue, internalOffset, testOffset, isRtcResetDetected);
|
SetupInternalStandardSteadyClock(clockSourceId, setupValue, internalOffset, testOffset, isRtcResetDetected);
|
||||||
|
|
||||||
TimeSpanType currentTimePoint = StandardSteadyClock.GetCurrentRawTimePoint(thread);
|
TimeSpanType currentTimePoint = StandardSteadyClock.GetCurrentRawTimePoint(tickSource);
|
||||||
|
|
||||||
SharedMemory.SetupStandardSteadyClock(thread, clockSourceId, currentTimePoint);
|
SharedMemory.SetupStandardSteadyClock(tickSource, clockSourceId, currentTimePoint);
|
||||||
|
|
||||||
// TODO: propagate IPC late binding of "time:s" and "time:p"
|
// TODO: propagate IPC late binding of "time:s" and "time:p"
|
||||||
}
|
}
|
||||||
@@ -97,18 +95,18 @@ namespace Ryujinx.HLE.HOS.Services.Time
|
|||||||
// TODO: propagate IPC late binding of "time:s" and "time:p"
|
// TODO: propagate IPC late binding of "time:s" and "time:p"
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetupStandardLocalSystemClock(KThread thread, SystemClockContext clockContext, long posixTime)
|
public void SetupStandardLocalSystemClock(ITickSource tickSource, SystemClockContext clockContext, long posixTime)
|
||||||
{
|
{
|
||||||
StandardLocalSystemClock.SetUpdateCallbackInstance(LocalClockContextWriter);
|
StandardLocalSystemClock.SetUpdateCallbackInstance(LocalClockContextWriter);
|
||||||
|
|
||||||
SteadyClockTimePoint currentTimePoint = StandardLocalSystemClock.GetSteadyClockCore().GetCurrentTimePoint(thread);
|
SteadyClockTimePoint currentTimePoint = StandardLocalSystemClock.GetSteadyClockCore().GetCurrentTimePoint(tickSource);
|
||||||
if (currentTimePoint.ClockSourceId == clockContext.SteadyTimePoint.ClockSourceId)
|
if (currentTimePoint.ClockSourceId == clockContext.SteadyTimePoint.ClockSourceId)
|
||||||
{
|
{
|
||||||
StandardLocalSystemClock.SetSystemClockContext(clockContext);
|
StandardLocalSystemClock.SetSystemClockContext(clockContext);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (StandardLocalSystemClock.SetCurrentTime(thread, posixTime) != ResultCode.Success)
|
if (StandardLocalSystemClock.SetCurrentTime(tickSource, posixTime) != ResultCode.Success)
|
||||||
{
|
{
|
||||||
throw new InternalServiceException("Cannot set current local time");
|
throw new InternalServiceException("Cannot set current local time");
|
||||||
}
|
}
|
||||||
@@ -157,9 +155,9 @@ namespace Ryujinx.HLE.HOS.Services.Time
|
|||||||
// TODO: propagate IPC late binding of "time:s" and "time:p"
|
// TODO: propagate IPC late binding of "time:s" and "time:p"
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetupStandardUserSystemClock(KThread thread, bool isAutomaticCorrectionEnabled, SteadyClockTimePoint steadyClockTimePoint)
|
public void SetupStandardUserSystemClock(ITickSource tickSource, bool isAutomaticCorrectionEnabled, SteadyClockTimePoint steadyClockTimePoint)
|
||||||
{
|
{
|
||||||
if (StandardUserSystemClock.SetAutomaticCorrectionEnabled(thread, isAutomaticCorrectionEnabled) != ResultCode.Success)
|
if (StandardUserSystemClock.SetAutomaticCorrectionEnabled(tickSource, isAutomaticCorrectionEnabled) != ResultCode.Success)
|
||||||
{
|
{
|
||||||
throw new InternalServiceException("Cannot set automatic user time correction state");
|
throw new InternalServiceException("Cannot set automatic user time correction state");
|
||||||
}
|
}
|
||||||
@@ -172,13 +170,13 @@ namespace Ryujinx.HLE.HOS.Services.Time
|
|||||||
// TODO: propagate IPC late binding of "time:s" and "time:p"
|
// TODO: propagate IPC late binding of "time:s" and "time:p"
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetStandardSteadyClockRtcOffset(KThread thread, TimeSpanType rtcOffset)
|
public void SetStandardSteadyClockRtcOffset(ITickSource tickSource, TimeSpanType rtcOffset)
|
||||||
{
|
{
|
||||||
StandardSteadyClock.SetSetupValue(rtcOffset);
|
StandardSteadyClock.SetSetupValue(rtcOffset);
|
||||||
|
|
||||||
TimeSpanType currentTimePoint = StandardSteadyClock.GetCurrentRawTimePoint(thread);
|
TimeSpanType currentTimePoint = StandardSteadyClock.GetCurrentRawTimePoint(tickSource);
|
||||||
|
|
||||||
SharedMemory.SetSteadyClockRawTimePoint(thread, currentTimePoint);
|
SharedMemory.SetSteadyClockRawTimePoint(tickSource, currentTimePoint);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,12 +1,11 @@
|
|||||||
using System;
|
using Ryujinx.Cpu;
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
using System.Threading;
|
|
||||||
using Ryujinx.HLE.HOS.Kernel.Memory;
|
using Ryujinx.HLE.HOS.Kernel.Memory;
|
||||||
using Ryujinx.HLE.HOS.Kernel.Threading;
|
|
||||||
using Ryujinx.HLE.HOS.Services.Time.Clock;
|
using Ryujinx.HLE.HOS.Services.Time.Clock;
|
||||||
using Ryujinx.HLE.HOS.Services.Time.Types;
|
using Ryujinx.HLE.HOS.Services.Time.Types;
|
||||||
using Ryujinx.HLE.Utilities;
|
using Ryujinx.HLE.Utilities;
|
||||||
|
using System;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Threading;
|
||||||
|
|
||||||
namespace Ryujinx.HLE.HOS.Services.Time
|
namespace Ryujinx.HLE.HOS.Services.Time
|
||||||
{
|
{
|
||||||
@@ -38,19 +37,9 @@ namespace Ryujinx.HLE.HOS.Services.Time
|
|||||||
return _sharedMemory;
|
return _sharedMemory;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetupStandardSteadyClock(KThread thread, UInt128 clockSourceId, TimeSpanType currentTimePoint)
|
public void SetupStandardSteadyClock(ITickSource tickSource, UInt128 clockSourceId, TimeSpanType currentTimePoint)
|
||||||
{
|
{
|
||||||
TimeSpanType ticksTimeSpan;
|
TimeSpanType ticksTimeSpan = TimeSpanType.FromTicks(tickSource.Counter, tickSource.Frequency);
|
||||||
|
|
||||||
// As this may be called before the guest code, we support passing a null thread to make this api usable.
|
|
||||||
if (thread == null)
|
|
||||||
{
|
|
||||||
ticksTimeSpan = TimeSpanType.FromSeconds(0);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ticksTimeSpan = TimeSpanType.FromTicks(thread.Context.CntpctEl0, thread.Context.CntfrqEl0);
|
|
||||||
}
|
|
||||||
|
|
||||||
SteadyClockContext context = new SteadyClockContext
|
SteadyClockContext context = new SteadyClockContext
|
||||||
{
|
{
|
||||||
@@ -67,10 +56,10 @@ namespace Ryujinx.HLE.HOS.Services.Time
|
|||||||
WriteObjectToSharedMemory(AutomaticCorrectionEnabledOffset, 0, Convert.ToByte(isAutomaticCorrectionEnabled));
|
WriteObjectToSharedMemory(AutomaticCorrectionEnabledOffset, 0, Convert.ToByte(isAutomaticCorrectionEnabled));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetSteadyClockRawTimePoint(KThread thread, TimeSpanType currentTimePoint)
|
public void SetSteadyClockRawTimePoint(ITickSource tickSource, TimeSpanType currentTimePoint)
|
||||||
{
|
{
|
||||||
SteadyClockContext context = ReadObjectFromSharedMemory<SteadyClockContext>(SteadyClockContextOffset, 4);
|
SteadyClockContext context = ReadObjectFromSharedMemory<SteadyClockContext>(SteadyClockContextOffset, 4);
|
||||||
TimeSpanType ticksTimeSpan = TimeSpanType.FromTicks(thread.Context.CntpctEl0, thread.Context.CntfrqEl0);
|
TimeSpanType ticksTimeSpan = TimeSpanType.FromTicks(tickSource.Counter, tickSource.Frequency);
|
||||||
|
|
||||||
context.InternalOffset = (ulong)(currentTimePoint.NanoSeconds - ticksTimeSpan.NanoSeconds);
|
context.InternalOffset = (ulong)(currentTimePoint.NanoSeconds - ticksTimeSpan.NanoSeconds);
|
||||||
|
|
||||||
|
@@ -7,6 +7,7 @@ using LibHac.Ncm;
|
|||||||
using LibHac.Tools.FsSystem;
|
using LibHac.Tools.FsSystem;
|
||||||
using LibHac.Tools.FsSystem.NcaUtils;
|
using LibHac.Tools.FsSystem.NcaUtils;
|
||||||
using Ryujinx.Common.Logging;
|
using Ryujinx.Common.Logging;
|
||||||
|
using Ryujinx.Cpu;
|
||||||
using Ryujinx.HLE.Exceptions;
|
using Ryujinx.HLE.Exceptions;
|
||||||
using Ryujinx.HLE.FileSystem;
|
using Ryujinx.HLE.FileSystem;
|
||||||
using Ryujinx.HLE.HOS.Services.Time.Clock;
|
using Ryujinx.HLE.HOS.Services.Time.Clock;
|
||||||
@@ -63,7 +64,9 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
|
|||||||
{
|
{
|
||||||
InitializeInstance(device.FileSystem, device.System.ContentManager, device.System.FsIntegrityCheckLevel);
|
InitializeInstance(device.FileSystem, device.System.ContentManager, device.System.FsIntegrityCheckLevel);
|
||||||
|
|
||||||
SteadyClockTimePoint timeZoneUpdatedTimePoint = timeManager.StandardSteadyClock.GetCurrentTimePoint(null);
|
ITickSource tickSource = device.System.TickSource;
|
||||||
|
|
||||||
|
SteadyClockTimePoint timeZoneUpdatedTimePoint = timeManager.StandardSteadyClock.GetCurrentTimePoint(tickSource);
|
||||||
|
|
||||||
string deviceLocationName = SanityCheckDeviceLocationName(device.Configuration.TimeZone);
|
string deviceLocationName = SanityCheckDeviceLocationName(device.Configuration.TimeZone);
|
||||||
|
|
||||||
|
@@ -1,8 +1,10 @@
|
|||||||
using ARMeilleure.Memory;
|
using ARMeilleure.Memory;
|
||||||
using ARMeilleure.State;
|
using ARMeilleure.State;
|
||||||
using ARMeilleure.Translation;
|
using ARMeilleure.Translation;
|
||||||
|
using Ryujinx.Cpu;
|
||||||
|
using Ryujinx.Cpu.Jit;
|
||||||
|
|
||||||
namespace Ryujinx.Cpu
|
namespace Ryujinx.Tests.Cpu
|
||||||
{
|
{
|
||||||
public class CpuContext
|
public class CpuContext
|
||||||
{
|
{
|
||||||
@@ -21,7 +23,7 @@ namespace Ryujinx.Cpu
|
|||||||
|
|
||||||
public static ExecutionContext CreateExecutionContext()
|
public static ExecutionContext CreateExecutionContext()
|
||||||
{
|
{
|
||||||
return new ExecutionContext(new JitMemoryAllocator());
|
return new ExecutionContext(new JitMemoryAllocator(), new TickSource(19200000));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Execute(ExecutionContext context, ulong address)
|
public void Execute(ExecutionContext context, ulong address)
|
@@ -2,7 +2,7 @@ using ARMeilleure;
|
|||||||
using ARMeilleure.State;
|
using ARMeilleure.State;
|
||||||
using ARMeilleure.Translation;
|
using ARMeilleure.Translation;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using Ryujinx.Cpu;
|
using Ryujinx.Cpu.Jit;
|
||||||
using Ryujinx.Memory;
|
using Ryujinx.Memory;
|
||||||
using Ryujinx.Tests.Unicorn;
|
using Ryujinx.Tests.Unicorn;
|
||||||
using System;
|
using System;
|
||||||
|
@@ -2,7 +2,7 @@
|
|||||||
using ARMeilleure.State;
|
using ARMeilleure.State;
|
||||||
using ARMeilleure.Translation;
|
using ARMeilleure.Translation;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using Ryujinx.Cpu;
|
using Ryujinx.Cpu.Jit;
|
||||||
using Ryujinx.Memory;
|
using Ryujinx.Memory;
|
||||||
using Ryujinx.Tests.Unicorn;
|
using Ryujinx.Tests.Unicorn;
|
||||||
using System;
|
using System;
|
||||||
|
Reference in New Issue
Block a user