diff --git a/ARMeilleure/Instructions/InstEmitSystem.cs b/ARMeilleure/Instructions/InstEmitSystem.cs index 499f16488..50dab07d2 100644 --- a/ARMeilleure/Instructions/InstEmitSystem.cs +++ b/ARMeilleure/Instructions/InstEmitSystem.cs @@ -33,13 +33,13 @@ namespace ARMeilleure.Instructions switch (GetPackedId(op)) { - 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_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_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_011: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetTpidr)); 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_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_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_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_001: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetCntpctEl0)); break; case 0b11_011_1110_0000_010: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetCntvctEl0)); break; diff --git a/ARMeilleure/Instructions/NativeInterface.cs b/ARMeilleure/Instructions/NativeInterface.cs index 0b76f6814..eebb824e1 100644 --- a/ARMeilleure/Instructions/NativeInterface.cs +++ b/ARMeilleure/Instructions/NativeInterface.cs @@ -107,14 +107,14 @@ namespace ARMeilleure.Instructions return (uint)GetContext().TpidrEl0; } - public static ulong GetTpidr() + public static ulong GetTpidrroEl0() { - return (ulong)GetContext().Tpidr; + return (ulong)GetContext().TpidrroEl0; } public static uint GetTpidr32() { - return (uint)GetContext().Tpidr; + return (uint)GetContext().TpidrroEl0; } public static ulong GetCntfrqEl0() diff --git a/ARMeilleure/State/ExceptionCallback.cs b/ARMeilleure/State/ExceptionCallback.cs new file mode 100644 index 000000000..38d6eef78 --- /dev/null +++ b/ARMeilleure/State/ExceptionCallback.cs @@ -0,0 +1,5 @@ +namespace ARMeilleure.State +{ + public delegate void ExceptionCallbackNoArgs(ExecutionContext context); + public delegate void ExceptionCallback(ExecutionContext context, ulong address, int id); +} \ No newline at end of file diff --git a/ARMeilleure/State/ExecutionContext.cs b/ARMeilleure/State/ExecutionContext.cs index 8309864f4..c73ca197d 100644 --- a/ARMeilleure/State/ExecutionContext.cs +++ b/ARMeilleure/State/ExecutionContext.cs @@ -1,6 +1,5 @@ using ARMeilleure.Memory; using System; -using System.Diagnostics; namespace ARMeilleure.State { @@ -14,34 +13,22 @@ namespace ARMeilleure.State 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 ulong CntfrqEl0 { get; set; } - public ulong CntpctEl0 - { - get - { - double ticks = _tickCounter.ElapsedTicks * _hostTickFreq; - - return (ulong)(ticks * CntfrqEl0); - } - } + public ulong CntfrqEl0 => _counter.Frequency; + public ulong CntpctEl0 => _counter.Counter; // CNTVCT_EL0 = CNTPCT_EL0 - CNTVOFF_EL2 // Since EL2 isn't implemented, CNTVOFF_EL2 = 0 public ulong CntvctEl0 => CntpctEl0; - public static TimeSpan ElapsedTime => _tickCounter.Elapsed; - public static long ElapsedTicks => _tickCounter.ElapsedTicks; - public static double TickFrequency => _hostTickFreq; - public long TpidrEl0 { get; set; } - public long Tpidr { get; set; } + public long TpidrroEl0 { get; set; } public uint Pstate { @@ -78,35 +65,38 @@ namespace ARMeilleure.State private set => _nativeContext.SetRunning(value); } - public event EventHandler Interrupt; - public event EventHandler Break; - public event EventHandler SupervisorCall; - public event EventHandler Undefined; + private readonly ExceptionCallbackNoArgs _interruptCallback; + private readonly ExceptionCallback _breakCallback; + private readonly ExceptionCallback _supervisorCallback; + private readonly ExceptionCallback _undefinedCallback; - static ExecutionContext() - { - _hostTickFreq = 1.0 / Stopwatch.Frequency; - - _tickCounter = new Stopwatch(); - _tickCounter.Start(); - } - - public ExecutionContext(IJitMemoryAllocator allocator) + public ExecutionContext( + IJitMemoryAllocator allocator, + ICounter counter, + ExceptionCallbackNoArgs interruptCallback = null, + ExceptionCallback breakCallback = null, + ExceptionCallback supervisorCallback = null, + ExceptionCallback undefinedCallback = null) { _nativeContext = new NativeContext(allocator); + _counter = counter; + _interruptCallback = interruptCallback; + _breakCallback = breakCallback; + _supervisorCallback = supervisorCallback; + _undefinedCallback = undefinedCallback; Running = true; _nativeContext.SetCounter(MinCountForCheck); } - public ulong GetX(int index) => _nativeContext.GetX(index); - public void SetX(int index, ulong value) => _nativeContext.SetX(index, value); + public ulong GetX(int index) => _nativeContext.GetX(index); + public void SetX(int index, ulong value) => _nativeContext.SetX(index, value); - public V128 GetV(int index) => _nativeContext.GetV(index); + public V128 GetV(int index) => _nativeContext.GetV(index); public void SetV(int index, V128 value) => _nativeContext.SetV(index, value); - public bool GetPstateFlag(PState flag) => _nativeContext.GetPstateFlag(flag); + public bool GetPstateFlag(PState flag) => _nativeContext.GetPstateFlag(flag); public void SetPstateFlag(PState flag, bool value) => _nativeContext.SetPstateFlag(flag, value); public bool GetFPstateFlag(FPState flag) => _nativeContext.GetFPStateFlag(flag); @@ -118,7 +108,7 @@ namespace ARMeilleure.State { _interrupted = false; - Interrupt?.Invoke(this, EventArgs.Empty); + _interruptCallback?.Invoke(this); } _nativeContext.SetCounter(MinCountForCheck); @@ -131,17 +121,17 @@ namespace ARMeilleure.State 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) { - SupervisorCall?.Invoke(this, new InstExceptionEventArgs(address, imm)); + _supervisorCallback?.Invoke(this, address, imm); } internal void OnUndefined(ulong address, int opCode) { - Undefined?.Invoke(this, new InstUndefinedEventArgs(address, opCode)); + _undefinedCallback?.Invoke(this, address, opCode); } public void StopRunning() @@ -151,16 +141,6 @@ namespace ARMeilleure.State _nativeContext.SetCounter(0); } - public static void SuspendCounter() - { - _tickCounter.Stop(); - } - - public static void ResumeCounter() - { - _tickCounter.Start(); - } - public void Dispose() { _nativeContext.Dispose(); diff --git a/ARMeilleure/State/ICounter.cs b/ARMeilleure/State/ICounter.cs new file mode 100644 index 000000000..93e721ea3 --- /dev/null +++ b/ARMeilleure/State/ICounter.cs @@ -0,0 +1,18 @@ +namespace ARMeilleure.State +{ + /// + /// CPU Counter interface. + /// + public interface ICounter + { + /// + /// Counter frequency in Hertz. + /// + ulong Frequency { get; } + + /// + /// Current counter value. + /// + ulong Counter { get; } + } +} \ No newline at end of file diff --git a/ARMeilleure/State/InstExceptionEventArgs.cs b/ARMeilleure/State/InstExceptionEventArgs.cs deleted file mode 100644 index c2460e4b4..000000000 --- a/ARMeilleure/State/InstExceptionEventArgs.cs +++ /dev/null @@ -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; - } - } -} \ No newline at end of file diff --git a/ARMeilleure/State/InstUndefinedEventArgs.cs b/ARMeilleure/State/InstUndefinedEventArgs.cs deleted file mode 100644 index c02b648e1..000000000 --- a/ARMeilleure/State/InstUndefinedEventArgs.cs +++ /dev/null @@ -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; - } - } -} \ No newline at end of file diff --git a/ARMeilleure/State/NativeContext.cs b/ARMeilleure/State/NativeContext.cs index f911f7626..11ab5ca3a 100644 --- a/ARMeilleure/State/NativeContext.cs +++ b/ARMeilleure/State/NativeContext.cs @@ -34,6 +34,12 @@ namespace ARMeilleure.State GetStorage().ExclusiveAddress = ulong.MaxValue; } + public ulong GetPc() + { + // TODO: More precise tracking of PC value. + return GetStorage().DispatchAddress; + } + public unsafe ulong GetX(int index) { if ((uint)index >= RegisterConsts.IntRegsCount) diff --git a/ARMeilleure/Translation/Delegates.cs b/ARMeilleure/Translation/Delegates.cs index 3cfe34b68..6d40dc96d 100644 --- a/ARMeilleure/Translation/Delegates.cs +++ b/ARMeilleure/Translation/Delegates.cs @@ -115,7 +115,7 @@ namespace ARMeilleure.Translation SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetFpsr))); SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetFunctionAddress))); 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.GetTpidrEl0))); SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetTpidrEl032))); // A32 only. diff --git a/ARMeilleure/Translation/PTC/Ptc.cs b/ARMeilleure/Translation/PTC/Ptc.cs index 43f3b08bd..9671a8714 100644 --- a/ARMeilleure/Translation/PTC/Ptc.cs +++ b/ARMeilleure/Translation/PTC/Ptc.cs @@ -27,7 +27,7 @@ namespace ARMeilleure.Translation.PTC private const string OuterHeaderMagicString = "PTCohd\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 BackupDir = "1"; diff --git a/Ryujinx.Audio/Renderer/Server/AudioRenderSystem.cs b/Ryujinx.Audio/Renderer/Server/AudioRenderSystem.cs index 0c41909e5..5fa5b797f 100644 --- a/Ryujinx.Audio/Renderer/Server/AudioRenderSystem.cs +++ b/Ryujinx.Audio/Renderer/Server/AudioRenderSystem.cs @@ -523,9 +523,7 @@ namespace Ryujinx.Audio.Renderer.Server private ulong GetSystemTicks() { - double ticks = ARMeilleure.State.ExecutionContext.ElapsedTicks * ARMeilleure.State.ExecutionContext.TickFrequency; - - return (ulong)(ticks * Constants.TargetTimerFrequency); + return (ulong)(_manager.TickSource.ElapsedSeconds * Constants.TargetTimerFrequency); } private uint ComputeVoiceDrop(CommandBuffer commandBuffer, long voicesEstimatedTime, long deltaTimeDsp) diff --git a/Ryujinx.Audio/Renderer/Server/AudioRendererManager.cs b/Ryujinx.Audio/Renderer/Server/AudioRendererManager.cs index d20c3c030..90be71119 100644 --- a/Ryujinx.Audio/Renderer/Server/AudioRendererManager.cs +++ b/Ryujinx.Audio/Renderer/Server/AudioRendererManager.cs @@ -19,6 +19,7 @@ using Ryujinx.Audio.Integration; using Ryujinx.Audio.Renderer.Dsp; using Ryujinx.Audio.Renderer.Parameter; using Ryujinx.Common.Logging; +using Ryujinx.Cpu; using Ryujinx.Memory; using System; using System.Diagnostics; @@ -77,6 +78,11 @@ namespace Ryujinx.Audio.Renderer.Server /// private IHardwareDeviceDriver _deviceDriver; + /// + /// Tick source used to measure elapsed time. + /// + public ITickSource TickSource { get; } + /// /// The instance associated to this manager. /// @@ -90,9 +96,11 @@ namespace Ryujinx.Audio.Renderer.Server /// /// Create a new . /// - public AudioRendererManager() + /// Tick source used to measure elapsed time. + public AudioRendererManager(ITickSource tickSource) { Processor = new AudioProcessor(); + TickSource = tickSource; _sessionIds = new int[Constants.AudioRendererSessionCountMax]; _sessions = new AudioRenderSystem[Constants.AudioRendererSessionCountMax]; _activeSessionCount = 0; diff --git a/Ryujinx.Cpu/ExceptionCallbacks.cs b/Ryujinx.Cpu/ExceptionCallbacks.cs new file mode 100644 index 000000000..1485ca7d2 --- /dev/null +++ b/Ryujinx.Cpu/ExceptionCallbacks.cs @@ -0,0 +1,64 @@ +namespace Ryujinx.Cpu +{ + /// + /// Exception callback without any additional arguments. + /// + /// Context for the thread where the exception was triggered + public delegate void ExceptionCallbackNoArgs(IExecutionContext context); + + /// + /// Exception callback. + /// + /// Context for the thread where the exception was triggered + /// Address of the instruction that caused the exception + /// Immediate value of the instruction that caused the exception, or for undefined instruction, the instruction itself + public delegate void ExceptionCallback(IExecutionContext context, ulong address, int imm); + + /// + /// Stores handlers for the various CPU exceptions. + /// + public struct ExceptionCallbacks + { + /// + /// Handler for CPU interrupts triggered using . + /// + public readonly ExceptionCallbackNoArgs InterruptCallback; + + /// + /// Handler for CPU software interrupts caused by the Arm BRK instruction. + /// + public readonly ExceptionCallback BreakCallback; + + /// + /// Handler for CPU software interrupts caused by the Arm SVC instruction. + /// + public readonly ExceptionCallback SupervisorCallback; + + /// + /// Handler for CPU software interrupts caused by any undefined Arm instruction. + /// + public readonly ExceptionCallback UndefinedCallback; + + /// + /// Creates a new exception callbacks structure. + /// + /// + /// All handlers are optional, and if null, the CPU will just continue executing as if nothing happened. + /// + /// Handler for CPU interrupts triggered using + /// Handler for CPU software interrupts caused by the Arm BRK instruction + /// Handler for CPU software interrupts caused by the Arm SVC instruction + /// Handler for CPU software interrupts caused by any undefined Arm instruction + public ExceptionCallbacks( + ExceptionCallbackNoArgs interruptCallback = null, + ExceptionCallback breakCallback = null, + ExceptionCallback supervisorCallback = null, + ExceptionCallback undefinedCallback = null) + { + InterruptCallback = interruptCallback; + BreakCallback = breakCallback; + SupervisorCallback = supervisorCallback; + UndefinedCallback = undefinedCallback; + } + } +} diff --git a/Ryujinx.Cpu/ICpuContext.cs b/Ryujinx.Cpu/ICpuContext.cs new file mode 100644 index 000000000..4a73a8338 --- /dev/null +++ b/Ryujinx.Cpu/ICpuContext.cs @@ -0,0 +1,39 @@ +namespace Ryujinx.Cpu +{ + /// + /// CPU context interface. + /// + public interface ICpuContext + { + /// + /// Creates a new execution context that will store thread CPU register state when executing guest code. + /// + /// Optional functions to be called when the CPU receives an interrupt + /// Execution context + IExecutionContext CreateExecutionContext(ExceptionCallbacks exceptionCallbacks); + + /// + /// Starts executing code at a specified entry point address. + /// + /// + /// This function only returns when the execution is stopped, by calling . + /// + /// Execution context to be used for this run + /// Entry point address + void Execute(IExecutionContext context, ulong address); + + /// + /// Invalidates the instruction cache for a given memory region. + /// + /// + /// 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. + /// + /// Address of the region to be invalidated + /// Size of the region to be invalidated + void InvalidateCacheRegion(ulong address, ulong size); + } +} diff --git a/Ryujinx.Cpu/ICpuEngine.cs b/Ryujinx.Cpu/ICpuEngine.cs new file mode 100644 index 000000000..b53b23a8c --- /dev/null +++ b/Ryujinx.Cpu/ICpuEngine.cs @@ -0,0 +1,18 @@ +using ARMeilleure.Memory; + +namespace Ryujinx.Cpu +{ + /// + /// CPU execution engine interface. + /// + public interface ICpuEngine + { + /// + /// Creates a new CPU context that can be used to run code for multiple threads sharing an address space. + /// + /// Memory manager for the address space of the context + /// Indicates if the context will be used to run 64-bit or 32-bit Arm code + /// CPU context + ICpuContext CreateCpuContext(IMemoryManager memoryManager, bool for64Bit); + } +} diff --git a/Ryujinx.Cpu/IExecutionContext.cs b/Ryujinx.Cpu/IExecutionContext.cs new file mode 100644 index 000000000..3455b5c1e --- /dev/null +++ b/Ryujinx.Cpu/IExecutionContext.cs @@ -0,0 +1,112 @@ +using ARMeilleure.State; +using System; + +namespace Ryujinx.Cpu +{ + /// + /// CPU register state interface. + /// + public interface IExecutionContext : IDisposable + { + /// + /// Current Program Counter. + /// + /// + /// In some implementations, this value might not be accurate and might not point to the last instruction executed. + /// + ulong Pc { get; } + + /// + /// Thread ID Register (EL0). + /// + long TpidrEl0 { get; set; } + + /// + /// Thread ID Register (read-only) (EL0). + /// + long TpidrroEl0 { get; set; } + + /// + /// Processor State register. + /// + uint Pstate { get; set; } + + /// + /// Floating-point Control Register. + /// + uint Fpcr { get; set; } + + /// + /// Floating-point Status Register. + /// + uint Fpsr { get; set; } + + /// + /// Indicates whenever the CPU is running 64-bit (AArch64 mode) or 32-bit (AArch32 mode) code. + /// + bool IsAarch32 { get; set; } + + /// + /// Indicates whenever the CPU is still running code. + /// + /// + /// 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. + /// + bool Running { get; } + + /// + /// Gets the value of a general purpose register. + /// + /// + /// The special of 31 can be used to access the SP (Stack Pointer) register. + /// + /// Index of the register, in the range 0-31 (inclusive) + /// The register value + ulong GetX(int index); + + /// + /// Sets the value of a general purpose register. + /// + /// + /// The special of 31 can be used to access the SP (Stack Pointer) register. + /// + /// Index of the register, in the range 0-31 (inclusive) + /// Value to be set + void SetX(int index, ulong value); + + /// + /// Gets the value of a FP/SIMD register. + /// + /// Index of the register, in the range 0-31 (inclusive) + /// The register value + V128 GetV(int index); + + /// + /// Sets the value of a FP/SIMD register. + /// + /// Index of the register, in the range 0-31 (inclusive) + /// Value to be set + void SetV(int index, V128 value); + + /// + /// Requests the thread to stop running temporarily and call . + /// + /// + /// 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. + /// + void RequestInterrupt(); + + /// + /// Requests the thread to stop running guest code and return as soon as possible. + /// + /// + /// 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 . + /// If you only need to pause the thread temporarily, use instead. + /// + void StopRunning(); + } +} \ No newline at end of file diff --git a/Ryujinx.Cpu/ITickSource.cs b/Ryujinx.Cpu/ITickSource.cs new file mode 100644 index 000000000..e65e99e26 --- /dev/null +++ b/Ryujinx.Cpu/ITickSource.cs @@ -0,0 +1,31 @@ +using ARMeilleure.State; +using System; + +namespace Ryujinx.Cpu +{ + /// + /// Tick source interface. + /// + public interface ITickSource : ICounter + { + /// + /// Time elapsed since the counter was created. + /// + TimeSpan ElapsedTime { get; } + + /// + /// Time elapsed since the counter was created, in seconds. + /// + double ElapsedSeconds { get; } + + /// + /// Stops counting. + /// + void Suspend(); + + /// + /// Resumes counting after a call to . + /// + void Resume(); + } +} diff --git a/Ryujinx.Cpu/Jit/JitCpuContext.cs b/Ryujinx.Cpu/Jit/JitCpuContext.cs new file mode 100644 index 000000000..d6892ea75 --- /dev/null +++ b/Ryujinx.Cpu/Jit/JitCpuContext.cs @@ -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); + } + + /// + public IExecutionContext CreateExecutionContext(ExceptionCallbacks exceptionCallbacks) + { + return new JitExecutionContext(new JitMemoryAllocator(), _tickSource, exceptionCallbacks); + } + + /// + public void Execute(IExecutionContext context, ulong address) + { + _translator.Execute(((JitExecutionContext)context).Impl, address); + } + + /// + public void InvalidateCacheRegion(ulong address, ulong size) + { + _translator.InvalidateJitCacheRegion(address, size); + } + } +} diff --git a/Ryujinx.Cpu/Jit/JitEngine.cs b/Ryujinx.Cpu/Jit/JitEngine.cs new file mode 100644 index 000000000..b158074f0 --- /dev/null +++ b/Ryujinx.Cpu/Jit/JitEngine.cs @@ -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; + } + + /// + public ICpuContext CreateCpuContext(IMemoryManager memoryManager, bool for64Bit) + { + return new JitCpuContext(_tickSource, memoryManager, for64Bit); + } + } +} \ No newline at end of file diff --git a/Ryujinx.Cpu/Jit/JitExecutionContext.cs b/Ryujinx.Cpu/Jit/JitExecutionContext.cs new file mode 100644 index 000000000..e1a527b1b --- /dev/null +++ b/Ryujinx.Cpu/Jit/JitExecutionContext.cs @@ -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; + + /// + public ulong Pc => _impl.Pc; + + /// + public long TpidrEl0 + { + get => _impl.TpidrEl0; + set => _impl.TpidrEl0 = value; + } + + /// + public long TpidrroEl0 + { + get => _impl.TpidrroEl0; + set => _impl.TpidrroEl0 = value; + } + + /// + public uint Pstate + { + get => _impl.Pstate; + set => _impl.Pstate = value; + } + + /// + public uint Fpcr + { + get => (uint)_impl.Fpcr; + set => _impl.Fpcr = (FPCR)value; + } + + /// + public uint Fpsr + { + get => (uint)_impl.Fpsr; + set => _impl.Fpsr = (FPSR)value; + } + + /// + public bool IsAarch32 + { + get => _impl.IsAarch32; + set => _impl.IsAarch32 = value; + } + + /// + 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; + } + + /// + public ulong GetX(int index) => _impl.GetX(index); + + /// + public void SetX(int index, ulong value) => _impl.SetX(index, value); + + /// + public V128 GetV(int index) => _impl.GetV(index); + + /// + 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); + } + + /// + public void RequestInterrupt() + { + _impl.RequestInterrupt(); + } + + /// + public void StopRunning() + { + _impl.StopRunning(); + } + + public void Dispose() + { + _impl.Dispose(); + } + } +} \ No newline at end of file diff --git a/Ryujinx.Cpu/JitMemoryAllocator.cs b/Ryujinx.Cpu/Jit/JitMemoryAllocator.cs similarity index 77% rename from Ryujinx.Cpu/JitMemoryAllocator.cs rename to Ryujinx.Cpu/Jit/JitMemoryAllocator.cs index 26ccd732b..27bb09ccb 100644 --- a/Ryujinx.Cpu/JitMemoryAllocator.cs +++ b/Ryujinx.Cpu/Jit/JitMemoryAllocator.cs @@ -1,9 +1,9 @@ using ARMeilleure.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 Reserve(ulong size) => new JitMemoryBlock(size, MemoryAllocationFlags.Reserve); diff --git a/Ryujinx.Cpu/JitMemoryBlock.cs b/Ryujinx.Cpu/Jit/JitMemoryBlock.cs similarity index 90% rename from Ryujinx.Cpu/JitMemoryBlock.cs rename to Ryujinx.Cpu/Jit/JitMemoryBlock.cs index 3ad62d713..327fb303e 100644 --- a/Ryujinx.Cpu/JitMemoryBlock.cs +++ b/Ryujinx.Cpu/Jit/JitMemoryBlock.cs @@ -2,9 +2,9 @@ using Ryujinx.Memory; using System; -namespace Ryujinx.Cpu +namespace Ryujinx.Cpu.Jit { - class JitMemoryBlock : IJitMemoryBlock + public class JitMemoryBlock : IJitMemoryBlock { private readonly MemoryBlock _impl; diff --git a/Ryujinx.Cpu/MemoryManager.cs b/Ryujinx.Cpu/Jit/MemoryManager.cs similarity index 99% rename from Ryujinx.Cpu/MemoryManager.cs rename to Ryujinx.Cpu/Jit/MemoryManager.cs index b9769fd40..86c69431d 100644 --- a/Ryujinx.Cpu/MemoryManager.cs +++ b/Ryujinx.Cpu/Jit/MemoryManager.cs @@ -10,7 +10,7 @@ using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Threading; -namespace Ryujinx.Cpu +namespace Ryujinx.Cpu.Jit { /// /// Represents a CPU memory manager. diff --git a/Ryujinx.Cpu/MemoryManagerHostMapped.cs b/Ryujinx.Cpu/Jit/MemoryManagerHostMapped.cs similarity index 99% rename from Ryujinx.Cpu/MemoryManagerHostMapped.cs rename to Ryujinx.Cpu/Jit/MemoryManagerHostMapped.cs index b5abae0cf..5961e3773 100644 --- a/Ryujinx.Cpu/MemoryManagerHostMapped.cs +++ b/Ryujinx.Cpu/Jit/MemoryManagerHostMapped.cs @@ -8,12 +8,12 @@ using System.Collections.Generic; using System.Runtime.CompilerServices; using System.Threading; -namespace Ryujinx.Cpu +namespace Ryujinx.Cpu.Jit { /// /// Represents a CPU memory manager which maps guest virtual memory directly onto a host virtual region. /// - public class MemoryManagerHostMapped : MemoryManagerBase, IMemoryManager, IVirtualMemoryManagerTracked, IWritableBlock + public sealed class MemoryManagerHostMapped : MemoryManagerBase, IMemoryManager, IVirtualMemoryManagerTracked, IWritableBlock { public const int PageBits = 12; public const int PageSize = 1 << PageBits; diff --git a/Ryujinx.Cpu/TickSource.cs b/Ryujinx.Cpu/TickSource.cs new file mode 100644 index 000000000..dc510bc26 --- /dev/null +++ b/Ryujinx.Cpu/TickSource.cs @@ -0,0 +1,45 @@ +using System; +using System.Diagnostics; + +namespace Ryujinx.Cpu +{ + public class TickSource : ITickSource + { + private static Stopwatch _tickCounter; + + private static double _hostTickFreq; + + /// + public ulong Frequency { get; } + + /// + public ulong Counter => (ulong)(ElapsedSeconds * Frequency); + + /// + public TimeSpan ElapsedTime => _tickCounter.Elapsed; + + /// + public double ElapsedSeconds => _tickCounter.ElapsedTicks * _hostTickFreq; + + public TickSource(ulong frequency) + { + Frequency = frequency; + _hostTickFreq = 1.0 / Stopwatch.Frequency; + + _tickCounter = new Stopwatch(); + _tickCounter.Start(); + } + + /// + public void Suspend() + { + _tickCounter.Stop(); + } + + /// + public void Resume() + { + _tickCounter.Start(); + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/ArmProcessContext.cs b/Ryujinx.HLE/HOS/ArmProcessContext.cs index dfa01c1ff..072df0b61 100644 --- a/Ryujinx.HLE/HOS/ArmProcessContext.cs +++ b/Ryujinx.HLE/HOS/ArmProcessContext.cs @@ -1,5 +1,4 @@ using ARMeilleure.Memory; -using ARMeilleure.State; using Ryujinx.Cpu; using Ryujinx.Graphics.Gpu; using Ryujinx.HLE.HOS.Kernel.Process; @@ -11,12 +10,12 @@ namespace Ryujinx.HLE.HOS { private readonly ulong _pid; private readonly GpuContext _gpuContext; - private readonly CpuContext _cpuContext; + private readonly ICpuContext _cpuContext; private T _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) { @@ -27,11 +26,16 @@ namespace Ryujinx.HLE.HOS _pid = pid; _gpuContext = gpuContext; - _cpuContext = new CpuContext(memoryManager, for64Bit); + _cpuContext = cpuEngine.CreateCpuContext(memoryManager, for64Bit); _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); } diff --git a/Ryujinx.HLE/HOS/ArmProcessContextFactory.cs b/Ryujinx.HLE/HOS/ArmProcessContextFactory.cs index 0561193ca..7d1c4e1d6 100644 --- a/Ryujinx.HLE/HOS/ArmProcessContextFactory.cs +++ b/Ryujinx.HLE/HOS/ArmProcessContextFactory.cs @@ -1,5 +1,6 @@ using Ryujinx.Common.Configuration; using Ryujinx.Cpu; +using Ryujinx.Cpu.Jit; using Ryujinx.Graphics.Gpu; using Ryujinx.HLE.HOS.Kernel; using Ryujinx.HLE.HOS.Kernel.Process; @@ -10,10 +11,12 @@ namespace Ryujinx.HLE.HOS { class ArmProcessContextFactory : IProcessContextFactory { + private readonly ICpuEngine _cpuEngine; private readonly GpuContext _gpu; - public ArmProcessContextFactory(GpuContext gpu) + public ArmProcessContextFactory(ICpuEngine cpuEngine, GpuContext gpu) { + _cpuEngine = cpuEngine; _gpu = gpu; } @@ -29,12 +32,14 @@ namespace Ryujinx.HLE.HOS switch (mode) { case MemoryManagerMode.SoftwarePageTable: - return new ArmProcessContext(pid, _gpu, new MemoryManager(context.Memory, addressSpaceSize, invalidAccessHandler), for64Bit); + var memoryManager = new MemoryManager(context.Memory, addressSpaceSize, invalidAccessHandler); + return new ArmProcessContext(pid, _cpuEngine, _gpu, memoryManager, for64Bit); case MemoryManagerMode.HostMapped: case MemoryManagerMode.HostMappedUnsafe: bool unsafeMode = mode == MemoryManagerMode.HostMappedUnsafe; - return new ArmProcessContext(pid, _gpu, new MemoryManagerHostMapped(context.Memory, addressSpaceSize, unsafeMode, invalidAccessHandler), for64Bit); + var memoryManagerHostMapped = new MemoryManagerHostMapped(context.Memory, addressSpaceSize, unsafeMode, invalidAccessHandler); + return new ArmProcessContext(pid, _cpuEngine, _gpu, memoryManagerHostMapped, for64Bit); default: throw new ArgumentOutOfRangeException(); diff --git a/Ryujinx.HLE/HOS/Horizon.cs b/Ryujinx.HLE/HOS/Horizon.cs index 7de9bdf33..b93ebc032 100644 --- a/Ryujinx.HLE/HOS/Horizon.cs +++ b/Ryujinx.HLE/HOS/Horizon.cs @@ -10,6 +10,8 @@ using Ryujinx.Audio.Integration; using Ryujinx.Audio.Output; using Ryujinx.Audio.Renderer.Device; using Ryujinx.Audio.Renderer.Server; +using Ryujinx.Cpu; +using Ryujinx.Cpu.Jit; using Ryujinx.HLE.FileSystem; using Ryujinx.HLE.HOS.Kernel; using Ryujinx.HLE.HOS.Kernel.Memory; @@ -57,6 +59,9 @@ namespace Ryujinx.HLE.HOS internal Switch Device { get; private set; } + internal ITickSource TickSource { get; } + internal ICpuEngine CpuEngine { get; } + internal SurfaceFlinger SurfaceFlinger { get; private set; } internal AudioManager AudioManager { get; private set; } internal AudioOutputManager AudioOutputManager { get; private set; } @@ -121,7 +126,11 @@ namespace Ryujinx.HLE.HOS public Horizon(Switch device) { + TickSource = new TickSource(KernelConstants.CounterFrequency); + CpuEngine = new JitEngine(TickSource); + KernelContext = new KernelContext( + TickSource, device, device.Memory, device.Configuration.MemoryConfiguration.ToKernelMemorySize(), @@ -215,40 +224,40 @@ namespace Ryujinx.HLE.HOS internalOffset = new TimeSpanType(-internalOffset.NanoSeconds); // First init the standard steady clock - TimeServiceManager.Instance.SetupStandardSteadyClock(null, clockSourceId, systemTime, internalOffset, TimeSpanType.Zero, false); - TimeServiceManager.Instance.SetupStandardLocalSystemClock(null, new SystemClockContext(), systemTime.ToSeconds()); + TimeServiceManager.Instance.SetupStandardSteadyClock(TickSource, clockSourceId, systemTime, internalOffset, TimeSpanType.Zero, false); + TimeServiceManager.Instance.SetupStandardLocalSystemClock(TickSource, new SystemClockContext(), systemTime.ToSeconds()); if (NxSettings.Settings.TryGetValue("time!standard_network_clock_sufficient_accuracy_minutes", out object standardNetworkClockSufficientAccuracyMinutes)) { 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. - TimeServiceManager.Instance.StandardLocalSystemClock.GetClockContext(null, out SystemClockContext localSytemClockContext); + TimeServiceManager.Instance.StandardLocalSystemClock.GetClockContext(TickSource, out SystemClockContext localSytemClockContext); 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 TimeServiceManager.Instance.SetupEphemeralNetworkSystemClock(); - DatabaseImpl.Instance.InitializeDatabase(LibHacHorizonManager.SdbClient); + DatabaseImpl.Instance.InitializeDatabase(TickSource, LibHacHorizonManager.SdbClient); HostSyncpoint = new NvHostSyncpt(device); SurfaceFlinger = new SurfaceFlinger(device); - InitializeAudioRenderer(); + InitializeAudioRenderer(TickSource); InitializeServices(); } - private void InitializeAudioRenderer() + private void InitializeAudioRenderer(ITickSource tickSource) { AudioManager = new AudioManager(); AudioOutputManager = new AudioOutputManager(); AudioInputManager = new AudioInputManager(); - AudioRendererManager = new AudioRendererManager(); + AudioRendererManager = new AudioRendererManager(tickSource); AudioRendererManager.SetVolume(Device.Configuration.AudioVolume); AudioDeviceSessionRegistry = new VirtualDeviceSessionRegistry(); @@ -492,12 +501,12 @@ namespace Ryujinx.HLE.HOS if (pause && !IsPaused) { Device.AudioDeviceDriver.GetPauseEvent().Reset(); - ARMeilleure.State.ExecutionContext.SuspendCounter(); + TickSource.Suspend(); } else if (!pause && IsPaused) { Device.AudioDeviceDriver.GetPauseEvent().Set(); - ARMeilleure.State.ExecutionContext.ResumeCounter(); + TickSource.Resume(); } } IsPaused = pause; diff --git a/Ryujinx.HLE/HOS/Kernel/KernelConstants.cs b/Ryujinx.HLE/HOS/Kernel/KernelConstants.cs index 5a1dbef26..3817b0aa3 100644 --- a/Ryujinx.HLE/HOS/Kernel/KernelConstants.cs +++ b/Ryujinx.HLE/HOS/Kernel/KernelConstants.cs @@ -12,5 +12,7 @@ namespace Ryujinx.HLE.HOS.Kernel public const ulong UserSlabHeapBase = DramMemoryMap.SlabHeapBase; public const ulong UserSlabHeapItemSize = KPageTableBase.PageSize; public const ulong UserSlabHeapSize = 0x3de000; + + public const ulong CounterFrequency = 19200000; } } diff --git a/Ryujinx.HLE/HOS/Kernel/KernelContext.cs b/Ryujinx.HLE/HOS/Kernel/KernelContext.cs index 4b8e4d159..6c58e1972 100644 --- a/Ryujinx.HLE/HOS/Kernel/KernelContext.cs +++ b/Ryujinx.HLE/HOS/Kernel/KernelContext.cs @@ -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.Process; using Ryujinx.HLE.HOS.Kernel.SupervisorCall; @@ -23,6 +24,7 @@ namespace Ryujinx.HLE.HOS.Kernel public Switch Device { get; } public MemoryBlock Memory { get; } + public ITickSource TickSource { get; } public Syscall Syscall { get; } public SyscallHandler SyscallHandler { get; } @@ -52,11 +54,13 @@ namespace Ryujinx.HLE.HOS.Kernel private ulong _threadUid; public KernelContext( + ITickSource tickSource, Switch device, MemoryBlock memory, MemorySize memorySize, MemoryArrange memoryArrange) { + TickSource = tickSource; Device = device; Memory = memory; diff --git a/Ryujinx.HLE/HOS/Kernel/Process/HleProcessDebugger.cs b/Ryujinx.HLE/HOS/Kernel/Process/HleProcessDebugger.cs index e0cd4fbf0..0a78a26dd 100644 --- a/Ryujinx.HLE/HOS/Kernel/Process/HleProcessDebugger.cs +++ b/Ryujinx.HLE/HOS/Kernel/Process/HleProcessDebugger.cs @@ -115,7 +115,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process 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)) { return $"0x{v:x16}"; diff --git a/Ryujinx.HLE/HOS/Kernel/Process/IProcessContext.cs b/Ryujinx.HLE/HOS/Kernel/Process/IProcessContext.cs index 707e6d981..c8063a62a 100644 --- a/Ryujinx.HLE/HOS/Kernel/Process/IProcessContext.cs +++ b/Ryujinx.HLE/HOS/Kernel/Process/IProcessContext.cs @@ -1,4 +1,4 @@ -using ARMeilleure.State; +using Ryujinx.Cpu; using Ryujinx.Memory; using System; @@ -8,7 +8,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Process { 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); } } diff --git a/Ryujinx.HLE/HOS/Kernel/Process/KProcess.cs b/Ryujinx.HLE/HOS/Kernel/Process/KProcess.cs index b10737b43..0caeacade 100644 --- a/Ryujinx.HLE/HOS/Kernel/Process/KProcess.cs +++ b/Ryujinx.HLE/HOS/Kernel/Process/KProcess.cs @@ -1,4 +1,3 @@ -using ARMeilleure.State; using Ryujinx.Common; using Ryujinx.Common.Logging; 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; - context.SupervisorCall += KernelContext.SyscallHandler.SvcCall; - context.Undefined += UndefinedInstructionHandler; + return Context?.CreateExecutionContext(new ExceptionCallbacks( + InterruptHandler, + null, + KernelContext.SyscallHandler.SvcCall, + UndefinedInstructionHandler)); } - private void InterruptHandler(object sender, EventArgs e) + private void InterruptHandler(IExecutionContext context) { KThread currentThread = KernelStatic.GetCurrentThread(); @@ -1093,12 +1094,12 @@ namespace Ryujinx.HLE.HOS.Kernel.Process return false; } - private void UndefinedInstructionHandler(object sender, InstUndefinedEventArgs e) + private void UndefinedInstructionHandler(IExecutionContext context, ulong address, int opCode) { KernelStatic.GetCurrentThread().PrintGuestStackTrace(); KernelStatic.GetCurrentThread()?.PrintGuestRegisterPrintout(); - throw new UndefinedInstructionException(e.Address, e.OpCode); + throw new UndefinedInstructionException(address, opCode); } protected override void Destroy() => Context.Dispose(); diff --git a/Ryujinx.HLE/HOS/Kernel/Process/ProcessContext.cs b/Ryujinx.HLE/HOS/Kernel/Process/ProcessContext.cs index bb3a15570..872968309 100644 --- a/Ryujinx.HLE/HOS/Kernel/Process/ProcessContext.cs +++ b/Ryujinx.HLE/HOS/Kernel/Process/ProcessContext.cs @@ -1,4 +1,4 @@ -using ARMeilleure.State; +using Ryujinx.Cpu; using Ryujinx.Memory; using System; @@ -13,7 +13,12 @@ namespace Ryujinx.HLE.HOS.Kernel.Process 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(); } diff --git a/Ryujinx.HLE/HOS/Kernel/Process/ProcessExecutionContext.cs b/Ryujinx.HLE/HOS/Kernel/Process/ProcessExecutionContext.cs new file mode 100644 index 000000000..a08412529 --- /dev/null +++ b/Ryujinx.HLE/HOS/Kernel/Process/ProcessExecutionContext.cs @@ -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() + { + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall.cs b/Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall.cs index d9d492a52..571699d99 100644 --- a/Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall.cs +++ b/Ryujinx.HLE/HOS/Kernel/SupervisorCall/Syscall.cs @@ -1755,7 +1755,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall public ulong GetSystemTick() { - return KernelStatic.GetCurrentThread().Context.CntpctEl0; + return _context.TickSource.Counter; } public void Break(ulong reason) diff --git a/Ryujinx.HLE/HOS/Kernel/SupervisorCall/SyscallHandler.cs b/Ryujinx.HLE/HOS/Kernel/SupervisorCall/SyscallHandler.cs index 5e795d356..cb693f595 100644 --- a/Ryujinx.HLE/HOS/Kernel/SupervisorCall/SyscallHandler.cs +++ b/Ryujinx.HLE/HOS/Kernel/SupervisorCall/SyscallHandler.cs @@ -1,4 +1,4 @@ -using ARMeilleure.State; +using Ryujinx.Cpu; using Ryujinx.HLE.HOS.Kernel.Threading; using System; @@ -17,7 +17,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall _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(); @@ -34,26 +34,24 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall _context.CriticalSection.Leave(); } - ExecutionContext context = (ExecutionContext)sender; - if (context.IsAarch32) { - var svcFunc = SyscallTable.SvcTable32[e.Id]; + var svcFunc = SyscallTable.SvcTable32[id]; 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); } else { - var svcFunc = SyscallTable.SvcTable64[e.Id]; + var svcFunc = SyscallTable.SvcTable64[id]; 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); diff --git a/Ryujinx.HLE/HOS/Kernel/SupervisorCall/SyscallTable.cs b/Ryujinx.HLE/HOS/Kernel/SupervisorCall/SyscallTable.cs index 6e0b70100..8b7e7fb8f 100644 --- a/Ryujinx.HLE/HOS/Kernel/SupervisorCall/SyscallTable.cs +++ b/Ryujinx.HLE/HOS/Kernel/SupervisorCall/SyscallTable.cs @@ -1,5 +1,5 @@ -using ARMeilleure.State; using Ryujinx.Common.Logging; +using Ryujinx.Cpu; using Ryujinx.HLE.HOS.Kernel.Common; using System; using System.Collections.Generic; @@ -14,13 +14,13 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall private const int SvcFuncMaxArguments32 = 4; private const int SvcMax = 0x80; - public static Action[] SvcTable32 { get; } - public static Action[] SvcTable64 { get; } + public static Action[] SvcTable32 { get; } + public static Action[] SvcTable64 { get; } static SyscallTable() { - SvcTable32 = new Action[SvcMax]; - SvcTable64 = new Action[SvcMax]; + SvcTable32 = new Action[SvcMax]; + SvcTable64 = new Action[SvcMax]; Dictionary svcFuncs64 = new Dictionary { @@ -182,9 +182,9 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall } } - private static Action GenerateMethod(string svcName, int registerCleanCount) + private static Action GenerateMethod(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); @@ -292,9 +292,9 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall generator.Emit(OpCodes.Ldarg_1); 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)); @@ -339,9 +339,9 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall generator.Emit(OpCodes.Ldarg_1); 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); @@ -355,9 +355,9 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall generator.Emit(OpCodes.Ldarg_1); 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); } @@ -393,9 +393,9 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall 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; } @@ -415,9 +415,9 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall 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; } @@ -434,14 +434,14 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall generator.Emit(OpCodes.Ldc_I4, i); 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); - return method.CreateDelegate>(); + return method.CreateDelegate>(); } private static void CheckIfTypeIsSupported(Type type, string svcName) diff --git a/Ryujinx.HLE/HOS/Kernel/Threading/KThread.cs b/Ryujinx.HLE/HOS/Kernel/Threading/KThread.cs index ee701a690..b9dd91ef8 100644 --- a/Ryujinx.HLE/HOS/Kernel/Threading/KThread.cs +++ b/Ryujinx.HLE/HOS/Kernel/Threading/KThread.cs @@ -23,7 +23,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading 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; } @@ -115,9 +115,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading public bool WaitingInArbitration { get; set; } - public long LastPc { get; set; } - - private object ActivityOperationLock = new object(); + private object _activityOperationLock; public KThread(KernelContext context) : base(context) { @@ -128,6 +126,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading _mutexWaiters = new LinkedList(); _pinnedWaiters = new LinkedList(); + + _activityOperationLock = new object(); } public KernelResult Initialize( @@ -192,7 +192,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading HostThread = new Thread(ThreadStart); - Context = CpuContext.CreateExecutionContext(); + Context = owner?.CreateExecutionContext() ?? new ProcessExecutionContext(); Context.IsAarch32 = !is64Bits; @@ -208,8 +208,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading Context.SetX(13, (uint)stackTop); } - Context.CntfrqEl0 = 19200000; - Context.Tpidr = (long)_tlsAddress; + Context.TpidrroEl0 = (long)_tlsAddress; ThreadUid = KernelContext.NewThreadUid(); @@ -221,7 +220,6 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading if (owner != null) { - owner.SubscribeThreadEventHandlers(Context); owner.AddThread(this); if (owner.IsPaused) @@ -538,7 +536,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading public KernelResult SetActivity(bool pause) { - lock (ActivityOperationLock) + lock (_activityOperationLock) { KernelResult result = KernelResult.Success; @@ -634,7 +632,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading { context = default; - lock (ActivityOperationLock) + lock (_activityOperationLock) { KernelContext.CriticalSection.Enter(); @@ -656,7 +654,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading return KernelResult.Success; } - private static uint GetPsr(ARMeilleure.State.ExecutionContext context) + private static uint GetPsr(IExecutionContext context) { return context.Pstate & 0xFF0FFE20; } @@ -683,9 +681,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading context.Fp = Context.GetX(29); context.Lr = Context.GetX(30); context.Sp = Context.GetX(31); - context.Pc = (ulong)LastPc; + context.Pc = Context.Pc; context.Pstate = GetPsr(Context); - context.Tpidr = (ulong)Context.Tpidr; + context.Tpidr = (ulong)Context.TpidrroEl0; } else { @@ -699,9 +697,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading context.FpuRegisters[i] = Context.GetV(i); } - context.Pc = (uint)LastPc; + context.Pc = (uint)Context.Pc; context.Pstate = GetPsr(Context); - context.Tpidr = (uint)Context.Tpidr; + context.Tpidr = (uint)Context.TpidrroEl0; } context.Fpcr = (uint)Context.Fpcr; @@ -743,7 +741,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading public KernelResult SetCoreAndAffinityMask(int newCore, ulong newAffinityMask) { - lock (ActivityOperationLock) + lock (_activityOperationLock) { KernelContext.CriticalSection.Enter(); diff --git a/Ryujinx.HLE/HOS/ProgramLoader.cs b/Ryujinx.HLE/HOS/ProgramLoader.cs index 294ca5b82..6b9b6820c 100644 --- a/Ryujinx.HLE/HOS/ProgramLoader.cs +++ b/Ryujinx.HLE/HOS/ProgramLoader.cs @@ -101,7 +101,7 @@ namespace Ryujinx.HLE.HOS 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( creationInfo, @@ -264,7 +264,7 @@ namespace Ryujinx.HLE.HOS return false; } - var processContextFactory = new ArmProcessContextFactory(context.Device.Gpu); + var processContextFactory = new ArmProcessContextFactory(context.Device.System.CpuEngine, context.Device.Gpu); result = process.Initialize( creationInfo, diff --git a/Ryujinx.HLE/HOS/Services/Mii/DatabaseImpl.cs b/Ryujinx.HLE/HOS/Services/Mii/DatabaseImpl.cs index ee094ddf2..6d65de95d 100644 --- a/Ryujinx.HLE/HOS/Services/Mii/DatabaseImpl.cs +++ b/Ryujinx.HLE/HOS/Services/Mii/DatabaseImpl.cs @@ -1,4 +1,5 @@ using LibHac; +using Ryujinx.Cpu; using Ryujinx.HLE.HOS.Services.Mii.Types; using System; @@ -27,7 +28,6 @@ namespace Ryujinx.HLE.HOS.Services.Mii public DatabaseImpl() { - _utilityImpl = new UtilityImpl(); _miiDatabase = new MiiDatabaseManager(); } @@ -148,12 +148,13 @@ namespace Ryujinx.HLE.HOS.Services.Mii 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.LoadFromFile(out _isBroken); - // Nintendo ignore any error code from before + // Nintendo ignores any error code from before. return ResultCode.Success; } diff --git a/Ryujinx.HLE/HOS/Services/Mii/UtilityImpl.cs b/Ryujinx.HLE/HOS/Services/Mii/UtilityImpl.cs index f0cc0fe1d..8b7f33130 100644 --- a/Ryujinx.HLE/HOS/Services/Mii/UtilityImpl.cs +++ b/Ryujinx.HLE/HOS/Services/Mii/UtilityImpl.cs @@ -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.Clock; using System; @@ -12,12 +13,12 @@ namespace Ryujinx.HLE.HOS.Services.Mii private uint _z; private uint _w; - public UtilityImpl() + public UtilityImpl(ITickSource tickSource) { _x = 123456789; _y = 362436069; - TimeSpanType time = TimeManager.Instance.TickBasedSteadyClock.GetCurrentRawTimePoint(null); + TimeSpanType time = TimeManager.Instance.TickBasedSteadyClock.GetCurrentRawTimePoint(tickSource); _w = (uint)(time.NanoSeconds & uint.MaxValue); _z = (uint)((time.NanoSeconds >> 32) & uint.MaxValue); diff --git a/Ryujinx.HLE/HOS/Services/Nfc/Nfp/NfpManager/INfp.cs b/Ryujinx.HLE/HOS/Services/Nfc/Nfp/NfpManager/INfp.cs index 54c784521..c29e07693 100644 --- a/Ryujinx.HLE/HOS/Services/Nfc/Nfp/NfpManager/INfp.cs +++ b/Ryujinx.HLE/HOS/Services/Nfc/Nfp/NfpManager/INfp.cs @@ -688,7 +688,10 @@ namespace Ryujinx.HLE.HOS.Services.Nfc.Nfp { 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); @@ -911,7 +914,7 @@ namespace Ryujinx.HLE.HOS.Services.Nfc.Nfp { throw new ArgumentOutOfRangeException(); } - + context.ResponseData.Write((uint)context.Device.System.NfpDevices[i].State); return ResultCode.Success; diff --git a/Ryujinx.HLE/HOS/Services/Nfc/Nfp/VirtualAmiibo.cs b/Ryujinx.HLE/HOS/Services/Nfc/Nfp/VirtualAmiibo.cs index 35aeade06..00e35799a 100644 --- a/Ryujinx.HLE/HOS/Services/Nfc/Nfp/VirtualAmiibo.cs +++ b/Ryujinx.HLE/HOS/Services/Nfc/Nfp/VirtualAmiibo.cs @@ -1,5 +1,6 @@ using Ryujinx.Common.Configuration; using Ryujinx.Common.Memory; +using Ryujinx.Cpu; using Ryujinx.HLE.HOS.Services.Mii; using Ryujinx.HLE.HOS.Services.Mii.Types; 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); - UtilityImpl utilityImpl = new UtilityImpl(); + UtilityImpl utilityImpl = new UtilityImpl(tickSource); CharInfo charInfo = new CharInfo(); charInfo.SetFromStoreData(StoreData.BuildDefault(utilityImpl, 0)); diff --git a/Ryujinx.HLE/HOS/Services/SurfaceFlinger/BufferQueue.cs b/Ryujinx.HLE/HOS/Services/SurfaceFlinger/BufferQueue.cs index 422414dee..bc0901ab2 100644 --- a/Ryujinx.HLE/HOS/Services/SurfaceFlinger/BufferQueue.cs +++ b/Ryujinx.HLE/HOS/Services/SurfaceFlinger/BufferQueue.cs @@ -6,7 +6,7 @@ { BufferQueueCore core = new BufferQueueCore(device, pid); - producer = new BufferQueueProducer(core); + producer = new BufferQueueProducer(core, device.System.TickSource); consumer = new BufferQueueConsumer(core); return core; diff --git a/Ryujinx.HLE/HOS/Services/SurfaceFlinger/BufferQueueCore.cs b/Ryujinx.HLE/HOS/Services/SurfaceFlinger/BufferQueueCore.cs index 3c9313936..1efd37f49 100644 --- a/Ryujinx.HLE/HOS/Services/SurfaceFlinger/BufferQueueCore.cs +++ b/Ryujinx.HLE/HOS/Services/SurfaceFlinger/BufferQueueCore.cs @@ -1,5 +1,4 @@ using Ryujinx.Common.Logging; -using Ryujinx.HLE.HOS.Kernel; using Ryujinx.HLE.HOS.Kernel.Threading; using Ryujinx.HLE.HOS.Services.SurfaceFlinger.Types; using System; @@ -241,7 +240,7 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger { 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; } diff --git a/Ryujinx.HLE/HOS/Services/SurfaceFlinger/BufferQueueProducer.cs b/Ryujinx.HLE/HOS/Services/SurfaceFlinger/BufferQueueProducer.cs index d4227f01d..833bc26ec 100644 --- a/Ryujinx.HLE/HOS/Services/SurfaceFlinger/BufferQueueProducer.cs +++ b/Ryujinx.HLE/HOS/Services/SurfaceFlinger/BufferQueueProducer.cs @@ -1,4 +1,5 @@ using Ryujinx.Common.Logging; +using Ryujinx.Cpu; using Ryujinx.HLE.HOS.Kernel.Threading; using Ryujinx.HLE.HOS.Services.Settings; using Ryujinx.HLE.HOS.Services.SurfaceFlinger.Types; @@ -12,6 +13,8 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger { public BufferQueueCore Core { get; } + private readonly ITickSource _tickSource; + private uint _stickyTransform; private uint _nextCallbackTicket; @@ -20,9 +23,10 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger private readonly object _callbackLock = new object(); - public BufferQueueProducer(BufferQueueCore core) + public BufferQueueProducer(BufferQueueCore core, ITickSource tickSource) { Core = core; + _tickSource = tickSource; _stickyTransform = 0; _callbackTicket = 0; @@ -179,8 +183,8 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger GraphicBuffer graphicBuffer = Core.Slots[slot].GraphicBuffer.Object; if (Core.Slots[slot].GraphicBuffer.IsNull - || graphicBuffer.Width != width - || graphicBuffer.Height != height + || graphicBuffer.Width != width + || graphicBuffer.Height != height || graphicBuffer.Format != format || (graphicBuffer.Usage & usage) != usage) { @@ -193,7 +197,7 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger } else { - Logger.Error?.Print(LogClass.SurfaceFlinger, + Logger.Error?.Print(LogClass.SurfaceFlinger, $"Preallocated buffer mismatch - slot {slot}\n" + $"available: Width = {graphicBuffer.Width} Height = {graphicBuffer.Height} Format = {graphicBuffer.Format} Usage = {graphicBuffer.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.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; item.AcquireCalled = Core.Slots[slot].AcquireCalled; diff --git a/Ryujinx.HLE/HOS/Services/Time/Clock/StandardNetworkSystemClockCore.cs b/Ryujinx.HLE/HOS/Services/Time/Clock/StandardNetworkSystemClockCore.cs index b86f703db..aec034850 100644 --- a/Ryujinx.HLE/HOS/Services/Time/Clock/StandardNetworkSystemClockCore.cs +++ b/Ryujinx.HLE/HOS/Services/Time/Clock/StandardNetworkSystemClockCore.cs @@ -1,4 +1,4 @@ -using Ryujinx.HLE.HOS.Kernel.Threading; +using Ryujinx.Cpu; namespace Ryujinx.HLE.HOS.Services.Time.Clock { @@ -11,14 +11,14 @@ namespace Ryujinx.HLE.HOS.Services.Time.Clock _standardNetworkClockSufficientAccuracy = new TimeSpanType(0); } - public bool IsStandardNetworkSystemClockAccuracySufficient(KThread thread) + public bool IsStandardNetworkSystemClockAccuracySufficient(ITickSource tickSource) { SteadyClockCore steadyClockCore = GetSteadyClockCore(); - SteadyClockTimePoint currentTimePoint = steadyClockCore.GetCurrentTimePoint(thread); + SteadyClockTimePoint currentTimePoint = steadyClockCore.GetCurrentTimePoint(tickSource); 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) { diff --git a/Ryujinx.HLE/HOS/Services/Time/Clock/StandardSteadyClockCore.cs b/Ryujinx.HLE/HOS/Services/Time/Clock/StandardSteadyClockCore.cs index 370e7d73c..8392c4b50 100644 --- a/Ryujinx.HLE/HOS/Services/Time/Clock/StandardSteadyClockCore.cs +++ b/Ryujinx.HLE/HOS/Services/Time/Clock/StandardSteadyClockCore.cs @@ -1,4 +1,4 @@ -using Ryujinx.HLE.HOS.Kernel.Threading; +using Ryujinx.Cpu; namespace Ryujinx.HLE.HOS.Services.Time.Clock { @@ -17,11 +17,11 @@ namespace Ryujinx.HLE.HOS.Services.Time.Clock _cachedRawTimePoint = TimeSpanType.Zero; } - public override SteadyClockTimePoint GetTimePoint(KThread thread) + public override SteadyClockTimePoint GetTimePoint(ITickSource tickSource) { SteadyClockTimePoint result = new SteadyClockTimePoint { - TimePoint = GetCurrentRawTimePoint(thread).ToSeconds(), + TimePoint = GetCurrentRawTimePoint(tickSource).ToSeconds(), ClockSourceId = GetClockSourceId() }; @@ -48,19 +48,9 @@ namespace Ryujinx.HLE.HOS.Services.Time.Clock _internalOffset = internalOffset; } - public override TimeSpanType GetCurrentRawTimePoint(KThread thread) + public override TimeSpanType GetCurrentRawTimePoint(ITickSource tickSource) { - TimeSpanType ticksTimeSpan; - - // 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 ticksTimeSpan = TimeSpanType.FromTicks(tickSource.Counter, tickSource.Frequency); TimeSpanType rawTimePoint = new TimeSpanType(_setupValue.NanoSeconds + ticksTimeSpan.NanoSeconds); diff --git a/Ryujinx.HLE/HOS/Services/Time/Clock/StandardUserSystemClockCore.cs b/Ryujinx.HLE/HOS/Services/Time/Clock/StandardUserSystemClockCore.cs index 2499b549f..fa485437b 100644 --- a/Ryujinx.HLE/HOS/Services/Time/Clock/StandardUserSystemClockCore.cs +++ b/Ryujinx.HLE/HOS/Services/Time/Clock/StandardUserSystemClockCore.cs @@ -1,4 +1,5 @@ -using Ryujinx.HLE.HOS.Kernel.Threading; +using Ryujinx.Cpu; +using Ryujinx.HLE.HOS.Kernel.Threading; using System; namespace Ryujinx.HLE.HOS.Services.Time.Clock @@ -26,15 +27,15 @@ namespace Ryujinx.HLE.HOS.Services.Time.Clock 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(); if (result == ResultCode.Success) { - return _localSystemClockCore.GetClockContext(thread, out context); + return _localSystemClockCore.GetClockContext(tickSource, out context); } return result; @@ -45,13 +46,13 @@ namespace Ryujinx.HLE.HOS.Services.Time.Clock return ResultCode.NotImplemented; } - private ResultCode ApplyAutomaticCorrection(KThread thread, bool autoCorrectionEnabled) + private ResultCode ApplyAutomaticCorrection(ITickSource tickSource, bool autoCorrectionEnabled) { 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) { @@ -67,9 +68,9 @@ namespace Ryujinx.HLE.HOS.Services.Time.Clock _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) { diff --git a/Ryujinx.HLE/HOS/Services/Time/Clock/SteadyClockCore.cs b/Ryujinx.HLE/HOS/Services/Time/Clock/SteadyClockCore.cs index 83ace9814..4bb19e752 100644 --- a/Ryujinx.HLE/HOS/Services/Time/Clock/SteadyClockCore.cs +++ b/Ryujinx.HLE/HOS/Services/Time/Clock/SteadyClockCore.cs @@ -1,4 +1,4 @@ -using Ryujinx.HLE.HOS.Kernel.Threading; +using Ryujinx.Cpu; using Ryujinx.HLE.Utilities; using System; @@ -63,21 +63,21 @@ namespace Ryujinx.HLE.HOS.Services.Time.Clock public virtual void SetInternalOffset(TimeSpanType internalOffset) {} - public virtual SteadyClockTimePoint GetTimePoint(KThread thread) + public virtual SteadyClockTimePoint GetTimePoint(ITickSource tickSource) { 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); } - public SteadyClockTimePoint GetCurrentTimePoint(KThread thread) + public SteadyClockTimePoint GetCurrentTimePoint(ITickSource tickSource) { - SteadyClockTimePoint result = GetTimePoint(thread); + SteadyClockTimePoint result = GetTimePoint(tickSource); result.TimePoint += GetTestOffset().ToSeconds(); result.TimePoint += GetInternalOffset().ToSeconds(); diff --git a/Ryujinx.HLE/HOS/Services/Time/Clock/SystemClockCore.cs b/Ryujinx.HLE/HOS/Services/Time/Clock/SystemClockCore.cs index 865b1c098..f4bbaa604 100644 --- a/Ryujinx.HLE/HOS/Services/Time/Clock/SystemClockCore.cs +++ b/Ryujinx.HLE/HOS/Services/Time/Clock/SystemClockCore.cs @@ -1,4 +1,4 @@ -using System; +using Ryujinx.Cpu; using Ryujinx.HLE.HOS.Kernel.Threading; namespace Ryujinx.HLE.HOS.Services.Time.Clock @@ -25,13 +25,13 @@ namespace Ryujinx.HLE.HOS.Services.Time.Clock return _steadyClockCore; } - public ResultCode GetCurrentTime(KThread thread, out long posixTime) + public ResultCode GetCurrentTime(ITickSource tickSource, out long posixTime) { 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) { @@ -48,9 +48,9 @@ namespace Ryujinx.HLE.HOS.Services.Time.Clock 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() { @@ -68,7 +68,7 @@ namespace Ryujinx.HLE.HOS.Services.Time.Clock return result; } - public virtual ResultCode GetClockContext(KThread thread, out SystemClockContext context) + public virtual ResultCode GetClockContext(ITickSource tickSource, out SystemClockContext context) { context = _context; @@ -127,13 +127,13 @@ namespace Ryujinx.HLE.HOS.Services.Time.Clock _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) { - SteadyClockTimePoint steadyClockTimePoint = _steadyClockCore.GetCurrentTimePoint(thread); + SteadyClockTimePoint steadyClockTimePoint = _steadyClockCore.GetCurrentTimePoint(tickSource); return steadyClockTimePoint.ClockSourceId == context.SteadyTimePoint.ClockSourceId; } diff --git a/Ryujinx.HLE/HOS/Services/Time/Clock/TickBasedSteadyClockCore.cs b/Ryujinx.HLE/HOS/Services/Time/Clock/TickBasedSteadyClockCore.cs index 065020827..fe74da7e9 100644 --- a/Ryujinx.HLE/HOS/Services/Time/Clock/TickBasedSteadyClockCore.cs +++ b/Ryujinx.HLE/HOS/Services/Time/Clock/TickBasedSteadyClockCore.cs @@ -1,4 +1,4 @@ -using Ryujinx.HLE.HOS.Kernel.Threading; +using Ryujinx.Cpu; namespace Ryujinx.HLE.HOS.Services.Time.Clock { @@ -6,7 +6,7 @@ namespace Ryujinx.HLE.HOS.Services.Time.Clock { public TickBasedSteadyClockCore() {} - public override SteadyClockTimePoint GetTimePoint(KThread thread) + public override SteadyClockTimePoint GetTimePoint(ITickSource tickSource) { SteadyClockTimePoint result = new SteadyClockTimePoint { @@ -14,17 +14,7 @@ namespace Ryujinx.HLE.HOS.Services.Time.Clock ClockSourceId = GetClockSourceId() }; - TimeSpanType ticksTimeSpan; - - // 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 ticksTimeSpan = TimeSpanType.FromTicks(tickSource.Counter, tickSource.Frequency); result.TimePoint = ticksTimeSpan.ToSeconds(); diff --git a/Ryujinx.HLE/HOS/Services/Time/IStaticServiceForPsc.cs b/Ryujinx.HLE/HOS/Services/Time/IStaticServiceForPsc.cs index 534af4576..441e4267b 100644 --- a/Ryujinx.HLE/HOS/Services/Time/IStaticServiceForPsc.cs +++ b/Ryujinx.HLE/HOS/Services/Time/IStaticServiceForPsc.cs @@ -2,7 +2,6 @@ using Ryujinx.Common; using Ryujinx.Cpu; using Ryujinx.HLE.HOS.Ipc; 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.StaticService; using Ryujinx.HLE.HOS.Services.Time.TimeZone; @@ -163,13 +162,15 @@ namespace Ryujinx.HLE.HOS.Services.Time 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) { _timeManager.SharedMemory.SetAutomaticCorrectionEnabled(autoCorrectionEnabled); - SteadyClockTimePoint currentTimePoint = userClock.GetSteadyClockCore().GetCurrentTimePoint(context.Thread); + SteadyClockTimePoint currentTimePoint = userClock.GetSteadyClockCore().GetCurrentTimePoint(tickSource); userClock.SetAutomaticCorrectionUpdatedTime(currentTimePoint); userClock.SignalAutomaticCorrectionEvent(); @@ -190,7 +191,9 @@ namespace Ryujinx.HLE.HOS.Services.Time // IsStandardNetworkSystemClockAccuracySufficient() -> bool 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; } @@ -222,14 +225,16 @@ namespace Ryujinx.HLE.HOS.Services.Time return ResultCode.UninitializedClock; } + ITickSource tickSource = context.Device.System.TickSource; + SystemClockContext otherContext = context.RequestData.ReadStruct(); - SteadyClockTimePoint currentTimePoint = steadyClock.GetCurrentTimePoint(context.Thread); + SteadyClockTimePoint currentTimePoint = steadyClock.GetCurrentTimePoint(tickSource); ResultCode result = ResultCode.TimeMismatch; 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(); 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()); - 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) { - result = _timeManager.StandardNetworkSystemClock.GetClockContext(context.Thread, out SystemClockContext networkContext); + result = _timeManager.StandardNetworkSystemClock.GetClockContext(tickSource, out SystemClockContext networkContext); 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) { @@ -281,7 +288,9 @@ namespace Ryujinx.HLE.HOS.Services.Time SystemClockContext userContext = context.RequestData.ReadStruct(); SystemClockContext networkContext = context.RequestData.ReadStruct(); - 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) { @@ -344,12 +353,12 @@ namespace Ryujinx.HLE.HOS.Services.Time 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(); SteadyClockCore steadyClockCore = _timeManager.StandardSteadyClock; - SteadyClockTimePoint currentTimePoint = steadyClockCore.GetCurrentTimePoint(thread); + SteadyClockTimePoint currentTimePoint = steadyClockCore.GetCurrentTimePoint(tickSource); clockSnapshot.IsAutomaticCorrectionEnabled = _timeManager.StandardUserSystemClock.IsAutomaticCorrectionEnabled(); clockSnapshot.UserContext = userContext; diff --git a/Ryujinx.HLE/HOS/Services/Time/ITimeServiceManager.cs b/Ryujinx.HLE/HOS/Services/Time/ITimeServiceManager.cs index be71bb4fc..1ff5b2d69 100644 --- a/Ryujinx.HLE/HOS/Services/Time/ITimeServiceManager.cs +++ b/Ryujinx.HLE/HOS/Services/Time/ITimeServiceManager.cs @@ -1,4 +1,5 @@ using Ryujinx.Common; +using Ryujinx.Cpu; using Ryujinx.HLE.Exceptions; using Ryujinx.HLE.HOS.Ipc; using Ryujinx.HLE.HOS.Kernel.Common; @@ -6,7 +7,6 @@ using Ryujinx.HLE.HOS.Services.Time.Clock; using Ryujinx.HLE.Utilities; using System; using System.IO; -using System.Text; namespace Ryujinx.HLE.HOS.Services.Time { @@ -68,7 +68,9 @@ namespace Ryujinx.HLE.HOS.Services.Time TimeSpanType testOffset = context.RequestData.ReadStruct(); 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; } @@ -80,7 +82,9 @@ namespace Ryujinx.HLE.HOS.Services.Time SystemClockContext clockContext = context.RequestData.ReadStruct(); 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; } @@ -107,7 +111,9 @@ namespace Ryujinx.HLE.HOS.Services.Time SteadyClockTimePoint steadyClockTimePoint = context.RequestData.ReadStruct(); - _timeManager.SetupStandardUserSystemClock(context.Thread, isAutomaticCorrectionEnabled, steadyClockTimePoint); + ITickSource tickSource = context.Device.System.TickSource; + + _timeManager.SetupStandardUserSystemClock(tickSource, isAutomaticCorrectionEnabled, steadyClockTimePoint); return ResultCode.Success; } @@ -191,7 +197,9 @@ namespace Ryujinx.HLE.HOS.Services.Time { TimeSpanType rtcOffset = context.RequestData.ReadStruct(); - _timeManager.SetStandardSteadyClockRtcOffset(context.Thread, rtcOffset); + ITickSource tickSource = context.Device.System.TickSource; + + _timeManager.SetStandardSteadyClockRtcOffset(tickSource, rtcOffset); return ResultCode.Success; } diff --git a/Ryujinx.HLE/HOS/Services/Time/StaticService/ISteadyClock.cs b/Ryujinx.HLE/HOS/Services/Time/StaticService/ISteadyClock.cs index a5ce8d6a3..1e5177131 100644 --- a/Ryujinx.HLE/HOS/Services/Time/StaticService/ISteadyClock.cs +++ b/Ryujinx.HLE/HOS/Services/Time/StaticService/ISteadyClock.cs @@ -1,4 +1,5 @@ using Ryujinx.Common; +using Ryujinx.Cpu; using Ryujinx.HLE.HOS.Services.Time.Clock; namespace Ryujinx.HLE.HOS.Services.Time.StaticService @@ -25,7 +26,9 @@ namespace Ryujinx.HLE.HOS.Services.Time.StaticService return ResultCode.UninitializedClock; } - SteadyClockTimePoint currentTimePoint = _steadyClock.GetCurrentTimePoint(context.Thread); + ITickSource tickSource = context.Device.System.TickSource; + + SteadyClockTimePoint currentTimePoint = _steadyClock.GetCurrentTimePoint(tickSource); context.ResponseData.WriteStruct(currentTimePoint); diff --git a/Ryujinx.HLE/HOS/Services/Time/StaticService/ISystemClock.cs b/Ryujinx.HLE/HOS/Services/Time/StaticService/ISystemClock.cs index 1d9f78739..085cc71dc 100644 --- a/Ryujinx.HLE/HOS/Services/Time/StaticService/ISystemClock.cs +++ b/Ryujinx.HLE/HOS/Services/Time/StaticService/ISystemClock.cs @@ -1,4 +1,5 @@ using Ryujinx.Common; +using Ryujinx.Cpu; using Ryujinx.HLE.HOS.Ipc; using Ryujinx.HLE.HOS.Kernel.Common; using Ryujinx.HLE.HOS.Kernel.Threading; @@ -31,7 +32,9 @@ namespace Ryujinx.HLE.HOS.Services.Time.StaticService 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) { @@ -57,7 +60,9 @@ namespace Ryujinx.HLE.HOS.Services.Time.StaticService long posixTime = context.RequestData.ReadInt64(); - return _clockCore.SetCurrentTime(context.Thread, posixTime); + ITickSource tickSource = context.Device.System.TickSource; + + return _clockCore.SetCurrentTime(tickSource, posixTime); } [CommandHipc(2)] @@ -69,7 +74,9 @@ namespace Ryujinx.HLE.HOS.Services.Time.StaticService 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) { diff --git a/Ryujinx.HLE/HOS/Services/Time/StaticService/ITimeZoneServiceForPsc.cs b/Ryujinx.HLE/HOS/Services/Time/StaticService/ITimeZoneServiceForPsc.cs index 83d745e32..202099b05 100644 --- a/Ryujinx.HLE/HOS/Services/Time/StaticService/ITimeZoneServiceForPsc.cs +++ b/Ryujinx.HLE/HOS/Services/Time/StaticService/ITimeZoneServiceForPsc.cs @@ -7,7 +7,6 @@ using Ryujinx.HLE.Utilities; using System; using System.Diagnostics; using System.IO; -using System.Text; namespace Ryujinx.HLE.HOS.Services.Time.StaticService { @@ -44,7 +43,7 @@ namespace Ryujinx.HLE.HOS.Services.Time.StaticService { return ResultCode.PermissionDenied; } - + return ResultCode.NotImplemented; } diff --git a/Ryujinx.HLE/HOS/Services/Time/TimeManager.cs b/Ryujinx.HLE/HOS/Services/Time/TimeManager.cs index e22178906..ac9f0880b 100644 --- a/Ryujinx.HLE/HOS/Services/Time/TimeManager.cs +++ b/Ryujinx.HLE/HOS/Services/Time/TimeManager.cs @@ -1,11 +1,10 @@ -using System; -using System.IO; +using Ryujinx.Cpu; using Ryujinx.HLE.Exceptions; 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.TimeZone; using Ryujinx.HLE.Utilities; +using System.IO; namespace Ryujinx.HLE.HOS.Services.Time { @@ -68,14 +67,13 @@ namespace Ryujinx.HLE.HOS.Services.Time TimeZone.Initialize(this, device); } - - public void SetupStandardSteadyClock(KThread thread, UInt128 clockSourceId, TimeSpanType setupValue, TimeSpanType internalOffset, TimeSpanType testOffset, bool isRtcResetDetected) + public void SetupStandardSteadyClock(ITickSource tickSource, UInt128 clockSourceId, TimeSpanType setupValue, TimeSpanType internalOffset, TimeSpanType testOffset, bool 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" } @@ -97,18 +95,18 @@ namespace Ryujinx.HLE.HOS.Services.Time // 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); - SteadyClockTimePoint currentTimePoint = StandardLocalSystemClock.GetSteadyClockCore().GetCurrentTimePoint(thread); + SteadyClockTimePoint currentTimePoint = StandardLocalSystemClock.GetSteadyClockCore().GetCurrentTimePoint(tickSource); if (currentTimePoint.ClockSourceId == clockContext.SteadyTimePoint.ClockSourceId) { StandardLocalSystemClock.SetSystemClockContext(clockContext); } else { - if (StandardLocalSystemClock.SetCurrentTime(thread, posixTime) != ResultCode.Success) + if (StandardLocalSystemClock.SetCurrentTime(tickSource, posixTime) != ResultCode.Success) { 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" } - 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"); } @@ -172,13 +170,13 @@ namespace Ryujinx.HLE.HOS.Services.Time // 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); - TimeSpanType currentTimePoint = StandardSteadyClock.GetCurrentRawTimePoint(thread); + TimeSpanType currentTimePoint = StandardSteadyClock.GetCurrentRawTimePoint(tickSource); - SharedMemory.SetSteadyClockRawTimePoint(thread, currentTimePoint); + SharedMemory.SetSteadyClockRawTimePoint(tickSource, currentTimePoint); } } } diff --git a/Ryujinx.HLE/HOS/Services/Time/TimeSharedMemory.cs b/Ryujinx.HLE/HOS/Services/Time/TimeSharedMemory.cs index 8b08b040a..7063290bc 100644 --- a/Ryujinx.HLE/HOS/Services/Time/TimeSharedMemory.cs +++ b/Ryujinx.HLE/HOS/Services/Time/TimeSharedMemory.cs @@ -1,12 +1,11 @@ -using System; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; -using System.Threading; +using Ryujinx.Cpu; 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.Types; using Ryujinx.HLE.Utilities; +using System; +using System.Runtime.CompilerServices; +using System.Threading; namespace Ryujinx.HLE.HOS.Services.Time { @@ -38,19 +37,9 @@ namespace Ryujinx.HLE.HOS.Services.Time return _sharedMemory; } - public void SetupStandardSteadyClock(KThread thread, UInt128 clockSourceId, TimeSpanType currentTimePoint) + public void SetupStandardSteadyClock(ITickSource tickSource, UInt128 clockSourceId, TimeSpanType currentTimePoint) { - TimeSpanType ticksTimeSpan; - - // 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 ticksTimeSpan = TimeSpanType.FromTicks(tickSource.Counter, tickSource.Frequency); SteadyClockContext context = new SteadyClockContext { @@ -67,10 +56,10 @@ namespace Ryujinx.HLE.HOS.Services.Time WriteObjectToSharedMemory(AutomaticCorrectionEnabledOffset, 0, Convert.ToByte(isAutomaticCorrectionEnabled)); } - public void SetSteadyClockRawTimePoint(KThread thread, TimeSpanType currentTimePoint) + public void SetSteadyClockRawTimePoint(ITickSource tickSource, TimeSpanType currentTimePoint) { SteadyClockContext context = ReadObjectFromSharedMemory(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); diff --git a/Ryujinx.HLE/HOS/Services/Time/TimeZone/TimeZoneContentManager.cs b/Ryujinx.HLE/HOS/Services/Time/TimeZone/TimeZoneContentManager.cs index 8ff090260..141c2b4a5 100644 --- a/Ryujinx.HLE/HOS/Services/Time/TimeZone/TimeZoneContentManager.cs +++ b/Ryujinx.HLE/HOS/Services/Time/TimeZone/TimeZoneContentManager.cs @@ -7,6 +7,7 @@ using LibHac.Ncm; using LibHac.Tools.FsSystem; using LibHac.Tools.FsSystem.NcaUtils; using Ryujinx.Common.Logging; +using Ryujinx.Cpu; using Ryujinx.HLE.Exceptions; using Ryujinx.HLE.FileSystem; 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); - SteadyClockTimePoint timeZoneUpdatedTimePoint = timeManager.StandardSteadyClock.GetCurrentTimePoint(null); + ITickSource tickSource = device.System.TickSource; + + SteadyClockTimePoint timeZoneUpdatedTimePoint = timeManager.StandardSteadyClock.GetCurrentTimePoint(tickSource); string deviceLocationName = SanityCheckDeviceLocationName(device.Configuration.TimeZone); diff --git a/Ryujinx.Cpu/CpuContext.cs b/Ryujinx.Tests/Cpu/CpuContext.cs similarity index 88% rename from Ryujinx.Cpu/CpuContext.cs rename to Ryujinx.Tests/Cpu/CpuContext.cs index 9c09746bf..96b4965a2 100644 --- a/Ryujinx.Cpu/CpuContext.cs +++ b/Ryujinx.Tests/Cpu/CpuContext.cs @@ -1,8 +1,10 @@ -using ARMeilleure.Memory; +using ARMeilleure.Memory; using ARMeilleure.State; using ARMeilleure.Translation; +using Ryujinx.Cpu; +using Ryujinx.Cpu.Jit; -namespace Ryujinx.Cpu +namespace Ryujinx.Tests.Cpu { public class CpuContext { @@ -21,7 +23,7 @@ namespace Ryujinx.Cpu public static ExecutionContext CreateExecutionContext() { - return new ExecutionContext(new JitMemoryAllocator()); + return new ExecutionContext(new JitMemoryAllocator(), new TickSource(19200000)); } public void Execute(ExecutionContext context, ulong address) diff --git a/Ryujinx.Tests/Cpu/CpuTest.cs b/Ryujinx.Tests/Cpu/CpuTest.cs index 9cee54970..5fe43dec4 100644 --- a/Ryujinx.Tests/Cpu/CpuTest.cs +++ b/Ryujinx.Tests/Cpu/CpuTest.cs @@ -2,7 +2,7 @@ using ARMeilleure; using ARMeilleure.State; using ARMeilleure.Translation; using NUnit.Framework; -using Ryujinx.Cpu; +using Ryujinx.Cpu.Jit; using Ryujinx.Memory; using Ryujinx.Tests.Unicorn; using System; diff --git a/Ryujinx.Tests/Cpu/CpuTest32.cs b/Ryujinx.Tests/Cpu/CpuTest32.cs index d5dc18eac..1bd87aee1 100644 --- a/Ryujinx.Tests/Cpu/CpuTest32.cs +++ b/Ryujinx.Tests/Cpu/CpuTest32.cs @@ -2,7 +2,7 @@ using ARMeilleure.State; using ARMeilleure.Translation; using NUnit.Framework; -using Ryujinx.Cpu; +using Ryujinx.Cpu.Jit; using Ryujinx.Memory; using Ryujinx.Tests.Unicorn; using System;