diff --git a/ARMeilleure/Instructions/InstEmitSystem.cs b/ARMeilleure/Instructions/InstEmitSystem.cs
index 499f16488e..50dab07d2d 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 0b76f68147..eebb824e11 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 0000000000..38d6eef78f
--- /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 8309864f4d..c73ca197d1 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<EventArgs>              Interrupt;
-        public event EventHandler<InstExceptionEventArgs> Break;
-        public event EventHandler<InstExceptionEventArgs> SupervisorCall;
-        public event EventHandler<InstUndefinedEventArgs> 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 0000000000..93e721ea3c
--- /dev/null
+++ b/ARMeilleure/State/ICounter.cs
@@ -0,0 +1,18 @@
+namespace ARMeilleure.State
+{
+    /// <summary>
+    /// CPU Counter interface.
+    /// </summary>
+    public interface ICounter
+    {
+        /// <summary>
+        /// Counter frequency in Hertz.
+        /// </summary>
+        ulong Frequency { get; }
+
+        /// <summary>
+        /// Current counter value.
+        /// </summary>
+        ulong Counter { get; }
+    }
+}
\ No newline at end of file
diff --git a/ARMeilleure/State/InstExceptionEventArgs.cs b/ARMeilleure/State/InstExceptionEventArgs.cs
deleted file mode 100644
index c2460e4b4f..0000000000
--- 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 c02b648e14..0000000000
--- 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 f911f76266..11ab5ca3a9 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 3cfe34b68d..6d40dc96d3 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 43f3b08bdb..9671a87148 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 0c41909e5f..5fa5b797f2 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 d20c3c0300..90be711198 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
         /// </summary>
         private IHardwareDeviceDriver _deviceDriver;
 
+        /// <summary>
+        /// Tick source used to measure elapsed time.
+        /// </summary>
+        public ITickSource TickSource { get; }
+
         /// <summary>
         /// The <see cref="AudioProcessor"/> instance associated to this manager.
         /// </summary>
@@ -90,9 +96,11 @@ namespace Ryujinx.Audio.Renderer.Server
         /// <summary>
         /// Create a new <see cref="AudioRendererManager"/>.
         /// </summary>
-        public AudioRendererManager()
+        /// <param name="tickSource">Tick source used to measure elapsed time.</param>
+        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 0000000000..1485ca7d2a
--- /dev/null
+++ b/Ryujinx.Cpu/ExceptionCallbacks.cs
@@ -0,0 +1,64 @@
+namespace Ryujinx.Cpu
+{
+    /// <summary>
+    /// Exception callback without any additional arguments.
+    /// </summary>
+    /// <param name="context">Context for the thread where the exception was triggered</param>
+    public delegate void ExceptionCallbackNoArgs(IExecutionContext context);
+
+    /// <summary>
+    /// Exception callback.
+    /// </summary>
+    /// <param name="context">Context for the thread where the exception was triggered</param>
+    /// <param name="address">Address of the instruction that caused the exception</param>
+    /// <param name="imm">Immediate value of the instruction that caused the exception, or for undefined instruction, the instruction itself</param>
+    public delegate void ExceptionCallback(IExecutionContext context, ulong address, int imm);
+
+    /// <summary>
+    /// Stores handlers for the various CPU exceptions.
+    /// </summary>
+    public struct ExceptionCallbacks
+    {
+        /// <summary>
+        /// Handler for CPU interrupts triggered using <see cref="IExecutionContext.RequestInterrupt"/>.
+        /// </summary>
+        public readonly ExceptionCallbackNoArgs InterruptCallback;
+
+        /// <summary>
+        /// Handler for CPU software interrupts caused by the Arm BRK instruction.
+        /// </summary>
+        public readonly ExceptionCallback BreakCallback;
+
+        /// <summary>
+        /// Handler for CPU software interrupts caused by the Arm SVC instruction.
+        /// </summary>
+        public readonly ExceptionCallback SupervisorCallback;
+
+        /// <summary>
+        /// Handler for CPU software interrupts caused by any undefined Arm instruction.
+        /// </summary>
+        public readonly ExceptionCallback UndefinedCallback;
+
+        /// <summary>
+        /// Creates a new exception callbacks structure.
+        /// </summary>
+        /// <remarks>
+        /// All handlers are optional, and if null, the CPU will just continue executing as if nothing happened.
+        /// </remarks>
+        /// <param name="interruptCallback">Handler for CPU interrupts triggered using <see cref="IExecutionContext.RequestInterrupt"/></param>
+        /// <param name="breakCallback">Handler for CPU software interrupts caused by the Arm BRK instruction</param>
+        /// <param name="supervisorCallback">Handler for CPU software interrupts caused by the Arm SVC instruction</param>
+        /// <param name="undefinedCallback">Handler for CPU software interrupts caused by any undefined Arm instruction</param>
+        public ExceptionCallbacks(
+            ExceptionCallbackNoArgs interruptCallback = null,
+            ExceptionCallback breakCallback = null,
+            ExceptionCallback supervisorCallback = null,
+            ExceptionCallback undefinedCallback = null)
+        {
+            InterruptCallback = interruptCallback;
+            BreakCallback = breakCallback;
+            SupervisorCallback = supervisorCallback;
+            UndefinedCallback = undefinedCallback;
+        }
+    }
+}
diff --git a/Ryujinx.Cpu/ICpuContext.cs b/Ryujinx.Cpu/ICpuContext.cs
new file mode 100644
index 0000000000..4a73a83384
--- /dev/null
+++ b/Ryujinx.Cpu/ICpuContext.cs
@@ -0,0 +1,39 @@
+namespace Ryujinx.Cpu
+{
+    /// <summary>
+    /// CPU context interface.
+    /// </summary>
+    public interface ICpuContext
+    {
+        /// <summary>
+        /// Creates a new execution context that will store thread CPU register state when executing guest code.
+        /// </summary>
+        /// <param name="exceptionCallbacks">Optional functions to be called when the CPU receives an interrupt</param>
+        /// <returns>Execution context</returns>
+        IExecutionContext CreateExecutionContext(ExceptionCallbacks exceptionCallbacks);
+
+        /// <summary>
+        /// Starts executing code at a specified entry point address.
+        /// </summary>
+        /// <remarks>
+        /// This function only returns when the execution is stopped, by calling <see cref="IExecutionContext.StopRunning"/>.
+        /// </remarks>
+        /// <param name="context">Execution context to be used for this run</param>
+        /// <param name="address">Entry point address</param>
+        void Execute(IExecutionContext context, ulong address);
+
+        /// <summary>
+        /// Invalidates the instruction cache for a given memory region.
+        /// </summary>
+        /// <remarks>
+        /// This should be called if code is modified to make the CPU emulator aware of the modifications,
+        /// otherwise it might run stale code which will lead to errors and crashes.
+        /// Calling this function is not necessary if the code memory was modified by guest code,
+        /// as the expectation is that it will do it on its own using the appropriate cache invalidation instructions,
+        /// except on Arm32 where those instructions can't be used in unprivileged mode.
+        /// </remarks>
+        /// <param name="address">Address of the region to be invalidated</param>
+        /// <param name="size">Size of the region to be invalidated</param>
+        void InvalidateCacheRegion(ulong address, ulong size);
+    }
+}
diff --git a/Ryujinx.Cpu/ICpuEngine.cs b/Ryujinx.Cpu/ICpuEngine.cs
new file mode 100644
index 0000000000..b53b23a8c6
--- /dev/null
+++ b/Ryujinx.Cpu/ICpuEngine.cs
@@ -0,0 +1,18 @@
+using ARMeilleure.Memory;
+
+namespace Ryujinx.Cpu
+{
+    /// <summary>
+    /// CPU execution engine interface.
+    /// </summary>
+    public interface ICpuEngine
+    {
+        /// <summary>
+        /// Creates a new CPU context that can be used to run code for multiple threads sharing an address space.
+        /// </summary>
+        /// <param name="memoryManager">Memory manager for the address space of the context</param>
+        /// <param name="for64Bit">Indicates if the context will be used to run 64-bit or 32-bit Arm code</param>
+        /// <returns>CPU context</returns>
+        ICpuContext CreateCpuContext(IMemoryManager memoryManager, bool for64Bit);
+    }
+}
diff --git a/Ryujinx.Cpu/IExecutionContext.cs b/Ryujinx.Cpu/IExecutionContext.cs
new file mode 100644
index 0000000000..3455b5c1e9
--- /dev/null
+++ b/Ryujinx.Cpu/IExecutionContext.cs
@@ -0,0 +1,112 @@
+using ARMeilleure.State;
+using System;
+
+namespace Ryujinx.Cpu
+{
+    /// <summary>
+    /// CPU register state interface.
+    /// </summary>
+    public interface IExecutionContext : IDisposable
+    {
+        /// <summary>
+        /// Current Program Counter.
+        /// </summary>
+        /// <remarks>
+        /// In some implementations, this value might not be accurate and might not point to the last instruction executed.
+        /// </remarks>
+        ulong Pc { get; }
+
+        /// <summary>
+        /// Thread ID Register (EL0).
+        /// </summary>
+        long TpidrEl0 { get; set; }
+
+        /// <summary>
+        /// Thread ID Register (read-only) (EL0).
+        /// </summary>
+        long TpidrroEl0 { get; set; }
+
+        /// <summary>
+        /// Processor State register.
+        /// </summary>
+        uint Pstate { get; set; }
+
+        /// <summary>
+        /// Floating-point Control Register.
+        /// </summary>
+        uint Fpcr { get; set; }
+
+        /// <summary>
+        /// Floating-point Status Register.
+        /// </summary>
+        uint Fpsr { get; set; }
+
+        /// <summary>
+        /// Indicates whenever the CPU is running 64-bit (AArch64 mode) or 32-bit (AArch32 mode) code.
+        /// </summary>
+        bool IsAarch32 { get; set; }
+
+        /// <summary>
+        /// Indicates whenever the CPU is still running code.
+        /// </summary>
+        /// <remarks>
+        /// Even if this is false, the guest code might be still exiting.
+        /// One must not assume that the code is no longer running from this property alone.
+        /// </remarks>
+        bool Running { get; }
+
+        /// <summary>
+        /// Gets the value of a general purpose register.
+        /// </summary>
+        /// <remarks>
+        /// The special <paramref name="index"/> of 31 can be used to access the SP (Stack Pointer) register.
+        /// </remarks>
+        /// <param name="index">Index of the register, in the range 0-31 (inclusive)</param>
+        /// <returns>The register value</returns>
+        ulong GetX(int index);
+
+        /// <summary>
+        /// Sets the value of a general purpose register.
+        /// </summary>
+        /// <remarks>
+        /// The special <paramref name="index"/> of 31 can be used to access the SP (Stack Pointer) register.
+        /// </remarks>
+        /// <param name="index">Index of the register, in the range 0-31 (inclusive)</param>
+        /// <param name="value">Value to be set</param>
+        void SetX(int index, ulong value);
+
+        /// <summary>
+        /// Gets the value of a FP/SIMD register.
+        /// </summary>
+        /// <param name="index">Index of the register, in the range 0-31 (inclusive)</param>
+        /// <returns>The register value</returns>
+        V128 GetV(int index);
+
+        /// <summary>
+        /// Sets the value of a FP/SIMD register.
+        /// </summary>
+        /// <param name="index">Index of the register, in the range 0-31 (inclusive)</param>
+        /// <param name="value">Value to be set</param>
+        void SetV(int index, V128 value);
+
+        /// <summary>
+        /// Requests the thread to stop running temporarily and call <see cref="ExceptionCallbacks.InterruptCallback"/>.
+        /// </summary>
+        /// <remarks>
+        /// The thread might not pause immediately.
+        /// One must not assume that guest code is no longer being executed by the thread after calling this function.
+        /// </remarks>
+        void RequestInterrupt();
+
+        /// <summary>
+        /// Requests the thread to stop running guest code and return as soon as possible.
+        /// </summary>
+        /// <remarks>
+        /// The thread might not stop immediately.
+        /// One must not assume that guest code is no longer being executed by the thread after calling this function.
+        /// After a thread has been stopped, it can't be restarted with the same <see cref="IExecutionContext"/>.
+        /// If you only need to pause the thread temporarily, use <see cref="RequestInterrupt"/> instead.
+        /// </remarks>
+        void StopRunning();
+    }
+}
\ No newline at end of file
diff --git a/Ryujinx.Cpu/ITickSource.cs b/Ryujinx.Cpu/ITickSource.cs
new file mode 100644
index 0000000000..e65e99e265
--- /dev/null
+++ b/Ryujinx.Cpu/ITickSource.cs
@@ -0,0 +1,31 @@
+using ARMeilleure.State;
+using System;
+
+namespace Ryujinx.Cpu
+{
+    /// <summary>
+    /// Tick source interface.
+    /// </summary>
+    public interface ITickSource : ICounter
+    {
+        /// <summary>
+        /// Time elapsed since the counter was created.
+        /// </summary>
+        TimeSpan ElapsedTime { get; }
+
+        /// <summary>
+        /// Time elapsed since the counter was created, in seconds.
+        /// </summary>
+        double ElapsedSeconds { get; }
+
+        /// <summary>
+        /// Stops counting.
+        /// </summary>
+        void Suspend();
+
+        /// <summary>
+        /// Resumes counting after a call to <see cref="Suspend"/>.
+        /// </summary>
+        void Resume();
+    }
+}
diff --git a/Ryujinx.Cpu/Jit/JitCpuContext.cs b/Ryujinx.Cpu/Jit/JitCpuContext.cs
new file mode 100644
index 0000000000..d6892ea759
--- /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);
+        }
+
+        /// <inheritdoc/>
+        public IExecutionContext CreateExecutionContext(ExceptionCallbacks exceptionCallbacks)
+        {
+            return new JitExecutionContext(new JitMemoryAllocator(), _tickSource, exceptionCallbacks);
+        }
+
+        /// <inheritdoc/>
+        public void Execute(IExecutionContext context, ulong address)
+        {
+            _translator.Execute(((JitExecutionContext)context).Impl, address);
+        }
+
+        /// <inheritdoc/>
+        public void InvalidateCacheRegion(ulong address, ulong size)
+        {
+            _translator.InvalidateJitCacheRegion(address, size);
+        }
+    }
+}
diff --git a/Ryujinx.Cpu/Jit/JitEngine.cs b/Ryujinx.Cpu/Jit/JitEngine.cs
new file mode 100644
index 0000000000..b158074f0f
--- /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;
+        }
+
+        /// <inheritdoc/>
+        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 0000000000..e1a527b1b4
--- /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;
+
+        /// <inheritdoc/>
+        public ulong Pc => _impl.Pc;
+
+        /// <inheritdoc/>
+        public long TpidrEl0
+        {
+            get => _impl.TpidrEl0;
+            set => _impl.TpidrEl0 = value;
+        }
+
+        /// <inheritdoc/>
+        public long TpidrroEl0
+        {
+            get => _impl.TpidrroEl0;
+            set => _impl.TpidrroEl0 = value;
+        }
+
+        /// <inheritdoc/>
+        public uint Pstate
+        {
+            get => _impl.Pstate;
+            set => _impl.Pstate = value;
+        }
+
+        /// <inheritdoc/>
+        public uint Fpcr
+        {
+            get => (uint)_impl.Fpcr;
+            set => _impl.Fpcr = (FPCR)value;
+        }
+
+        /// <inheritdoc/>
+        public uint Fpsr
+        {
+            get => (uint)_impl.Fpsr;
+            set => _impl.Fpsr = (FPSR)value;
+        }
+
+        /// <inheritdoc/>
+        public bool IsAarch32
+        {
+            get => _impl.IsAarch32;
+            set => _impl.IsAarch32 = value;
+        }
+
+        /// <inheritdoc/>
+        public bool Running => _impl.Running;
+
+        private readonly ExceptionCallbacks _exceptionCallbacks;
+
+        public JitExecutionContext(IJitMemoryAllocator allocator, ICounter counter, ExceptionCallbacks exceptionCallbacks)
+        {
+            _impl = new ExecutionContext(
+                allocator,
+                counter,
+                InterruptHandler,
+                BreakHandler,
+                SupervisorCallHandler,
+                UndefinedHandler);
+
+            _exceptionCallbacks = exceptionCallbacks;
+        }
+
+        /// <inheritdoc/>
+        public ulong GetX(int index) => _impl.GetX(index);
+
+        /// <inheritdoc/>
+        public void SetX(int index, ulong value) => _impl.SetX(index, value);
+
+        /// <inheritdoc/>
+        public V128 GetV(int index) => _impl.GetV(index);
+
+        /// <inheritdoc/>
+        public void SetV(int index, V128 value) => _impl.SetV(index, value);
+
+        private void InterruptHandler(ExecutionContext context)
+        {
+            _exceptionCallbacks.InterruptCallback?.Invoke(this);
+        }
+
+        private void BreakHandler(ExecutionContext context, ulong address, int imm)
+        {
+            _exceptionCallbacks.BreakCallback?.Invoke(this, address, imm);
+        }
+
+        private void SupervisorCallHandler(ExecutionContext context, ulong address, int imm)
+        {
+            _exceptionCallbacks.SupervisorCallback?.Invoke(this, address, imm);
+        }
+
+        private void UndefinedHandler(ExecutionContext context, ulong address, int opCode)
+        {
+            _exceptionCallbacks.UndefinedCallback?.Invoke(this, address, opCode);
+        }
+
+        /// <inheritdoc/>
+        public void RequestInterrupt()
+        {
+            _impl.RequestInterrupt();
+        }
+
+        /// <inheritdoc/>
+        public void StopRunning()
+        {
+            _impl.StopRunning();
+        }
+
+        public void Dispose()
+        {
+            _impl.Dispose();
+        }
+    }
+}
\ 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 26ccd732b1..27bb09ccb1 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 3ad62d7130..327fb303e1 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 b9769fd406..86c69431d3 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
 {
     /// <summary>
     /// 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 b5abae0cfe..5961e37738 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
 {
     /// <summary>
     /// Represents a CPU memory manager which maps guest virtual memory directly onto a host virtual region.
     /// </summary>
-    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 0000000000..dc510bc26a
--- /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;
+
+        /// <inheritdoc/>
+        public ulong Frequency { get; }
+
+        /// <inheritdoc/>
+        public ulong Counter => (ulong)(ElapsedSeconds * Frequency);
+
+        /// <inheritdoc/>
+        public TimeSpan ElapsedTime => _tickCounter.Elapsed;
+
+        /// <inheritdoc/>
+        public double ElapsedSeconds => _tickCounter.ElapsedTicks * _hostTickFreq;
+
+        public TickSource(ulong frequency)
+        {
+            Frequency = frequency;
+            _hostTickFreq = 1.0 / Stopwatch.Frequency;
+
+            _tickCounter = new Stopwatch();
+            _tickCounter.Start();
+        }
+
+        /// <inheritdoc/>
+        public void Suspend()
+        {
+            _tickCounter.Stop();
+        }
+
+        /// <inheritdoc/>
+        public void Resume()
+        {
+            _tickCounter.Start();
+        }
+    }
+}
\ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/ArmProcessContext.cs b/Ryujinx.HLE/HOS/ArmProcessContext.cs
index dfa01c1ffb..072df0b612 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 0561193caa..7d1c4e1d6e 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<MemoryManager>(pid, _gpu, new MemoryManager(context.Memory, addressSpaceSize, invalidAccessHandler), for64Bit);
+                    var memoryManager = new MemoryManager(context.Memory, addressSpaceSize, invalidAccessHandler);
+                    return new ArmProcessContext<MemoryManager>(pid, _cpuEngine, _gpu, memoryManager, for64Bit);
 
                 case MemoryManagerMode.HostMapped:
                 case MemoryManagerMode.HostMappedUnsafe:
                     bool unsafeMode = mode == MemoryManagerMode.HostMappedUnsafe;
-                    return new ArmProcessContext<MemoryManagerHostMapped>(pid, _gpu, new MemoryManagerHostMapped(context.Memory, addressSpaceSize, unsafeMode, invalidAccessHandler), for64Bit);
+                    var memoryManagerHostMapped = new MemoryManagerHostMapped(context.Memory, addressSpaceSize, unsafeMode, invalidAccessHandler);
+                    return new ArmProcessContext<MemoryManagerHostMapped>(pid, _cpuEngine, _gpu, memoryManagerHostMapped, for64Bit);
 
                 default:
                     throw new ArgumentOutOfRangeException();
diff --git a/Ryujinx.HLE/HOS/Horizon.cs b/Ryujinx.HLE/HOS/Horizon.cs
index 7de9bdf339..b93ebc0329 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 5a1dbef26f..3817b0aa37 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 4b8e4d1598..6c58e1972e 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 e0cd4fbf0c..0a78a26dd0 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 707e6d9816..c8063a62aa 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 b10737b431..0caeacade0 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 bb3a155703..8729683092 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 0000000000..a084125291
--- /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 d9d492a522..571699d995 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 5e795d356b..cb693f5950 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 6e0b701001..8b7e7fb8fd 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<Syscall32, ExecutionContext>[] SvcTable32 { get; }
-        public static Action<Syscall64, ExecutionContext>[] SvcTable64 { get; }
+        public static Action<Syscall32, IExecutionContext>[] SvcTable32 { get; }
+        public static Action<Syscall64, IExecutionContext>[] SvcTable64 { get; }
 
         static SyscallTable()
         {
-            SvcTable32 = new Action<Syscall32, ExecutionContext>[SvcMax];
-            SvcTable64 = new Action<Syscall64, ExecutionContext>[SvcMax];
+            SvcTable32 = new Action<Syscall32, IExecutionContext>[SvcMax];
+            SvcTable64 = new Action<Syscall64, IExecutionContext>[SvcMax];
 
             Dictionary<int, string> svcFuncs64 = new Dictionary<int, string>
             {
@@ -182,9 +182,9 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
             }
         }
 
-        private static Action<T, ExecutionContext> GenerateMethod<T>(string svcName, int registerCleanCount)
+        private static Action<T, IExecutionContext> GenerateMethod<T>(string svcName, int registerCleanCount)
         {
-            Type[] argTypes = new Type[] { typeof(T), typeof(ExecutionContext) };
+            Type[] argTypes = new Type[] { typeof(T), typeof(IExecutionContext) };
 
             DynamicMethod method = new DynamicMethod(svcName, null, argTypes);
 
@@ -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<Action<T, ExecutionContext>>();
+            return method.CreateDelegate<Action<T, IExecutionContext>>();
         }
 
         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 ee701a6903..b9dd91ef88 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<KThread>();
             _pinnedWaiters = new LinkedList<KThread>();
+
+            _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 294ca5b826..6b9b6820c5 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 ee094ddf25..6d65de95d4 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 f0cc0fe1dc..8b7f331305 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 54c7845218..c29e076936 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 35aeade063..00e35799a5 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 422414dee0..bc0901ab22 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 3c93139361..1efd37f498 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 d4227f01d2..833bc26eca 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 b86f703dbe..aec034850d 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 370e7d73c9..8392c4b50f 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 2499b549f8..fa485437bc 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 83ace9814f..4bb19e752f 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 865b1c0982..f4bbaa6045 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 0650208276..fe74da7e97 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 534af45766..441e4267b4 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<SystemClockContext>();
-            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<ClockSnapshot>());
 
-            ResultCode result = _timeManager.StandardUserSystemClock.GetClockContext(context.Thread, out SystemClockContext userContext);
+            ITickSource tickSource = context.Device.System.TickSource;
+
+            ResultCode result = _timeManager.StandardUserSystemClock.GetClockContext(tickSource, out SystemClockContext userContext);
 
             if (result == ResultCode.Success)
             {
-                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>();
             SystemClockContext networkContext = context.RequestData.ReadStruct<SystemClockContext>();
 
-            ResultCode result = GetClockSnapshotFromSystemClockContextInternal(context.Thread, userContext, networkContext, type, out ClockSnapshot clockSnapshot);
+            ITickSource tickSource = context.Device.System.TickSource;
+
+            ResultCode result = GetClockSnapshotFromSystemClockContextInternal(tickSource, userContext, networkContext, type, out ClockSnapshot clockSnapshot);
 
             if (result == ResultCode.Success)
             {
@@ -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 be71bb4fc5..1ff5b2d69a 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<TimeSpanType>();
             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<SystemClockContext>();
             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<SteadyClockTimePoint>();
 
-            _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<TimeSpanType>();
 
-            _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 a5ce8d6a31..1e51771310 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 1d9f787397..085cc71dca 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 83d745e320..202099b052 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 e221789061..ac9f0880bd 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 8b08b040af..7063290bc0 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<SteadyClockContext>(SteadyClockContextOffset, 4);
-            TimeSpanType       ticksTimeSpan = TimeSpanType.FromTicks(thread.Context.CntpctEl0, thread.Context.CntfrqEl0);
+            TimeSpanType       ticksTimeSpan = TimeSpanType.FromTicks(tickSource.Counter, tickSource.Frequency);
 
             context.InternalOffset = (ulong)(currentTimePoint.NanoSeconds - ticksTimeSpan.NanoSeconds);
 
diff --git a/Ryujinx.HLE/HOS/Services/Time/TimeZone/TimeZoneContentManager.cs b/Ryujinx.HLE/HOS/Services/Time/TimeZone/TimeZoneContentManager.cs
index 8ff090260b..141c2b4a57 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 9c09746bf0..96b4965a21 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 9cee54970a..5fe43dec4d 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 d5dc18eace..1bd87aee19 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;