@@ -49,15 +49,19 @@ class ScopeInit final
Config::Init();
SConfig::Init();
PowerPC::Init(PowerPC::CPUCore::Interpreter);
CoreTiming::Init();
auto& system = Core::System::GetInstance();
auto& core_timing = system.GetCoreTiming();
core_timing.Init();
}
~ScopeInit()
{
if (!UserDirectoryExists())
{
return;
}
CoreTiming::Shutdown();
auto& system = Core::System::GetInstance();
auto& core_timing = system.GetCoreTiming();
core_timing.Shutdown();
PowerPC::Shutdown();
SConfig::Shutdown();
Config::Shutdown();
@@ -78,7 +82,9 @@ static void AdvanceAndCheck(u32 idx, int downcount, int expected_lateness = 0,
s_lateness = expected_lateness;

PowerPC::ppcState.downcount = cpu_downcount; // Pretend we executed X cycles of instructions.
CoreTiming::Advance();
auto& system = Core::System::GetInstance();
auto& core_timing = system.GetCoreTiming();
core_timing.Advance();

EXPECT_EQ(decltype(s_callbacks_ran_flags)().set(idx), s_callbacks_ran_flags);
EXPECT_EQ(downcount, PowerPC::ppcState.downcount);
@@ -89,25 +95,28 @@ TEST(CoreTiming, BasicOrder)
ScopeInit guard;
ASSERT_TRUE(guard.UserDirectoryExists());

CoreTiming::EventType* cb_a = CoreTiming::RegisterEvent("callbackA", CallbackTemplate<0>);
CoreTiming::EventType* cb_b = CoreTiming::RegisterEvent("callbackB", CallbackTemplate<1>);
CoreTiming::EventType* cb_c = CoreTiming::RegisterEvent("callbackC", CallbackTemplate<2>);
CoreTiming::EventType* cb_d = CoreTiming::RegisterEvent("callbackD", CallbackTemplate<3>);
CoreTiming::EventType* cb_e = CoreTiming::RegisterEvent("callbackE", CallbackTemplate<4>);
auto& system = Core::System::GetInstance();
auto& core_timing = system.GetCoreTiming();

CoreTiming::EventType* cb_a = core_timing.RegisterEvent("callbackA", CallbackTemplate<0>);
CoreTiming::EventType* cb_b = core_timing.RegisterEvent("callbackB", CallbackTemplate<1>);
CoreTiming::EventType* cb_c = core_timing.RegisterEvent("callbackC", CallbackTemplate<2>);
CoreTiming::EventType* cb_d = core_timing.RegisterEvent("callbackD", CallbackTemplate<3>);
CoreTiming::EventType* cb_e = core_timing.RegisterEvent("callbackE", CallbackTemplate<4>);

// Enter slice 0
CoreTiming::Advance();
core_timing.Advance();

// D -> B -> C -> A -> E
CoreTiming::ScheduleEvent(1000, cb_a, CB_IDS[0]);
core_timing.ScheduleEvent(1000, cb_a, CB_IDS[0]);
EXPECT_EQ(1000, PowerPC::ppcState.downcount);
CoreTiming::ScheduleEvent(500, cb_b, CB_IDS[1]);
core_timing.ScheduleEvent(500, cb_b, CB_IDS[1]);
EXPECT_EQ(500, PowerPC::ppcState.downcount);
CoreTiming::ScheduleEvent(800, cb_c, CB_IDS[2]);
core_timing.ScheduleEvent(800, cb_c, CB_IDS[2]);
EXPECT_EQ(500, PowerPC::ppcState.downcount);
CoreTiming::ScheduleEvent(100, cb_d, CB_IDS[3]);
core_timing.ScheduleEvent(100, cb_d, CB_IDS[3]);
EXPECT_EQ(100, PowerPC::ppcState.downcount);
CoreTiming::ScheduleEvent(1200, cb_e, CB_IDS[4]);
core_timing.ScheduleEvent(1200, cb_e, CB_IDS[4]);
EXPECT_EQ(100, PowerPC::ppcState.downcount);

AdvanceAndCheck(3, 400);
@@ -140,27 +149,30 @@ TEST(CoreTiming, SharedSlot)
ScopeInit guard;
ASSERT_TRUE(guard.UserDirectoryExists());

CoreTiming::EventType* cb_a = CoreTiming::RegisterEvent("callbackA", FifoCallback<0>);
CoreTiming::EventType* cb_b = CoreTiming::RegisterEvent("callbackB", FifoCallback<1>);
CoreTiming::EventType* cb_c = CoreTiming::RegisterEvent("callbackC", FifoCallback<2>);
CoreTiming::EventType* cb_d = CoreTiming::RegisterEvent("callbackD", FifoCallback<3>);
CoreTiming::EventType* cb_e = CoreTiming::RegisterEvent("callbackE", FifoCallback<4>);
auto& system = Core::System::GetInstance();
auto& core_timing = system.GetCoreTiming();

CoreTiming::EventType* cb_a = core_timing.RegisterEvent("callbackA", FifoCallback<0>);
CoreTiming::EventType* cb_b = core_timing.RegisterEvent("callbackB", FifoCallback<1>);
CoreTiming::EventType* cb_c = core_timing.RegisterEvent("callbackC", FifoCallback<2>);
CoreTiming::EventType* cb_d = core_timing.RegisterEvent("callbackD", FifoCallback<3>);
CoreTiming::EventType* cb_e = core_timing.RegisterEvent("callbackE", FifoCallback<4>);

CoreTiming::ScheduleEvent(1000, cb_a, CB_IDS[0]);
CoreTiming::ScheduleEvent(1000, cb_b, CB_IDS[1]);
CoreTiming::ScheduleEvent(1000, cb_c, CB_IDS[2]);
CoreTiming::ScheduleEvent(1000, cb_d, CB_IDS[3]);
CoreTiming::ScheduleEvent(1000, cb_e, CB_IDS[4]);
core_timing.ScheduleEvent(1000, cb_a, CB_IDS[0]);
core_timing.ScheduleEvent(1000, cb_b, CB_IDS[1]);
core_timing.ScheduleEvent(1000, cb_c, CB_IDS[2]);
core_timing.ScheduleEvent(1000, cb_d, CB_IDS[3]);
core_timing.ScheduleEvent(1000, cb_e, CB_IDS[4]);

// Enter slice 0
CoreTiming::Advance();
core_timing.Advance();
EXPECT_EQ(1000, PowerPC::ppcState.downcount);

s_callbacks_ran_flags = 0;
s_counter = 0;
s_lateness = 0;
PowerPC::ppcState.downcount = 0;
CoreTiming::Advance();
core_timing.Advance();
EXPECT_EQ(MAX_SLICE_LENGTH, PowerPC::ppcState.downcount);
EXPECT_EQ(0x1FULL, s_callbacks_ran_flags.to_ullong());
}
@@ -170,14 +182,17 @@ TEST(CoreTiming, PredictableLateness)
ScopeInit guard;
ASSERT_TRUE(guard.UserDirectoryExists());

CoreTiming::EventType* cb_a = CoreTiming::RegisterEvent("callbackA", CallbackTemplate<0>);
CoreTiming::EventType* cb_b = CoreTiming::RegisterEvent("callbackB", CallbackTemplate<1>);
auto& system = Core::System::GetInstance();
auto& core_timing = system.GetCoreTiming();

CoreTiming::EventType* cb_a = core_timing.RegisterEvent("callbackA", CallbackTemplate<0>);
CoreTiming::EventType* cb_b = core_timing.RegisterEvent("callbackB", CallbackTemplate<1>);

// Enter slice 0
CoreTiming::Advance();
core_timing.Advance();

CoreTiming::ScheduleEvent(100, cb_a, CB_IDS[0]);
CoreTiming::ScheduleEvent(200, cb_b, CB_IDS[1]);
core_timing.ScheduleEvent(100, cb_a, CB_IDS[0]);
core_timing.ScheduleEvent(200, cb_b, CB_IDS[1]);

AdvanceAndCheck(0, 90, 10, -10); // (100 - 10)
AdvanceAndCheck(1, MAX_SLICE_LENGTH, 50, -50);
@@ -194,7 +209,10 @@ static void RescheduleCallback(Core::System& system, u64 userdata, s64 lateness)
EXPECT_EQ(s_lateness, lateness);

if (s_reschedules > 0)
CoreTiming::ScheduleEvent(1000, reinterpret_cast<CoreTiming::EventType*>(userdata), userdata);
{
system.GetCoreTiming().ScheduleEvent(1000, reinterpret_cast<CoreTiming::EventType*>(userdata),
userdata);
}
}
} // namespace ChainSchedulingTest

@@ -205,19 +223,22 @@ TEST(CoreTiming, ChainScheduling)
ScopeInit guard;
ASSERT_TRUE(guard.UserDirectoryExists());

CoreTiming::EventType* cb_a = CoreTiming::RegisterEvent("callbackA", CallbackTemplate<0>);
CoreTiming::EventType* cb_b = CoreTiming::RegisterEvent("callbackB", CallbackTemplate<1>);
CoreTiming::EventType* cb_c = CoreTiming::RegisterEvent("callbackC", CallbackTemplate<2>);
auto& system = Core::System::GetInstance();
auto& core_timing = system.GetCoreTiming();

CoreTiming::EventType* cb_a = core_timing.RegisterEvent("callbackA", CallbackTemplate<0>);
CoreTiming::EventType* cb_b = core_timing.RegisterEvent("callbackB", CallbackTemplate<1>);
CoreTiming::EventType* cb_c = core_timing.RegisterEvent("callbackC", CallbackTemplate<2>);
CoreTiming::EventType* cb_rs =
CoreTiming::RegisterEvent("callbackReschedule", RescheduleCallback);
core_timing.RegisterEvent("callbackReschedule", RescheduleCallback);

// Enter slice 0
CoreTiming::Advance();
core_timing.Advance();

CoreTiming::ScheduleEvent(800, cb_a, CB_IDS[0]);
CoreTiming::ScheduleEvent(1000, cb_b, CB_IDS[1]);
CoreTiming::ScheduleEvent(2200, cb_c, CB_IDS[2]);
CoreTiming::ScheduleEvent(1000, cb_rs, reinterpret_cast<u64>(cb_rs));
core_timing.ScheduleEvent(800, cb_a, CB_IDS[0]);
core_timing.ScheduleEvent(1000, cb_b, CB_IDS[1]);
core_timing.ScheduleEvent(2200, cb_c, CB_IDS[2]);
core_timing.ScheduleEvent(1000, cb_rs, reinterpret_cast<u64>(cb_rs));
EXPECT_EQ(800, PowerPC::ppcState.downcount);

s_reschedules = 3;
@@ -226,14 +247,14 @@ TEST(CoreTiming, ChainScheduling)
EXPECT_EQ(2, s_reschedules);

PowerPC::ppcState.downcount = 0;
CoreTiming::Advance(); // cb_rs
core_timing.Advance(); // cb_rs
EXPECT_EQ(1, s_reschedules);
EXPECT_EQ(200, PowerPC::ppcState.downcount);

AdvanceAndCheck(2, 800); // cb_c

PowerPC::ppcState.downcount = 0;
CoreTiming::Advance(); // cb_rs
core_timing.Advance(); // cb_rs
EXPECT_EQ(0, s_reschedules);
EXPECT_EQ(MAX_SLICE_LENGTH, PowerPC::ppcState.downcount);
}
@@ -247,7 +268,7 @@ static void ChainCallback(Core::System& system, u64 userdata, s64 lateness)
EXPECT_EQ(CB_IDS[0] + 1, userdata);
EXPECT_EQ(0, lateness);

CoreTiming::ScheduleEvent(-1000, s_cb_next, userdata - 1);
system.GetCoreTiming().ScheduleEvent(-1000, s_cb_next, userdata - 1);
}
} // namespace ScheduleIntoPastTest

@@ -261,14 +282,17 @@ TEST(CoreTiming, ScheduleIntoPast)
ScopeInit guard;
ASSERT_TRUE(guard.UserDirectoryExists());

s_cb_next = CoreTiming::RegisterEvent("callbackA", CallbackTemplate<0>);
CoreTiming::EventType* cb_b = CoreTiming::RegisterEvent("callbackB", CallbackTemplate<1>);
CoreTiming::EventType* cb_chain = CoreTiming::RegisterEvent("callbackChain", ChainCallback);
auto& system = Core::System::GetInstance();
auto& core_timing = system.GetCoreTiming();

s_cb_next = core_timing.RegisterEvent("callbackA", CallbackTemplate<0>);
CoreTiming::EventType* cb_b = core_timing.RegisterEvent("callbackB", CallbackTemplate<1>);
CoreTiming::EventType* cb_chain = core_timing.RegisterEvent("callbackChain", ChainCallback);

// Enter slice 0
CoreTiming::Advance();
core_timing.Advance();

CoreTiming::ScheduleEvent(1000, cb_chain, CB_IDS[0] + 1);
core_timing.ScheduleEvent(1000, cb_chain, CB_IDS[0] + 1);
EXPECT_EQ(1000, PowerPC::ppcState.downcount);

AdvanceAndCheck(0, MAX_SLICE_LENGTH, 1000); // Run cb_chain into late cb_a
@@ -280,17 +304,17 @@ TEST(CoreTiming, ScheduleIntoPast)
// the stale value, i.e. effectively half-way through the previous slice.
// NOTE: We're only testing that the scheduler doesn't break, not whether this makes sense.
Core::UndeclareAsCPUThread();
auto& core_timing_globals = Core::System::GetInstance().GetCoreTimingGlobals();
auto& core_timing_globals = core_timing.GetGlobals();
core_timing_globals.global_timer -= 1000;
CoreTiming::ScheduleEvent(0, cb_b, CB_IDS[1], CoreTiming::FromThread::NON_CPU);
core_timing.ScheduleEvent(0, cb_b, CB_IDS[1], CoreTiming::FromThread::NON_CPU);
core_timing_globals.global_timer += 1000;
Core::DeclareAsCPUThread();
AdvanceAndCheck(1, MAX_SLICE_LENGTH, MAX_SLICE_LENGTH + 1000);

// Schedule directly into the past from the CPU.
// This shouldn't happen in practice, but it's best if we don't mess up the slice length and
// downcount if we do.
CoreTiming::ScheduleEvent(-1000, s_cb_next, CB_IDS[0]);
core_timing.ScheduleEvent(-1000, s_cb_next, CB_IDS[0]);
EXPECT_EQ(0, PowerPC::ppcState.downcount);
AdvanceAndCheck(0, MAX_SLICE_LENGTH, 1000);
}
@@ -300,25 +324,28 @@ TEST(CoreTiming, Overclocking)
ScopeInit guard;
ASSERT_TRUE(guard.UserDirectoryExists());

CoreTiming::EventType* cb_a = CoreTiming::RegisterEvent("callbackA", CallbackTemplate<0>);
CoreTiming::EventType* cb_b = CoreTiming::RegisterEvent("callbackB", CallbackTemplate<1>);
CoreTiming::EventType* cb_c = CoreTiming::RegisterEvent("callbackC", CallbackTemplate<2>);
CoreTiming::EventType* cb_d = CoreTiming::RegisterEvent("callbackD", CallbackTemplate<3>);
CoreTiming::EventType* cb_e = CoreTiming::RegisterEvent("callbackE", CallbackTemplate<4>);
auto& system = Core::System::GetInstance();
auto& core_timing = system.GetCoreTiming();

CoreTiming::EventType* cb_a = core_timing.RegisterEvent("callbackA", CallbackTemplate<0>);
CoreTiming::EventType* cb_b = core_timing.RegisterEvent("callbackB", CallbackTemplate<1>);
CoreTiming::EventType* cb_c = core_timing.RegisterEvent("callbackC", CallbackTemplate<2>);
CoreTiming::EventType* cb_d = core_timing.RegisterEvent("callbackD", CallbackTemplate<3>);
CoreTiming::EventType* cb_e = core_timing.RegisterEvent("callbackE", CallbackTemplate<4>);

// Overclock
Config::SetCurrent(Config::MAIN_OVERCLOCK_ENABLE, true);
Config::SetCurrent(Config::MAIN_OVERCLOCK, 2.0f);

// Enter slice 0
// Updates s_last_OC_factor.
CoreTiming::Advance();
core_timing.Advance();

CoreTiming::ScheduleEvent(100, cb_a, CB_IDS[0]);
CoreTiming::ScheduleEvent(200, cb_b, CB_IDS[1]);
CoreTiming::ScheduleEvent(400, cb_c, CB_IDS[2]);
CoreTiming::ScheduleEvent(800, cb_d, CB_IDS[3]);
CoreTiming::ScheduleEvent(1600, cb_e, CB_IDS[4]);
core_timing.ScheduleEvent(100, cb_a, CB_IDS[0]);
core_timing.ScheduleEvent(200, cb_b, CB_IDS[1]);
core_timing.ScheduleEvent(400, cb_c, CB_IDS[2]);
core_timing.ScheduleEvent(800, cb_d, CB_IDS[3]);
core_timing.ScheduleEvent(1600, cb_e, CB_IDS[4]);
EXPECT_EQ(200, PowerPC::ppcState.downcount);

AdvanceAndCheck(0, 200); // (200 - 100) * 2
@@ -329,13 +356,13 @@ TEST(CoreTiming, Overclocking)

// Underclock
Config::SetCurrent(Config::MAIN_OVERCLOCK, 0.5f);
CoreTiming::Advance();
core_timing.Advance();

CoreTiming::ScheduleEvent(100, cb_a, CB_IDS[0]);
CoreTiming::ScheduleEvent(200, cb_b, CB_IDS[1]);
CoreTiming::ScheduleEvent(400, cb_c, CB_IDS[2]);
CoreTiming::ScheduleEvent(800, cb_d, CB_IDS[3]);
CoreTiming::ScheduleEvent(1600, cb_e, CB_IDS[4]);
core_timing.ScheduleEvent(100, cb_a, CB_IDS[0]);
core_timing.ScheduleEvent(200, cb_b, CB_IDS[1]);
core_timing.ScheduleEvent(400, cb_c, CB_IDS[2]);
core_timing.ScheduleEvent(800, cb_d, CB_IDS[3]);
core_timing.ScheduleEvent(1600, cb_e, CB_IDS[4]);
EXPECT_EQ(50, PowerPC::ppcState.downcount);

AdvanceAndCheck(0, 50); // (200 - 100) / 2
@@ -346,13 +373,13 @@ TEST(CoreTiming, Overclocking)

// Try switching the clock mid-emulation
Config::SetCurrent(Config::MAIN_OVERCLOCK, 1.0f);
CoreTiming::Advance();
core_timing.Advance();

CoreTiming::ScheduleEvent(100, cb_a, CB_IDS[0]);
CoreTiming::ScheduleEvent(200, cb_b, CB_IDS[1]);
CoreTiming::ScheduleEvent(400, cb_c, CB_IDS[2]);
CoreTiming::ScheduleEvent(800, cb_d, CB_IDS[3]);
CoreTiming::ScheduleEvent(1600, cb_e, CB_IDS[4]);
core_timing.ScheduleEvent(100, cb_a, CB_IDS[0]);
core_timing.ScheduleEvent(200, cb_b, CB_IDS[1]);
core_timing.ScheduleEvent(400, cb_c, CB_IDS[2]);
core_timing.ScheduleEvent(800, cb_d, CB_IDS[3]);
core_timing.ScheduleEvent(1600, cb_e, CB_IDS[4]);
EXPECT_EQ(100, PowerPC::ppcState.downcount);

AdvanceAndCheck(0, 100); // (200 - 100)