Skip to content
Permalink
Browse files
Merge pull request #11630 from AdmiralCurtiss/globals-cpu
HW/CPU: Refactor to class, move to System.
  • Loading branch information
lioncash committed Mar 8, 2023
2 parents f1e4b6a + 3b364c5 commit c592c94
Show file tree
Hide file tree
Showing 22 changed files with 383 additions and 291 deletions.
@@ -298,7 +298,7 @@ void Stop() // - Hammertime!

// Stop the CPU
INFO_LOG_FMT(CONSOLE, "{}", StopMessage(true, "Stop CPU"));
CPU::Stop();
system.GetCPU().Stop();

if (system.IsDualCoreMode())
{
@@ -410,7 +410,8 @@ static void CpuThread(const std::optional<std::string>& savestate_path, bool del
}

// Enter CPU run loop. When we leave it - we are done.
CPU::Run();
auto& system = Core::System::GetInstance();
system.GetCPU().Run();

#ifdef USE_MEMORYWATCHER
s_memory_watcher.reset();
@@ -446,7 +447,8 @@ static void FifoPlayerThread(const std::optional<std::string>& savestate_path,
s_is_started = true;

CPUSetInitialExecutionState();
CPU::Run();
auto& system = Core::System::GetInstance();
system.GetCPU().Run();

s_is_started = false;
PowerPC::InjectExternalCPUCore(nullptr);
@@ -583,7 +585,7 @@ static void EmuThread(std::unique_ptr<BootParameters> boot, WindowSystemInfo wsi
s_is_booting.Clear();

// Set execution state to known values (CPU/FIFO/Audio Paused)
CPU::Break();
system.GetCPU().Break();

// Load GCM/DOL/ELF whatever ... we boot with the interpreter core
PowerPC::SetMode(PowerPC::CoreMode::Interpreter);
@@ -674,18 +676,19 @@ void SetState(State state)
if (!IsRunningAndStarted())
return;

auto& system = Core::System::GetInstance();
switch (state)
{
case State::Paused:
// NOTE: GetState() will return State::Paused immediately, even before anything has
// stopped (including the CPU).
CPU::EnableStepping(true); // Break
system.GetCPU().EnableStepping(true); // Break
Wiimote::Pause();
ResetRumble();
break;
case State::Running:
{
CPU::EnableStepping(false);
system.GetCPU().EnableStepping(false);
Wiimote::Resume();
break;
}
@@ -704,7 +707,8 @@ State GetState()

if (s_hardware_initialized)
{
if (CPU::IsStepping() || s_frame_step)
auto& system = Core::System::GetInstance();
if (system.GetCPU().IsStepping() || s_frame_step)
return State::Paused;

return State::Running;
@@ -763,7 +767,7 @@ void SaveScreenShot(std::string_view name)
});
}

static bool PauseAndLock(bool do_lock, bool unpause_on_unlock)
static bool PauseAndLock(Core::System& system, bool do_lock, bool unpause_on_unlock)
{
// WARNING: PauseAndLock is not fully threadsafe so is only valid on the Host Thread
if (!IsRunningAndStarted())
@@ -775,7 +779,7 @@ static bool PauseAndLock(bool do_lock, bool unpause_on_unlock)
// first pause the CPU
// This acquires a wrapper mutex and converts the current thread into
// a temporary replacement CPU Thread.
was_unpaused = CPU::PauseAndLock(true);
was_unpaused = system.GetCPU().PauseAndLock(true);
}

ExpansionInterface::PauseAndLock(do_lock, false);
@@ -785,7 +789,6 @@ static bool PauseAndLock(bool do_lock, bool unpause_on_unlock)

// video has to come after CPU, because CPU thread can wait for video thread
// (s_efbAccessRequested).
auto& system = Core::System::GetInstance();
system.GetFifo().PauseAndLock(system, do_lock, false);

ResetRumble();
@@ -798,23 +801,24 @@ static bool PauseAndLock(bool do_lock, bool unpause_on_unlock)
// mechanism to unpause them. If we unpaused the systems above when releasing
// the locks then they could call CPU::Break which would require detecting it
// and re-pausing with CPU::EnableStepping.
was_unpaused = CPU::PauseAndLock(false, unpause_on_unlock, true);
was_unpaused = system.GetCPU().PauseAndLock(false, unpause_on_unlock, true);
}

return was_unpaused;
}

void RunAsCPUThread(std::function<void()> function)
{
auto& system = Core::System::GetInstance();
const bool is_cpu_thread = IsCPUThread();
bool was_unpaused = false;
if (!is_cpu_thread)
was_unpaused = PauseAndLock(true, true);
was_unpaused = PauseAndLock(system, true, true);

function();

if (!is_cpu_thread)
PauseAndLock(false, was_unpaused);
PauseAndLock(system, false, was_unpaused);
}

void RunOnCPUThread(std::function<void()> function, bool wait_for_completion)
@@ -826,26 +830,28 @@ void RunOnCPUThread(std::function<void()> function, bool wait_for_completion)
return;
}

auto& system = Core::System::GetInstance();

// Pause the CPU (set it to stepping mode).
const bool was_running = PauseAndLock(true, true);
const bool was_running = PauseAndLock(system, true, true);

// Queue the job function.
if (wait_for_completion)
{
// Trigger the event after executing the function.
s_cpu_thread_job_finished.Reset();
CPU::AddCPUThreadJob([&function]() {
system.GetCPU().AddCPUThreadJob([&function]() {
function();
s_cpu_thread_job_finished.Set();
});
}
else
{
CPU::AddCPUThreadJob(std::move(function));
system.GetCPU().AddCPUThreadJob(std::move(function));
}

// Release the CPU thread, and let it execute the callback.
PauseAndLock(false, was_running);
PauseAndLock(system, false, was_running);

// If we're waiting for completion, block until the event fires.
if (wait_for_completion)
@@ -869,7 +875,7 @@ void Callback_FramePresented(double actual_emulation_speed)
}

// Called from VideoInterface::Update (CPU thread) at emulated field boundaries
void Callback_NewField()
void Callback_NewField(Core::System& system)
{
if (s_frame_step)
{
@@ -883,7 +889,7 @@ void Callback_NewField()
if (s_stop_frame_step.load())
{
s_frame_step = false;
CPU::Break();
system.GetCPU().Break();
CallOnStateChangedCallbacks(Core::GetState());
}
}
@@ -1055,13 +1061,13 @@ void UpdateInputGate(bool require_focus, bool require_full_focus)
CPUThreadGuard::CPUThreadGuard() : m_was_cpu_thread(IsCPUThread())
{
if (!m_was_cpu_thread)
m_was_unpaused = PauseAndLock(true, true);
m_was_unpaused = PauseAndLock(Core::System::GetInstance(), true, true);
}

CPUThreadGuard::~CPUThreadGuard()
{
if (!m_was_cpu_thread)
PauseAndLock(false, m_was_unpaused);
PauseAndLock(Core::System::GetInstance(), false, m_was_unpaused);
}

} // namespace Core
@@ -21,14 +21,16 @@ struct WindowSystemInfo;

namespace Core
{
class System;

bool GetIsThrottlerTempDisabled();
void SetIsThrottlerTempDisabled(bool disable);

// Returns the latest emulation speed (1 is full speed) (swings a lot)
double GetActualEmulationSpeed();

void Callback_FramePresented(double actual_emulation_speed = 1.0);
void Callback_NewField();
void Callback_NewField(Core::System& system);

enum class State
{
@@ -232,7 +232,8 @@ class FifoPlayer::CPUCore final : public CPUCoreBase
IsPlayingBackFifologWithBrokenEFBCopies = m_parent->m_File->HasBrokenEFBCopies();
// Without this call, we deadlock in initialization in dual core, as the FIFO is disabled and
// thus ClearEfb()'s call to WaitForGPUInactive() never returns
CPU::EnableStepping(false);
auto& system = Core::System::GetInstance();
system.GetCPU().EnableStepping(false);

m_parent->m_CurrentFrame = m_parent->m_FrameRangeStart;
m_parent->LoadMemory();
@@ -254,17 +255,19 @@ class FifoPlayer::CPUCore final : public CPUCoreBase
const char* GetName() const override { return "FifoPlayer"; }
void Run() override
{
while (CPU::GetState() == CPU::State::Running)
auto& system = Core::System::GetInstance();
auto& cpu = system.GetCPU();
while (cpu.GetState() == CPU::State::Running)
{
switch (m_parent->AdvanceFrame())
{
case CPU::State::PowerDown:
CPU::Break();
cpu.Break();
Host_Message(HostMessageID::WMUserStop);
break;

case CPU::State::Stepping:
CPU::Break();
cpu.Break();
Host_UpdateMainFrame();
break;

@@ -519,6 +522,7 @@ void FifoPlayer::WriteFifo(const u8* data, u32 start, u32 end)
u32 lastBurstEnd = end - 1;

auto& system = Core::System::GetInstance();
auto& cpu = system.GetCPU();
auto& core_timing = system.GetCoreTiming();
auto& gpfifo = system.GetGPFifo();
auto& ppc_state = system.GetPPCState();
@@ -528,7 +532,7 @@ void FifoPlayer::WriteFifo(const u8* data, u32 start, u32 end)
{
while (IsHighWatermarkSet())
{
if (CPU::GetState() != CPU::State::Running)
if (cpu.GetState() != CPU::State::Running)
break;
core_timing.Idle();
core_timing.Advance();
@@ -733,10 +737,12 @@ void FifoPlayer::FlushWGP()

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

// Sleep while the GPU is active
while (!IsIdleSet() && CPU::GetState() != CPU::State::PowerDown)
while (!IsIdleSet() && cpu.GetState() != CPU::State::PowerDown)
{
core_timing.Idle();
core_timing.Advance();
@@ -26,7 +26,8 @@ void UnimplementedFunction(const Core::CPUThreadGuard&)
void HBReload(const Core::CPUThreadGuard&)
{
// There isn't much we can do. Just stop cleanly.
CPU::Break();
auto& system = Core::System::GetInstance();
system.GetCPU().Break();
Host_Message(HostMessageID::WMUserStop);
}

0 comments on commit c592c94

Please sign in to comment.