364 changes: 134 additions & 230 deletions Source/Core/Core/CoreTiming.cpp

Large diffs are not rendered by default.

195 changes: 120 additions & 75 deletions Source/Core/Core/CoreTiming.h
Expand Up @@ -16,10 +16,13 @@
// inside callback:
// ScheduleEvent(periodInCycles - cyclesLate, callback, "whatever")

#include <memory>
#include <mutex>
#include <string>
#include <unordered_map>
#include <vector>

#include "Common/CommonTypes.h"
#include "Common/SPSCQueue.h"

class PointerWrap;

Expand All @@ -30,55 +33,31 @@ class System;

namespace CoreTiming
{
class CoreTimingState
{
public:
CoreTimingState();
CoreTimingState(const CoreTimingState&) = delete;
CoreTimingState(CoreTimingState&&) = delete;
CoreTimingState& operator=(const CoreTimingState&) = delete;
CoreTimingState& operator=(CoreTimingState&&) = delete;
~CoreTimingState();

struct Data;
Data& GetData() { return *m_data; }

private:
std::unique_ptr<Data> m_data;
};

// These really shouldn't be global, but jit64 accesses them directly
struct Globals
{
s64 global_timer;
int slice_length;
u64 fake_TB_start_value;
u64 fake_TB_start_ticks;
float last_OC_factor_inverted;
s64 global_timer = 0;
int slice_length = 0;
u64 fake_TB_start_value = 0;
u64 fake_TB_start_ticks = 0;
float last_OC_factor_inverted = 0.0f;
};

// CoreTiming begins at the boundary of timing slice -1. An initial call to Advance() is
// required to end slice -1 and start slice 0 before the first cycle of code is executed.
void Init();
void Shutdown();

typedef void (*TimedCallback)(Core::System& system, u64 userdata, s64 cyclesLate);

// This should only be called from the CPU thread, if you are calling it any other thread, you are
// doing something evil
u64 GetTicks();
u64 GetIdleTicks();

void RefreshConfig();

void DoState(PointerWrap& p);

struct EventType;
struct EventType
{
TimedCallback callback;
const std::string* name;
};

// Returns the event_type identifier. if name is not unique, an existing event_type will be
// discarded.
EventType* RegisterEvent(const std::string& name, TimedCallback callback);
void UnregisterAllEvents();
struct Event
{
s64 time;
u64 fifo_order;
u64 userdata;
EventType* type;
};

enum class FromThread
{
Expand All @@ -89,47 +68,113 @@ enum class FromThread
ANY
};

// userdata MAY NOT CONTAIN POINTERS. userdata might get written and reloaded from savestates.
// After the first Advance, the slice lengths and the downcount will be reduced whenever an event
// is scheduled earlier than the current values (when scheduled from the CPU Thread only).
// Scheduling from a callback will not update the downcount until the Advance() completes.
void ScheduleEvent(s64 cycles_into_future, EventType* event_type, u64 userdata = 0,
FromThread from = FromThread::CPU);
// helpers until the JIT is updated to use the instance
void GlobalAdvance();
void GlobalIdle();

class CoreTimingManager
{
public:
// CoreTiming begins at the boundary of timing slice -1. An initial call to Advance() is
// required to end slice -1 and start slice 0 before the first cycle of code is executed.
void Init();
void Shutdown();

// We only permit one event of each type in the queue at a time.
void RemoveEvent(EventType* event_type);
void RemoveAllEvents(EventType* event_type);
// This should only be called from the CPU thread, if you are calling it any other thread, you are
// doing something evil
u64 GetTicks() const;
u64 GetIdleTicks() const;

// Advance must be called at the beginning of dispatcher loops, not the end. Advance() ends
// the previous timing slice and begins the next one, you must Advance from the previous
// slice to the current one before executing any cycles. CoreTiming starts in slice -1 so an
// Advance() is required to initialize the slice length before the first cycle of emulated
// instructions is executed.
// NOTE: Advance updates the PowerPC downcount and performs a PPC external exception check.
void Advance();
void MoveEvents();
void RefreshConfig();

// Pretend that the main CPU has executed enough cycles to reach the next event.
void Idle();
void DoState(PointerWrap& p);

// Clear all pending events. This should ONLY be done on exit or state load.
void ClearPendingEvents();
// Returns the event_type identifier. if name is not unique, an existing event_type will be
// discarded.
EventType* RegisterEvent(const std::string& name, TimedCallback callback);
void UnregisterAllEvents();

void LogPendingEvents();
// userdata MAY NOT CONTAIN POINTERS. userdata might get written and reloaded from savestates.
// After the first Advance, the slice lengths and the downcount will be reduced whenever an event
// is scheduled earlier than the current values (when scheduled from the CPU Thread only).
// Scheduling from a callback will not update the downcount until the Advance() completes.
void ScheduleEvent(s64 cycles_into_future, EventType* event_type, u64 userdata = 0,
FromThread from = FromThread::CPU);

std::string GetScheduledEventsSummary();
// We only permit one event of each type in the queue at a time.
void RemoveEvent(EventType* event_type);
void RemoveAllEvents(EventType* event_type);

void AdjustEventQueueTimes(u32 new_ppc_clock, u32 old_ppc_clock);
// Advance must be called at the beginning of dispatcher loops, not the end. Advance() ends
// the previous timing slice and begins the next one, you must Advance from the previous
// slice to the current one before executing any cycles. CoreTiming starts in slice -1 so an
// Advance() is required to initialize the slice length before the first cycle of emulated
// instructions is executed.
// NOTE: Advance updates the PowerPC downcount and performs a PPC external exception check.
void Advance();
void MoveEvents();

u32 GetFakeDecStartValue();
void SetFakeDecStartValue(u32 val);
u64 GetFakeDecStartTicks();
void SetFakeDecStartTicks(u64 val);
u64 GetFakeTBStartValue();
void SetFakeTBStartValue(u64 val);
u64 GetFakeTBStartTicks();
void SetFakeTBStartTicks(u64 val);
// Pretend that the main CPU has executed enough cycles to reach the next event.
void Idle();

void ForceExceptionCheck(s64 cycles);
// Clear all pending events. This should ONLY be done on exit or state load.
void ClearPendingEvents();

void LogPendingEvents() const;

std::string GetScheduledEventsSummary() const;

void AdjustEventQueueTimes(u32 new_ppc_clock, u32 old_ppc_clock);

u32 GetFakeDecStartValue() const;
void SetFakeDecStartValue(u32 val);
u64 GetFakeDecStartTicks() const;
void SetFakeDecStartTicks(u64 val);
u64 GetFakeTBStartValue() const;
void SetFakeTBStartValue(u64 val);
u64 GetFakeTBStartTicks() const;
void SetFakeTBStartTicks(u64 val);

void ForceExceptionCheck(s64 cycles);

// Directly accessed by the JIT.
Globals& GetGlobals() { return m_globals; }

private:
Globals m_globals;

// unordered_map stores each element separately as a linked list node so pointers to elements
// remain stable regardless of rehashes/resizing.
std::unordered_map<std::string, EventType> m_event_types;

// STATE_TO_SAVE
// The queue is a min-heap using std::make_heap/push_heap/pop_heap.
// We don't use std::priority_queue because we need to be able to serialize, unserialize and
// erase arbitrary events (RemoveEvent()) regardless of the queue order. These aren't accomodated
// by the standard adaptor class.
std::vector<Event> m_event_queue;
u64 m_event_fifo_id = 0;
std::mutex m_ts_write_lock;
Common::SPSCQueue<Event, false> m_ts_queue;

float m_last_oc_factor = 0.0f;

s64 m_idled_cycles = 0;
u32 m_fake_dec_start_value = 0;
u64 m_fake_dec_start_ticks = 0;

// Are we in a function that has been called from Advance()
bool m_is_global_timer_sane = false;

EventType* m_ev_lost = nullptr;

size_t m_registered_config_callback_id = 0;
float m_config_oc_factor = 0.0f;
float m_config_oc_inv_factor = 0.0f;
bool m_config_sync_on_skip_idle = false;

int DowncountToCycles(int downcount) const;
int CyclesToDowncount(int cycles) const;
};

} // namespace CoreTiming
3 changes: 2 additions & 1 deletion Source/Core/Core/DSP/Interpreter/DSPInterpreter.cpp
Expand Up @@ -18,6 +18,7 @@
#include "Core/DSP/Interpreter/DSPIntTables.h"
#include "Core/HW/Memmap.h"
#include "Core/HW/SystemTimers.h"
#include "Core/System.h"

namespace DSP::Interpreter
{
Expand Down Expand Up @@ -271,7 +272,7 @@ u16 Interpreter::ReadControlRegister()
if (SystemTimers::GetFakeTimeBase() >= state.control_reg_init_code_clear_time)
state.control_reg &= ~CR_INIT_CODE;
else
CoreTiming::ForceExceptionCheck(50); // Keep checking
Core::System::GetInstance().GetCoreTiming().ForceExceptionCheck(50); // Keep checking
}
return state.control_reg;
}
Expand Down
15 changes: 10 additions & 5 deletions Source/Core/Core/FifoPlayer/FifoPlayer.cpp
Expand Up @@ -23,6 +23,7 @@
#include "Core/Host.h"
#include "Core/PowerPC/MMU.h"
#include "Core/PowerPC/PowerPC.h"
#include "Core/System.h"
#include "VideoCommon/BPMemory.h"
#include "VideoCommon/CommandProcessor.h"
#include "VideoCommon/VideoCommon.h"
Expand Down Expand Up @@ -508,15 +509,17 @@ void FifoPlayer::WriteFifo(const u8* data, u32 start, u32 end)
u32 written = start;
u32 lastBurstEnd = end - 1;

auto& core_timing = Core::System::GetInstance().GetCoreTiming();

// Write up to 256 bytes at a time
while (written < end)
{
while (IsHighWatermarkSet())
{
if (CPU::GetState() != CPU::State::Running)
break;
CoreTiming::Idle();
CoreTiming::Advance();
core_timing.Idle();
core_timing.Advance();
}

u32 burstEnd = std::min(written + 255, lastBurstEnd);
Expand All @@ -533,7 +536,7 @@ void FifoPlayer::WriteFifo(const u8* data, u32 start, u32 end)
m_ElapsedCycles = elapsedCycles;

PowerPC::ppcState.downcount -= cyclesUsed;
CoreTiming::Advance();
core_timing.Advance();
}
}

Expand Down Expand Up @@ -712,11 +715,13 @@ void FifoPlayer::FlushWGP()

void FifoPlayer::WaitForGPUInactive()
{
auto& core_timing = Core::System::GetInstance().GetCoreTiming();

// Sleep while the GPU is active
while (!IsIdleSet() && CPU::GetState() != CPU::State::PowerDown)
{
CoreTiming::Idle();
CoreTiming::Advance();
core_timing.Idle();
core_timing.Advance();
}
}

Expand Down
38 changes: 22 additions & 16 deletions Source/Core/Core/HW/AudioInterface.cpp
Expand Up @@ -204,15 +204,16 @@ static void Update(Core::System& system, u64 userdata, s64 cycles_late)
return;

auto& state = system.GetAudioInterfaceState().GetData();
auto& core_timing = system.GetCoreTiming();

const u64 diff = CoreTiming::GetTicks() - state.last_cpu_time;
const u64 diff = core_timing.GetTicks() - state.last_cpu_time;
if (diff > state.cpu_cycles_per_sample)
{
const u32 samples = static_cast<u32>(diff / state.cpu_cycles_per_sample);
state.last_cpu_time += samples * state.cpu_cycles_per_sample;
IncreaseSampleCount(samples);
}
CoreTiming::ScheduleEvent(GetAIPeriod() - cycles_late, state.event_type_ai);
core_timing.ScheduleEvent(GetAIPeriod() - cycles_late, state.event_type_ai);
}

void SetAIDSampleRate(SampleRate sample_rate)
Expand Down Expand Up @@ -258,7 +259,9 @@ void SetAISSampleRate(SampleRate sample_rate)

void Init()
{
auto& state = Core::System::GetInstance().GetAudioInterfaceState().GetData();
auto& system = Core::System::GetInstance();
auto& core_timing = system.GetCoreTiming();
auto& state = system.GetAudioInterfaceState().GetData();

state.control.hex = 0;
SetAISSampleRate(SampleRate::AI48KHz);
Expand All @@ -269,7 +272,7 @@ void Init()

state.last_cpu_time = 0;

state.event_type_ai = CoreTiming::RegisterEvent("AICallback", Update);
state.event_type_ai = core_timing.RegisterEvent("AICallback", Update);
}

void Shutdown()
Expand All @@ -285,6 +288,7 @@ void RegisterMMIO(MMIO::Mapping* mmio, u32 base)
MMIO::ComplexWrite<u32>([](Core::System& system, u32, u32 val) {
const AICR tmp_ai_ctrl(val);

auto& core_timing = system.GetCoreTiming();
auto& state = system.GetAudioInterfaceState().GetData();
if (state.control.AIINTMSK != tmp_ai_ctrl.AIINTMSK)
{
Expand Down Expand Up @@ -321,10 +325,10 @@ void RegisterMMIO(MMIO::Mapping* mmio, u32 base)
DEBUG_LOG_FMT(AUDIO_INTERFACE, "{} streaming audio",
tmp_ai_ctrl.PSTAT ? "start" : "stop");
state.control.PSTAT = tmp_ai_ctrl.PSTAT;
state.last_cpu_time = CoreTiming::GetTicks();
state.last_cpu_time = core_timing.GetTicks();

CoreTiming::RemoveEvent(state.event_type_ai);
CoreTiming::ScheduleEvent(GetAIPeriod(), state.event_type_ai);
core_timing.RemoveEvent(state.event_type_ai);
core_timing.ScheduleEvent(GetAIPeriod(), state.event_type_ai);
}

// AI Interrupt
Expand All @@ -340,7 +344,7 @@ void RegisterMMIO(MMIO::Mapping* mmio, u32 base)
DEBUG_LOG_FMT(AUDIO_INTERFACE, "Reset AIS sample counter");
state.sample_counter = 0;

state.last_cpu_time = CoreTiming::GetTicks();
state.last_cpu_time = core_timing.GetTicks();
}

UpdateInterrupts();
Expand All @@ -357,28 +361,30 @@ void RegisterMMIO(MMIO::Mapping* mmio, u32 base)

mmio->Register(base | AI_SAMPLE_COUNTER, MMIO::ComplexRead<u32>([](Core::System& system, u32) {
auto& state = system.GetAudioInterfaceState().GetData();
const u64 cycles_streamed = IsPlaying() ?
(CoreTiming::GetTicks() - state.last_cpu_time) :
state.last_cpu_time;
const u64 cycles_streamed =
IsPlaying() ? (system.GetCoreTiming().GetTicks() - state.last_cpu_time) :
state.last_cpu_time;
return state.sample_counter +
static_cast<u32>(cycles_streamed / state.cpu_cycles_per_sample);
}),
MMIO::ComplexWrite<u32>([](Core::System& system, u32, u32 val) {
auto& core_timing = system.GetCoreTiming();
auto& state = system.GetAudioInterfaceState().GetData();
state.sample_counter = val;
state.last_cpu_time = CoreTiming::GetTicks();
CoreTiming::RemoveEvent(state.event_type_ai);
CoreTiming::ScheduleEvent(GetAIPeriod(), state.event_type_ai);
state.last_cpu_time = core_timing.GetTicks();
core_timing.RemoveEvent(state.event_type_ai);
core_timing.ScheduleEvent(GetAIPeriod(), state.event_type_ai);
}));

mmio->Register(base | AI_INTERRUPT_TIMING, MMIO::DirectRead<u32>(&state.interrupt_timing),
MMIO::ComplexWrite<u32>([](Core::System& system, u32, u32 val) {
auto& core_timing = system.GetCoreTiming();
auto& state = system.GetAudioInterfaceState().GetData();
DEBUG_LOG_FMT(AUDIO_INTERFACE, "AI_INTERRUPT_TIMING={:08x} at PC: {:08x}", val,
PowerPC::ppcState.pc);
state.interrupt_timing = val;
CoreTiming::RemoveEvent(state.event_type_ai);
CoreTiming::ScheduleEvent(GetAIPeriod(), state.event_type_ai);
core_timing.RemoveEvent(state.event_type_ai);
core_timing.ScheduleEvent(GetAIPeriod(), state.event_type_ai);
}));
}

Expand Down
23 changes: 15 additions & 8 deletions Source/Core/Core/HW/DSP.cpp
Expand Up @@ -194,11 +194,13 @@ DSPEmulator* GetDSPEmulator()

void Init(bool hle)
{
auto& state = Core::System::GetInstance().GetDSPState().GetData();
auto& system = Core::System::GetInstance();
auto& core_timing = system.GetCoreTiming();
auto& state = system.GetDSPState().GetData();
Reinit(hle);
state.event_type_generate_dsp_interrupt =
CoreTiming::RegisterEvent("DSPint", GenerateDSPInterrupt);
state.event_type_complete_aram = CoreTiming::RegisterEvent("ARAMint", CompleteARAM);
core_timing.RegisterEvent("DSPint", GenerateDSPInterrupt);
state.event_type_complete_aram = core_timing.RegisterEvent("ARAMint", CompleteARAM);
}

void Reinit(bool hle)
Expand Down Expand Up @@ -432,7 +434,8 @@ void RegisterMMIO(MMIO::Mapping* mmio, u32 base)
// TODO: need hardware tests for the timing of this interrupt.
// Sky Crawlers crashes at boot if this is scheduled less than 87 cycles in the future.
// Other Namco games crash too, see issue 9509. For now we will just push it to 200 cycles
CoreTiming::ScheduleEvent(200, state.event_type_generate_dsp_interrupt, INT_AID);
system.GetCoreTiming().ScheduleEvent(200, state.event_type_generate_dsp_interrupt,
INT_AID);
}
}));

Expand Down Expand Up @@ -486,8 +489,10 @@ static void GenerateDSPInterrupt(Core::System& system, u64 DSPIntType, s64 cycle
// CALLED FROM DSP EMULATOR, POSSIBLY THREADED
void GenerateDSPInterruptFromDSPEmu(DSPInterruptType type, int cycles_into_future)
{
auto& state = Core::System::GetInstance().GetDSPState().GetData();
CoreTiming::ScheduleEvent(cycles_into_future, state.event_type_generate_dsp_interrupt, type,
auto& system = Core::System::GetInstance();
auto& core_timing = system.GetCoreTiming();
auto& state = system.GetDSPState().GetData();
core_timing.ScheduleEvent(cycles_into_future, state.event_type_generate_dsp_interrupt, type,
CoreTiming::FromThread::ANY);
}

Expand Down Expand Up @@ -547,13 +552,15 @@ void UpdateAudioDMA()

static void Do_ARAM_DMA()
{
auto& state = Core::System::GetInstance().GetDSPState().GetData();
auto& system = Core::System::GetInstance();
auto& core_timing = system.GetCoreTiming();
auto& state = system.GetDSPState().GetData();

state.dsp_control.DMAState = 1;

// ARAM DMA transfer rate has been measured on real hw
int ticksToTransfer = (state.aram_dma.Cnt.count / 32) * 246;
CoreTiming::ScheduleEvent(ticksToTransfer, state.event_type_complete_aram);
core_timing.ScheduleEvent(ticksToTransfer, state.event_type_complete_aram);

// Real hardware DMAs in 32byte chunks, but we can get by with 8byte chunks
if (state.aram_dma.Cnt.dir)
Expand Down
3 changes: 2 additions & 1 deletion Source/Core/Core/HW/DSPHLE/DSPHLE.cpp
Expand Up @@ -10,6 +10,7 @@
#include "Core/CoreTiming.h"
#include "Core/HW/DSPHLE/UCodes/UCodes.h"
#include "Core/HW/SystemTimers.h"
#include "Core/System.h"

namespace DSP::HLE
{
Expand Down Expand Up @@ -234,7 +235,7 @@ u16 DSPHLE::DSP_ReadControlRegister()
if (SystemTimers::GetFakeTimeBase() >= m_control_reg_init_code_clear_time)
m_dsp_control.DSPInitCode = 0;
else
CoreTiming::ForceExceptionCheck(50); // Keep checking
Core::System::GetInstance().GetCoreTiming().ForceExceptionCheck(50); // Keep checking
}
return m_dsp_control.Hex;
}
Expand Down
80 changes: 46 additions & 34 deletions Source/Core/Core/HW/DVD/DVDInterface.cpp
Expand Up @@ -309,7 +309,8 @@ static u32 AdvanceDTK(u32 maximum_samples, u32* samples_to_process)
static void DTKStreamingCallback(DIInterruptType interrupt_type, const std::vector<u8>& audio_data,
s64 cycles_late)
{
auto& state = Core::System::GetInstance().GetDVDInterfaceState().GetData();
auto& system = Core::System::GetInstance();
auto& state = system.GetDVDInterfaceState().GetData();

// Actual games always set this to 48 KHz
// but let's make sure to use GetAISSampleRateDivisor()
Expand All @@ -330,7 +331,6 @@ static void DTKStreamingCallback(DIInterruptType interrupt_type, const std::vect
std::vector<s16> temp_pcm(state.pending_samples * 2, 0);
ProcessDTKSamples(&temp_pcm, audio_data);

auto& system = Core::System::GetInstance();
SoundStream* sound_stream = system.GetSoundStream();
sound_stream->GetMixer()->PushStreamingSamples(temp_pcm.data(), state.pending_samples);

Expand Down Expand Up @@ -364,7 +364,7 @@ static void DTKStreamingCallback(DIInterruptType interrupt_type, const std::vect
{
// There's nothing to read, so using DVDThread is unnecessary.
u64 userdata = PackFinishExecutingCommandUserdata(ReplyType::DTK, DIInterruptType::TCINT);
CoreTiming::ScheduleEvent(ticks_to_dtk, state.finish_executing_command, userdata);
system.GetCoreTiming().ScheduleEvent(ticks_to_dtk, state.finish_executing_command, userdata);
}
}

Expand All @@ -374,7 +374,10 @@ void Init()

DVDThread::Start();

auto& state = Core::System::GetInstance().GetDVDInterfaceState().GetData();
auto& system = Core::System::GetInstance();
auto& core_timing = system.GetCoreTiming();
auto& state = system.GetDVDInterfaceState().GetData();

state.DISR.Hex = 0;
state.DICVR.Hex = 1; // Disc Channel relies on cover being open when no disc is inserted
state.DICMDBUF[0] = 0;
Expand All @@ -389,15 +392,15 @@ void Init()

ResetDrive(false);

state.auto_change_disc = CoreTiming::RegisterEvent("AutoChangeDisc", AutoChangeDiscCallback);
state.eject_disc = CoreTiming::RegisterEvent("EjectDisc", EjectDiscCallback);
state.insert_disc = CoreTiming::RegisterEvent("InsertDisc", InsertDiscCallback);
state.auto_change_disc = core_timing.RegisterEvent("AutoChangeDisc", AutoChangeDiscCallback);
state.eject_disc = core_timing.RegisterEvent("EjectDisc", EjectDiscCallback);
state.insert_disc = core_timing.RegisterEvent("InsertDisc", InsertDiscCallback);

state.finish_executing_command =
CoreTiming::RegisterEvent("FinishExecutingCommand", FinishExecutingCommandCallback);
core_timing.RegisterEvent("FinishExecutingCommand", FinishExecutingCommandCallback);

u64 userdata = PackFinishExecutingCommandUserdata(ReplyType::DTK, DIInterruptType::TCINT);
CoreTiming::ScheduleEvent(0, state.finish_executing_command, userdata);
core_timing.ScheduleEvent(0, state.finish_executing_command, userdata);
}

// Resets state on the MN102 chip in the drive itself, but not the DI registers exposed on the
Expand Down Expand Up @@ -557,8 +560,10 @@ static void InsertDiscCallback(Core::System& system, u64 userdata, s64 cyclesLat
// Must only be called on the CPU thread
void EjectDisc(EjectCause cause)
{
auto& state = Core::System::GetInstance().GetDVDInterfaceState().GetData();
CoreTiming::ScheduleEvent(0, state.eject_disc);
auto& system = Core::System::GetInstance();
auto& core_timing = system.GetCoreTiming();
auto& state = system.GetDVDInterfaceState().GetData();
core_timing.ScheduleEvent(0, state.eject_disc);
if (cause == EjectCause::User)
ExpansionInterface::g_rtc_flags[ExpansionInterface::RTCFlag::EjectButton] = true;
}
Expand All @@ -581,7 +586,8 @@ void ChangeDisc(const std::vector<std::string>& paths)
// Must only be called on the CPU thread
void ChangeDisc(const std::string& new_path)
{
auto& state = Core::System::GetInstance().GetDVDInterfaceState().GetData();
auto& system = Core::System::GetInstance();
auto& state = system.GetDVDInterfaceState().GetData();
if (!state.disc_path_to_insert.empty())
{
PanicAlertFmtT("A disc is already about to be inserted.");
Expand All @@ -591,7 +597,7 @@ void ChangeDisc(const std::string& new_path)
EjectDisc(EjectCause::User);

state.disc_path_to_insert = new_path;
CoreTiming::ScheduleEvent(SystemTimers::GetTicksPerSecond(), state.insert_disc);
system.GetCoreTiming().ScheduleEvent(SystemTimers::GetTicksPerSecond(), state.insert_disc);
Movie::SignalDiscChange(new_path);

for (size_t i = 0; i < state.auto_disc_change_paths.size(); ++i)
Expand Down Expand Up @@ -724,7 +730,8 @@ void RegisterMMIO(MMIO::Mapping* mmio, u32 base, bool is_wii)

static void UpdateInterrupts()
{
auto& state = Core::System::GetInstance().GetDVDInterfaceState().GetData();
auto& system = Core::System::GetInstance();
auto& state = system.GetDVDInterfaceState().GetData();
const bool set_mask = (state.DISR.DEINT & state.DISR.DEINTMASK) != 0 ||
(state.DISR.TCINT & state.DISR.TCINTMASK) != 0 ||
(state.DISR.BRKINT & state.DISR.BRKINTMASK) != 0 ||
Expand All @@ -733,7 +740,7 @@ static void UpdateInterrupts()
ProcessorInterface::SetInterrupt(ProcessorInterface::INT_CAUSE_DI, set_mask);

// Required for Summoner: A Goddess Reborn
CoreTiming::ForceExceptionCheck(50);
system.GetCoreTiming().ForceExceptionCheck(50);
}

static void GenerateDIInterrupt(DIInterruptType dvd_interrupt)
Expand Down Expand Up @@ -876,7 +883,8 @@ static bool ExecuteReadCommand(u64 dvd_offset, u32 output_address, u32 dvd_lengt
// with the userdata set to the interrupt type.
void ExecuteCommand(ReplyType reply_type)
{
auto& state = Core::System::GetInstance().GetDVDInterfaceState().GetData();
auto& system = Core::System::GetInstance();
auto& state = system.GetDVDInterfaceState().GetData();
DIInterruptType interrupt_type = DIInterruptType::TCINT;
bool command_handled_by_thread = false;

Expand Down Expand Up @@ -1214,8 +1222,8 @@ void ExecuteCommand(ReplyType reply_type)
if (Config::Get(Config::MAIN_AUTO_DISC_CHANGE) && !Movie::IsPlayingInput() &&
DVDThread::IsInsertedDiscRunning() && !state.auto_disc_change_paths.empty())
{
CoreTiming::ScheduleEvent(force_eject ? 0 : SystemTimers::GetTicksPerSecond() / 2,
state.auto_change_disc);
system.GetCoreTiming().ScheduleEvent(force_eject ? 0 : SystemTimers::GetTicksPerSecond() / 2,
state.auto_change_disc);
OSD::AddMessage("Changing discs automatically...", OSD::Duration::NORMAL);
}
else if (force_eject)
Expand Down Expand Up @@ -1306,17 +1314,18 @@ void ExecuteCommand(ReplyType reply_type)
if (!command_handled_by_thread)
{
// TODO: Needs testing to determine if MINIMUM_COMMAND_LATENCY_US is accurate for this
CoreTiming::ScheduleEvent(MINIMUM_COMMAND_LATENCY_US *
(SystemTimers::GetTicksPerSecond() / 1000000),
state.finish_executing_command,
PackFinishExecutingCommandUserdata(reply_type, interrupt_type));
system.GetCoreTiming().ScheduleEvent(
MINIMUM_COMMAND_LATENCY_US * (SystemTimers::GetTicksPerSecond() / 1000000),
state.finish_executing_command,
PackFinishExecutingCommandUserdata(reply_type, interrupt_type));
}
}

void PerformDecryptingRead(u32 position, u32 length, u32 output_address,
const DiscIO::Partition& partition, ReplyType reply_type)
{
auto& state = Core::System::GetInstance().GetDVDInterfaceState().GetData();
auto& system = Core::System::GetInstance();
auto& state = system.GetDVDInterfaceState().GetData();
DIInterruptType interrupt_type = DIInterruptType::TCINT;

if (state.drive_state == DriveState::ReadyNoReadsMade)
Expand All @@ -1329,16 +1338,17 @@ void PerformDecryptingRead(u32 position, u32 length, u32 output_address,
if (!command_handled_by_thread)
{
// TODO: Needs testing to determine if MINIMUM_COMMAND_LATENCY_US is accurate for this
CoreTiming::ScheduleEvent(MINIMUM_COMMAND_LATENCY_US *
(SystemTimers::GetTicksPerSecond() / 1000000),
state.finish_executing_command,
PackFinishExecutingCommandUserdata(reply_type, interrupt_type));
system.GetCoreTiming().ScheduleEvent(
MINIMUM_COMMAND_LATENCY_US * (SystemTimers::GetTicksPerSecond() / 1000000),
state.finish_executing_command,
PackFinishExecutingCommandUserdata(reply_type, interrupt_type));
}
}

void ForceOutOfBoundsRead(ReplyType reply_type)
{
auto& state = Core::System::GetInstance().GetDVDInterfaceState().GetData();
auto& system = Core::System::GetInstance();
auto& state = system.GetDVDInterfaceState().GetData();
INFO_LOG_FMT(DVDINTERFACE, "Forcing an out-of-bounds disc read.");

if (state.drive_state == DriveState::ReadyNoReadsMade)
Expand All @@ -1348,10 +1358,10 @@ void ForceOutOfBoundsRead(ReplyType reply_type)

// TODO: Needs testing to determine if MINIMUM_COMMAND_LATENCY_US is accurate for this
const DIInterruptType interrupt_type = DIInterruptType::DEINT;
CoreTiming::ScheduleEvent(MINIMUM_COMMAND_LATENCY_US *
(SystemTimers::GetTicksPerSecond() / 1000000),
state.finish_executing_command,
PackFinishExecutingCommandUserdata(reply_type, interrupt_type));
system.GetCoreTiming().ScheduleEvent(
MINIMUM_COMMAND_LATENCY_US * (SystemTimers::GetTicksPerSecond() / 1000000),
state.finish_executing_command,
PackFinishExecutingCommandUserdata(reply_type, interrupt_type));
}

void AudioBufferConfig(bool enable_dtk, u8 dtk_buffer_length)
Expand Down Expand Up @@ -1445,6 +1455,8 @@ void FinishExecutingCommand(ReplyType reply_type, DIInterruptType interrupt_type
static void ScheduleReads(u64 offset, u32 length, const DiscIO::Partition& partition,
u32 output_address, ReplyType reply_type)
{
auto& system = Core::System::GetInstance();
auto& core_timing = system.GetCoreTiming();
auto& state = Core::System::GetInstance().GetDVDInterfaceState().GetData();

// The drive continues to read 1 MiB beyond the last read position when idle.
Expand All @@ -1456,7 +1468,7 @@ static void ScheduleReads(u64 offset, u32 length, const DiscIO::Partition& parti
// faster than on real hardware, and if there's too much latency in the wrong
// places, the video before the save-file select screen lags.

const u64 current_time = CoreTiming::GetTicks();
const u64 current_time = core_timing.GetTicks();
const u32 ticks_per_second = SystemTimers::GetTicksPerSecond();
const bool wii_disc = DVDThread::GetDiscType() == DiscIO::Platform::WiiDisc;

Expand Down Expand Up @@ -1581,7 +1593,7 @@ static void ScheduleReads(u64 offset, u32 length, const DiscIO::Partition& parti
// should actually happen before reading data from the disc.

const double time_after_seek =
(CoreTiming::GetTicks() + ticks_until_completion) / ticks_per_second;
(core_timing.GetTicks() + ticks_until_completion) / ticks_per_second;
ticks_until_completion += ticks_per_second * DVDMath::CalculateRotationalLatency(
dvd_offset, time_after_seek, wii_disc);

Expand Down
15 changes: 9 additions & 6 deletions Source/Core/Core/HW/DVD/DVDThread.cpp
Expand Up @@ -102,9 +102,10 @@ DVDThreadState::~DVDThreadState() = default;

void Start()
{
auto& state = Core::System::GetInstance().GetDVDThreadState().GetData();
auto& system = Core::System::GetInstance();
auto& state = system.GetDVDThreadState().GetData();

state.finish_read = CoreTiming::RegisterEvent("FinishReadDVDThread", FinishRead);
state.finish_read = system.GetCoreTiming().RegisterEvent("FinishReadDVDThread", FinishRead);

state.request_queue_expanded.Reset();
state.result_queue_expanded.Reset();
Expand Down Expand Up @@ -305,7 +306,9 @@ static void StartReadInternal(bool copy_to_ram, u32 output_address, u64 dvd_offs
{
ASSERT(Core::IsCPUThread());

auto& state = Core::System::GetInstance().GetDVDThreadState().GetData();
auto& system = Core::System::GetInstance();
auto& core_timing = system.GetCoreTiming();
auto& state = system.GetDVDThreadState().GetData();

ReadRequest request;

Expand All @@ -319,13 +322,13 @@ static void StartReadInternal(bool copy_to_ram, u32 output_address, u64 dvd_offs
u64 id = state.next_id++;
request.id = id;

request.time_started_ticks = CoreTiming::GetTicks();
request.time_started_ticks = core_timing.GetTicks();
request.realtime_started_us = Common::Timer::NowUs();

state.request_queue.Push(std::move(request));
state.request_queue_expanded.Set();

CoreTiming::ScheduleEvent(ticks_until_completion, state.finish_read, id);
core_timing.ScheduleEvent(ticks_until_completion, state.finish_read, id);
}

static void FinishRead(Core::System& system, u64 id, s64 cycles_late)
Expand Down Expand Up @@ -373,7 +376,7 @@ static void FinishRead(Core::System& system, u64 id, s64 cycles_late)
"Emulated time including delay: {} us.",
request.realtime_done_us - request.realtime_started_us,
Common::Timer::NowUs() - request.realtime_started_us,
(CoreTiming::GetTicks() - request.time_started_ticks) /
(system.GetCoreTiming().GetTicks() - request.time_started_ticks) /
(SystemTimers::GetTicksPerSecond() / 1000000));

DVDInterface::DIInterruptType interrupt;
Expand Down
16 changes: 10 additions & 6 deletions Source/Core/Core/HW/EXI/EXI.cpp
Expand Up @@ -161,10 +161,11 @@ void Init(const Sram* override_sram)
SlotToEXIDevice(Slot::SP1));
state.channels[2]->AddDevice(EXIDeviceType::AD16, 0);

auto& core_timing = system.GetCoreTiming();
state.event_type_change_device =
CoreTiming::RegisterEvent("ChangeEXIDevice", ChangeDeviceCallback);
core_timing.RegisterEvent("ChangeEXIDevice", ChangeDeviceCallback);
state.event_type_update_interrupts =
CoreTiming::RegisterEvent("EXIUpdateInterrupts", UpdateInterruptsCallback);
core_timing.RegisterEvent("EXIUpdateInterrupts", UpdateInterruptsCallback);
}

void Shutdown()
Expand Down Expand Up @@ -233,11 +234,13 @@ void ChangeDevice(u8 channel, u8 device_num, EXIDeviceType device_type,
CoreTiming::FromThread from_thread)
{
// Let the hardware see no device for 1 second
auto& state = Core::System::GetInstance().GetExpansionInterfaceState().GetData();
CoreTiming::ScheduleEvent(0, state.event_type_change_device,
auto& system = Core::System::GetInstance();
auto& core_timing = system.GetCoreTiming();
auto& state = system.GetExpansionInterfaceState().GetData();
core_timing.ScheduleEvent(0, state.event_type_change_device,
((u64)channel << 32) | ((u64)EXIDeviceType::None << 16) | device_num,
from_thread);
CoreTiming::ScheduleEvent(SystemTimers::GetTicksPerSecond(), state.event_type_change_device,
core_timing.ScheduleEvent(SystemTimers::GetTicksPerSecond(), state.event_type_change_device,
((u64)channel << 32) | ((u64)device_type << 16) | device_num,
from_thread);
}
Expand Down Expand Up @@ -277,8 +280,9 @@ static void UpdateInterruptsCallback(Core::System& system, u64 userdata, s64 cyc

void ScheduleUpdateInterrupts(CoreTiming::FromThread from, int cycles_late)
{
auto& system = Core::System::GetInstance();
auto& state = Core::System::GetInstance().GetExpansionInterfaceState().GetData();
CoreTiming::ScheduleEvent(cycles_late, state.event_type_update_interrupts, 0, from);
system.GetCoreTiming().ScheduleEvent(cycles_late, state.event_type_update_interrupts, 0, from);
}

} // namespace ExpansionInterface
6 changes: 4 additions & 2 deletions Source/Core/Core/HW/EXI/EXI_DeviceIPL.cpp
Expand Up @@ -405,14 +405,16 @@ u32 CEXIIPL::GetEmulatedTime(u32 epoch)
ltime = Movie::GetRecordingStartTime();

// let's keep time moving forward, regardless of what it starts at
ltime += CoreTiming::GetTicks() / SystemTimers::GetTicksPerSecond();
ltime +=
Core::System::GetInstance().GetCoreTiming().GetTicks() / SystemTimers::GetTicksPerSecond();
}
else if (NetPlay::IsNetPlayRunning())
{
ltime = NetPlay_GetEmulatedTime();

// let's keep time moving forward, regardless of what it starts at
ltime += CoreTiming::GetTicks() / SystemTimers::GetTicksPerSecond();
ltime +=
Core::System::GetInstance().GetCoreTiming().GetTicks() / SystemTimers::GetTicksPerSecond();
}
else
{
Expand Down
28 changes: 18 additions & 10 deletions Source/Core/Core/HW/EXI/EXI_DeviceMemoryCard.cpp
Expand Up @@ -86,11 +86,13 @@ void CEXIMemoryCard::Init()
{
static_assert(s_et_cmd_done.size() == s_et_transfer_complete.size(), "Event array size differs");
static_assert(s_et_cmd_done.size() == MEMCARD_SLOTS.size(), "Event array size differs");
auto& system = Core::System::GetInstance();
auto& core_timing = system.GetCoreTiming();
for (Slot slot : MEMCARD_SLOTS)
{
s_et_cmd_done[slot] = CoreTiming::RegisterEvent(
s_et_cmd_done[slot] = core_timing.RegisterEvent(
fmt::format("memcardDone{}", s_card_short_names[slot]), CmdDoneCallback);
s_et_transfer_complete[slot] = CoreTiming::RegisterEvent(
s_et_transfer_complete[slot] = core_timing.RegisterEvent(
fmt::format("memcardTransferComplete{}", s_card_short_names[slot]),
TransferCompleteCallback);
}
Expand Down Expand Up @@ -233,8 +235,10 @@ void CEXIMemoryCard::SetupRawMemcard(u16 size_mb)

CEXIMemoryCard::~CEXIMemoryCard()
{
CoreTiming::RemoveEvent(s_et_cmd_done[m_card_slot]);
CoreTiming::RemoveEvent(s_et_transfer_complete[m_card_slot]);
auto& system = Core::System::GetInstance();
auto& core_timing = system.GetCoreTiming();
core_timing.RemoveEvent(s_et_cmd_done[m_card_slot]);
core_timing.RemoveEvent(s_et_transfer_complete[m_card_slot]);
}

bool CEXIMemoryCard::UseDelayedTransferCompletion() const
Expand Down Expand Up @@ -265,8 +269,10 @@ void CEXIMemoryCard::TransferComplete()

void CEXIMemoryCard::CmdDoneLater(u64 cycles)
{
CoreTiming::RemoveEvent(s_et_cmd_done[m_card_slot]);
CoreTiming::ScheduleEvent(cycles, s_et_cmd_done[m_card_slot], static_cast<u64>(m_card_slot));
auto& system = Core::System::GetInstance();
auto& core_timing = system.GetCoreTiming();
core_timing.RemoveEvent(s_et_cmd_done[m_card_slot]);
core_timing.ScheduleEvent(cycles, s_et_cmd_done[m_card_slot], static_cast<u64>(m_card_slot));
}

void CEXIMemoryCard::SetCS(int cs)
Expand Down Expand Up @@ -525,8 +531,9 @@ void CEXIMemoryCard::DMARead(u32 addr, u32 size)
}

// Schedule transfer complete later based on read speed
CoreTiming::ScheduleEvent(size * (SystemTimers::GetTicksPerSecond() / MC_TRANSFER_RATE_READ),
s_et_transfer_complete[m_card_slot], static_cast<u64>(m_card_slot));
Core::System::GetInstance().GetCoreTiming().ScheduleEvent(
size * (SystemTimers::GetTicksPerSecond() / MC_TRANSFER_RATE_READ),
s_et_transfer_complete[m_card_slot], static_cast<u64>(m_card_slot));
}

// DMA write are preceded by all of the necessary setup via IMMWrite
Expand All @@ -541,7 +548,8 @@ void CEXIMemoryCard::DMAWrite(u32 addr, u32 size)
}

// Schedule transfer complete later based on write speed
CoreTiming::ScheduleEvent(size * (SystemTimers::GetTicksPerSecond() / MC_TRANSFER_RATE_WRITE),
s_et_transfer_complete[m_card_slot], static_cast<u64>(m_card_slot));
Core::System::GetInstance().GetCoreTiming().ScheduleEvent(
size * (SystemTimers::GetTicksPerSecond() / MC_TRANSFER_RATE_WRITE),
s_et_transfer_complete[m_card_slot], static_cast<u64>(m_card_slot));
}
} // namespace ExpansionInterface
5 changes: 3 additions & 2 deletions Source/Core/Core/HW/EXI/EXI_DeviceMic.cpp
Expand Up @@ -20,6 +20,7 @@
#include "Core/HW/EXI/EXI.h"
#include "Core/HW/GCPad.h"
#include "Core/HW/SystemTimers.h"
#include "Core/System.h"

#ifdef _WIN32
#include <Objbase.h>
Expand Down Expand Up @@ -264,13 +265,13 @@ void CEXIMic::SetCS(int cs)
void CEXIMic::UpdateNextInterruptTicks()
{
int diff = (SystemTimers::GetTicksPerSecond() / sample_rate) * buff_size_samples;
next_int_ticks = CoreTiming::GetTicks() + diff;
next_int_ticks = Core::System::GetInstance().GetCoreTiming().GetTicks() + diff;
ExpansionInterface::ScheduleUpdateInterrupts(CoreTiming::FromThread::CPU, diff);
}

bool CEXIMic::IsInterruptSet()
{
if (next_int_ticks && CoreTiming::GetTicks() >= next_int_ticks)
if (next_int_ticks && Core::System::GetInstance().GetCoreTiming().GetTicks() >= next_int_ticks)
{
if (status.is_active)
UpdateNextInterruptTicks();
Expand Down
5 changes: 3 additions & 2 deletions Source/Core/Core/HW/HW.cpp
Expand Up @@ -27,12 +27,13 @@
#include "Core/HW/WII_IPC.h"
#include "Core/IOS/IOS.h"
#include "Core/State.h"
#include "Core/System.h"

namespace HW
{
void Init(const Sram* override_sram)
{
CoreTiming::Init();
Core::System::GetInstance().GetCoreTiming().Init();
SystemTimers::PreInit();

State::Init();
Expand Down Expand Up @@ -79,7 +80,7 @@ void Shutdown()
AudioInterface::Shutdown();

State::Shutdown();
CoreTiming::Shutdown();
Core::System::GetInstance().GetCoreTiming().Shutdown();
}

void DoState(PointerWrap& p)
Expand Down
22 changes: 15 additions & 7 deletions Source/Core/Core/HW/ProcessorInterface.cpp
Expand Up @@ -72,11 +72,13 @@ void Init()
m_ResetCode = 0; // Cold reset
m_InterruptCause = INT_CAUSE_RST_BUTTON | INT_CAUSE_VI;

toggleResetButton = CoreTiming::RegisterEvent("ToggleResetButton", ToggleResetButtonCallback);
auto& system = Core::System::GetInstance();
auto& core_timing = system.GetCoreTiming();
toggleResetButton = core_timing.RegisterEvent("ToggleResetButton", ToggleResetButtonCallback);
iosNotifyResetButton =
CoreTiming::RegisterEvent("IOSNotifyResetButton", IOSNotifyResetButtonCallback);
core_timing.RegisterEvent("IOSNotifyResetButton", IOSNotifyResetButtonCallback);
iosNotifyPowerButton =
CoreTiming::RegisterEvent("IOSNotifyPowerButton", IOSNotifyPowerButtonCallback);
core_timing.RegisterEvent("IOSNotifyPowerButton", IOSNotifyPowerButtonCallback);
}

void RegisterMMIO(MMIO::Mapping* mmio, u32 base)
Expand Down Expand Up @@ -261,17 +263,23 @@ void ResetButton_Tap()
{
if (!Core::IsRunning())
return;
CoreTiming::ScheduleEvent(0, toggleResetButton, true, CoreTiming::FromThread::ANY);
CoreTiming::ScheduleEvent(0, iosNotifyResetButton, 0, CoreTiming::FromThread::ANY);
CoreTiming::ScheduleEvent(SystemTimers::GetTicksPerSecond() / 2, toggleResetButton, false,

auto& system = Core::System::GetInstance();
auto& core_timing = system.GetCoreTiming();
core_timing.ScheduleEvent(0, toggleResetButton, true, CoreTiming::FromThread::ANY);
core_timing.ScheduleEvent(0, iosNotifyResetButton, 0, CoreTiming::FromThread::ANY);
core_timing.ScheduleEvent(SystemTimers::GetTicksPerSecond() / 2, toggleResetButton, false,
CoreTiming::FromThread::ANY);
}

void PowerButton_Tap()
{
if (!Core::IsRunning())
return;
CoreTiming::ScheduleEvent(0, iosNotifyPowerButton, 0, CoreTiming::FromThread::ANY);

auto& system = Core::System::GetInstance();
auto& core_timing = system.GetCoreTiming();
core_timing.ScheduleEvent(0, iosNotifyPowerButton, 0, CoreTiming::FromThread::ANY);
}

} // namespace ProcessorInterface
35 changes: 21 additions & 14 deletions Source/Core/Core/HW/SI/SI.cpp
Expand Up @@ -344,8 +344,8 @@ static void RunSIBuffer(Core::System& system, u64 user_data, s64 cycles_late)
}
else
{
CoreTiming::ScheduleEvent(device->TransferInterval() - cycles_late,
state.event_type_tranfer_pending);
system.GetCoreTiming().ScheduleEvent(device->TransferInterval() - cycles_late,
state.event_type_tranfer_pending);
}
}
}
Expand Down Expand Up @@ -388,10 +388,12 @@ static void DeviceEventCallback(Core::System& system, u64 userdata, s64 cyclesLa

static void RegisterEvents()
{
auto& state = Core::System::GetInstance().GetSerialInterfaceState().GetData();
auto& system = Core::System::GetInstance();
auto& core_timing = system.GetCoreTiming();
auto& state = system.GetSerialInterfaceState().GetData();
state.event_type_change_device =
CoreTiming::RegisterEvent("ChangeSIDevice", ChangeDeviceCallback);
state.event_type_tranfer_pending = CoreTiming::RegisterEvent("SITransferPending", RunSIBuffer);
core_timing.RegisterEvent("ChangeSIDevice", ChangeDeviceCallback);
state.event_type_tranfer_pending = core_timing.RegisterEvent("SITransferPending", RunSIBuffer);

constexpr std::array<CoreTiming::TimedCallback, MAX_SI_CHANNELS> event_callbacks = {
DeviceEventCallback<0>,
Expand All @@ -402,20 +404,24 @@ static void RegisterEvents()
for (int i = 0; i < MAX_SI_CHANNELS; ++i)
{
state.event_types_device[i] =
CoreTiming::RegisterEvent(fmt::format("SIEventChannel{}", i), event_callbacks[i]);
core_timing.RegisterEvent(fmt::format("SIEventChannel{}", i), event_callbacks[i]);
}
}

void ScheduleEvent(int device_number, s64 cycles_into_future, u64 userdata)
{
auto& state = Core::System::GetInstance().GetSerialInterfaceState().GetData();
CoreTiming::ScheduleEvent(cycles_into_future, state.event_types_device[device_number], userdata);
auto& system = Core::System::GetInstance();
auto& core_timing = system.GetCoreTiming();
auto& state = system.GetSerialInterfaceState().GetData();
core_timing.ScheduleEvent(cycles_into_future, state.event_types_device[device_number], userdata);
}

void RemoveEvent(int device_number)
{
auto& state = Core::System::GetInstance().GetSerialInterfaceState().GetData();
CoreTiming::RemoveEvent(state.event_types_device[device_number]);
auto& system = Core::System::GetInstance();
auto& core_timing = system.GetCoreTiming();
auto& state = system.GetSerialInterfaceState().GetData();
core_timing.RemoveEvent(state.event_types_device[device_number]);
}

void Init()
Expand Down Expand Up @@ -573,7 +579,7 @@ void RegisterMMIO(MMIO::Mapping* mmio, u32 base)
if (tmp_com_csr.TSTART)
{
if (state.com_csr.TSTART)
CoreTiming::RemoveEvent(state.event_type_tranfer_pending);
system.GetCoreTiming().RemoveEvent(state.event_type_tranfer_pending);
state.com_csr.TSTART = 1;
RunSIBuffer(system, 0, 0);
}
Expand Down Expand Up @@ -676,7 +682,8 @@ void ChangeDevice(SIDevices device, int channel)

static void ChangeDeviceDeterministic(SIDevices device, int channel)
{
auto& state = Core::System::GetInstance().GetSerialInterfaceState().GetData();
auto& system = Core::System::GetInstance();
auto& state = system.GetSerialInterfaceState().GetData();
if (state.channel[channel].has_recent_device_change)
return;

Expand All @@ -696,8 +703,8 @@ static void ChangeDeviceDeterministic(SIDevices device, int channel)

// Prevent additional device changes on this channel for one second.
state.channel[channel].has_recent_device_change = true;
CoreTiming::ScheduleEvent(SystemTimers::GetTicksPerSecond(), state.event_type_change_device,
channel);
system.GetCoreTiming().ScheduleEvent(SystemTimers::GetTicksPerSecond(),
state.event_type_change_device, channel);
}

void UpdateDevices()
Expand Down
15 changes: 10 additions & 5 deletions Source/Core/Core/HW/SI/SI_DeviceGBA.cpp
Expand Up @@ -20,6 +20,7 @@
#include "Core/CoreTiming.h"
#include "Core/HW/SI/SI_Device.h"
#include "Core/HW/SystemTimers.h"
#include "Core/System.h"

namespace SerialInterface
{
Expand Down Expand Up @@ -145,21 +146,24 @@ void GBASockServer::ClockSync()
if (!(m_clock_sync = GetNextClock()))
return;

auto& system = Core::System::GetInstance();
auto& core_timing = system.GetCoreTiming();

u32 time_slice = 0;

if (m_last_time_slice == 0)
{
s_num_connected++;
m_last_time_slice = CoreTiming::GetTicks();
m_last_time_slice = core_timing.GetTicks();
time_slice = (u32)(SystemTimers::GetTicksPerSecond() / 60);
}
else
{
time_slice = (u32)(CoreTiming::GetTicks() - m_last_time_slice);
time_slice = (u32)(core_timing.GetTicks() - m_last_time_slice);
}

time_slice = (u32)((u64)time_slice * 16777216 / SystemTimers::GetTicksPerSecond());
m_last_time_slice = CoreTiming::GetTicks();
m_last_time_slice = core_timing.GetTicks();
char bytes[4] = {0, 0, 0, 0};
bytes[0] = (time_slice >> 24) & 0xff;
bytes[1] = (time_slice >> 16) & 0xff;
Expand Down Expand Up @@ -285,14 +289,15 @@ int CSIDevice_GBA::RunBuffer(u8* buffer, int request_length)
}

m_last_cmd = static_cast<EBufferCommands>(buffer[0]);
m_timestamp_sent = CoreTiming::GetTicks();
m_timestamp_sent = Core::System::GetInstance().GetCoreTiming().GetTicks();
m_next_action = NextAction::WaitTransferTime;
return 0;
}

case NextAction::WaitTransferTime:
{
int elapsed_time = static_cast<int>(CoreTiming::GetTicks() - m_timestamp_sent);
int elapsed_time =
static_cast<int>(Core::System::GetInstance().GetCoreTiming().GetTicks() - m_timestamp_sent);
// Tell SI to ask again after TransferInterval() cycles
if (SIDevice_GetGBATransferTime(m_last_cmd) > elapsed_time)
return 0;
Expand Down
11 changes: 7 additions & 4 deletions Source/Core/Core/HW/SI/SI_DeviceGBAEmu.cpp
Expand Up @@ -18,6 +18,7 @@
#include "Core/HW/SystemTimers.h"
#include "Core/Host.h"
#include "Core/NetPlayProto.h"
#include "Core/System.h"

namespace SerialInterface
{
Expand All @@ -30,7 +31,7 @@ CSIDevice_GBAEmu::CSIDevice_GBAEmu(SIDevices device, int device_number)
: ISIDevice(device, device_number)
{
m_core = std::make_shared<HW::GBA::Core>(m_device_number);
m_core->Start(CoreTiming::GetTicks());
m_core->Start(Core::System::GetInstance().GetCoreTiming().GetTicks());
m_gbahost = Host_CreateGBAHost(m_core);
m_core->SetHost(m_gbahost);
ScheduleEvent(m_device_number, GetSyncInterval());
Expand All @@ -55,7 +56,7 @@ int CSIDevice_GBAEmu::RunBuffer(u8* buffer, int request_length)
buffer[0], buffer[1], buffer[2], buffer[3], buffer[4]);
#endif
m_last_cmd = static_cast<EBufferCommands>(buffer[0]);
m_timestamp_sent = CoreTiming::GetTicks();
m_timestamp_sent = Core::System::GetInstance().GetCoreTiming().GetTicks();
m_core->SendJoybusCommand(m_timestamp_sent, TransferInterval(), buffer, m_keys);

RemoveEvent(m_device_number);
Expand All @@ -74,7 +75,8 @@ int CSIDevice_GBAEmu::RunBuffer(u8* buffer, int request_length)

case NextAction::WaitTransferTime:
{
int elapsed_time = static_cast<int>(CoreTiming::GetTicks() - m_timestamp_sent);
int elapsed_time =
static_cast<int>(Core::System::GetInstance().GetCoreTiming().GetTicks() - m_timestamp_sent);
// Tell SI to ask again after TransferInterval() cycles
if (TransferInterval() > elapsed_time)
return 0;
Expand Down Expand Up @@ -162,7 +164,8 @@ void CSIDevice_GBAEmu::DoState(PointerWrap& p)

void CSIDevice_GBAEmu::OnEvent(u64 userdata, s64 cycles_late)
{
m_core->SendJoybusCommand(CoreTiming::GetTicks() + userdata, 0, nullptr, m_keys);
m_core->SendJoybusCommand(Core::System::GetInstance().GetCoreTiming().GetTicks() + userdata, 0,
nullptr, m_keys);
ScheduleEvent(m_device_number, userdata + GetSyncInterval());
}
} // namespace SerialInterface
5 changes: 3 additions & 2 deletions Source/Core/Core/HW/SI/SI_DeviceGCController.cpp
Expand Up @@ -18,6 +18,7 @@
#include "Core/HW/SystemTimers.h"
#include "Core/Movie.h"
#include "Core/NetPlayProto.h"
#include "Core/System.h"
#include "InputCommon/GCPadStatus.h"

namespace SerialInterface
Expand Down Expand Up @@ -263,12 +264,12 @@ CSIDevice_GCController::HandleButtonCombos(const GCPadStatus& pad_status)
{
m_last_button_combo = temp_combo;
if (m_last_button_combo != COMBO_NONE)
m_timer_button_combo_start = CoreTiming::GetTicks();
m_timer_button_combo_start = Core::System::GetInstance().GetCoreTiming().GetTicks();
}

if (m_last_button_combo != COMBO_NONE)
{
const u64 current_time = CoreTiming::GetTicks();
const u64 current_time = Core::System::GetInstance().GetCoreTiming().GetTicks();
if (u32(current_time - m_timer_button_combo_start) > SystemTimers::GetTicksPerSecond() * 3)
{
if (m_last_button_combo == COMBO_RESET)
Expand Down
86 changes: 51 additions & 35 deletions Source/Core/Core/HW/SystemTimers.cpp
Expand Up @@ -65,6 +65,7 @@ IPC_HLE_PERIOD: For the Wii Remote this is the call schedule:
#include "Core/IOS/IOS.h"
#include "Core/PatchEngine.h"
#include "Core/PowerPC/PowerPC.h"
#include "Core/System.h"
#include "VideoCommon/Fifo.h"

namespace SystemTimers
Expand Down Expand Up @@ -105,7 +106,8 @@ void DSPCallback(Core::System& system, u64 userdata, s64 cyclesLate)
// splits up the cycle budget in case lle is used
// for hle, just gives all of the slice to hle
DSP::UpdateDSPSlice(static_cast<int>(DSP::GetDSPEmulator()->DSP_UpdateRate() - cyclesLate));
CoreTiming::ScheduleEvent(DSP::GetDSPEmulator()->DSP_UpdateRate() - cyclesLate, et_DSP);
system.GetCoreTiming().ScheduleEvent(DSP::GetDSPEmulator()->DSP_UpdateRate() - cyclesLate,
et_DSP);
}

int GetAudioDMACallbackPeriod()
Expand All @@ -118,22 +120,23 @@ int GetAudioDMACallbackPeriod()
void AudioDMACallback(Core::System& system, u64 userdata, s64 cyclesLate)
{
DSP::UpdateAudioDMA(); // Push audio to speakers.
CoreTiming::ScheduleEvent(GetAudioDMACallbackPeriod() - cyclesLate, et_AudioDMA);
system.GetCoreTiming().ScheduleEvent(GetAudioDMACallbackPeriod() - cyclesLate, et_AudioDMA);
}

void IPC_HLE_UpdateCallback(Core::System& system, u64 userdata, s64 cyclesLate)
{
if (SConfig::GetInstance().bWii)
{
IOS::HLE::GetIOS()->UpdateDevices();
CoreTiming::ScheduleEvent(s_ipc_hle_period - cyclesLate, et_IPC_HLE);
system.GetCoreTiming().ScheduleEvent(s_ipc_hle_period - cyclesLate, et_IPC_HLE);
}
}

void VICallback(Core::System& system, u64 userdata, s64 cyclesLate)
{
VideoInterface::Update(CoreTiming::GetTicks() - cyclesLate);
CoreTiming::ScheduleEvent(VideoInterface::GetTicksPerHalfLine() - cyclesLate, et_VI);
auto& core_timing = system.GetCoreTiming();
VideoInterface::Update(core_timing.GetTicks() - cyclesLate);
core_timing.ScheduleEvent(VideoInterface::GetTicksPerHalfLine() - cyclesLate, et_VI);
}

void DecrementerCallback(Core::System& system, u64 userdata, s64 cyclesLate)
Expand Down Expand Up @@ -164,7 +167,7 @@ void PatchEngineCallback(Core::System& system, u64 userdata, s64 cycles_late)
cycles_pruned += next_schedule;
}

CoreTiming::ScheduleEvent(next_schedule, et_PatchEngine, cycles_pruned);
system.GetCoreTiming().ScheduleEvent(next_schedule, et_PatchEngine, cycles_pruned);
}

void ThrottleCallback(Core::System& system, u64 deadline, s64 cyclesLate)
Expand Down Expand Up @@ -208,7 +211,7 @@ void ThrottleCallback(Core::System& system, u64 deadline, s64 cyclesLate)
}
// reschedule 1ms (possibly scaled by emulation_speed) into future on ppc
// add 1ms to the deadline
CoreTiming::ScheduleEvent(next_event - cyclesLate, et_Throttle, deadline + 1000);
system.GetCoreTiming().ScheduleEvent(next_event - cyclesLate, et_Throttle, deadline + 1000);
}
} // namespace

Expand All @@ -219,34 +222,43 @@ u32 GetTicksPerSecond()

void DecrementerSet()
{
auto& system = Core::System::GetInstance();
auto& core_timing = system.GetCoreTiming();

u32 decValue = PowerPC::ppcState.spr[SPR_DEC];

CoreTiming::RemoveEvent(et_Dec);
core_timing.RemoveEvent(et_Dec);
if ((decValue & 0x80000000) == 0)
{
CoreTiming::SetFakeDecStartTicks(CoreTiming::GetTicks());
CoreTiming::SetFakeDecStartValue(decValue);
core_timing.SetFakeDecStartTicks(core_timing.GetTicks());
core_timing.SetFakeDecStartValue(decValue);

CoreTiming::ScheduleEvent(decValue * TIMER_RATIO, et_Dec);
core_timing.ScheduleEvent(decValue * TIMER_RATIO, et_Dec);
}
}

u32 GetFakeDecrementer()
{
return (CoreTiming::GetFakeDecStartValue() -
(u32)((CoreTiming::GetTicks() - CoreTiming::GetFakeDecStartTicks()) / TIMER_RATIO));
auto& system = Core::System::GetInstance();
auto& core_timing = system.GetCoreTiming();
return (core_timing.GetFakeDecStartValue() -
(u32)((core_timing.GetTicks() - core_timing.GetFakeDecStartTicks()) / TIMER_RATIO));
}

void TimeBaseSet()
{
CoreTiming::SetFakeTBStartTicks(CoreTiming::GetTicks());
CoreTiming::SetFakeTBStartValue(PowerPC::ReadFullTimeBaseValue());
auto& system = Core::System::GetInstance();
auto& core_timing = system.GetCoreTiming();
core_timing.SetFakeTBStartTicks(core_timing.GetTicks());
core_timing.SetFakeTBStartValue(PowerPC::ReadFullTimeBaseValue());
}

u64 GetFakeTimeBase()
{
return CoreTiming::GetFakeTBStartValue() +
((CoreTiming::GetTicks() - CoreTiming::GetFakeTBStartTicks()) / TIMER_RATIO);
auto& system = Core::System::GetInstance();
auto& core_timing = system.GetCoreTiming();
return core_timing.GetFakeTBStartValue() +
((core_timing.GetTicks() - core_timing.GetFakeTBStartTicks()) / TIMER_RATIO);
}

s64 GetLocalTimeRTCOffset()
Expand Down Expand Up @@ -293,7 +305,8 @@ void ChangePPCClock(Mode mode)
s_cpu_core_clock = 729000000u;
else
s_cpu_core_clock = 486000000u;
CoreTiming::AdjustEventQueueTimes(s_cpu_core_clock, previous_clock);
Core::System::GetInstance().GetCoreTiming().AdjustEventQueueTimes(s_cpu_core_clock,
previous_clock);
}

void Init()
Expand All @@ -315,32 +328,35 @@ void Init()
Common::Timer::GetLocalTimeSinceJan1970() - Config::Get(Config::MAIN_CUSTOM_RTC_VALUE);
}

CoreTiming::SetFakeTBStartValue(static_cast<u64>(s_cpu_core_clock / TIMER_RATIO) *
auto& system = Core::System::GetInstance();
auto& core_timing = system.GetCoreTiming();

core_timing.SetFakeTBStartValue(static_cast<u64>(s_cpu_core_clock / TIMER_RATIO) *
static_cast<u64>(ExpansionInterface::CEXIIPL::GetEmulatedTime(
ExpansionInterface::CEXIIPL::GC_EPOCH)));

CoreTiming::SetFakeTBStartTicks(CoreTiming::GetTicks());
core_timing.SetFakeTBStartTicks(core_timing.GetTicks());

CoreTiming::SetFakeDecStartValue(0xFFFFFFFF);
CoreTiming::SetFakeDecStartTicks(CoreTiming::GetTicks());
core_timing.SetFakeDecStartValue(0xFFFFFFFF);
core_timing.SetFakeDecStartTicks(core_timing.GetTicks());

et_Dec = CoreTiming::RegisterEvent("DecCallback", DecrementerCallback);
et_VI = CoreTiming::RegisterEvent("VICallback", VICallback);
et_DSP = CoreTiming::RegisterEvent("DSPCallback", DSPCallback);
et_AudioDMA = CoreTiming::RegisterEvent("AudioDMACallback", AudioDMACallback);
et_IPC_HLE = CoreTiming::RegisterEvent("IPC_HLE_UpdateCallback", IPC_HLE_UpdateCallback);
et_PatchEngine = CoreTiming::RegisterEvent("PatchEngine", PatchEngineCallback);
et_Throttle = CoreTiming::RegisterEvent("Throttle", ThrottleCallback);
et_Dec = core_timing.RegisterEvent("DecCallback", DecrementerCallback);
et_VI = core_timing.RegisterEvent("VICallback", VICallback);
et_DSP = core_timing.RegisterEvent("DSPCallback", DSPCallback);
et_AudioDMA = core_timing.RegisterEvent("AudioDMACallback", AudioDMACallback);
et_IPC_HLE = core_timing.RegisterEvent("IPC_HLE_UpdateCallback", IPC_HLE_UpdateCallback);
et_PatchEngine = core_timing.RegisterEvent("PatchEngine", PatchEngineCallback);
et_Throttle = core_timing.RegisterEvent("Throttle", ThrottleCallback);

CoreTiming::ScheduleEvent(VideoInterface::GetTicksPerHalfLine(), et_VI);
CoreTiming::ScheduleEvent(0, et_DSP);
CoreTiming::ScheduleEvent(GetAudioDMACallbackPeriod(), et_AudioDMA);
CoreTiming::ScheduleEvent(0, et_Throttle, 0);
core_timing.ScheduleEvent(VideoInterface::GetTicksPerHalfLine(), et_VI);
core_timing.ScheduleEvent(0, et_DSP);
core_timing.ScheduleEvent(GetAudioDMACallbackPeriod(), et_AudioDMA);
core_timing.ScheduleEvent(0, et_Throttle, 0);

CoreTiming::ScheduleEvent(VideoInterface::GetTicksPerField(), et_PatchEngine);
core_timing.ScheduleEvent(VideoInterface::GetTicksPerField(), et_PatchEngine);

if (SConfig::GetInstance().bWii)
CoreTiming::ScheduleEvent(s_ipc_hle_period, et_IPC_HLE);
core_timing.ScheduleEvent(s_ipc_hle_period, et_IPC_HLE);

s_emu_to_real_time_ring_buffer.fill(0);
}
Expand Down
8 changes: 5 additions & 3 deletions Source/Core/Core/HW/VideoInterface.cpp
Expand Up @@ -317,7 +317,8 @@ void RegisterMMIO(MMIO::Mapping* mmio, u32 base)
base | VI_HORIZONTAL_BEAM_POSITION, MMIO::ComplexRead<u16>([](Core::System& system, u32) {
auto& state = system.GetVideoInterfaceState().GetData();
u16 value = static_cast<u16>(
1 + state.h_timing_0.HLW * (CoreTiming::GetTicks() - state.ticks_last_line_start) /
1 + state.h_timing_0.HLW *
(system.GetCoreTiming().GetTicks() - state.ticks_last_line_start) /
(GetTicksPerHalfLine()));
return std::clamp<u16>(value, 1, state.h_timing_0.HLW * 2);
}),
Expand Down Expand Up @@ -878,7 +879,8 @@ static void EndField(FieldType field, u64 ticks)
// Run when: When a frame is scanned (progressive/interlace)
void Update(u64 ticks)
{
auto& state = Core::System::GetInstance().GetVideoInterfaceState().GetData();
auto& system = Core::System::GetInstance();
auto& state = system.GetVideoInterfaceState().GetData();

// Movie's frame counter should be updated before actually rendering the frame,
// in case frame counter display is enabled
Expand Down Expand Up @@ -946,7 +948,7 @@ void Update(u64 ticks)

if (!(state.half_line_count & 1))
{
state.ticks_last_line_start = CoreTiming::GetTicks();
state.ticks_last_line_start = system.GetCoreTiming().GetTicks();
}

// Check if we need to assert IR_INT. Note that the granularity of our current horizontal
Expand Down
21 changes: 12 additions & 9 deletions Source/Core/Core/HW/WII_IPC.cpp
Expand Up @@ -157,7 +157,8 @@ static void InitState()
void Init()
{
InitState();
updateInterrupts = CoreTiming::RegisterEvent("IPCInterrupt", UpdateInterrupts);
updateInterrupts =
Core::System::GetInstance().GetCoreTiming().RegisterEvent("IPCInterrupt", UpdateInterrupts);
}

void Reset()
Expand All @@ -176,7 +177,7 @@ void RegisterMMIO(MMIO::Mapping* mmio, u32 base)

mmio->Register(base | IPC_PPCCTRL,
MMIO::ComplexRead<u32>([](Core::System&, u32) { return ctrl.ppc(); }),
MMIO::ComplexWrite<u32>([](Core::System&, u32, u32 val) {
MMIO::ComplexWrite<u32>([](Core::System& system, u32, u32 val) {
ctrl.ppc(val);
// The IPC interrupt is triggered when IY1/IY2 is set and
// Y1/Y2 is written to -- even when this results in clearing the bit.
Expand All @@ -185,25 +186,25 @@ void RegisterMMIO(MMIO::Mapping* mmio, u32 base)
if (ctrl.X1)
HLE::GetIOS()->EnqueueIPCRequest(ppc_msg);
HLE::GetIOS()->UpdateIPC();
CoreTiming::ScheduleEvent(0, updateInterrupts, 0);
system.GetCoreTiming().ScheduleEvent(0, updateInterrupts, 0);
}));

mmio->Register(base | IPC_ARMMSG, MMIO::DirectRead<u32>(&arm_msg), MMIO::InvalidWrite<u32>());

mmio->Register(base | PPC_IRQFLAG, MMIO::InvalidRead<u32>(),
MMIO::ComplexWrite<u32>([](Core::System&, u32, u32 val) {
MMIO::ComplexWrite<u32>([](Core::System& system, u32, u32 val) {
ppc_irq_flags &= ~val;
HLE::GetIOS()->UpdateIPC();
CoreTiming::ScheduleEvent(0, updateInterrupts, 0);
system.GetCoreTiming().ScheduleEvent(0, updateInterrupts, 0);
}));

mmio->Register(base | PPC_IRQMASK, MMIO::InvalidRead<u32>(),
MMIO::ComplexWrite<u32>([](Core::System&, u32, u32 val) {
MMIO::ComplexWrite<u32>([](Core::System& system, u32, u32 val) {
ppc_irq_masks = val;
if (ppc_irq_masks & INT_CAUSE_IPC_BROADWAY) // wtf?
Reset();
HLE::GetIOS()->UpdateIPC();
CoreTiming::ScheduleEvent(0, updateInterrupts, 0);
system.GetCoreTiming().ScheduleEvent(0, updateInterrupts, 0);
}));

mmio->Register(base | GPIOB_OUT, MMIO::DirectRead<u32>(&g_gpio_out.m_hex),
Expand Down Expand Up @@ -313,7 +314,8 @@ void GenerateAck(u32 address)
ctrl.Y2, ctrl.X1);
// Based on a hardware test, the IPC interrupt takes approximately 100 TB ticks to fire
// after Y2 is seen in the control register.
CoreTiming::ScheduleEvent(100 * SystemTimers::TIMER_RATIO, updateInterrupts);
Core::System::GetInstance().GetCoreTiming().ScheduleEvent(100 * SystemTimers::TIMER_RATIO,
updateInterrupts);
}

void GenerateReply(u32 address)
Expand All @@ -324,7 +326,8 @@ void GenerateReply(u32 address)
ctrl.Y1, ctrl.Y2, ctrl.X1);
// Based on a hardware test, the IPC interrupt takes approximately 100 TB ticks to fire
// after Y1 is seen in the control register.
CoreTiming::ScheduleEvent(100 * SystemTimers::TIMER_RATIO, updateInterrupts);
Core::System::GetInstance().GetCoreTiming().ScheduleEvent(100 * SystemTimers::TIMER_RATIO,
updateInterrupts);
}

bool IsReady()
Expand Down
4 changes: 2 additions & 2 deletions Source/Core/Core/IOS/DI/DI.cpp
Expand Up @@ -113,8 +113,8 @@ void DIDevice::ProcessQueuedIOCtl()
auto finished = StartIOCtl(request);
if (finished)
{
CoreTiming::ScheduleEvent(IPC_OVERHEAD_TICKS, s_finish_executing_di_command,
static_cast<u64>(finished.value()));
Core::System::GetInstance().GetCoreTiming().ScheduleEvent(
IPC_OVERHEAD_TICKS, s_finish_executing_di_command, static_cast<u64>(finished.value()));
return;
}
}
Expand Down
27 changes: 18 additions & 9 deletions Source/Core/Core/IOS/ES/ES.cpp
Expand Up @@ -26,6 +26,7 @@
#include "Core/IOS/IOSC.h"
#include "Core/IOS/Uids.h"
#include "Core/IOS/VersionInfo.h"
#include "Core/System.h"
#include "DiscIO/Enums.h"

namespace IOS::HLE
Expand Down Expand Up @@ -103,8 +104,10 @@ ESDevice::ESDevice(Kernel& ios, const std::string& device_name) : Device(ios, de

if (Core::IsRunningAndStarted())
{
CoreTiming::RemoveEvent(s_finish_init_event);
CoreTiming::ScheduleEvent(GetESBootTicks(m_ios.GetVersion()), s_finish_init_event);
auto& system = Core::System::GetInstance();
auto& core_timing = system.GetCoreTiming();
core_timing.RemoveEvent(s_finish_init_event);
core_timing.ScheduleEvent(GetESBootTicks(m_ios.GetVersion()), s_finish_init_event);
}
else
{
Expand All @@ -114,14 +117,16 @@ ESDevice::ESDevice(Kernel& ios, const std::string& device_name) : Device(ios, de

void ESDevice::InitializeEmulationState()
{
s_finish_init_event = CoreTiming::RegisterEvent(
auto& system = Core::System::GetInstance();
auto& core_timing = system.GetCoreTiming();
s_finish_init_event = core_timing.RegisterEvent(
"IOS-ESFinishInit", [](Core::System& system, u64, s64) { GetIOS()->GetES()->FinishInit(); });
s_reload_ios_for_ppc_launch_event = CoreTiming::RegisterEvent(
s_reload_ios_for_ppc_launch_event = core_timing.RegisterEvent(
"IOS-ESReloadIOSForPPCLaunch", [](Core::System& system, u64 ios_id, s64) {
GetIOS()->GetES()->LaunchTitle(ios_id, HangPPC::Yes);
});
s_bootstrap_ppc_for_launch_event =
CoreTiming::RegisterEvent("IOS-ESBootstrapPPCForLaunch", [](Core::System& system, u64, s64) {
core_timing.RegisterEvent("IOS-ESBootstrapPPCForLaunch", [](Core::System& system, u64, s64) {
GetIOS()->GetES()->BootstrapPPC();
});
}
Expand Down Expand Up @@ -397,6 +402,9 @@ bool ESDevice::LaunchPPCTitle(u64 title_id)
return false;
}

auto& system = Core::System::GetInstance();
auto& core_timing = system.GetCoreTiming();

// Before launching a title, IOS first reads the TMD and reloads into the specified IOS version,
// even when that version is already running. After it has reloaded, ES_Launch will be called
// again and the PPC will be bootstrapped then.
Expand All @@ -417,8 +425,8 @@ bool ESDevice::LaunchPPCTitle(u64 title_id)
const u64 required_ios = tmd.GetIOSId();
if (!Core::IsRunningAndStarted())
return LaunchTitle(required_ios, HangPPC::Yes);
CoreTiming::RemoveEvent(s_reload_ios_for_ppc_launch_event);
CoreTiming::ScheduleEvent(ticks, s_reload_ios_for_ppc_launch_event, required_ios);
core_timing.RemoveEvent(s_reload_ios_for_ppc_launch_event);
core_timing.ScheduleEvent(ticks, s_reload_ios_for_ppc_launch_event, required_ios);
return true;
}

Expand Down Expand Up @@ -446,8 +454,9 @@ bool ESDevice::LaunchPPCTitle(u64 title_id)
m_pending_ppc_boot_content_path = GetContentPath(tmd.GetTitleId(), content);
if (!Core::IsRunningAndStarted())
return BootstrapPPC();
CoreTiming::RemoveEvent(s_bootstrap_ppc_for_launch_event);
CoreTiming::ScheduleEvent(ticks, s_bootstrap_ppc_for_launch_event);

core_timing.RemoveEvent(s_bootstrap_ppc_for_launch_event);
core_timing.ScheduleEvent(ticks, s_bootstrap_ppc_for_launch_event);
return true;
}

Expand Down
36 changes: 25 additions & 11 deletions Source/Core/Core/IOS/IOS.cpp
Expand Up @@ -56,6 +56,7 @@
#include "Core/IOS/WFS/WFSI.h"
#include "Core/IOS/WFS/WFSSRV.h"
#include "Core/PowerPC/PowerPC.h"
#include "Core/System.h"
#include "Core/WiiRoot.h"

namespace IOS::HLE
Expand Down Expand Up @@ -320,7 +321,7 @@ EmulationKernel::EmulationKernel(u64 title_id) : Kernel(title_id)

EmulationKernel::~EmulationKernel()
{
CoreTiming::RemoveAllEvents(s_event_enqueue);
Core::System::GetInstance().GetCoreTiming().RemoveAllEvents(s_event_enqueue);
}

// The title ID is a u64 where the first 32 bits are used for the title type.
Expand Down Expand Up @@ -410,7 +411,8 @@ bool Kernel::BootstrapPPC(const std::string& boot_content_path)
return false;

INFO_LOG_FMT(IOS, "BootstrapPPC: {}", boot_content_path);
CoreTiming::ScheduleEvent(ticks, s_event_finish_ppc_bootstrap, dol.IsAncast());
Core::System::GetInstance().GetCoreTiming().ScheduleEvent(ticks, s_event_finish_ppc_bootstrap,
dol.IsAncast());
return true;
}

Expand Down Expand Up @@ -485,9 +487,14 @@ bool Kernel::BootIOS(const u64 ios_title_id, HangPPC hang_ppc, const std::string
ResetAndPausePPC();

if (Core::IsRunningAndStarted())
CoreTiming::ScheduleEvent(GetIOSBootTicks(GetVersion()), s_event_finish_ios_boot, ios_title_id);
{
Core::System::GetInstance().GetCoreTiming().ScheduleEvent(
GetIOSBootTicks(GetVersion()), s_event_finish_ios_boot, ios_title_id);
}
else
{
FinishIOSBoot(ios_title_id);
}

return true;
}
Expand Down Expand Up @@ -720,10 +727,12 @@ void Kernel::ExecuteIPCCommand(const u32 address)
return;

// Ensure replies happen in order
const s64 ticks_until_last_reply = m_last_reply_time - CoreTiming::GetTicks();
auto& system = Core::System::GetInstance();
auto& core_timing = system.GetCoreTiming();
const s64 ticks_until_last_reply = m_last_reply_time - core_timing.GetTicks();
if (ticks_until_last_reply > 0)
result->reply_delay_ticks += ticks_until_last_reply;
m_last_reply_time = CoreTiming::GetTicks() + result->reply_delay_ticks;
m_last_reply_time = core_timing.GetTicks() + result->reply_delay_ticks;

EnqueueIPCReply(request, result->return_value, result->reply_delay_ticks);
}
Expand All @@ -734,7 +743,8 @@ void Kernel::EnqueueIPCRequest(u32 address)
// Based on hardware tests, IOS takes between 5µs and 10µs to acknowledge an IPC request.
// Console 1: 456 TB ticks before ACK
// Console 2: 658 TB ticks before ACK
CoreTiming::ScheduleEvent(500_tbticks, s_event_enqueue, address | ENQUEUE_REQUEST_FLAG);
Core::System::GetInstance().GetCoreTiming().ScheduleEvent(500_tbticks, s_event_enqueue,
address | ENQUEUE_REQUEST_FLAG);
}

// Called to send a reply to an IOS syscall
Expand All @@ -746,7 +756,8 @@ void Kernel::EnqueueIPCReply(const Request& request, const s32 return_value, s64
Memory::Write_U32(request.command, request.address + 8);
// IOS also overwrites the command type with the reply type.
Memory::Write_U32(IPC_REPLY, request.address);
CoreTiming::ScheduleEvent(cycles_in_future, s_event_enqueue, request.address, from);
Core::System::GetInstance().GetCoreTiming().ScheduleEvent(cycles_in_future, s_event_enqueue,
request.address, from);
}

void Kernel::HandleIPCEvent(u64 userdata)
Expand Down Expand Up @@ -892,23 +903,26 @@ static void FinishPPCBootstrap(Core::System& system, u64 userdata, s64 cycles_la

void Init()
{
auto& system = Core::System::GetInstance();
auto& core_timing = system.GetCoreTiming();

s_event_enqueue =
CoreTiming::RegisterEvent("IPCEvent", [](Core::System& system, u64 userdata, s64) {
core_timing.RegisterEvent("IPCEvent", [](Core::System& system, u64 userdata, s64) {
if (s_ios)
s_ios->HandleIPCEvent(userdata);
});

ESDevice::InitializeEmulationState();

s_event_finish_ppc_bootstrap =
CoreTiming::RegisterEvent("IOSFinishPPCBootstrap", FinishPPCBootstrap);
core_timing.RegisterEvent("IOSFinishPPCBootstrap", FinishPPCBootstrap);

s_event_finish_ios_boot =
CoreTiming::RegisterEvent("IOSFinishIOSBoot", [](Core::System& system, u64 ios_title_id,
core_timing.RegisterEvent("IOSFinishIOSBoot", [](Core::System& system, u64 ios_title_id,
s64) { FinishIOSBoot(ios_title_id); });

DIDevice::s_finish_executing_di_command =
CoreTiming::RegisterEvent("FinishDICommand", DIDevice::FinishDICommandCallback);
core_timing.RegisterEvent("FinishDICommand", DIDevice::FinishDICommandCallback);

// Start with IOS80 to simulate part of the Wii boot process.
s_ios = std::make_unique<EmulationKernel>(Titles::SYSTEM_MENU_IOS);
Expand Down
3 changes: 2 additions & 1 deletion Source/Core/Core/IOS/USB/Bluetooth/BTEmu.cpp
Expand Up @@ -25,6 +25,7 @@
#include "Core/NetPlayClient.h"
#include "Core/NetPlayProto.h"
#include "Core/SysConf.h"
#include "Core/System.h"
#include "InputCommon/ControllerInterface/ControllerInterface.h"

namespace IOS::HLE
Expand Down Expand Up @@ -339,7 +340,7 @@ void BluetoothEmuDevice::Update()
wiimote->Update();

const u64 interval = SystemTimers::GetTicksPerSecond() / Wiimote::UPDATE_FREQ;
const u64 now = CoreTiming::GetTicks();
const u64 now = Core::System::GetInstance().GetCoreTiming().GetTicks();

if (now - m_last_ticks > interval)
{
Expand Down
11 changes: 8 additions & 3 deletions Source/Core/Core/Movie.cpp
Expand Up @@ -63,6 +63,7 @@
#include "Core/IOS/USB/Bluetooth/WiimoteDevice.h"
#include "Core/NetPlayProto.h"
#include "Core/State.h"
#include "Core/System.h"
#include "Core/WiiUtils.h"

#include "DiscIO/Enums.h"
Expand Down Expand Up @@ -290,9 +291,12 @@ void InputUpdate()
s_currentInputCount++;
if (IsRecordingInput())
{
auto& system = Core::System::GetInstance();
auto& core_timing = system.GetCoreTiming();

s_totalInputCount = s_currentInputCount;
s_totalTickCount += CoreTiming::GetTicks() - s_tickCountAtLastInput;
s_tickCountAtLastInput = CoreTiming::GetTicks();
s_totalTickCount += core_timing.GetTicks() - s_tickCountAtLastInput;
s_tickCountAtLastInput = core_timing.GetTicks();
}
}

Expand Down Expand Up @@ -1181,7 +1185,8 @@ void LoadInput(const std::string& movie_path)
static void CheckInputEnd()
{
if (s_currentByte >= s_temp_input.size() ||
(CoreTiming::GetTicks() > s_totalTickCount && !IsRecordingInputFromSaveState()))
(Core::System::GetInstance().GetCoreTiming().GetTicks() > s_totalTickCount &&
!IsRecordingInputFromSaveState()))
{
EndPlayInput(!s_bReadOnly);
}
Expand Down
10 changes: 7 additions & 3 deletions Source/Core/Core/PowerPC/CachedInterpreter/CachedInterpreter.cpp
Expand Up @@ -13,6 +13,7 @@
#include "Core/PowerPC/Jit64Common/Jit64Constants.h"
#include "Core/PowerPC/PPCAnalyst.h"
#include "Core/PowerPC/PowerPC.h"
#include "Core/System.h"

struct CachedInterpreter::Instruction
{
Expand Down Expand Up @@ -109,12 +110,15 @@ void CachedInterpreter::ExecuteOneBlock()

void CachedInterpreter::Run()
{
auto& system = Core::System::GetInstance();
auto& core_timing = system.GetCoreTiming();

const CPU::State* state_ptr = CPU::GetStatePtr();
while (CPU::GetState() == CPU::State::Running)
{
// Start new timing slice
// NOTE: Exceptions may change PC
CoreTiming::Advance();
core_timing.Advance();

do
{
Expand All @@ -126,7 +130,7 @@ void CachedInterpreter::Run()
void CachedInterpreter::SingleStep()
{
// Enter new timing slice
CoreTiming::Advance();
Core::System::GetInstance().GetCoreTiming().Advance();
ExecuteOneBlock();
}

Expand Down Expand Up @@ -207,7 +211,7 @@ static bool CheckIdle(u32 idle_pc)
{
if (PowerPC::ppcState.npc == idle_pc)
{
CoreTiming::Idle();
Core::System::GetInstance().GetCoreTiming().Idle();
}
return false;
}
Expand Down
9 changes: 6 additions & 3 deletions Source/Core/Core/PowerPC/GDBStub.cpp
Expand Up @@ -37,6 +37,7 @@ typedef SSIZE_T ssize_t;
#include "Core/PowerPC/Gekko.h"
#include "Core/PowerPC/PPCCache.h"
#include "Core/PowerPC/PowerPC.h"
#include "Core/System.h"

namespace GDBStub
{
Expand Down Expand Up @@ -128,7 +129,7 @@ static void UpdateCallback(Core::System& system, u64 userdata, s64 cycles_late)
{
ProcessCommands(false);
if (IsActive())
CoreTiming::ScheduleEvent(GDB_UPDATE_CYCLES, s_update_event);
Core::System::GetInstance().GetCoreTiming().ScheduleEvent(GDB_UPDATE_CYCLES, s_update_event);
}

static u8 ReadByte()
Expand Down Expand Up @@ -1068,8 +1069,10 @@ static void InitGeneric(int domain, const sockaddr* server_addr, socklen_t serve
#endif
s_tmpsock = -1;

s_update_event = CoreTiming::RegisterEvent("GDBStubUpdate", UpdateCallback);
CoreTiming::ScheduleEvent(GDB_UPDATE_CYCLES, s_update_event);
auto& system = Core::System::GetInstance();
auto& core_timing = system.GetCoreTiming();
s_update_event = core_timing.RegisterEvent("GDBStubUpdate", UpdateCallback);
core_timing.ScheduleEvent(GDB_UPDATE_CYCLES, s_update_event);
s_has_control = true;
}

Expand Down
9 changes: 6 additions & 3 deletions Source/Core/Core/PowerPC/Interpreter/Interpreter.cpp
Expand Up @@ -212,10 +212,11 @@ int Interpreter::SingleStepInner()

void Interpreter::SingleStep()
{
auto& core_timing_globals = Core::System::GetInstance().GetCoreTimingGlobals();
auto& core_timing = Core::System::GetInstance().GetCoreTiming();
auto& core_timing_globals = core_timing.GetGlobals();

// Declare start of new slice
CoreTiming::Advance();
core_timing.Advance();

SingleStepInner();

Expand All @@ -241,12 +242,14 @@ constexpr u32 s_show_steps = 300;
// FastRun - inspired by GCemu (to imitate the JIT so that they can be compared).
void Interpreter::Run()
{
auto& system = Core::System::GetInstance();
auto& core_timing = system.GetCoreTiming();
while (CPU::GetState() == CPU::State::Running)
{
// CoreTiming Advance() ends the previous slice and declares the start of the next
// one so it must always be called at the start. At boot, we are in slice -1 and must
// advance into slice 0 to get a correct slice length before executing any cycles.
CoreTiming::Advance();
core_timing.Advance();

// we have to check exceptions at branches apparently (or maybe just rfi?)
if (Config::Get(Config::MAIN_ENABLE_DEBUGGING))
Expand Down
5 changes: 3 additions & 2 deletions Source/Core/Core/PowerPC/Jit64/Jit.cpp
Expand Up @@ -44,6 +44,7 @@
#include "Core/PowerPC/PPCAnalyst.h"
#include "Core/PowerPC/PowerPC.h"
#include "Core/PowerPC/Profiler.h"
#include "Core/System.h"

using namespace Gen;
using namespace PowerPC;
Expand Down Expand Up @@ -205,7 +206,7 @@ bool Jit64::HandleStackFault()
// to reset the guard page.
// Yeah, it's kind of gross.
GetBlockCache()->InvalidateICache(0, 0xffffffff, true);
CoreTiming::ForceExceptionCheck(0);
Core::System::GetInstance().GetCoreTiming().ForceExceptionCheck(0);
m_cleanup_after_stackfault = true;

return true;
Expand Down Expand Up @@ -685,7 +686,7 @@ void Jit64::WriteRfiExitDestInRSCRATCH()
void Jit64::WriteIdleExit(u32 destination)
{
ABI_PushRegistersAndAdjustStack({}, 0);
ABI_CallFunction(CoreTiming::Idle);
ABI_CallFunction(CoreTiming::GlobalIdle);
ABI_PopRegistersAndAdjustStack({}, 0);
MOV(32, PPCSTATE(pc), Imm32(destination));
WriteExceptionExit();
Expand Down
2 changes: 1 addition & 1 deletion Source/Core/Core/PowerPC/Jit64/JitAsm.cpp
Expand Up @@ -65,7 +65,7 @@ void Jit64AsmRoutineManager::Generate()

const u8* outerLoop = GetCodePtr();
ABI_PushRegistersAndAdjustStack({}, 0);
ABI_CallFunction(CoreTiming::Advance);
ABI_CallFunction(CoreTiming::GlobalAdvance);
ABI_PopRegistersAndAdjustStack({}, 0);
FixupBranch skipToRealDispatch = J(enable_debugging); // skip the sync and compare first time
dispatcher_mispredicted_blr = GetCodePtr();
Expand Down
2 changes: 1 addition & 1 deletion Source/Core/Core/PowerPC/Jit64/Jit_SystemRegisters.cpp
Expand Up @@ -323,7 +323,7 @@ void Jit64::mfspr(UGeckoInstruction inst)
RCX64Reg rax = gpr.Scratch(RAX);
RCX64Reg rcx = gpr.Scratch(RCX);

auto& core_timing_globals = Core::System::GetInstance().GetCoreTimingGlobals();
auto& core_timing_globals = Core::System::GetInstance().GetCoreTiming().GetGlobals();
MOV(64, rcx, ImmPtr(&core_timing_globals));

// An inline implementation of CoreTiming::GetFakeTimeBase, since in timer-heavy games the
Expand Down
3 changes: 2 additions & 1 deletion Source/Core/Core/PowerPC/JitArm64/Jit.cpp
Expand Up @@ -24,6 +24,7 @@
#include "Core/PowerPC/JitArm64/JitArm64_RegCache.h"
#include "Core/PowerPC/JitInterface.h"
#include "Core/PowerPC/Profiler.h"
#include "Core/System.h"

using namespace Arm64Gen;

Expand Down Expand Up @@ -120,7 +121,7 @@ bool JitArm64::HandleStackFault()
Common::UnWriteProtectMemory(m_stack_base + GUARD_OFFSET, GUARD_SIZE);
#endif
GetBlockCache()->InvalidateICache(0, 0xffffffff, true);
CoreTiming::ForceExceptionCheck(0);
Core::System::GetInstance().GetCoreTiming().ForceExceptionCheck(0);
m_cleanup_after_stackfault = true;

return true;
Expand Down
6 changes: 3 additions & 3 deletions Source/Core/Core/PowerPC/JitArm64/JitArm64_Branch.cpp
Expand Up @@ -105,7 +105,7 @@ void JitArm64::bx(UGeckoInstruction inst)
ARM64Reg WA = gpr.GetReg();
ARM64Reg XA = EncodeRegTo64(WA);

MOVP2R(XA, &CoreTiming::Idle);
MOVP2R(XA, &CoreTiming::GlobalIdle);
BLR(XA);
gpr.Unlock(WA);

Expand Down Expand Up @@ -161,7 +161,7 @@ void JitArm64::bcx(UGeckoInstruction inst)
// make idle loops go faster
ARM64Reg XA = EncodeRegTo64(WA);

MOVP2R(XA, &CoreTiming::Idle);
MOVP2R(XA, &CoreTiming::GlobalIdle);
BLR(XA);

WriteExceptionExit(js.op->branchTo);
Expand Down Expand Up @@ -281,7 +281,7 @@ void JitArm64::bclrx(UGeckoInstruction inst)
// make idle loops go faster
ARM64Reg XA = EncodeRegTo64(WA);

MOVP2R(XA, &CoreTiming::Idle);
MOVP2R(XA, &CoreTiming::GlobalIdle);
BLR(XA);

WriteExceptionExit(js.op->branchTo);
Expand Down
Expand Up @@ -307,7 +307,7 @@ void JitArm64::mfspr(UGeckoInstruction inst)
// An inline implementation of CoreTiming::GetFakeTimeBase, since in timer-heavy games the
// cost of calling out to C for this is actually significant.

auto& core_timing_globals = Core::System::GetInstance().GetCoreTimingGlobals();
auto& core_timing_globals = Core::System::GetInstance().GetCoreTiming().GetGlobals();
MOVP2R(Xg, &core_timing_globals);

LDR(IndexType::Unsigned, WA, PPC_REG, PPCSTATE_OFF(downcount));
Expand Down
2 changes: 1 addition & 1 deletion Source/Core/Core/PowerPC/JitArm64/JitAsm.cpp
Expand Up @@ -172,7 +172,7 @@ void JitArm64::GenerateAsm()
FixupBranch Exit = B(CC_NEQ);

SetJumpTarget(to_start_of_timing_slice);
MOVP2R(ARM64Reg::X8, &CoreTiming::Advance);
MOVP2R(ARM64Reg::X8, &CoreTiming::GlobalAdvance);
BLR(ARM64Reg::X8);

// Load the PC back into DISPATCHER_PC (the exception handler might have changed it)
Expand Down
9 changes: 5 additions & 4 deletions Source/Core/Core/PowerPC/PowerPC.cpp
Expand Up @@ -31,6 +31,7 @@
#include "Core/PowerPC/JitInterface.h"
#include "Core/PowerPC/MMU.h"
#include "Core/PowerPC/PPCSymbolDB.h"
#include "Core/System.h"

namespace PowerPC
{
Expand Down Expand Up @@ -258,8 +259,8 @@ CPUCore DefaultCPUCore()

void Init(CPUCore cpu_core)
{
s_invalidate_cache_thread_safe =
CoreTiming::RegisterEvent("invalidateEmulatedCache", InvalidateCacheThreadSafe);
s_invalidate_cache_thread_safe = Core::System::GetInstance().GetCoreTiming().RegisterEvent(
"invalidateEmulatedCache", InvalidateCacheThreadSafe);

Reset();

Expand All @@ -284,8 +285,8 @@ void ScheduleInvalidateCacheThreadSafe(u32 address)
{
if (CPU::GetState() == CPU::State::Running)
{
CoreTiming::ScheduleEvent(0, s_invalidate_cache_thread_safe, address,
CoreTiming::FromThread::NON_CPU);
Core::System::GetInstance().GetCoreTiming().ScheduleEvent(
0, s_invalidate_cache_thread_safe, address, CoreTiming::FromThread::NON_CPU);
}
else
{
Expand Down
3 changes: 2 additions & 1 deletion Source/Core/Core/State.cpp
Expand Up @@ -39,6 +39,7 @@
#include "Core/Movie.h"
#include "Core/NetPlayClient.h"
#include "Core/PowerPC/PowerPC.h"
#include "Core/System.h"

#include "VideoCommon/FrameDump.h"
#include "VideoCommon/OnScreenDisplay.h"
Expand Down Expand Up @@ -224,7 +225,7 @@ static void DoState(PointerWrap& p)
p.DoMarker("PowerPC");
// CoreTiming needs to be restored before restoring Hardware because
// the controller code might need to schedule an event if the controller has changed.
CoreTiming::DoState(p);
Core::System::GetInstance().GetCoreTiming().DoState(p);
p.DoMarker("CoreTiming");
HW::DoState(p);
p.DoMarker("HW");
Expand Down
12 changes: 3 additions & 9 deletions Source/Core/Core/System.cpp
Expand Up @@ -27,8 +27,7 @@ struct System::Impl
bool m_audio_dump_started = false;

AudioInterface::AudioInterfaceState m_audio_interface_state;
CoreTiming::CoreTimingState m_core_timing_state;
CoreTiming::Globals m_core_timing_globals;
CoreTiming::CoreTimingManager m_core_timing;
DSP::DSPState m_dsp_state;
DVDInterface::DVDInterfaceState m_dvd_interface_state;
DVDThread::DVDThreadState m_dvd_thread_state;
Expand Down Expand Up @@ -87,14 +86,9 @@ AudioInterface::AudioInterfaceState& System::GetAudioInterfaceState() const
return m_impl->m_audio_interface_state;
}

CoreTiming::CoreTimingState& System::GetCoreTimingState() const
CoreTiming::CoreTimingManager& System::GetCoreTiming() const
{
return m_impl->m_core_timing_state;
}

CoreTiming::Globals& System::GetCoreTimingGlobals() const
{
return m_impl->m_core_timing_globals;
return m_impl->m_core_timing;
}

DSP::DSPState& System::GetDSPState() const
Expand Down
8 changes: 3 additions & 5 deletions Source/Core/Core/System.h
Expand Up @@ -14,9 +14,8 @@ class AudioInterfaceState;
};
namespace CoreTiming
{
class CoreTimingState;
struct Globals;
} // namespace CoreTiming
class CoreTimingManager;
}
namespace DSP
{
class DSPState;
Expand Down Expand Up @@ -81,8 +80,7 @@ class System
void SetAudioDumpStarted(bool started);

AudioInterface::AudioInterfaceState& GetAudioInterfaceState() const;
CoreTiming::CoreTimingState& GetCoreTimingState() const;
CoreTiming::Globals& GetCoreTimingGlobals() const;
CoreTiming::CoreTimingManager& GetCoreTiming() const;
DSP::DSPState& GetDSPState() const;
DVDInterface::DVDInterfaceState& GetDVDInterfaceState() const;
DVDThread::DVDThreadState& GetDVDThreadState() const;
Expand Down
6 changes: 4 additions & 2 deletions Source/Core/DolphinQt/GBAWidget.cpp
Expand Up @@ -42,10 +42,12 @@ static void RestartCore(const std::weak_ptr<HW::GBA::Core>& core, std::string_vi
auto& info = Config::MAIN_GBA_ROM_PATHS[core_ptr->GetCoreInfo().device_number];
core_ptr->Stop();
Config::SetCurrent(info, rom_path);
if (core_ptr->Start(CoreTiming::GetTicks()))
auto& system = Core::System::GetInstance();
auto& core_timing = system.GetCoreTiming();
if (core_ptr->Start(core_timing.GetTicks()))
return;
Config::SetCurrent(info, Config::GetBase(info));
core_ptr->Start(CoreTiming::GetTicks());
core_ptr->Start(core_timing.GetTicks());
}
},
false);
Expand Down
7 changes: 5 additions & 2 deletions Source/Core/InputCommon/GCAdapter.cpp
Expand Up @@ -33,6 +33,7 @@
#include "Core/HW/SI/SI.h"
#include "Core/HW/SI/SI_Device.h"
#include "Core/HW/SystemTimers.h"
#include "Core/System.h"
#include "InputCommon/GCPadStatus.h"

#if GCADAPTER_USE_LIBUSB_IMPLEMENTATION
Expand Down Expand Up @@ -419,10 +420,12 @@ void Init()

if (Core::GetState() != Core::State::Uninitialized && Core::GetState() != Core::State::Starting)
{
if ((CoreTiming::GetTicks() - s_last_init) < SystemTimers::GetTicksPerSecond())
auto& system = Core::System::GetInstance();
auto& core_timing = system.GetCoreTiming();
if ((core_timing.GetTicks() - s_last_init) < SystemTimers::GetTicksPerSecond())
return;

s_last_init = CoreTiming::GetTicks();
s_last_init = core_timing.GetTicks();
}

#if GCADAPTER_USE_LIBUSB_IMPLEMENTATION
Expand Down
4 changes: 3 additions & 1 deletion Source/Core/VideoCommon/BPStructs.cpp
Expand Up @@ -21,6 +21,7 @@
#include "Core/FifoPlayer/FifoRecorder.h"
#include "Core/HW/Memmap.h"
#include "Core/HW/VideoInterface.h"
#include "Core/System.h"

#include "VideoCommon/BPFunctions.h"
#include "VideoCommon/BPMemory.h"
Expand Down Expand Up @@ -324,7 +325,8 @@ static void BPWritten(const BPCmd& bp, int cycles_into_future)
if (g_ActiveConfig.bImmediateXFB)
{
// below div two to convert from bytes to pixels - it expects width, not stride
g_renderer->Swap(destAddr, destStride / 2, destStride, height, CoreTiming::GetTicks());
g_renderer->Swap(destAddr, destStride / 2, destStride, height,
Core::System::GetInstance().GetCoreTiming().GetTicks());
}
else
{
Expand Down
12 changes: 8 additions & 4 deletions Source/Core/VideoCommon/CommandProcessor.cpp
Expand Up @@ -149,7 +149,8 @@ void Init()
s_interrupt_set.Clear();
s_interrupt_waiting.Clear();

et_UpdateInterrupts = CoreTiming::RegisterEvent("CPInterrupt", UpdateInterrupts_Wrapper);
et_UpdateInterrupts = Core::System::GetInstance().GetCoreTiming().RegisterEvent(
"CPInterrupt", UpdateInterrupts_Wrapper);
}

u32 GetPhysicalAddressMask()
Expand Down Expand Up @@ -406,7 +407,7 @@ void GatherPipeBursted()

// If the game is running close to overflowing, make the exception checking more frequent.
if (fifo.bFF_HiWatermark.load(std::memory_order_relaxed) != 0)
CoreTiming::ForceExceptionCheck(0);
Core::System::GetInstance().GetCoreTiming().ForceExceptionCheck(0);

fifo.CPReadWriteDistance.fetch_add(GPFifo::GATHER_PIPE_SIZE, std::memory_order_seq_cst);

Expand Down Expand Up @@ -445,15 +446,18 @@ void UpdateInterrupts(u64 userdata)
DEBUG_LOG_FMT(COMMANDPROCESSOR, "Interrupt cleared");
ProcessorInterface::SetInterrupt(INT_CAUSE_CP, false);
}
CoreTiming::ForceExceptionCheck(0);
Core::System::GetInstance().GetCoreTiming().ForceExceptionCheck(0);
s_interrupt_waiting.Clear();
Fifo::RunGpu();
}

void UpdateInterruptsFromVideoBackend(u64 userdata)
{
if (!Fifo::UseDeterministicGPUThread())
CoreTiming::ScheduleEvent(0, et_UpdateInterrupts, userdata, CoreTiming::FromThread::NON_CPU);
{
Core::System::GetInstance().GetCoreTiming().ScheduleEvent(0, et_UpdateInterrupts, userdata,
CoreTiming::FromThread::NON_CPU);
}
}

bool IsInterruptWaiting()
Expand Down
11 changes: 7 additions & 4 deletions Source/Core/VideoCommon/Fifo.cpp
Expand Up @@ -448,7 +448,8 @@ bool AtBreakpoint()

void RunGpu()
{
const bool is_dual_core = Core::System::GetInstance().IsDualCoreMode();
auto& system = Core::System::GetInstance();
const bool is_dual_core = system.IsDualCoreMode();

// wake up GPU thread
if (is_dual_core && !s_use_deterministic_gpu_thread)
Expand All @@ -462,7 +463,8 @@ void RunGpu()
if (s_syncing_suspended)
{
s_syncing_suspended = false;
CoreTiming::ScheduleEvent(GPU_TIME_SLOT_SIZE, s_event_sync_gpu, GPU_TIME_SLOT_SIZE);
system.GetCoreTiming().ScheduleEvent(GPU_TIME_SLOT_SIZE, s_event_sync_gpu,
GPU_TIME_SLOT_SIZE);
}
}
}
Expand Down Expand Up @@ -611,7 +613,7 @@ static void SyncGPUCallback(Core::System& system, u64 ticks, s64 cyclesLate)

s_syncing_suspended = next < 0;
if (!s_syncing_suspended)
CoreTiming::ScheduleEvent(next, s_event_sync_gpu, next);
system.GetCoreTiming().ScheduleEvent(next, s_event_sync_gpu, next);
}

void SyncGPUForRegisterAccess()
Expand All @@ -627,7 +629,8 @@ void SyncGPUForRegisterAccess()
// Initialize GPU - CPU thread syncing, this gives us a deterministic way to start the GPU thread.
void Prepare()
{
s_event_sync_gpu = CoreTiming::RegisterEvent("SyncGPUCallback", SyncGPUCallback);
s_event_sync_gpu =
Core::System::GetInstance().GetCoreTiming().RegisterEvent("SyncGPUCallback", SyncGPUCallback);
s_syncing_suspended = true;
}
} // namespace Fifo
7 changes: 4 additions & 3 deletions Source/Core/VideoCommon/PixelEngine.cpp
Expand Up @@ -202,8 +202,8 @@ void Init()
s_signal_token_interrupt = false;
s_signal_finish_interrupt = false;

et_SetTokenFinishOnMainThread =
CoreTiming::RegisterEvent("SetTokenFinish", SetTokenFinish_OnMainThread);
et_SetTokenFinishOnMainThread = Core::System::GetInstance().GetCoreTiming().RegisterEvent(
"SetTokenFinish", SetTokenFinish_OnMainThread);
}

void RegisterMMIO(MMIO::Mapping* mmio, u32 base)
Expand Down Expand Up @@ -341,7 +341,8 @@ static void RaiseEvent(int cycles_into_future)
// games time to setup any interrupt state
cycles = std::max(500, cycles_into_future);
}
CoreTiming::ScheduleEvent(cycles, et_SetTokenFinishOnMainThread, 0, from);
Core::System::GetInstance().GetCoreTiming().ScheduleEvent(cycles, et_SetTokenFinishOnMainThread,
0, from);
}

// SetToken
Expand Down