mirror of
https://github.com/Lime3DS/Lime3DS.git
synced 2024-11-27 20:14:17 +01:00
Merge pull request #4400 from wwylele/core-timing-global
CoreTiming: wrap into class
This commit is contained in:
commit
1444d60109
@ -12,6 +12,7 @@
|
|||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
|
#include "core/core.h"
|
||||||
#include "core/core_timing.h"
|
#include "core/core_timing.h"
|
||||||
|
|
||||||
using InterruptType = Service::DSP::DSP_DSP::InterruptType;
|
using InterruptType = Service::DSP::DSP_DSP::InterruptType;
|
||||||
@ -63,7 +64,7 @@ private:
|
|||||||
HLE::Mixers mixers;
|
HLE::Mixers mixers;
|
||||||
|
|
||||||
DspHle& parent;
|
DspHle& parent;
|
||||||
CoreTiming::EventType* tick_event;
|
Core::TimingEventType* tick_event;
|
||||||
|
|
||||||
std::weak_ptr<DSP_DSP> dsp_dsp;
|
std::weak_ptr<DSP_DSP> dsp_dsp;
|
||||||
};
|
};
|
||||||
@ -71,15 +72,17 @@ private:
|
|||||||
DspHle::Impl::Impl(DspHle& parent_) : parent(parent_) {
|
DspHle::Impl::Impl(DspHle& parent_) : parent(parent_) {
|
||||||
dsp_memory.raw_memory.fill(0);
|
dsp_memory.raw_memory.fill(0);
|
||||||
|
|
||||||
|
Core::Timing& timing = Core::System::GetInstance().CoreTiming();
|
||||||
tick_event =
|
tick_event =
|
||||||
CoreTiming::RegisterEvent("AudioCore::DspHle::tick_event", [this](u64, s64 cycles_late) {
|
timing.RegisterEvent("AudioCore::DspHle::tick_event", [this](u64, s64 cycles_late) {
|
||||||
this->AudioTickCallback(cycles_late);
|
this->AudioTickCallback(cycles_late);
|
||||||
});
|
});
|
||||||
CoreTiming::ScheduleEvent(audio_frame_ticks, tick_event);
|
timing.ScheduleEvent(audio_frame_ticks, tick_event);
|
||||||
}
|
}
|
||||||
|
|
||||||
DspHle::Impl::~Impl() {
|
DspHle::Impl::~Impl() {
|
||||||
CoreTiming::UnscheduleEvent(tick_event, 0);
|
Core::Timing& timing = Core::System::GetInstance().CoreTiming();
|
||||||
|
timing.UnscheduleEvent(tick_event, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
DspState DspHle::Impl::GetDspState() const {
|
DspState DspHle::Impl::GetDspState() const {
|
||||||
@ -328,7 +331,8 @@ void DspHle::Impl::AudioTickCallback(s64 cycles_late) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Reschedule recurrent event
|
// Reschedule recurrent event
|
||||||
CoreTiming::ScheduleEvent(audio_frame_ticks - cycles_late, tick_event);
|
Core::Timing& timing = Core::System::GetInstance().CoreTiming();
|
||||||
|
timing.ScheduleEvent(audio_frame_ticks - cycles_late, tick_event);
|
||||||
}
|
}
|
||||||
|
|
||||||
DspHle::DspHle() : impl(std::make_unique<Impl>(*this)) {}
|
DspHle::DspHle() : impl(std::make_unique<Impl>(*this)) {}
|
||||||
|
@ -71,7 +71,8 @@ private:
|
|||||||
|
|
||||||
class DynarmicUserCallbacks final : public Dynarmic::A32::UserCallbacks {
|
class DynarmicUserCallbacks final : public Dynarmic::A32::UserCallbacks {
|
||||||
public:
|
public:
|
||||||
explicit DynarmicUserCallbacks(ARM_Dynarmic& parent) : parent(parent) {}
|
explicit DynarmicUserCallbacks(ARM_Dynarmic& parent)
|
||||||
|
: parent(parent), timing(parent.system.CoreTiming()) {}
|
||||||
~DynarmicUserCallbacks() = default;
|
~DynarmicUserCallbacks() = default;
|
||||||
|
|
||||||
std::uint8_t MemoryRead8(VAddr vaddr) override {
|
std::uint8_t MemoryRead8(VAddr vaddr) override {
|
||||||
@ -148,18 +149,19 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void AddTicks(std::uint64_t ticks) override {
|
void AddTicks(std::uint64_t ticks) override {
|
||||||
CoreTiming::AddTicks(ticks);
|
timing.AddTicks(ticks);
|
||||||
}
|
}
|
||||||
std::uint64_t GetTicksRemaining() override {
|
std::uint64_t GetTicksRemaining() override {
|
||||||
s64 ticks = CoreTiming::GetDowncount();
|
s64 ticks = timing.GetDowncount();
|
||||||
return static_cast<u64>(ticks <= 0 ? 0 : ticks);
|
return static_cast<u64>(ticks <= 0 ? 0 : ticks);
|
||||||
}
|
}
|
||||||
|
|
||||||
ARM_Dynarmic& parent;
|
ARM_Dynarmic& parent;
|
||||||
|
Core::Timing& timing;
|
||||||
};
|
};
|
||||||
|
|
||||||
ARM_Dynarmic::ARM_Dynarmic(PrivilegeMode initial_mode)
|
ARM_Dynarmic::ARM_Dynarmic(Core::System& system, PrivilegeMode initial_mode)
|
||||||
: cb(std::make_unique<DynarmicUserCallbacks>(*this)) {
|
: system(system), cb(std::make_unique<DynarmicUserCallbacks>(*this)) {
|
||||||
interpreter_state = std::make_shared<ARMul_State>(initial_mode);
|
interpreter_state = std::make_shared<ARMul_State>(initial_mode);
|
||||||
PageTableChanged();
|
PageTableChanged();
|
||||||
}
|
}
|
||||||
|
@ -15,11 +15,15 @@ namespace Memory {
|
|||||||
struct PageTable;
|
struct PageTable;
|
||||||
} // namespace Memory
|
} // namespace Memory
|
||||||
|
|
||||||
|
namespace Core {
|
||||||
|
struct System;
|
||||||
|
}
|
||||||
|
|
||||||
class DynarmicUserCallbacks;
|
class DynarmicUserCallbacks;
|
||||||
|
|
||||||
class ARM_Dynarmic final : public ARM_Interface {
|
class ARM_Dynarmic final : public ARM_Interface {
|
||||||
public:
|
public:
|
||||||
explicit ARM_Dynarmic(PrivilegeMode initial_mode);
|
ARM_Dynarmic(Core::System& system, PrivilegeMode initial_mode);
|
||||||
~ARM_Dynarmic();
|
~ARM_Dynarmic();
|
||||||
|
|
||||||
void Run() override;
|
void Run() override;
|
||||||
@ -50,6 +54,7 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
friend class DynarmicUserCallbacks;
|
friend class DynarmicUserCallbacks;
|
||||||
|
Core::System& system;
|
||||||
std::unique_ptr<DynarmicUserCallbacks> cb;
|
std::unique_ptr<DynarmicUserCallbacks> cb;
|
||||||
std::unique_ptr<Dynarmic::A32::Jit> MakeJit();
|
std::unique_ptr<Dynarmic::A32::Jit> MakeJit();
|
||||||
|
|
||||||
|
@ -75,7 +75,7 @@ ARM_DynCom::ARM_DynCom(PrivilegeMode initial_mode) {
|
|||||||
ARM_DynCom::~ARM_DynCom() {}
|
ARM_DynCom::~ARM_DynCom() {}
|
||||||
|
|
||||||
void ARM_DynCom::Run() {
|
void ARM_DynCom::Run() {
|
||||||
ExecuteInstructions(std::max<s64>(CoreTiming::GetDowncount(), 0));
|
ExecuteInstructions(std::max<s64>(Core::System::GetInstance().CoreTiming().GetDowncount(), 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ARM_DynCom::Step() {
|
void ARM_DynCom::Step() {
|
||||||
@ -146,7 +146,7 @@ void ARM_DynCom::SetCP15Register(CP15Register reg, u32 value) {
|
|||||||
void ARM_DynCom::ExecuteInstructions(u64 num_instructions) {
|
void ARM_DynCom::ExecuteInstructions(u64 num_instructions) {
|
||||||
state->NumInstrsToExecute = num_instructions;
|
state->NumInstrsToExecute = num_instructions;
|
||||||
unsigned ticks_executed = InterpreterMainLoop(state.get());
|
unsigned ticks_executed = InterpreterMainLoop(state.get());
|
||||||
CoreTiming::AddTicks(ticks_executed);
|
Core::System::GetInstance().CoreTiming().AddTicks(ticks_executed);
|
||||||
state->ServeBreak();
|
state->ServeBreak();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
#include "core/arm/skyeye_common/armstate.h"
|
#include "core/arm/skyeye_common/armstate.h"
|
||||||
#include "core/arm/skyeye_common/armsupp.h"
|
#include "core/arm/skyeye_common/armsupp.h"
|
||||||
#include "core/arm/skyeye_common/vfp/vfp.h"
|
#include "core/arm/skyeye_common/vfp/vfp.h"
|
||||||
|
#include "core/core.h"
|
||||||
#include "core/core_timing.h"
|
#include "core/core_timing.h"
|
||||||
#include "core/gdbstub/gdbstub.h"
|
#include "core/gdbstub/gdbstub.h"
|
||||||
#include "core/hle/kernel/svc.h"
|
#include "core/hle/kernel/svc.h"
|
||||||
@ -3859,7 +3860,7 @@ SUB_INST : {
|
|||||||
SWI_INST : {
|
SWI_INST : {
|
||||||
if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) {
|
if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) {
|
||||||
swi_inst* const inst_cream = (swi_inst*)inst_base->component;
|
swi_inst* const inst_cream = (swi_inst*)inst_base->component;
|
||||||
CoreTiming::AddTicks(num_instrs);
|
Core::System::GetInstance().CoreTiming().AddTicks(num_instrs);
|
||||||
cpu->NumInstrsToExecute =
|
cpu->NumInstrsToExecute =
|
||||||
num_instrs >= cpu->NumInstrsToExecute ? 0 : cpu->NumInstrsToExecute - num_instrs;
|
num_instrs >= cpu->NumInstrsToExecute ? 0 : cpu->NumInstrsToExecute - num_instrs;
|
||||||
num_instrs = 0;
|
num_instrs = 0;
|
||||||
|
@ -61,11 +61,11 @@ System::ResultStatus System::RunLoop(bool tight_loop) {
|
|||||||
// instead advance to the next event and try to yield to the next thread
|
// instead advance to the next event and try to yield to the next thread
|
||||||
if (kernel->GetThreadManager().GetCurrentThread() == nullptr) {
|
if (kernel->GetThreadManager().GetCurrentThread() == nullptr) {
|
||||||
LOG_TRACE(Core_ARM11, "Idling");
|
LOG_TRACE(Core_ARM11, "Idling");
|
||||||
CoreTiming::Idle();
|
timing->Idle();
|
||||||
CoreTiming::Advance();
|
timing->Advance();
|
||||||
PrepareReschedule();
|
PrepareReschedule();
|
||||||
} else {
|
} else {
|
||||||
CoreTiming::Advance();
|
timing->Advance();
|
||||||
if (tight_loop) {
|
if (tight_loop) {
|
||||||
cpu_core->Run();
|
cpu_core->Run();
|
||||||
} else {
|
} else {
|
||||||
@ -155,7 +155,7 @@ void System::PrepareReschedule() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
PerfStats::Results System::GetAndResetPerfStats() {
|
PerfStats::Results System::GetAndResetPerfStats() {
|
||||||
return perf_stats.GetAndResetStats(CoreTiming::GetGlobalTimeUs());
|
return perf_stats.GetAndResetStats(timing->GetGlobalTimeUs());
|
||||||
}
|
}
|
||||||
|
|
||||||
void System::Reschedule() {
|
void System::Reschedule() {
|
||||||
@ -170,11 +170,11 @@ void System::Reschedule() {
|
|||||||
System::ResultStatus System::Init(EmuWindow& emu_window, u32 system_mode) {
|
System::ResultStatus System::Init(EmuWindow& emu_window, u32 system_mode) {
|
||||||
LOG_DEBUG(HW_Memory, "initialized OK");
|
LOG_DEBUG(HW_Memory, "initialized OK");
|
||||||
|
|
||||||
CoreTiming::Init();
|
timing = std::make_unique<Timing>();
|
||||||
|
|
||||||
if (Settings::values.use_cpu_jit) {
|
if (Settings::values.use_cpu_jit) {
|
||||||
#ifdef ARCHITECTURE_x86_64
|
#ifdef ARCHITECTURE_x86_64
|
||||||
cpu_core = std::make_unique<ARM_Dynarmic>(USER32MODE);
|
cpu_core = std::make_unique<ARM_Dynarmic>(*this, USER32MODE);
|
||||||
#else
|
#else
|
||||||
cpu_core = std::make_unique<ARM_DynCom>(USER32MODE);
|
cpu_core = std::make_unique<ARM_DynCom>(USER32MODE);
|
||||||
LOG_WARNING(Core, "CPU JIT requested, but Dynarmic not available");
|
LOG_WARNING(Core, "CPU JIT requested, but Dynarmic not available");
|
||||||
@ -239,6 +239,14 @@ const Kernel::KernelSystem& System::Kernel() const {
|
|||||||
return *kernel;
|
return *kernel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Timing& System::CoreTiming() {
|
||||||
|
return *timing;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Timing& System::CoreTiming() const {
|
||||||
|
return *timing;
|
||||||
|
}
|
||||||
|
|
||||||
void System::RegisterSoftwareKeyboard(std::shared_ptr<Frontend::SoftwareKeyboard> swkbd) {
|
void System::RegisterSoftwareKeyboard(std::shared_ptr<Frontend::SoftwareKeyboard> swkbd) {
|
||||||
registered_swkbd = std::move(swkbd);
|
registered_swkbd = std::move(swkbd);
|
||||||
}
|
}
|
||||||
@ -265,7 +273,7 @@ void System::Shutdown() {
|
|||||||
service_manager.reset();
|
service_manager.reset();
|
||||||
dsp_core.reset();
|
dsp_core.reset();
|
||||||
cpu_core.reset();
|
cpu_core.reset();
|
||||||
CoreTiming::Shutdown();
|
timing.reset();
|
||||||
app_loader.reset();
|
app_loader.reset();
|
||||||
|
|
||||||
if (auto room_member = Network::GetRoomMember().lock()) {
|
if (auto room_member = Network::GetRoomMember().lock()) {
|
||||||
|
@ -41,6 +41,8 @@ class KernelSystem;
|
|||||||
|
|
||||||
namespace Core {
|
namespace Core {
|
||||||
|
|
||||||
|
class Timing;
|
||||||
|
|
||||||
class System {
|
class System {
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
@ -176,6 +178,12 @@ public:
|
|||||||
/// Gets a const reference to the kernel
|
/// Gets a const reference to the kernel
|
||||||
const Kernel::KernelSystem& Kernel() const;
|
const Kernel::KernelSystem& Kernel() const;
|
||||||
|
|
||||||
|
/// Gets a reference to the timing system
|
||||||
|
Timing& CoreTiming();
|
||||||
|
|
||||||
|
/// Gets a const reference to the timing system
|
||||||
|
const Timing& CoreTiming() const;
|
||||||
|
|
||||||
PerfStats perf_stats;
|
PerfStats perf_stats;
|
||||||
FrameLimiter frame_limiter;
|
FrameLimiter frame_limiter;
|
||||||
|
|
||||||
@ -246,6 +254,7 @@ private:
|
|||||||
public: // HACK: this is temporary exposed for tests,
|
public: // HACK: this is temporary exposed for tests,
|
||||||
// due to WIP kernel refactor causing desync state in memory
|
// due to WIP kernel refactor causing desync state in memory
|
||||||
std::unique_ptr<Kernel::KernelSystem> kernel;
|
std::unique_ptr<Kernel::KernelSystem> kernel;
|
||||||
|
std::unique_ptr<Timing> timing;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static System s_instance;
|
static System s_instance;
|
||||||
|
@ -2,75 +2,25 @@
|
|||||||
// Licensed under GPLv2+
|
// Licensed under GPLv2+
|
||||||
// Refer to the license.txt file included.
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
#include "core/core_timing.h"
|
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cinttypes>
|
#include <cinttypes>
|
||||||
#include <mutex>
|
|
||||||
#include <string>
|
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
#include <unordered_map>
|
|
||||||
#include <vector>
|
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
#include "common/thread.h"
|
#include "core/core_timing.h"
|
||||||
#include "common/threadsafe_queue.h"
|
|
||||||
|
|
||||||
namespace CoreTiming {
|
namespace Core {
|
||||||
|
|
||||||
static s64 global_timer;
|
|
||||||
static s64 slice_length;
|
|
||||||
static s64 downcount;
|
|
||||||
|
|
||||||
struct EventType {
|
|
||||||
TimedCallback callback;
|
|
||||||
const std::string* name;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Event {
|
|
||||||
s64 time;
|
|
||||||
u64 fifo_order;
|
|
||||||
u64 userdata;
|
|
||||||
const EventType* type;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Sort by time, unless the times are the same, in which case sort by the order added to the queue
|
// Sort by time, unless the times are the same, in which case sort by the order added to the queue
|
||||||
static bool operator>(const Event& left, const Event& right) {
|
bool Timing::Event::operator>(const Event& right) const {
|
||||||
return std::tie(left.time, left.fifo_order) > std::tie(right.time, right.fifo_order);
|
return std::tie(time, fifo_order) > std::tie(right.time, right.fifo_order);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool operator<(const Event& left, const Event& right) {
|
bool Timing::Event::operator<(const Event& right) const {
|
||||||
return std::tie(left.time, left.fifo_order) < std::tie(right.time, right.fifo_order);
|
return std::tie(time, fifo_order) < std::tie(right.time, right.fifo_order);
|
||||||
}
|
}
|
||||||
|
|
||||||
// unordered_map stores each element separately as a linked list node so pointers to elements
|
TimingEventType* Timing::RegisterEvent(const std::string& name, TimedCallback callback) {
|
||||||
// remain stable regardless of rehashes/resizing.
|
|
||||||
static std::unordered_map<std::string, EventType> event_types;
|
|
||||||
|
|
||||||
// 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.
|
|
||||||
static std::vector<Event> event_queue;
|
|
||||||
static u64 event_fifo_id;
|
|
||||||
// the queue for storing the events from other threads threadsafe until they will be added
|
|
||||||
// to the event_queue by the emu thread
|
|
||||||
static Common::MPSCQueue<Event, false> ts_queue;
|
|
||||||
|
|
||||||
static constexpr int MAX_SLICE_LENGTH = 20000;
|
|
||||||
|
|
||||||
static s64 idled_cycles;
|
|
||||||
|
|
||||||
// Are we in a function that has been called from Advance()
|
|
||||||
// If events are sheduled from a function that gets called from Advance(),
|
|
||||||
// don't change slice_length and downcount.
|
|
||||||
static bool is_global_timer_sane;
|
|
||||||
|
|
||||||
static EventType* ev_lost = nullptr;
|
|
||||||
|
|
||||||
static void EmptyTimedCallback(u64 userdata, s64 cyclesLate) {}
|
|
||||||
|
|
||||||
EventType* RegisterEvent(const std::string& name, TimedCallback callback) {
|
|
||||||
// check for existing type with same name.
|
// check for existing type with same name.
|
||||||
// we want event type names to remain unique so that we can use them for serialization.
|
// we want event type names to remain unique so that we can use them for serialization.
|
||||||
ASSERT_MSG(event_types.find(name) == event_types.end(),
|
ASSERT_MSG(event_types.find(name) == event_types.end(),
|
||||||
@ -78,42 +28,17 @@ EventType* RegisterEvent(const std::string& name, TimedCallback callback) {
|
|||||||
"during Init to avoid breaking save states.",
|
"during Init to avoid breaking save states.",
|
||||||
name);
|
name);
|
||||||
|
|
||||||
auto info = event_types.emplace(name, EventType{callback, nullptr});
|
auto info = event_types.emplace(name, TimingEventType{callback, nullptr});
|
||||||
EventType* event_type = &info.first->second;
|
TimingEventType* event_type = &info.first->second;
|
||||||
event_type->name = &info.first->first;
|
event_type->name = &info.first->first;
|
||||||
return event_type;
|
return event_type;
|
||||||
}
|
}
|
||||||
|
|
||||||
void UnregisterAllEvents() {
|
Timing::~Timing() {
|
||||||
ASSERT_MSG(event_queue.empty(), "Cannot unregister events with events pending");
|
|
||||||
event_types.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Init() {
|
|
||||||
downcount = MAX_SLICE_LENGTH;
|
|
||||||
slice_length = MAX_SLICE_LENGTH;
|
|
||||||
global_timer = 0;
|
|
||||||
idled_cycles = 0;
|
|
||||||
|
|
||||||
// The time between CoreTiming being intialized and the first call to Advance() is considered
|
|
||||||
// the slice boundary between slice -1 and slice 0. Dispatcher loops must call Advance() before
|
|
||||||
// executing the first cycle of each slice to prepare the slice length and downcount for
|
|
||||||
// that slice.
|
|
||||||
is_global_timer_sane = true;
|
|
||||||
|
|
||||||
event_fifo_id = 0;
|
|
||||||
ev_lost = RegisterEvent("_lost_event", &EmptyTimedCallback);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Shutdown() {
|
|
||||||
MoveEvents();
|
MoveEvents();
|
||||||
ClearPendingEvents();
|
|
||||||
UnregisterAllEvents();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// This should only be called from the CPU thread. If you are calling
|
u64 Timing::GetTicks() const {
|
||||||
// it from any other thread, you are doing something evil
|
|
||||||
u64 GetTicks() {
|
|
||||||
u64 ticks = static_cast<u64>(global_timer);
|
u64 ticks = static_cast<u64>(global_timer);
|
||||||
if (!is_global_timer_sane) {
|
if (!is_global_timer_sane) {
|
||||||
ticks += slice_length - downcount;
|
ticks += slice_length - downcount;
|
||||||
@ -121,19 +46,16 @@ u64 GetTicks() {
|
|||||||
return ticks;
|
return ticks;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AddTicks(u64 ticks) {
|
void Timing::AddTicks(u64 ticks) {
|
||||||
downcount -= ticks;
|
downcount -= ticks;
|
||||||
}
|
}
|
||||||
|
|
||||||
u64 GetIdleTicks() {
|
u64 Timing::GetIdleTicks() const {
|
||||||
return static_cast<u64>(idled_cycles);
|
return static_cast<u64>(idled_cycles);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClearPendingEvents() {
|
void Timing::ScheduleEvent(s64 cycles_into_future, const TimingEventType* event_type,
|
||||||
event_queue.clear();
|
u64 userdata) {
|
||||||
}
|
|
||||||
|
|
||||||
void ScheduleEvent(s64 cycles_into_future, const EventType* event_type, u64 userdata) {
|
|
||||||
ASSERT(event_type != nullptr);
|
ASSERT(event_type != nullptr);
|
||||||
s64 timeout = GetTicks() + cycles_into_future;
|
s64 timeout = GetTicks() + cycles_into_future;
|
||||||
|
|
||||||
@ -145,11 +67,12 @@ void ScheduleEvent(s64 cycles_into_future, const EventType* event_type, u64 user
|
|||||||
std::push_heap(event_queue.begin(), event_queue.end(), std::greater<>());
|
std::push_heap(event_queue.begin(), event_queue.end(), std::greater<>());
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScheduleEventThreadsafe(s64 cycles_into_future, const EventType* event_type, u64 userdata) {
|
void Timing::ScheduleEventThreadsafe(s64 cycles_into_future, const TimingEventType* event_type,
|
||||||
|
u64 userdata) {
|
||||||
ts_queue.Push(Event{global_timer + cycles_into_future, 0, userdata, event_type});
|
ts_queue.Push(Event{global_timer + cycles_into_future, 0, userdata, event_type});
|
||||||
}
|
}
|
||||||
|
|
||||||
void UnscheduleEvent(const EventType* event_type, u64 userdata) {
|
void Timing::UnscheduleEvent(const TimingEventType* event_type, u64 userdata) {
|
||||||
auto itr = std::remove_if(event_queue.begin(), event_queue.end(), [&](const Event& e) {
|
auto itr = std::remove_if(event_queue.begin(), event_queue.end(), [&](const Event& e) {
|
||||||
return e.type == event_type && e.userdata == userdata;
|
return e.type == event_type && e.userdata == userdata;
|
||||||
});
|
});
|
||||||
@ -161,7 +84,7 @@ void UnscheduleEvent(const EventType* event_type, u64 userdata) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void RemoveEvent(const EventType* event_type) {
|
void Timing::RemoveEvent(const TimingEventType* event_type) {
|
||||||
auto itr = std::remove_if(event_queue.begin(), event_queue.end(),
|
auto itr = std::remove_if(event_queue.begin(), event_queue.end(),
|
||||||
[&](const Event& e) { return e.type == event_type; });
|
[&](const Event& e) { return e.type == event_type; });
|
||||||
|
|
||||||
@ -172,12 +95,12 @@ void RemoveEvent(const EventType* event_type) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void RemoveNormalAndThreadsafeEvent(const EventType* event_type) {
|
void Timing::RemoveNormalAndThreadsafeEvent(const TimingEventType* event_type) {
|
||||||
MoveEvents();
|
MoveEvents();
|
||||||
RemoveEvent(event_type);
|
RemoveEvent(event_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ForceExceptionCheck(s64 cycles) {
|
void Timing::ForceExceptionCheck(s64 cycles) {
|
||||||
cycles = std::max<s64>(0, cycles);
|
cycles = std::max<s64>(0, cycles);
|
||||||
if (downcount > cycles) {
|
if (downcount > cycles) {
|
||||||
slice_length -= downcount - cycles;
|
slice_length -= downcount - cycles;
|
||||||
@ -185,7 +108,7 @@ void ForceExceptionCheck(s64 cycles) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MoveEvents() {
|
void Timing::MoveEvents() {
|
||||||
for (Event ev; ts_queue.Pop(ev);) {
|
for (Event ev; ts_queue.Pop(ev);) {
|
||||||
ev.fifo_order = event_fifo_id++;
|
ev.fifo_order = event_fifo_id++;
|
||||||
event_queue.emplace_back(std::move(ev));
|
event_queue.emplace_back(std::move(ev));
|
||||||
@ -193,7 +116,7 @@ void MoveEvents() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Advance() {
|
void Timing::Advance() {
|
||||||
MoveEvents();
|
MoveEvents();
|
||||||
|
|
||||||
s64 cycles_executed = slice_length - downcount;
|
s64 cycles_executed = slice_length - downcount;
|
||||||
@ -220,17 +143,17 @@ void Advance() {
|
|||||||
downcount = slice_length;
|
downcount = slice_length;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Idle() {
|
void Timing::Idle() {
|
||||||
idled_cycles += downcount;
|
idled_cycles += downcount;
|
||||||
downcount = 0;
|
downcount = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::chrono::microseconds GetGlobalTimeUs() {
|
std::chrono::microseconds Timing::GetGlobalTimeUs() const {
|
||||||
return std::chrono::microseconds{GetTicks() * 1000000 / BASE_CLOCK_RATE_ARM11};
|
return std::chrono::microseconds{GetTicks() * 1000000 / BASE_CLOCK_RATE_ARM11};
|
||||||
}
|
}
|
||||||
|
|
||||||
s64 GetDowncount() {
|
s64 Timing::GetDowncount() const {
|
||||||
return downcount;
|
return downcount;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace CoreTiming
|
} // namespace Core
|
||||||
|
@ -21,8 +21,11 @@
|
|||||||
#include <functional>
|
#include <functional>
|
||||||
#include <limits>
|
#include <limits>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <vector>
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
|
#include "common/threadsafe_queue.h"
|
||||||
|
|
||||||
// The timing we get from the assembly is 268,111,855.956 Hz
|
// The timing we get from the assembly is 268,111,855.956 Hz
|
||||||
// It is possible that this number isn't just an integer because the compiler could have
|
// It is possible that this number isn't just an integer because the compiler could have
|
||||||
@ -120,39 +123,38 @@ inline u64 cyclesToMs(s64 cycles) {
|
|||||||
return cycles * 1000 / BASE_CLOCK_RATE_ARM11;
|
return cycles * 1000 / BASE_CLOCK_RATE_ARM11;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace CoreTiming {
|
namespace Core {
|
||||||
|
|
||||||
struct EventType;
|
|
||||||
|
|
||||||
using TimedCallback = std::function<void(u64 userdata, int cycles_late)>;
|
using TimedCallback = std::function<void(u64 userdata, int cycles_late)>;
|
||||||
|
|
||||||
/**
|
struct TimingEventType {
|
||||||
* CoreTiming begins at the boundary of timing slice -1. An initial call to Advance() is
|
TimedCallback callback;
|
||||||
* required to end slice -1 and start slice 0 before the first cycle of code is executed.
|
const std::string* name;
|
||||||
*/
|
};
|
||||||
void Init();
|
|
||||||
void Shutdown();
|
class Timing {
|
||||||
|
public:
|
||||||
|
~Timing();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This should only be called from the emu thread, if you are calling it any other thread, you are
|
* This should only be called from the emu thread, if you are calling it any other thread, you
|
||||||
* doing something evil
|
* are doing something evil
|
||||||
*/
|
*/
|
||||||
u64 GetTicks();
|
u64 GetTicks() const;
|
||||||
u64 GetIdleTicks();
|
u64 GetIdleTicks() const;
|
||||||
void AddTicks(u64 ticks);
|
void AddTicks(u64 ticks);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the event_type identifier. if name is not unique, it will assert.
|
* Returns the event_type identifier. if name is not unique, it will assert.
|
||||||
*/
|
*/
|
||||||
EventType* RegisterEvent(const std::string& name, TimedCallback callback);
|
TimingEventType* RegisterEvent(const std::string& name, TimedCallback callback);
|
||||||
void UnregisterAllEvents();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* After the first Advance, the slice lengths and the downcount will be reduced whenever an event
|
* After the first Advance, the slice lengths and the downcount will be reduced whenever an
|
||||||
* is scheduled earlier than the current values.
|
* event is scheduled earlier than the current values. Scheduling from a callback will not
|
||||||
* Scheduling from a callback will not update the downcount until the Advance() completes.
|
* update the downcount until the Advance() completes.
|
||||||
*/
|
*/
|
||||||
void ScheduleEvent(s64 cycles_into_future, const EventType* event_type, u64 userdata = 0);
|
void ScheduleEvent(s64 cycles_into_future, const TimingEventType* event_type, u64 userdata = 0);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is to be called when outside of hle threads, such as the graphics thread, wants to
|
* This is to be called when outside of hle threads, such as the graphics thread, wants to
|
||||||
@ -160,13 +162,14 @@ void ScheduleEvent(s64 cycles_into_future, const EventType* event_type, u64 user
|
|||||||
* Not that this doesn't change slice_length and thus events scheduled by this might be called
|
* Not that this doesn't change slice_length and thus events scheduled by this might be called
|
||||||
* with a delay of up to MAX_SLICE_LENGTH
|
* with a delay of up to MAX_SLICE_LENGTH
|
||||||
*/
|
*/
|
||||||
void ScheduleEventThreadsafe(s64 cycles_into_future, const EventType* event_type, u64 userdata);
|
void ScheduleEventThreadsafe(s64 cycles_into_future, const TimingEventType* event_type,
|
||||||
|
u64 userdata);
|
||||||
|
|
||||||
void UnscheduleEvent(const EventType* event_type, u64 userdata);
|
void UnscheduleEvent(const TimingEventType* event_type, u64 userdata);
|
||||||
|
|
||||||
/// We only permit one event of each type in the queue at a time.
|
/// We only permit one event of each type in the queue at a time.
|
||||||
void RemoveEvent(const EventType* event_type);
|
void RemoveEvent(const TimingEventType* event_type);
|
||||||
void RemoveNormalAndThreadsafeEvent(const EventType* event_type);
|
void RemoveNormalAndThreadsafeEvent(const TimingEventType* event_type);
|
||||||
|
|
||||||
/** Advance must be called at the beginning of dispatcher loops, not the end. Advance() ends
|
/** 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
|
* the previous timing slice and begins the next one, you must Advance from the previous
|
||||||
@ -180,13 +183,52 @@ void MoveEvents();
|
|||||||
/// Pretend that the main CPU has executed enough cycles to reach the next event.
|
/// Pretend that the main CPU has executed enough cycles to reach the next event.
|
||||||
void Idle();
|
void Idle();
|
||||||
|
|
||||||
/// Clear all pending events. This should ONLY be done on exit.
|
|
||||||
void ClearPendingEvents();
|
|
||||||
|
|
||||||
void ForceExceptionCheck(s64 cycles);
|
void ForceExceptionCheck(s64 cycles);
|
||||||
|
|
||||||
std::chrono::microseconds GetGlobalTimeUs();
|
std::chrono::microseconds GetGlobalTimeUs() const;
|
||||||
|
|
||||||
s64 GetDowncount();
|
s64 GetDowncount() const;
|
||||||
|
|
||||||
} // namespace CoreTiming
|
private:
|
||||||
|
struct Event {
|
||||||
|
s64 time;
|
||||||
|
u64 fifo_order;
|
||||||
|
u64 userdata;
|
||||||
|
const TimingEventType* type;
|
||||||
|
|
||||||
|
bool operator>(const Event& right) const;
|
||||||
|
bool operator<(const Event& right) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
static constexpr int MAX_SLICE_LENGTH = 20000;
|
||||||
|
|
||||||
|
s64 global_timer = 0;
|
||||||
|
s64 slice_length = MAX_SLICE_LENGTH;
|
||||||
|
s64 downcount = MAX_SLICE_LENGTH;
|
||||||
|
|
||||||
|
// 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, TimingEventType> event_types;
|
||||||
|
|
||||||
|
// 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> event_queue;
|
||||||
|
u64 event_fifo_id = 0;
|
||||||
|
// the queue for storing the events from other threads threadsafe until they will be added
|
||||||
|
// to the event_queue by the emu thread
|
||||||
|
Common::MPSCQueue<Event, false> ts_queue;
|
||||||
|
s64 idled_cycles = 0;
|
||||||
|
|
||||||
|
// Are we in a function that has been called from Advance()
|
||||||
|
// If events are sheduled from a function that gets called from Advance(),
|
||||||
|
// don't change slice_length and downcount.
|
||||||
|
// The time between CoreTiming being intialized and the first call to Advance() is considered
|
||||||
|
// the slice boundary between slice -1 and slice 0. Dispatcher loops must call Advance() before
|
||||||
|
// executing the first cycle of each slice to prepare the slice length and downcount for
|
||||||
|
// that slice.
|
||||||
|
bool is_global_timer_sane = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Core
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
|
#include "core/core.h"
|
||||||
#include "core/core_timing.h"
|
#include "core/core_timing.h"
|
||||||
#include "core/hle/applets/applet.h"
|
#include "core/hle/applets/applet.h"
|
||||||
#include "core/hle/applets/erreula.h"
|
#include "core/hle/applets/erreula.h"
|
||||||
@ -38,7 +39,7 @@ namespace Applets {
|
|||||||
|
|
||||||
static std::unordered_map<Service::APT::AppletId, std::shared_ptr<Applet>> applets;
|
static std::unordered_map<Service::APT::AppletId, std::shared_ptr<Applet>> applets;
|
||||||
/// The CoreTiming event identifier for the Applet update callback.
|
/// The CoreTiming event identifier for the Applet update callback.
|
||||||
static CoreTiming::EventType* applet_update_event = nullptr;
|
static Core::TimingEventType* applet_update_event = nullptr;
|
||||||
/// The interval at which the Applet update callback will be called, 16.6ms
|
/// The interval at which the Applet update callback will be called, 16.6ms
|
||||||
static const u64 applet_update_interval_us = 16666;
|
static const u64 applet_update_interval_us = 16666;
|
||||||
|
|
||||||
@ -88,8 +89,8 @@ static void AppletUpdateEvent(u64 applet_id, s64 cycles_late) {
|
|||||||
|
|
||||||
// If the applet is still running after the last update, reschedule the event
|
// If the applet is still running after the last update, reschedule the event
|
||||||
if (applet->IsRunning()) {
|
if (applet->IsRunning()) {
|
||||||
CoreTiming::ScheduleEvent(usToCycles(applet_update_interval_us) - cycles_late,
|
Core::System::GetInstance().CoreTiming().ScheduleEvent(
|
||||||
applet_update_event, applet_id);
|
usToCycles(applet_update_interval_us) - cycles_late, applet_update_event, applet_id);
|
||||||
} else {
|
} else {
|
||||||
// Otherwise the applet has terminated, in which case we should clean it up
|
// Otherwise the applet has terminated, in which case we should clean it up
|
||||||
applets[id] = nullptr;
|
applets[id] = nullptr;
|
||||||
@ -101,8 +102,8 @@ ResultCode Applet::Start(const Service::APT::AppletStartupParameter& parameter)
|
|||||||
if (result.IsError())
|
if (result.IsError())
|
||||||
return result;
|
return result;
|
||||||
// Schedule the update event
|
// Schedule the update event
|
||||||
CoreTiming::ScheduleEvent(usToCycles(applet_update_interval_us), applet_update_event,
|
Core::System::GetInstance().CoreTiming().ScheduleEvent(
|
||||||
static_cast<u64>(id));
|
usToCycles(applet_update_interval_us), applet_update_event, static_cast<u64>(id));
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -128,11 +129,12 @@ bool IsLibraryAppletRunning() {
|
|||||||
|
|
||||||
void Init() {
|
void Init() {
|
||||||
// Register the applet update callback
|
// Register the applet update callback
|
||||||
applet_update_event = CoreTiming::RegisterEvent("HLE Applet Update Event", AppletUpdateEvent);
|
applet_update_event = Core::System::GetInstance().CoreTiming().RegisterEvent(
|
||||||
|
"HLE Applet Update Event", AppletUpdateEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Shutdown() {
|
void Shutdown() {
|
||||||
CoreTiming::RemoveEvent(applet_update_event);
|
Core::System::GetInstance().CoreTiming().RemoveEvent(applet_update_event);
|
||||||
}
|
}
|
||||||
} // namespace Applets
|
} // namespace Applets
|
||||||
} // namespace HLE
|
} // namespace HLE
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
#include "core/core.h"
|
||||||
#include "core/core_timing.h"
|
#include "core/core_timing.h"
|
||||||
#include "core/hle/kernel/shared_page.h"
|
#include "core/hle/kernel/shared_page.h"
|
||||||
#include "core/hle/service/ptm/ptm.h"
|
#include "core/hle/service/ptm/ptm.h"
|
||||||
@ -53,9 +54,9 @@ Handler::Handler() {
|
|||||||
init_time = GetInitTime();
|
init_time = GetInitTime();
|
||||||
|
|
||||||
using namespace std::placeholders;
|
using namespace std::placeholders;
|
||||||
update_time_event = CoreTiming::RegisterEvent(
|
update_time_event = Core::System::GetInstance().CoreTiming().RegisterEvent(
|
||||||
"SharedPage::UpdateTimeCallback", std::bind(&Handler::UpdateTimeCallback, this, _1, _2));
|
"SharedPage::UpdateTimeCallback", std::bind(&Handler::UpdateTimeCallback, this, _1, _2));
|
||||||
CoreTiming::ScheduleEvent(0, update_time_event);
|
Core::System::GetInstance().CoreTiming().ScheduleEvent(0, update_time_event);
|
||||||
|
|
||||||
float slidestate =
|
float slidestate =
|
||||||
Settings::values.toggle_3d ? (float_le)Settings::values.factor_3d / 100 : 0.0f;
|
Settings::values.toggle_3d ? (float_le)Settings::values.factor_3d / 100 : 0.0f;
|
||||||
@ -65,8 +66,8 @@ Handler::Handler() {
|
|||||||
/// Gets system time in 3DS format. The epoch is Jan 1900, and the unit is millisecond.
|
/// Gets system time in 3DS format. The epoch is Jan 1900, and the unit is millisecond.
|
||||||
u64 Handler::GetSystemTime() const {
|
u64 Handler::GetSystemTime() const {
|
||||||
std::chrono::milliseconds now =
|
std::chrono::milliseconds now =
|
||||||
init_time +
|
init_time + std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||||
std::chrono::duration_cast<std::chrono::milliseconds>(CoreTiming::GetGlobalTimeUs());
|
Core::System::GetInstance().CoreTiming().GetGlobalTimeUs());
|
||||||
|
|
||||||
// 3DS system does't allow user to set a time before Jan 1 2000,
|
// 3DS system does't allow user to set a time before Jan 1 2000,
|
||||||
// so we use it as an auxiliary epoch to calculate the console time.
|
// so we use it as an auxiliary epoch to calculate the console time.
|
||||||
@ -97,14 +98,15 @@ void Handler::UpdateTimeCallback(u64 userdata, int cycles_late) {
|
|||||||
shared_page.date_time_counter % 2 ? shared_page.date_time_0 : shared_page.date_time_1;
|
shared_page.date_time_counter % 2 ? shared_page.date_time_0 : shared_page.date_time_1;
|
||||||
|
|
||||||
date_time.date_time = GetSystemTime();
|
date_time.date_time = GetSystemTime();
|
||||||
date_time.update_tick = CoreTiming::GetTicks();
|
date_time.update_tick = Core::System::GetInstance().CoreTiming().GetTicks();
|
||||||
date_time.tick_to_second_coefficient = BASE_CLOCK_RATE_ARM11;
|
date_time.tick_to_second_coefficient = BASE_CLOCK_RATE_ARM11;
|
||||||
date_time.tick_offset = 0;
|
date_time.tick_offset = 0;
|
||||||
|
|
||||||
++shared_page.date_time_counter;
|
++shared_page.date_time_counter;
|
||||||
|
|
||||||
// system time is updated hourly
|
// system time is updated hourly
|
||||||
CoreTiming::ScheduleEvent(msToCycles(60 * 60 * 1000) - cycles_late, update_time_event);
|
Core::System::GetInstance().CoreTiming().ScheduleEvent(msToCycles(60 * 60 * 1000) - cycles_late,
|
||||||
|
update_time_event);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Handler::SetMacAddress(const MacAddress& addr) {
|
void Handler::SetMacAddress(const MacAddress& addr) {
|
||||||
|
@ -21,8 +21,8 @@
|
|||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
namespace CoreTiming {
|
namespace Core {
|
||||||
struct EventType;
|
struct TimingEventType;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace SharedPage {
|
namespace SharedPage {
|
||||||
@ -96,7 +96,7 @@ public:
|
|||||||
private:
|
private:
|
||||||
u64 GetSystemTime() const;
|
u64 GetSystemTime() const;
|
||||||
void UpdateTimeCallback(u64 userdata, int cycles_late);
|
void UpdateTimeCallback(u64 userdata, int cycles_late);
|
||||||
CoreTiming::EventType* update_time_event;
|
Core::TimingEventType* update_time_event;
|
||||||
std::chrono::seconds init_time;
|
std::chrono::seconds init_time;
|
||||||
|
|
||||||
SharedPageDef shared_page;
|
SharedPageDef shared_page;
|
||||||
|
@ -1107,9 +1107,10 @@ static void SleepThread(s64 nanoseconds) {
|
|||||||
|
|
||||||
/// This returns the total CPU ticks elapsed since the CPU was powered-on
|
/// This returns the total CPU ticks elapsed since the CPU was powered-on
|
||||||
static s64 GetSystemTick() {
|
static s64 GetSystemTick() {
|
||||||
s64 result = CoreTiming::GetTicks();
|
s64 result = Core::System::GetInstance().CoreTiming().GetTicks();
|
||||||
// Advance time to defeat dumb games (like Cubic Ninja) that busy-wait for the frame to end.
|
// Advance time to defeat dumb games (like Cubic Ninja) that busy-wait for the frame to end.
|
||||||
CoreTiming::AddTicks(150); // Measured time between two calls on a 9.2 o3DS with Ninjhax 1.1b
|
// Measured time between two calls on a 9.2 o3DS with Ninjhax 1.1b
|
||||||
|
Core::System::GetInstance().CoreTiming().AddTicks(150);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,7 +48,8 @@ Thread* ThreadManager::GetCurrentThread() const {
|
|||||||
|
|
||||||
void Thread::Stop() {
|
void Thread::Stop() {
|
||||||
// Cancel any outstanding wakeup events for this thread
|
// Cancel any outstanding wakeup events for this thread
|
||||||
CoreTiming::UnscheduleEvent(thread_manager.ThreadWakeupEventType, thread_id);
|
Core::System::GetInstance().CoreTiming().UnscheduleEvent(thread_manager.ThreadWakeupEventType,
|
||||||
|
thread_id);
|
||||||
thread_manager.wakeup_callback_table.erase(thread_id);
|
thread_manager.wakeup_callback_table.erase(thread_id);
|
||||||
|
|
||||||
// Clean up thread from ready queue
|
// Clean up thread from ready queue
|
||||||
@ -80,9 +81,11 @@ void Thread::Stop() {
|
|||||||
void ThreadManager::SwitchContext(Thread* new_thread) {
|
void ThreadManager::SwitchContext(Thread* new_thread) {
|
||||||
Thread* previous_thread = GetCurrentThread();
|
Thread* previous_thread = GetCurrentThread();
|
||||||
|
|
||||||
|
Core::Timing& timing = Core::System::GetInstance().CoreTiming();
|
||||||
|
|
||||||
// Save context for previous thread
|
// Save context for previous thread
|
||||||
if (previous_thread) {
|
if (previous_thread) {
|
||||||
previous_thread->last_running_ticks = CoreTiming::GetTicks();
|
previous_thread->last_running_ticks = timing.GetTicks();
|
||||||
Core::CPU().SaveContext(previous_thread->context);
|
Core::CPU().SaveContext(previous_thread->context);
|
||||||
|
|
||||||
if (previous_thread->status == ThreadStatus::Running) {
|
if (previous_thread->status == ThreadStatus::Running) {
|
||||||
@ -99,7 +102,7 @@ void ThreadManager::SwitchContext(Thread* new_thread) {
|
|||||||
"Thread must be ready to become running.");
|
"Thread must be ready to become running.");
|
||||||
|
|
||||||
// Cancel any outstanding wakeup events for this thread
|
// Cancel any outstanding wakeup events for this thread
|
||||||
CoreTiming::UnscheduleEvent(ThreadWakeupEventType, new_thread->thread_id);
|
timing.UnscheduleEvent(ThreadWakeupEventType, new_thread->thread_id);
|
||||||
|
|
||||||
auto previous_process = Core::System::GetInstance().Kernel().GetCurrentProcess();
|
auto previous_process = Core::System::GetInstance().Kernel().GetCurrentProcess();
|
||||||
|
|
||||||
@ -182,8 +185,8 @@ void Thread::WakeAfterDelay(s64 nanoseconds) {
|
|||||||
if (nanoseconds == -1)
|
if (nanoseconds == -1)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
CoreTiming::ScheduleEvent(nsToCycles(nanoseconds), thread_manager.ThreadWakeupEventType,
|
Core::System::GetInstance().CoreTiming().ScheduleEvent(
|
||||||
thread_id);
|
nsToCycles(nanoseconds), thread_manager.ThreadWakeupEventType, thread_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Thread::ResumeFromWait() {
|
void Thread::ResumeFromWait() {
|
||||||
@ -316,7 +319,7 @@ ResultVal<SharedPtr<Thread>> KernelSystem::CreateThread(std::string name, VAddr
|
|||||||
thread->entry_point = entry_point;
|
thread->entry_point = entry_point;
|
||||||
thread->stack_top = stack_top;
|
thread->stack_top = stack_top;
|
||||||
thread->nominal_priority = thread->current_priority = priority;
|
thread->nominal_priority = thread->current_priority = priority;
|
||||||
thread->last_running_ticks = CoreTiming::GetTicks();
|
thread->last_running_ticks = Core::System::GetInstance().CoreTiming().GetTicks();
|
||||||
thread->processor_id = processor_id;
|
thread->processor_id = processor_id;
|
||||||
thread->wait_objects.clear();
|
thread->wait_objects.clear();
|
||||||
thread->wait_address = 0;
|
thread->wait_address = 0;
|
||||||
@ -459,10 +462,9 @@ VAddr Thread::GetCommandBufferAddress() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ThreadManager::ThreadManager() {
|
ThreadManager::ThreadManager() {
|
||||||
ThreadWakeupEventType =
|
ThreadWakeupEventType = Core::System::GetInstance().CoreTiming().RegisterEvent(
|
||||||
CoreTiming::RegisterEvent("ThreadWakeupCallback", [this](u64 thread_id, s64 cycle_late) {
|
"ThreadWakeupCallback",
|
||||||
ThreadWakeupCallback(thread_id, cycle_late);
|
[this](u64 thread_id, s64 cycle_late) { ThreadWakeupCallback(thread_id, cycle_late); });
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ThreadManager::~ThreadManager() {
|
ThreadManager::~ThreadManager() {
|
||||||
|
@ -127,7 +127,7 @@ private:
|
|||||||
std::unordered_map<u64, Thread*> wakeup_callback_table;
|
std::unordered_map<u64, Thread*> wakeup_callback_table;
|
||||||
|
|
||||||
/// Event type for the thread wake up event
|
/// Event type for the thread wake up event
|
||||||
CoreTiming::EventType* ThreadWakeupEventType = nullptr;
|
Core::TimingEventType* ThreadWakeupEventType = nullptr;
|
||||||
|
|
||||||
// Lists all threadsthat aren't deleted.
|
// Lists all threadsthat aren't deleted.
|
||||||
std::vector<SharedPtr<Thread>> thread_list;
|
std::vector<SharedPtr<Thread>> thread_list;
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
|
#include "core/core.h"
|
||||||
#include "core/hle/kernel/handle_table.h"
|
#include "core/hle/kernel/handle_table.h"
|
||||||
#include "core/hle/kernel/object.h"
|
#include "core/hle/kernel/object.h"
|
||||||
#include "core/hle/kernel/thread.h"
|
#include "core/hle/kernel/thread.h"
|
||||||
@ -55,13 +56,14 @@ void Timer::Set(s64 initial, s64 interval) {
|
|||||||
// Immediately invoke the callback
|
// Immediately invoke the callback
|
||||||
Signal(0);
|
Signal(0);
|
||||||
} else {
|
} else {
|
||||||
CoreTiming::ScheduleEvent(nsToCycles(initial), timer_manager.timer_callback_event_type,
|
Core::System::GetInstance().CoreTiming().ScheduleEvent(
|
||||||
callback_id);
|
nsToCycles(initial), timer_manager.timer_callback_event_type, callback_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Timer::Cancel() {
|
void Timer::Cancel() {
|
||||||
CoreTiming::UnscheduleEvent(timer_manager.timer_callback_event_type, callback_id);
|
Core::System::GetInstance().CoreTiming().UnscheduleEvent(
|
||||||
|
timer_manager.timer_callback_event_type, callback_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Timer::Clear() {
|
void Timer::Clear() {
|
||||||
@ -85,8 +87,9 @@ void Timer::Signal(s64 cycles_late) {
|
|||||||
|
|
||||||
if (interval_delay != 0) {
|
if (interval_delay != 0) {
|
||||||
// Reschedule the timer with the interval delay
|
// Reschedule the timer with the interval delay
|
||||||
CoreTiming::ScheduleEvent(nsToCycles(interval_delay) - cycles_late,
|
Core::System::GetInstance().CoreTiming().ScheduleEvent(
|
||||||
timer_manager.timer_callback_event_type, callback_id);
|
nsToCycles(interval_delay) - cycles_late, timer_manager.timer_callback_event_type,
|
||||||
|
callback_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -103,10 +106,9 @@ void TimerManager::TimerCallback(u64 callback_id, s64 cycles_late) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TimerManager::TimerManager() {
|
TimerManager::TimerManager() {
|
||||||
timer_callback_event_type =
|
timer_callback_event_type = Core::System::GetInstance().CoreTiming().RegisterEvent(
|
||||||
CoreTiming::RegisterEvent("TimerCallback", [this](u64 thread_id, s64 cycle_late) {
|
"TimerCallback",
|
||||||
TimerCallback(thread_id, cycle_late);
|
[this](u64 thread_id, s64 cycle_late) { TimerCallback(thread_id, cycle_late); });
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Kernel
|
} // namespace Kernel
|
||||||
|
@ -20,7 +20,7 @@ private:
|
|||||||
void TimerCallback(u64 callback_id, s64 cycles_late);
|
void TimerCallback(u64 callback_id, s64 cycles_late);
|
||||||
|
|
||||||
/// The event type of the generic timer callback event
|
/// The event type of the generic timer callback event
|
||||||
CoreTiming::EventType* timer_callback_event_type = nullptr;
|
Core::TimingEventType* timer_callback_event_type = nullptr;
|
||||||
|
|
||||||
u64 next_timer_callback_id = 0;
|
u64 next_timer_callback_id = 0;
|
||||||
std::unordered_map<u64, Timer*> timer_callback_table;
|
std::unordered_map<u64, Timer*> timer_callback_table;
|
||||||
|
@ -151,7 +151,7 @@ void Module::StartReceiving(int port_id) {
|
|||||||
|
|
||||||
// schedules a completion event according to the frame rate. The event will block on the
|
// schedules a completion event according to the frame rate. The event will block on the
|
||||||
// capture task if it is not finished within the expected time
|
// capture task if it is not finished within the expected time
|
||||||
CoreTiming::ScheduleEvent(
|
system.CoreTiming().ScheduleEvent(
|
||||||
msToCycles(LATENCY_BY_FRAME_RATE[static_cast<int>(camera.frame_rate)]),
|
msToCycles(LATENCY_BY_FRAME_RATE[static_cast<int>(camera.frame_rate)]),
|
||||||
completion_event_callback, port_id);
|
completion_event_callback, port_id);
|
||||||
}
|
}
|
||||||
@ -160,7 +160,7 @@ void Module::CancelReceiving(int port_id) {
|
|||||||
if (!ports[port_id].is_receiving)
|
if (!ports[port_id].is_receiving)
|
||||||
return;
|
return;
|
||||||
LOG_WARNING(Service_CAM, "tries to cancel an ongoing receiving process.");
|
LOG_WARNING(Service_CAM, "tries to cancel an ongoing receiving process.");
|
||||||
CoreTiming::UnscheduleEvent(completion_event_callback, port_id);
|
system.CoreTiming().UnscheduleEvent(completion_event_callback, port_id);
|
||||||
ports[port_id].capture_result.wait();
|
ports[port_id].capture_result.wait();
|
||||||
ports[port_id].is_receiving = false;
|
ports[port_id].is_receiving = false;
|
||||||
}
|
}
|
||||||
@ -1019,7 +1019,7 @@ void Module::Interface::DriverFinalize(Kernel::HLERequestContext& ctx) {
|
|||||||
LOG_DEBUG(Service_CAM, "called");
|
LOG_DEBUG(Service_CAM, "called");
|
||||||
}
|
}
|
||||||
|
|
||||||
Module::Module(Core::System& system) {
|
Module::Module(Core::System& system) : system(system) {
|
||||||
using namespace Kernel;
|
using namespace Kernel;
|
||||||
for (PortConfig& port : ports) {
|
for (PortConfig& port : ports) {
|
||||||
port.completion_event =
|
port.completion_event =
|
||||||
@ -1029,7 +1029,7 @@ Module::Module(Core::System& system) {
|
|||||||
port.vsync_interrupt_event =
|
port.vsync_interrupt_event =
|
||||||
system.Kernel().CreateEvent(ResetType::OneShot, "CAM::vsync_interrupt_event");
|
system.Kernel().CreateEvent(ResetType::OneShot, "CAM::vsync_interrupt_event");
|
||||||
}
|
}
|
||||||
completion_event_callback = CoreTiming::RegisterEvent(
|
completion_event_callback = system.CoreTiming().RegisterEvent(
|
||||||
"CAM::CompletionEventCallBack",
|
"CAM::CompletionEventCallBack",
|
||||||
[this](u64 userdata, s64 cycles_late) { CompletionEventCallBack(userdata, cycles_late); });
|
[this](u64 userdata, s64 cycles_late) { CompletionEventCallBack(userdata, cycles_late); });
|
||||||
}
|
}
|
||||||
|
@ -21,8 +21,8 @@ namespace Camera {
|
|||||||
class CameraInterface;
|
class CameraInterface;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace CoreTiming {
|
namespace Core {
|
||||||
struct EventType;
|
struct TimingEventType;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace Kernel {
|
namespace Kernel {
|
||||||
@ -779,9 +779,10 @@ private:
|
|||||||
|
|
||||||
void LoadCameraImplementation(CameraConfig& camera, int camera_id);
|
void LoadCameraImplementation(CameraConfig& camera, int camera_id);
|
||||||
|
|
||||||
|
Core::System& system;
|
||||||
std::array<CameraConfig, NumCameras> cameras;
|
std::array<CameraConfig, NumCameras> cameras;
|
||||||
std::array<PortConfig, 2> ports;
|
std::array<PortConfig, 2> ports;
|
||||||
CoreTiming::EventType* completion_event_callback;
|
Core::TimingEventType* completion_event_callback;
|
||||||
std::atomic<bool> is_camera_reload_pending{false};
|
std::atomic<bool> is_camera_reload_pending{false};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -128,7 +128,7 @@ void Module::UpdatePadCallback(u64 userdata, s64 cycles_late) {
|
|||||||
// If we just updated index 0, provide a new timestamp
|
// If we just updated index 0, provide a new timestamp
|
||||||
if (mem->pad.index == 0) {
|
if (mem->pad.index == 0) {
|
||||||
mem->pad.index_reset_ticks_previous = mem->pad.index_reset_ticks;
|
mem->pad.index_reset_ticks_previous = mem->pad.index_reset_ticks;
|
||||||
mem->pad.index_reset_ticks = (s64)CoreTiming::GetTicks();
|
mem->pad.index_reset_ticks = (s64)system.CoreTiming().GetTicks();
|
||||||
}
|
}
|
||||||
|
|
||||||
mem->touch.index = next_touch_index;
|
mem->touch.index = next_touch_index;
|
||||||
@ -152,7 +152,7 @@ void Module::UpdatePadCallback(u64 userdata, s64 cycles_late) {
|
|||||||
// If we just updated index 0, provide a new timestamp
|
// If we just updated index 0, provide a new timestamp
|
||||||
if (mem->touch.index == 0) {
|
if (mem->touch.index == 0) {
|
||||||
mem->touch.index_reset_ticks_previous = mem->touch.index_reset_ticks;
|
mem->touch.index_reset_ticks_previous = mem->touch.index_reset_ticks;
|
||||||
mem->touch.index_reset_ticks = (s64)CoreTiming::GetTicks();
|
mem->touch.index_reset_ticks = (s64)system.CoreTiming().GetTicks();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Signal both handles when there's an update to Pad or touch
|
// Signal both handles when there's an update to Pad or touch
|
||||||
@ -160,7 +160,7 @@ void Module::UpdatePadCallback(u64 userdata, s64 cycles_late) {
|
|||||||
event_pad_or_touch_2->Signal();
|
event_pad_or_touch_2->Signal();
|
||||||
|
|
||||||
// Reschedule recurrent event
|
// Reschedule recurrent event
|
||||||
CoreTiming::ScheduleEvent(pad_update_ticks - cycles_late, pad_update_event);
|
system.CoreTiming().ScheduleEvent(pad_update_ticks - cycles_late, pad_update_event);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Module::UpdateAccelerometerCallback(u64 userdata, s64 cycles_late) {
|
void Module::UpdateAccelerometerCallback(u64 userdata, s64 cycles_late) {
|
||||||
@ -198,13 +198,14 @@ void Module::UpdateAccelerometerCallback(u64 userdata, s64 cycles_late) {
|
|||||||
// If we just updated index 0, provide a new timestamp
|
// If we just updated index 0, provide a new timestamp
|
||||||
if (mem->accelerometer.index == 0) {
|
if (mem->accelerometer.index == 0) {
|
||||||
mem->accelerometer.index_reset_ticks_previous = mem->accelerometer.index_reset_ticks;
|
mem->accelerometer.index_reset_ticks_previous = mem->accelerometer.index_reset_ticks;
|
||||||
mem->accelerometer.index_reset_ticks = (s64)CoreTiming::GetTicks();
|
mem->accelerometer.index_reset_ticks = (s64)system.CoreTiming().GetTicks();
|
||||||
}
|
}
|
||||||
|
|
||||||
event_accelerometer->Signal();
|
event_accelerometer->Signal();
|
||||||
|
|
||||||
// Reschedule recurrent event
|
// Reschedule recurrent event
|
||||||
CoreTiming::ScheduleEvent(accelerometer_update_ticks - cycles_late, accelerometer_update_event);
|
system.CoreTiming().ScheduleEvent(accelerometer_update_ticks - cycles_late,
|
||||||
|
accelerometer_update_event);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Module::UpdateGyroscopeCallback(u64 userdata, s64 cycles_late) {
|
void Module::UpdateGyroscopeCallback(u64 userdata, s64 cycles_late) {
|
||||||
@ -233,13 +234,13 @@ void Module::UpdateGyroscopeCallback(u64 userdata, s64 cycles_late) {
|
|||||||
// If we just updated index 0, provide a new timestamp
|
// If we just updated index 0, provide a new timestamp
|
||||||
if (mem->gyroscope.index == 0) {
|
if (mem->gyroscope.index == 0) {
|
||||||
mem->gyroscope.index_reset_ticks_previous = mem->gyroscope.index_reset_ticks;
|
mem->gyroscope.index_reset_ticks_previous = mem->gyroscope.index_reset_ticks;
|
||||||
mem->gyroscope.index_reset_ticks = (s64)CoreTiming::GetTicks();
|
mem->gyroscope.index_reset_ticks = (s64)system.CoreTiming().GetTicks();
|
||||||
}
|
}
|
||||||
|
|
||||||
event_gyroscope->Signal();
|
event_gyroscope->Signal();
|
||||||
|
|
||||||
// Reschedule recurrent event
|
// Reschedule recurrent event
|
||||||
CoreTiming::ScheduleEvent(gyroscope_update_ticks - cycles_late, gyroscope_update_event);
|
system.CoreTiming().ScheduleEvent(gyroscope_update_ticks - cycles_late, gyroscope_update_event);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Module::Interface::GetIPCHandles(Kernel::HLERequestContext& ctx) {
|
void Module::Interface::GetIPCHandles(Kernel::HLERequestContext& ctx) {
|
||||||
@ -257,7 +258,8 @@ void Module::Interface::EnableAccelerometer(Kernel::HLERequestContext& ctx) {
|
|||||||
|
|
||||||
// Schedules the accelerometer update event if the accelerometer was just enabled
|
// Schedules the accelerometer update event if the accelerometer was just enabled
|
||||||
if (hid->enable_accelerometer_count == 1) {
|
if (hid->enable_accelerometer_count == 1) {
|
||||||
CoreTiming::ScheduleEvent(accelerometer_update_ticks, hid->accelerometer_update_event);
|
hid->system.CoreTiming().ScheduleEvent(accelerometer_update_ticks,
|
||||||
|
hid->accelerometer_update_event);
|
||||||
}
|
}
|
||||||
|
|
||||||
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
|
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
|
||||||
@ -273,7 +275,7 @@ void Module::Interface::DisableAccelerometer(Kernel::HLERequestContext& ctx) {
|
|||||||
|
|
||||||
// Unschedules the accelerometer update event if the accelerometer was just disabled
|
// Unschedules the accelerometer update event if the accelerometer was just disabled
|
||||||
if (hid->enable_accelerometer_count == 0) {
|
if (hid->enable_accelerometer_count == 0) {
|
||||||
CoreTiming::UnscheduleEvent(hid->accelerometer_update_event, 0);
|
hid->system.CoreTiming().UnscheduleEvent(hid->accelerometer_update_event, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
|
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
|
||||||
@ -289,7 +291,7 @@ void Module::Interface::EnableGyroscopeLow(Kernel::HLERequestContext& ctx) {
|
|||||||
|
|
||||||
// Schedules the gyroscope update event if the gyroscope was just enabled
|
// Schedules the gyroscope update event if the gyroscope was just enabled
|
||||||
if (hid->enable_gyroscope_count == 1) {
|
if (hid->enable_gyroscope_count == 1) {
|
||||||
CoreTiming::ScheduleEvent(gyroscope_update_ticks, hid->gyroscope_update_event);
|
hid->system.CoreTiming().ScheduleEvent(gyroscope_update_ticks, hid->gyroscope_update_event);
|
||||||
}
|
}
|
||||||
|
|
||||||
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
|
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
|
||||||
@ -305,7 +307,7 @@ void Module::Interface::DisableGyroscopeLow(Kernel::HLERequestContext& ctx) {
|
|||||||
|
|
||||||
// Unschedules the gyroscope update event if the gyroscope was just disabled
|
// Unschedules the gyroscope update event if the gyroscope was just disabled
|
||||||
if (hid->enable_gyroscope_count == 0) {
|
if (hid->enable_gyroscope_count == 0) {
|
||||||
CoreTiming::UnscheduleEvent(hid->gyroscope_update_event, 0);
|
hid->system.CoreTiming().UnscheduleEvent(hid->gyroscope_update_event, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
|
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
|
||||||
@ -371,19 +373,21 @@ Module::Module(Core::System& system) : system(system) {
|
|||||||
event_debug_pad = system.Kernel().CreateEvent(ResetType::OneShot, "HID:EventDebugPad");
|
event_debug_pad = system.Kernel().CreateEvent(ResetType::OneShot, "HID:EventDebugPad");
|
||||||
|
|
||||||
// Register update callbacks
|
// Register update callbacks
|
||||||
|
Core::Timing& timing = system.CoreTiming();
|
||||||
pad_update_event =
|
pad_update_event =
|
||||||
CoreTiming::RegisterEvent("HID::UpdatePadCallback", [this](u64 userdata, s64 cycles_late) {
|
timing.RegisterEvent("HID::UpdatePadCallback", [this](u64 userdata, s64 cycles_late) {
|
||||||
UpdatePadCallback(userdata, cycles_late);
|
UpdatePadCallback(userdata, cycles_late);
|
||||||
});
|
});
|
||||||
accelerometer_update_event = CoreTiming::RegisterEvent(
|
accelerometer_update_event = timing.RegisterEvent(
|
||||||
"HID::UpdateAccelerometerCallback", [this](u64 userdata, s64 cycles_late) {
|
"HID::UpdateAccelerometerCallback", [this](u64 userdata, s64 cycles_late) {
|
||||||
UpdateAccelerometerCallback(userdata, cycles_late);
|
UpdateAccelerometerCallback(userdata, cycles_late);
|
||||||
});
|
});
|
||||||
gyroscope_update_event = CoreTiming::RegisterEvent(
|
gyroscope_update_event =
|
||||||
"HID::UpdateGyroscopeCallback",
|
timing.RegisterEvent("HID::UpdateGyroscopeCallback", [this](u64 userdata, s64 cycles_late) {
|
||||||
[this](u64 userdata, s64 cycles_late) { UpdateGyroscopeCallback(userdata, cycles_late); });
|
UpdateGyroscopeCallback(userdata, cycles_late);
|
||||||
|
});
|
||||||
|
|
||||||
CoreTiming::ScheduleEvent(pad_update_ticks, pad_update_event);
|
timing.ScheduleEvent(pad_update_ticks, pad_update_event);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Module::ReloadInputDevices() {
|
void Module::ReloadInputDevices() {
|
||||||
|
@ -27,8 +27,8 @@ class Event;
|
|||||||
class SharedMemory;
|
class SharedMemory;
|
||||||
} // namespace Kernel
|
} // namespace Kernel
|
||||||
|
|
||||||
namespace CoreTiming {
|
namespace Core {
|
||||||
struct EventType;
|
struct TimingEventType;
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace Service::HID {
|
namespace Service::HID {
|
||||||
@ -325,9 +325,9 @@ private:
|
|||||||
int enable_accelerometer_count = 0; // positive means enabled
|
int enable_accelerometer_count = 0; // positive means enabled
|
||||||
int enable_gyroscope_count = 0; // positive means enabled
|
int enable_gyroscope_count = 0; // positive means enabled
|
||||||
|
|
||||||
CoreTiming::EventType* pad_update_event;
|
Core::TimingEventType* pad_update_event;
|
||||||
CoreTiming::EventType* accelerometer_update_event;
|
Core::TimingEventType* accelerometer_update_event;
|
||||||
CoreTiming::EventType* gyroscope_update_event;
|
Core::TimingEventType* gyroscope_update_event;
|
||||||
|
|
||||||
std::atomic<bool> is_device_reload_pending{true};
|
std::atomic<bool> is_device_reload_pending{true};
|
||||||
std::array<std::unique_ptr<Input::ButtonDevice>, Settings::NativeButton::NUM_BUTTONS_HID>
|
std::array<std::unique_ptr<Input::ButtonDevice>, Settings::NativeButton::NUM_BUTTONS_HID>
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
#include "common/alignment.h"
|
#include "common/alignment.h"
|
||||||
#include "common/string_util.h"
|
#include "common/string_util.h"
|
||||||
|
#include "core/core.h"
|
||||||
#include "core/core_timing.h"
|
#include "core/core_timing.h"
|
||||||
#include "core/hle/service/ir/extra_hid.h"
|
#include "core/hle/service/ir/extra_hid.h"
|
||||||
#include "core/movie.h"
|
#include "core/movie.h"
|
||||||
@ -144,11 +145,11 @@ ExtraHID::ExtraHID(SendFunc send_func) : IRDevice(send_func) {
|
|||||||
0x65,
|
0x65,
|
||||||
}};
|
}};
|
||||||
|
|
||||||
hid_polling_callback_id =
|
hid_polling_callback_id = Core::System::GetInstance().CoreTiming().RegisterEvent(
|
||||||
CoreTiming::RegisterEvent("ExtraHID::SendHIDStatus", [this](u64, s64 cycles_late) {
|
"ExtraHID::SendHIDStatus", [this](u64, s64 cycles_late) {
|
||||||
SendHIDStatus();
|
SendHIDStatus();
|
||||||
CoreTiming::ScheduleEvent(msToCycles(hid_period) - cycles_late,
|
Core::System::GetInstance().CoreTiming().ScheduleEvent(
|
||||||
hid_polling_callback_id);
|
msToCycles(hid_period) - cycles_late, hid_polling_callback_id);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -159,7 +160,7 @@ ExtraHID::~ExtraHID() {
|
|||||||
void ExtraHID::OnConnect() {}
|
void ExtraHID::OnConnect() {}
|
||||||
|
|
||||||
void ExtraHID::OnDisconnect() {
|
void ExtraHID::OnDisconnect() {
|
||||||
CoreTiming::UnscheduleEvent(hid_polling_callback_id, 0);
|
Core::System::GetInstance().CoreTiming().UnscheduleEvent(hid_polling_callback_id, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ExtraHID::HandleConfigureHIDPollingRequest(const std::vector<u8>& request) {
|
void ExtraHID::HandleConfigureHIDPollingRequest(const std::vector<u8>& request) {
|
||||||
@ -170,9 +171,10 @@ void ExtraHID::HandleConfigureHIDPollingRequest(const std::vector<u8>& request)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Change HID input polling interval
|
// Change HID input polling interval
|
||||||
CoreTiming::UnscheduleEvent(hid_polling_callback_id, 0);
|
Core::System::GetInstance().CoreTiming().UnscheduleEvent(hid_polling_callback_id, 0);
|
||||||
hid_period = request[1];
|
hid_period = request[1];
|
||||||
CoreTiming::ScheduleEvent(msToCycles(hid_period), hid_polling_callback_id);
|
Core::System::GetInstance().CoreTiming().ScheduleEvent(msToCycles(hid_period),
|
||||||
|
hid_polling_callback_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ExtraHID::HandleReadCalibrationDataRequest(const std::vector<u8>& request_buf) {
|
void ExtraHID::HandleReadCalibrationDataRequest(const std::vector<u8>& request_buf) {
|
||||||
|
@ -11,9 +11,9 @@
|
|||||||
#include "core/frontend/input.h"
|
#include "core/frontend/input.h"
|
||||||
#include "core/hle/service/ir/ir_user.h"
|
#include "core/hle/service/ir/ir_user.h"
|
||||||
|
|
||||||
namespace CoreTiming {
|
namespace Core {
|
||||||
struct EventType;
|
struct TimingEventType;
|
||||||
} // namespace CoreTiming
|
} // namespace Core
|
||||||
|
|
||||||
namespace Service::IR {
|
namespace Service::IR {
|
||||||
|
|
||||||
@ -57,7 +57,7 @@ private:
|
|||||||
void LoadInputDevices();
|
void LoadInputDevices();
|
||||||
|
|
||||||
u8 hid_period;
|
u8 hid_period;
|
||||||
CoreTiming::EventType* hid_polling_callback_id;
|
Core::TimingEventType* hid_polling_callback_id;
|
||||||
std::array<u8, 0x40> calibration_data;
|
std::array<u8, 0x40> calibration_data;
|
||||||
std::unique_ptr<Input::ButtonDevice> zl;
|
std::unique_ptr<Input::ButtonDevice> zl;
|
||||||
std::unique_ptr<Input::ButtonDevice> zr;
|
std::unique_ptr<Input::ButtonDevice> zr;
|
||||||
|
@ -100,13 +100,13 @@ void IR_RST::UpdateCallback(u64 userdata, s64 cycles_late) {
|
|||||||
// If we just updated index 0, provide a new timestamp
|
// If we just updated index 0, provide a new timestamp
|
||||||
if (mem->index == 0) {
|
if (mem->index == 0) {
|
||||||
mem->index_reset_ticks_previous = mem->index_reset_ticks;
|
mem->index_reset_ticks_previous = mem->index_reset_ticks;
|
||||||
mem->index_reset_ticks = CoreTiming::GetTicks();
|
mem->index_reset_ticks = system.CoreTiming().GetTicks();
|
||||||
}
|
}
|
||||||
|
|
||||||
update_event->Signal();
|
update_event->Signal();
|
||||||
|
|
||||||
// Reschedule recurrent event
|
// Reschedule recurrent event
|
||||||
CoreTiming::ScheduleEvent(msToCycles(update_period) - cycles_late, update_callback_id);
|
system.CoreTiming().ScheduleEvent(msToCycles(update_period) - cycles_late, update_callback_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
void IR_RST::GetHandles(Kernel::HLERequestContext& ctx) {
|
void IR_RST::GetHandles(Kernel::HLERequestContext& ctx) {
|
||||||
@ -126,7 +126,7 @@ void IR_RST::Initialize(Kernel::HLERequestContext& ctx) {
|
|||||||
|
|
||||||
next_pad_index = 0;
|
next_pad_index = 0;
|
||||||
is_device_reload_pending.store(true);
|
is_device_reload_pending.store(true);
|
||||||
CoreTiming::ScheduleEvent(msToCycles(update_period), update_callback_id);
|
system.CoreTiming().ScheduleEvent(msToCycles(update_period), update_callback_id);
|
||||||
|
|
||||||
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
|
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
|
||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
@ -137,7 +137,7 @@ void IR_RST::Initialize(Kernel::HLERequestContext& ctx) {
|
|||||||
void IR_RST::Shutdown(Kernel::HLERequestContext& ctx) {
|
void IR_RST::Shutdown(Kernel::HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp(ctx, 0x03, 0, 0);
|
IPC::RequestParser rp(ctx, 0x03, 0, 0);
|
||||||
|
|
||||||
CoreTiming::UnscheduleEvent(update_callback_id, 0);
|
system.CoreTiming().UnscheduleEvent(update_callback_id, 0);
|
||||||
UnloadInputDevices();
|
UnloadInputDevices();
|
||||||
|
|
||||||
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
|
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
|
||||||
@ -145,7 +145,7 @@ void IR_RST::Shutdown(Kernel::HLERequestContext& ctx) {
|
|||||||
LOG_DEBUG(Service_IR, "called");
|
LOG_DEBUG(Service_IR, "called");
|
||||||
}
|
}
|
||||||
|
|
||||||
IR_RST::IR_RST(Core::System& system) : ServiceFramework("ir:rst", 1) {
|
IR_RST::IR_RST(Core::System& system) : ServiceFramework("ir:rst", 1), system(system) {
|
||||||
using namespace Kernel;
|
using namespace Kernel;
|
||||||
// Note: these two kernel objects are even available before Initialize service function is
|
// Note: these two kernel objects are even available before Initialize service function is
|
||||||
// called.
|
// called.
|
||||||
@ -154,10 +154,9 @@ IR_RST::IR_RST(Core::System& system) : ServiceFramework("ir:rst", 1) {
|
|||||||
MemoryRegion::BASE, "IRRST:SharedMemory");
|
MemoryRegion::BASE, "IRRST:SharedMemory");
|
||||||
update_event = system.Kernel().CreateEvent(ResetType::OneShot, "IRRST:UpdateEvent");
|
update_event = system.Kernel().CreateEvent(ResetType::OneShot, "IRRST:UpdateEvent");
|
||||||
|
|
||||||
update_callback_id =
|
update_callback_id = system.CoreTiming().RegisterEvent(
|
||||||
CoreTiming::RegisterEvent("IRRST:UpdateCallBack", [this](u64 userdata, s64 cycles_late) {
|
"IRRST:UpdateCallBack",
|
||||||
UpdateCallback(userdata, cycles_late);
|
[this](u64 userdata, s64 cycles_late) { UpdateCallback(userdata, cycles_late); });
|
||||||
});
|
|
||||||
|
|
||||||
static const FunctionInfo functions[] = {
|
static const FunctionInfo functions[] = {
|
||||||
{0x00010000, &IR_RST::GetHandles, "GetHandles"},
|
{0x00010000, &IR_RST::GetHandles, "GetHandles"},
|
||||||
|
@ -18,8 +18,8 @@ class Event;
|
|||||||
class SharedMemory;
|
class SharedMemory;
|
||||||
} // namespace Kernel
|
} // namespace Kernel
|
||||||
|
|
||||||
namespace CoreTiming {
|
namespace Core {
|
||||||
struct EventType;
|
struct TimingEventType;
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace Service::IR {
|
namespace Service::IR {
|
||||||
@ -77,10 +77,11 @@ private:
|
|||||||
void UnloadInputDevices();
|
void UnloadInputDevices();
|
||||||
void UpdateCallback(u64 userdata, s64 cycles_late);
|
void UpdateCallback(u64 userdata, s64 cycles_late);
|
||||||
|
|
||||||
|
Core::System& system;
|
||||||
Kernel::SharedPtr<Kernel::Event> update_event;
|
Kernel::SharedPtr<Kernel::Event> update_event;
|
||||||
Kernel::SharedPtr<Kernel::SharedMemory> shared_memory;
|
Kernel::SharedPtr<Kernel::SharedMemory> shared_memory;
|
||||||
u32 next_pad_index{0};
|
u32 next_pad_index{0};
|
||||||
CoreTiming::EventType* update_callback_id;
|
Core::TimingEventType* update_callback_id;
|
||||||
std::unique_ptr<Input::ButtonDevice> zl_button;
|
std::unique_ptr<Input::ButtonDevice> zl_button;
|
||||||
std::unique_ptr<Input::ButtonDevice> zr_button;
|
std::unique_ptr<Input::ButtonDevice> zr_button;
|
||||||
std::unique_ptr<Input::AnalogDevice> c_stick;
|
std::unique_ptr<Input::AnalogDevice> c_stick;
|
||||||
|
@ -14,10 +14,6 @@ class Event;
|
|||||||
class SharedMemory;
|
class SharedMemory;
|
||||||
} // namespace Kernel
|
} // namespace Kernel
|
||||||
|
|
||||||
namespace CoreTiming {
|
|
||||||
struct EventType;
|
|
||||||
};
|
|
||||||
|
|
||||||
namespace Service::IR {
|
namespace Service::IR {
|
||||||
|
|
||||||
class BufferManager;
|
class BufferManager;
|
||||||
|
@ -88,7 +88,7 @@ struct Node {
|
|||||||
static std::map<MacAddress, Node> node_map;
|
static std::map<MacAddress, Node> node_map;
|
||||||
|
|
||||||
// Event that will generate and send the 802.11 beacon frames.
|
// Event that will generate and send the 802.11 beacon frames.
|
||||||
static CoreTiming::EventType* beacon_broadcast_event;
|
static Core::TimingEventType* beacon_broadcast_event;
|
||||||
|
|
||||||
// Callback identifier for the OnWifiPacketReceived event.
|
// Callback identifier for the OnWifiPacketReceived event.
|
||||||
static Network::RoomMember::CallbackHandle<Network::WifiPacket> wifi_packet_received;
|
static Network::RoomMember::CallbackHandle<Network::WifiPacket> wifi_packet_received;
|
||||||
@ -955,7 +955,7 @@ void NWM_UDS::BeginHostingNetwork(Kernel::HLERequestContext& ctx) {
|
|||||||
connection_status_event->Signal();
|
connection_status_event->Signal();
|
||||||
|
|
||||||
// Start broadcasting the network, send a beacon frame every 102.4ms.
|
// Start broadcasting the network, send a beacon frame every 102.4ms.
|
||||||
CoreTiming::ScheduleEvent(msToCycles(DefaultBeaconInterval * MillisecondsPerTU),
|
system.CoreTiming().ScheduleEvent(msToCycles(DefaultBeaconInterval * MillisecondsPerTU),
|
||||||
beacon_broadcast_event, 0);
|
beacon_broadcast_event, 0);
|
||||||
|
|
||||||
LOG_DEBUG(Service_NWM, "An UDS network has been created.");
|
LOG_DEBUG(Service_NWM, "An UDS network has been created.");
|
||||||
@ -976,7 +976,7 @@ void NWM_UDS::DestroyNetwork(Kernel::HLERequestContext& ctx) {
|
|||||||
IPC::RequestParser rp(ctx, 0x08, 0, 0);
|
IPC::RequestParser rp(ctx, 0x08, 0, 0);
|
||||||
|
|
||||||
// Unschedule the beacon broadcast event.
|
// Unschedule the beacon broadcast event.
|
||||||
CoreTiming::UnscheduleEvent(beacon_broadcast_event, 0);
|
system.CoreTiming().UnscheduleEvent(beacon_broadcast_event, 0);
|
||||||
|
|
||||||
// Only a host can destroy
|
// Only a host can destroy
|
||||||
std::lock_guard<std::mutex> lock(connection_status_mutex);
|
std::lock_guard<std::mutex> lock(connection_status_mutex);
|
||||||
@ -1336,7 +1336,7 @@ void NWM_UDS::DecryptBeaconData(Kernel::HLERequestContext& ctx) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Sends a 802.11 beacon frame with information about the current network.
|
// Sends a 802.11 beacon frame with information about the current network.
|
||||||
static void BeaconBroadcastCallback(u64 userdata, s64 cycles_late) {
|
void NWM_UDS::BeaconBroadcastCallback(u64 userdata, s64 cycles_late) {
|
||||||
// Don't do anything if we're not actually hosting a network
|
// Don't do anything if we're not actually hosting a network
|
||||||
if (connection_status.status != static_cast<u32>(NetworkStatus::ConnectedAsHost))
|
if (connection_status.status != static_cast<u32>(NetworkStatus::ConnectedAsHost))
|
||||||
return;
|
return;
|
||||||
@ -1353,7 +1353,8 @@ static void BeaconBroadcastCallback(u64 userdata, s64 cycles_late) {
|
|||||||
SendPacket(packet);
|
SendPacket(packet);
|
||||||
|
|
||||||
// Start broadcasting the network, send a beacon frame every 102.4ms.
|
// Start broadcasting the network, send a beacon frame every 102.4ms.
|
||||||
CoreTiming::ScheduleEvent(msToCycles(DefaultBeaconInterval * MillisecondsPerTU) - cycles_late,
|
system.CoreTiming().ScheduleEvent(msToCycles(DefaultBeaconInterval * MillisecondsPerTU) -
|
||||||
|
cycles_late,
|
||||||
beacon_broadcast_event, 0);
|
beacon_broadcast_event, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1394,8 +1395,9 @@ NWM_UDS::NWM_UDS(Core::System& system) : ServiceFramework("nwm::UDS"), system(sy
|
|||||||
|
|
||||||
RegisterHandlers(functions);
|
RegisterHandlers(functions);
|
||||||
|
|
||||||
beacon_broadcast_event =
|
beacon_broadcast_event = system.CoreTiming().RegisterEvent(
|
||||||
CoreTiming::RegisterEvent("UDS::BeaconBroadcastCallback", BeaconBroadcastCallback);
|
"UDS::BeaconBroadcastCallback",
|
||||||
|
[this](u64 userdata, s64 cycles_late) { BeaconBroadcastCallback(userdata, cycles_late); });
|
||||||
|
|
||||||
CryptoPP::AutoSeededRandomPool rng;
|
CryptoPP::AutoSeededRandomPool rng;
|
||||||
auto mac = SharedPage::DefaultMac;
|
auto mac = SharedPage::DefaultMac;
|
||||||
@ -1428,7 +1430,7 @@ NWM_UDS::~NWM_UDS() {
|
|||||||
if (auto room_member = Network::GetRoomMember().lock())
|
if (auto room_member = Network::GetRoomMember().lock())
|
||||||
room_member->Unbind(wifi_packet_received);
|
room_member->Unbind(wifi_packet_received);
|
||||||
|
|
||||||
CoreTiming::UnscheduleEvent(beacon_broadcast_event, 0);
|
system.CoreTiming().UnscheduleEvent(beacon_broadcast_event, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Service::NWM
|
} // namespace Service::NWM
|
||||||
|
@ -352,6 +352,8 @@ private:
|
|||||||
* 2, 3: output buffer return descriptor & ptr
|
* 2, 3: output buffer return descriptor & ptr
|
||||||
*/
|
*/
|
||||||
void DecryptBeaconData(Kernel::HLERequestContext& ctx);
|
void DecryptBeaconData(Kernel::HLERequestContext& ctx);
|
||||||
|
|
||||||
|
void BeaconBroadcastCallback(u64 userdata, s64 cycles_late);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Service::NWM
|
} // namespace Service::NWM
|
||||||
|
@ -31,7 +31,7 @@ Regs g_regs;
|
|||||||
/// 268MHz CPU clocks / 60Hz frames per second
|
/// 268MHz CPU clocks / 60Hz frames per second
|
||||||
const u64 frame_ticks = static_cast<u64>(BASE_CLOCK_RATE_ARM11 / SCREEN_REFRESH_RATE);
|
const u64 frame_ticks = static_cast<u64>(BASE_CLOCK_RATE_ARM11 / SCREEN_REFRESH_RATE);
|
||||||
/// Event id for CoreTiming
|
/// Event id for CoreTiming
|
||||||
static CoreTiming::EventType* vblank_event;
|
static Core::TimingEventType* vblank_event;
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
inline void Read(T& var, const u32 raw_addr) {
|
inline void Read(T& var, const u32 raw_addr) {
|
||||||
@ -522,7 +522,7 @@ static void VBlankCallback(u64 userdata, s64 cycles_late) {
|
|||||||
Service::GSP::SignalInterrupt(Service::GSP::InterruptId::PDC1);
|
Service::GSP::SignalInterrupt(Service::GSP::InterruptId::PDC1);
|
||||||
|
|
||||||
// Reschedule recurrent event
|
// Reschedule recurrent event
|
||||||
CoreTiming::ScheduleEvent(frame_ticks - cycles_late, vblank_event);
|
Core::System::GetInstance().CoreTiming().ScheduleEvent(frame_ticks - cycles_late, vblank_event);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Initialize hardware
|
/// Initialize hardware
|
||||||
@ -555,8 +555,9 @@ void Init() {
|
|||||||
framebuffer_sub.color_format.Assign(Regs::PixelFormat::RGB8);
|
framebuffer_sub.color_format.Assign(Regs::PixelFormat::RGB8);
|
||||||
framebuffer_sub.active_fb = 0;
|
framebuffer_sub.active_fb = 0;
|
||||||
|
|
||||||
vblank_event = CoreTiming::RegisterEvent("GPU::VBlankCallback", VBlankCallback);
|
Core::Timing& timing = Core::System::GetInstance().CoreTiming();
|
||||||
CoreTiming::ScheduleEvent(frame_ticks, vblank_event);
|
vblank_event = timing.RegisterEvent("GPU::VBlankCallback", VBlankCallback);
|
||||||
|
timing.ScheduleEvent(frame_ticks, vblank_event);
|
||||||
|
|
||||||
LOG_DEBUG(HW_GPU, "initialized OK");
|
LOG_DEBUG(HW_GPU, "initialized OK");
|
||||||
}
|
}
|
||||||
|
@ -16,10 +16,10 @@ static Memory::PageTable* page_table = nullptr;
|
|||||||
TestEnvironment::TestEnvironment(bool mutable_memory_)
|
TestEnvironment::TestEnvironment(bool mutable_memory_)
|
||||||
: mutable_memory(mutable_memory_), test_memory(std::make_shared<TestMemory>(this)) {
|
: mutable_memory(mutable_memory_), test_memory(std::make_shared<TestMemory>(this)) {
|
||||||
|
|
||||||
CoreTiming::Init();
|
|
||||||
// HACK: some memory functions are currently referring kernel from the global instance,
|
// HACK: some memory functions are currently referring kernel from the global instance,
|
||||||
// so we need to create the kernel object there.
|
// so we need to create the kernel object there.
|
||||||
// Change this when all global states are eliminated.
|
// Change this when all global states are eliminated.
|
||||||
|
Core::System::GetInstance().timing = std::make_unique<Core::Timing>();
|
||||||
Core::System::GetInstance().kernel = std::make_unique<Kernel::KernelSystem>(0);
|
Core::System::GetInstance().kernel = std::make_unique<Kernel::KernelSystem>(0);
|
||||||
kernel = Core::System::GetInstance().kernel.get();
|
kernel = Core::System::GetInstance().kernel.get();
|
||||||
|
|
||||||
@ -38,8 +38,6 @@ TestEnvironment::TestEnvironment(bool mutable_memory_)
|
|||||||
TestEnvironment::~TestEnvironment() {
|
TestEnvironment::~TestEnvironment() {
|
||||||
Memory::UnmapRegion(*page_table, 0x80000000, 0x80000000);
|
Memory::UnmapRegion(*page_table, 0x80000000, 0x80000000);
|
||||||
Memory::UnmapRegion(*page_table, 0x00000000, 0x80000000);
|
Memory::UnmapRegion(*page_table, 0x00000000, 0x80000000);
|
||||||
|
|
||||||
CoreTiming::Shutdown();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TestEnvironment::SetMemory64(VAddr vaddr, u64 value) {
|
void TestEnvironment::SetMemory64(VAddr vaddr, u64 value) {
|
||||||
|
@ -28,100 +28,90 @@ void CallbackTemplate(u64 userdata, s64 cycles_late) {
|
|||||||
REQUIRE(lateness == cycles_late);
|
REQUIRE(lateness == cycles_late);
|
||||||
}
|
}
|
||||||
|
|
||||||
class ScopeInit final {
|
static void AdvanceAndCheck(Core::Timing& timing, u32 idx, int downcount, int expected_lateness = 0,
|
||||||
public:
|
|
||||||
ScopeInit() {
|
|
||||||
CoreTiming::Init();
|
|
||||||
}
|
|
||||||
~ScopeInit() {
|
|
||||||
CoreTiming::Shutdown();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
static void AdvanceAndCheck(u32 idx, int downcount, int expected_lateness = 0,
|
|
||||||
int cpu_downcount = 0) {
|
int cpu_downcount = 0) {
|
||||||
callbacks_ran_flags = 0;
|
callbacks_ran_flags = 0;
|
||||||
expected_callback = CB_IDS[idx];
|
expected_callback = CB_IDS[idx];
|
||||||
lateness = expected_lateness;
|
lateness = expected_lateness;
|
||||||
|
|
||||||
CoreTiming::AddTicks(CoreTiming::GetDowncount() -
|
timing.AddTicks(timing.GetDowncount() -
|
||||||
cpu_downcount); // Pretend we executed X cycles of instructions.
|
cpu_downcount); // Pretend we executed X cycles of instructions.
|
||||||
CoreTiming::Advance();
|
timing.Advance();
|
||||||
|
|
||||||
REQUIRE(decltype(callbacks_ran_flags)().set(idx) == callbacks_ran_flags);
|
REQUIRE(decltype(callbacks_ran_flags)().set(idx) == callbacks_ran_flags);
|
||||||
REQUIRE(downcount == CoreTiming::GetDowncount());
|
REQUIRE(downcount == timing.GetDowncount());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("CoreTiming[BasicOrder]", "[core]") {
|
TEST_CASE("CoreTiming[BasicOrder]", "[core]") {
|
||||||
ScopeInit guard;
|
Core::Timing timing;
|
||||||
|
|
||||||
CoreTiming::EventType* cb_a = CoreTiming::RegisterEvent("callbackA", CallbackTemplate<0>);
|
Core::TimingEventType* cb_a = timing.RegisterEvent("callbackA", CallbackTemplate<0>);
|
||||||
CoreTiming::EventType* cb_b = CoreTiming::RegisterEvent("callbackB", CallbackTemplate<1>);
|
Core::TimingEventType* cb_b = timing.RegisterEvent("callbackB", CallbackTemplate<1>);
|
||||||
CoreTiming::EventType* cb_c = CoreTiming::RegisterEvent("callbackC", CallbackTemplate<2>);
|
Core::TimingEventType* cb_c = timing.RegisterEvent("callbackC", CallbackTemplate<2>);
|
||||||
CoreTiming::EventType* cb_d = CoreTiming::RegisterEvent("callbackD", CallbackTemplate<3>);
|
Core::TimingEventType* cb_d = timing.RegisterEvent("callbackD", CallbackTemplate<3>);
|
||||||
CoreTiming::EventType* cb_e = CoreTiming::RegisterEvent("callbackE", CallbackTemplate<4>);
|
Core::TimingEventType* cb_e = timing.RegisterEvent("callbackE", CallbackTemplate<4>);
|
||||||
|
|
||||||
// Enter slice 0
|
// Enter slice 0
|
||||||
CoreTiming::Advance();
|
timing.Advance();
|
||||||
|
|
||||||
// D -> B -> C -> A -> E
|
// D -> B -> C -> A -> E
|
||||||
CoreTiming::ScheduleEvent(1000, cb_a, CB_IDS[0]);
|
timing.ScheduleEvent(1000, cb_a, CB_IDS[0]);
|
||||||
REQUIRE(1000 == CoreTiming::GetDowncount());
|
REQUIRE(1000 == timing.GetDowncount());
|
||||||
CoreTiming::ScheduleEvent(500, cb_b, CB_IDS[1]);
|
timing.ScheduleEvent(500, cb_b, CB_IDS[1]);
|
||||||
REQUIRE(500 == CoreTiming::GetDowncount());
|
REQUIRE(500 == timing.GetDowncount());
|
||||||
CoreTiming::ScheduleEvent(800, cb_c, CB_IDS[2]);
|
timing.ScheduleEvent(800, cb_c, CB_IDS[2]);
|
||||||
REQUIRE(500 == CoreTiming::GetDowncount());
|
REQUIRE(500 == timing.GetDowncount());
|
||||||
CoreTiming::ScheduleEvent(100, cb_d, CB_IDS[3]);
|
timing.ScheduleEvent(100, cb_d, CB_IDS[3]);
|
||||||
REQUIRE(100 == CoreTiming::GetDowncount());
|
REQUIRE(100 == timing.GetDowncount());
|
||||||
CoreTiming::ScheduleEvent(1200, cb_e, CB_IDS[4]);
|
timing.ScheduleEvent(1200, cb_e, CB_IDS[4]);
|
||||||
REQUIRE(100 == CoreTiming::GetDowncount());
|
REQUIRE(100 == timing.GetDowncount());
|
||||||
|
|
||||||
AdvanceAndCheck(3, 400);
|
AdvanceAndCheck(timing, 3, 400);
|
||||||
AdvanceAndCheck(1, 300);
|
AdvanceAndCheck(timing, 1, 300);
|
||||||
AdvanceAndCheck(2, 200);
|
AdvanceAndCheck(timing, 2, 200);
|
||||||
AdvanceAndCheck(0, 200);
|
AdvanceAndCheck(timing, 0, 200);
|
||||||
AdvanceAndCheck(4, MAX_SLICE_LENGTH);
|
AdvanceAndCheck(timing, 4, MAX_SLICE_LENGTH);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("CoreTiming[Threadsave]", "[core]") {
|
TEST_CASE("CoreTiming[Threadsave]", "[core]") {
|
||||||
ScopeInit guard;
|
Core::Timing timing;
|
||||||
|
|
||||||
CoreTiming::EventType* cb_a = CoreTiming::RegisterEvent("callbackA", CallbackTemplate<0>);
|
Core::TimingEventType* cb_a = timing.RegisterEvent("callbackA", CallbackTemplate<0>);
|
||||||
CoreTiming::EventType* cb_b = CoreTiming::RegisterEvent("callbackB", CallbackTemplate<1>);
|
Core::TimingEventType* cb_b = timing.RegisterEvent("callbackB", CallbackTemplate<1>);
|
||||||
CoreTiming::EventType* cb_c = CoreTiming::RegisterEvent("callbackC", CallbackTemplate<2>);
|
Core::TimingEventType* cb_c = timing.RegisterEvent("callbackC", CallbackTemplate<2>);
|
||||||
CoreTiming::EventType* cb_d = CoreTiming::RegisterEvent("callbackD", CallbackTemplate<3>);
|
Core::TimingEventType* cb_d = timing.RegisterEvent("callbackD", CallbackTemplate<3>);
|
||||||
CoreTiming::EventType* cb_e = CoreTiming::RegisterEvent("callbackE", CallbackTemplate<4>);
|
Core::TimingEventType* cb_e = timing.RegisterEvent("callbackE", CallbackTemplate<4>);
|
||||||
|
|
||||||
// Enter slice 0
|
// Enter slice 0
|
||||||
CoreTiming::Advance();
|
timing.Advance();
|
||||||
|
|
||||||
// D -> B -> C -> A -> E
|
// D -> B -> C -> A -> E
|
||||||
CoreTiming::ScheduleEventThreadsafe(1000, cb_a, CB_IDS[0]);
|
timing.ScheduleEventThreadsafe(1000, cb_a, CB_IDS[0]);
|
||||||
// Manually force since ScheduleEventThreadsafe doesn't call it
|
// Manually force since ScheduleEventThreadsafe doesn't call it
|
||||||
CoreTiming::ForceExceptionCheck(1000);
|
timing.ForceExceptionCheck(1000);
|
||||||
REQUIRE(1000 == CoreTiming::GetDowncount());
|
REQUIRE(1000 == timing.GetDowncount());
|
||||||
CoreTiming::ScheduleEventThreadsafe(500, cb_b, CB_IDS[1]);
|
timing.ScheduleEventThreadsafe(500, cb_b, CB_IDS[1]);
|
||||||
// Manually force since ScheduleEventThreadsafe doesn't call it
|
// Manually force since ScheduleEventThreadsafe doesn't call it
|
||||||
CoreTiming::ForceExceptionCheck(500);
|
timing.ForceExceptionCheck(500);
|
||||||
REQUIRE(500 == CoreTiming::GetDowncount());
|
REQUIRE(500 == timing.GetDowncount());
|
||||||
CoreTiming::ScheduleEventThreadsafe(800, cb_c, CB_IDS[2]);
|
timing.ScheduleEventThreadsafe(800, cb_c, CB_IDS[2]);
|
||||||
// Manually force since ScheduleEventThreadsafe doesn't call it
|
// Manually force since ScheduleEventThreadsafe doesn't call it
|
||||||
CoreTiming::ForceExceptionCheck(800);
|
timing.ForceExceptionCheck(800);
|
||||||
REQUIRE(500 == CoreTiming::GetDowncount());
|
REQUIRE(500 == timing.GetDowncount());
|
||||||
CoreTiming::ScheduleEventThreadsafe(100, cb_d, CB_IDS[3]);
|
timing.ScheduleEventThreadsafe(100, cb_d, CB_IDS[3]);
|
||||||
// Manually force since ScheduleEventThreadsafe doesn't call it
|
// Manually force since ScheduleEventThreadsafe doesn't call it
|
||||||
CoreTiming::ForceExceptionCheck(100);
|
timing.ForceExceptionCheck(100);
|
||||||
REQUIRE(100 == CoreTiming::GetDowncount());
|
REQUIRE(100 == timing.GetDowncount());
|
||||||
CoreTiming::ScheduleEventThreadsafe(1200, cb_e, CB_IDS[4]);
|
timing.ScheduleEventThreadsafe(1200, cb_e, CB_IDS[4]);
|
||||||
// Manually force since ScheduleEventThreadsafe doesn't call it
|
// Manually force since ScheduleEventThreadsafe doesn't call it
|
||||||
CoreTiming::ForceExceptionCheck(1200);
|
timing.ForceExceptionCheck(1200);
|
||||||
REQUIRE(100 == CoreTiming::GetDowncount());
|
REQUIRE(100 == timing.GetDowncount());
|
||||||
|
|
||||||
AdvanceAndCheck(3, 400);
|
AdvanceAndCheck(timing, 3, 400);
|
||||||
AdvanceAndCheck(1, 300);
|
AdvanceAndCheck(timing, 1, 300);
|
||||||
AdvanceAndCheck(2, 200);
|
AdvanceAndCheck(timing, 2, 200);
|
||||||
AdvanceAndCheck(0, 200);
|
AdvanceAndCheck(timing, 0, 200);
|
||||||
AdvanceAndCheck(4, MAX_SLICE_LENGTH);
|
AdvanceAndCheck(timing, 4, MAX_SLICE_LENGTH);
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace SharedSlotTest {
|
namespace SharedSlotTest {
|
||||||
@ -141,97 +131,98 @@ void FifoCallback(u64 userdata, s64 cycles_late) {
|
|||||||
TEST_CASE("CoreTiming[SharedSlot]", "[core]") {
|
TEST_CASE("CoreTiming[SharedSlot]", "[core]") {
|
||||||
using namespace SharedSlotTest;
|
using namespace SharedSlotTest;
|
||||||
|
|
||||||
ScopeInit guard;
|
Core::Timing timing;
|
||||||
|
|
||||||
CoreTiming::EventType* cb_a = CoreTiming::RegisterEvent("callbackA", FifoCallback<0>);
|
Core::TimingEventType* cb_a = timing.RegisterEvent("callbackA", FifoCallback<0>);
|
||||||
CoreTiming::EventType* cb_b = CoreTiming::RegisterEvent("callbackB", FifoCallback<1>);
|
Core::TimingEventType* cb_b = timing.RegisterEvent("callbackB", FifoCallback<1>);
|
||||||
CoreTiming::EventType* cb_c = CoreTiming::RegisterEvent("callbackC", FifoCallback<2>);
|
Core::TimingEventType* cb_c = timing.RegisterEvent("callbackC", FifoCallback<2>);
|
||||||
CoreTiming::EventType* cb_d = CoreTiming::RegisterEvent("callbackD", FifoCallback<3>);
|
Core::TimingEventType* cb_d = timing.RegisterEvent("callbackD", FifoCallback<3>);
|
||||||
CoreTiming::EventType* cb_e = CoreTiming::RegisterEvent("callbackE", FifoCallback<4>);
|
Core::TimingEventType* cb_e = timing.RegisterEvent("callbackE", FifoCallback<4>);
|
||||||
|
|
||||||
CoreTiming::ScheduleEvent(1000, cb_a, CB_IDS[0]);
|
timing.ScheduleEvent(1000, cb_a, CB_IDS[0]);
|
||||||
CoreTiming::ScheduleEvent(1000, cb_b, CB_IDS[1]);
|
timing.ScheduleEvent(1000, cb_b, CB_IDS[1]);
|
||||||
CoreTiming::ScheduleEvent(1000, cb_c, CB_IDS[2]);
|
timing.ScheduleEvent(1000, cb_c, CB_IDS[2]);
|
||||||
CoreTiming::ScheduleEvent(1000, cb_d, CB_IDS[3]);
|
timing.ScheduleEvent(1000, cb_d, CB_IDS[3]);
|
||||||
CoreTiming::ScheduleEvent(1000, cb_e, CB_IDS[4]);
|
timing.ScheduleEvent(1000, cb_e, CB_IDS[4]);
|
||||||
|
|
||||||
// Enter slice 0
|
// Enter slice 0
|
||||||
CoreTiming::Advance();
|
timing.Advance();
|
||||||
REQUIRE(1000 == CoreTiming::GetDowncount());
|
REQUIRE(1000 == timing.GetDowncount());
|
||||||
|
|
||||||
callbacks_ran_flags = 0;
|
callbacks_ran_flags = 0;
|
||||||
counter = 0;
|
counter = 0;
|
||||||
lateness = 0;
|
lateness = 0;
|
||||||
CoreTiming::AddTicks(CoreTiming::GetDowncount());
|
timing.AddTicks(timing.GetDowncount());
|
||||||
CoreTiming::Advance();
|
timing.Advance();
|
||||||
REQUIRE(MAX_SLICE_LENGTH == CoreTiming::GetDowncount());
|
REQUIRE(MAX_SLICE_LENGTH == timing.GetDowncount());
|
||||||
REQUIRE(0x1FULL == callbacks_ran_flags.to_ullong());
|
REQUIRE(0x1FULL == callbacks_ran_flags.to_ullong());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("CoreTiming[PredictableLateness]", "[core]") {
|
TEST_CASE("CoreTiming[PredictableLateness]", "[core]") {
|
||||||
ScopeInit guard;
|
Core::Timing timing;
|
||||||
|
|
||||||
CoreTiming::EventType* cb_a = CoreTiming::RegisterEvent("callbackA", CallbackTemplate<0>);
|
Core::TimingEventType* cb_a = timing.RegisterEvent("callbackA", CallbackTemplate<0>);
|
||||||
CoreTiming::EventType* cb_b = CoreTiming::RegisterEvent("callbackB", CallbackTemplate<1>);
|
Core::TimingEventType* cb_b = timing.RegisterEvent("callbackB", CallbackTemplate<1>);
|
||||||
|
|
||||||
// Enter slice 0
|
// Enter slice 0
|
||||||
CoreTiming::Advance();
|
timing.Advance();
|
||||||
|
|
||||||
CoreTiming::ScheduleEvent(100, cb_a, CB_IDS[0]);
|
timing.ScheduleEvent(100, cb_a, CB_IDS[0]);
|
||||||
CoreTiming::ScheduleEvent(200, cb_b, CB_IDS[1]);
|
timing.ScheduleEvent(200, cb_b, CB_IDS[1]);
|
||||||
|
|
||||||
AdvanceAndCheck(0, 90, 10, -10); // (100 - 10)
|
AdvanceAndCheck(timing, 0, 90, 10, -10); // (100 - 10)
|
||||||
AdvanceAndCheck(1, MAX_SLICE_LENGTH, 50, -50);
|
AdvanceAndCheck(timing, 1, MAX_SLICE_LENGTH, 50, -50);
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace ChainSchedulingTest {
|
namespace ChainSchedulingTest {
|
||||||
static int reschedules = 0;
|
static int reschedules = 0;
|
||||||
|
|
||||||
static void RescheduleCallback(u64 userdata, s64 cycles_late) {
|
static void RescheduleCallback(Core::Timing& timing, u64 userdata, s64 cycles_late) {
|
||||||
--reschedules;
|
--reschedules;
|
||||||
REQUIRE(reschedules >= 0);
|
REQUIRE(reschedules >= 0);
|
||||||
REQUIRE(lateness == cycles_late);
|
REQUIRE(lateness == cycles_late);
|
||||||
|
|
||||||
if (reschedules > 0)
|
if (reschedules > 0)
|
||||||
CoreTiming::ScheduleEvent(1000, reinterpret_cast<CoreTiming::EventType*>(userdata),
|
timing.ScheduleEvent(1000, reinterpret_cast<Core::TimingEventType*>(userdata), userdata);
|
||||||
userdata);
|
|
||||||
}
|
}
|
||||||
} // namespace ChainSchedulingTest
|
} // namespace ChainSchedulingTest
|
||||||
|
|
||||||
TEST_CASE("CoreTiming[ChainScheduling]", "[core]") {
|
TEST_CASE("CoreTiming[ChainScheduling]", "[core]") {
|
||||||
using namespace ChainSchedulingTest;
|
using namespace ChainSchedulingTest;
|
||||||
|
|
||||||
ScopeInit guard;
|
Core::Timing timing;
|
||||||
|
|
||||||
CoreTiming::EventType* cb_a = CoreTiming::RegisterEvent("callbackA", CallbackTemplate<0>);
|
Core::TimingEventType* cb_a = timing.RegisterEvent("callbackA", CallbackTemplate<0>);
|
||||||
CoreTiming::EventType* cb_b = CoreTiming::RegisterEvent("callbackB", CallbackTemplate<1>);
|
Core::TimingEventType* cb_b = timing.RegisterEvent("callbackB", CallbackTemplate<1>);
|
||||||
CoreTiming::EventType* cb_c = CoreTiming::RegisterEvent("callbackC", CallbackTemplate<2>);
|
Core::TimingEventType* cb_c = timing.RegisterEvent("callbackC", CallbackTemplate<2>);
|
||||||
CoreTiming::EventType* cb_rs =
|
Core::TimingEventType* cb_rs =
|
||||||
CoreTiming::RegisterEvent("callbackReschedule", RescheduleCallback);
|
timing.RegisterEvent("callbackReschedule", [&timing](u64 userdata, s64 cycles_late) {
|
||||||
|
RescheduleCallback(timing, userdata, cycles_late);
|
||||||
|
});
|
||||||
|
|
||||||
// Enter slice 0
|
// Enter slice 0
|
||||||
CoreTiming::Advance();
|
timing.Advance();
|
||||||
|
|
||||||
CoreTiming::ScheduleEvent(800, cb_a, CB_IDS[0]);
|
timing.ScheduleEvent(800, cb_a, CB_IDS[0]);
|
||||||
CoreTiming::ScheduleEvent(1000, cb_b, CB_IDS[1]);
|
timing.ScheduleEvent(1000, cb_b, CB_IDS[1]);
|
||||||
CoreTiming::ScheduleEvent(2200, cb_c, CB_IDS[2]);
|
timing.ScheduleEvent(2200, cb_c, CB_IDS[2]);
|
||||||
CoreTiming::ScheduleEvent(1000, cb_rs, reinterpret_cast<u64>(cb_rs));
|
timing.ScheduleEvent(1000, cb_rs, reinterpret_cast<u64>(cb_rs));
|
||||||
REQUIRE(800 == CoreTiming::GetDowncount());
|
REQUIRE(800 == timing.GetDowncount());
|
||||||
|
|
||||||
reschedules = 3;
|
reschedules = 3;
|
||||||
AdvanceAndCheck(0, 200); // cb_a
|
AdvanceAndCheck(timing, 0, 200); // cb_a
|
||||||
AdvanceAndCheck(1, 1000); // cb_b, cb_rs
|
AdvanceAndCheck(timing, 1, 1000); // cb_b, cb_rs
|
||||||
REQUIRE(2 == reschedules);
|
REQUIRE(2 == reschedules);
|
||||||
|
|
||||||
CoreTiming::AddTicks(CoreTiming::GetDowncount());
|
timing.AddTicks(timing.GetDowncount());
|
||||||
CoreTiming::Advance(); // cb_rs
|
timing.Advance(); // cb_rs
|
||||||
REQUIRE(1 == reschedules);
|
REQUIRE(1 == reschedules);
|
||||||
REQUIRE(200 == CoreTiming::GetDowncount());
|
REQUIRE(200 == timing.GetDowncount());
|
||||||
|
|
||||||
AdvanceAndCheck(2, 800); // cb_c
|
AdvanceAndCheck(timing, 2, 800); // cb_c
|
||||||
|
|
||||||
CoreTiming::AddTicks(CoreTiming::GetDowncount());
|
timing.AddTicks(timing.GetDowncount());
|
||||||
CoreTiming::Advance(); // cb_rs
|
timing.Advance(); // cb_rs
|
||||||
REQUIRE(0 == reschedules);
|
REQUIRE(0 == reschedules);
|
||||||
REQUIRE(MAX_SLICE_LENGTH == CoreTiming::GetDowncount());
|
REQUIRE(MAX_SLICE_LENGTH == timing.GetDowncount());
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
// Refer to the license.txt file included.
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
#include <catch2/catch.hpp>
|
#include <catch2/catch.hpp>
|
||||||
|
#include "core/core.h"
|
||||||
#include "core/core_timing.h"
|
#include "core/core_timing.h"
|
||||||
#include "core/hle/ipc.h"
|
#include "core/hle/ipc.h"
|
||||||
#include "core/hle/kernel/client_port.h"
|
#include "core/hle/kernel/client_port.h"
|
||||||
@ -20,7 +21,8 @@ static SharedPtr<Object> MakeObject(Kernel::KernelSystem& kernel) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("HLERequestContext::PopulateFromIncomingCommandBuffer", "[core][kernel]") {
|
TEST_CASE("HLERequestContext::PopulateFromIncomingCommandBuffer", "[core][kernel]") {
|
||||||
CoreTiming::Init();
|
// HACK: see comments of member timing
|
||||||
|
Core::System::GetInstance().timing = std::make_unique<Core::Timing>();
|
||||||
Kernel::KernelSystem kernel(0);
|
Kernel::KernelSystem kernel(0);
|
||||||
auto session = std::get<SharedPtr<ServerSession>>(kernel.CreateSessionPair());
|
auto session = std::get<SharedPtr<ServerSession>>(kernel.CreateSessionPair());
|
||||||
HLERequestContext context(std::move(session));
|
HLERequestContext context(std::move(session));
|
||||||
@ -227,12 +229,11 @@ TEST_CASE("HLERequestContext::PopulateFromIncomingCommandBuffer", "[core][kernel
|
|||||||
REQUIRE(process->vm_manager.UnmapRange(target_address_mapped, buffer_mapped->size()) ==
|
REQUIRE(process->vm_manager.UnmapRange(target_address_mapped, buffer_mapped->size()) ==
|
||||||
RESULT_SUCCESS);
|
RESULT_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
CoreTiming::Shutdown();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("HLERequestContext::WriteToOutgoingCommandBuffer", "[core][kernel]") {
|
TEST_CASE("HLERequestContext::WriteToOutgoingCommandBuffer", "[core][kernel]") {
|
||||||
CoreTiming::Init();
|
// HACK: see comments of member timing
|
||||||
|
Core::System::GetInstance().timing = std::make_unique<Core::Timing>();
|
||||||
Kernel::KernelSystem kernel(0);
|
Kernel::KernelSystem kernel(0);
|
||||||
auto session = std::get<SharedPtr<ServerSession>>(kernel.CreateSessionPair());
|
auto session = std::get<SharedPtr<ServerSession>>(kernel.CreateSessionPair());
|
||||||
HLERequestContext context(std::move(session));
|
HLERequestContext context(std::move(session));
|
||||||
@ -369,8 +370,6 @@ TEST_CASE("HLERequestContext::WriteToOutgoingCommandBuffer", "[core][kernel]") {
|
|||||||
REQUIRE(process->vm_manager.UnmapRange(target_address, output_buffer->size()) ==
|
REQUIRE(process->vm_manager.UnmapRange(target_address, output_buffer->size()) ==
|
||||||
RESULT_SUCCESS);
|
RESULT_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
CoreTiming::Shutdown();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Kernel
|
} // namespace Kernel
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
// Refer to the license.txt file included.
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
#include <catch2/catch.hpp>
|
#include <catch2/catch.hpp>
|
||||||
|
#include "core/core.h"
|
||||||
#include "core/core_timing.h"
|
#include "core/core_timing.h"
|
||||||
#include "core/hle/kernel/memory.h"
|
#include "core/hle/kernel/memory.h"
|
||||||
#include "core/hle/kernel/process.h"
|
#include "core/hle/kernel/process.h"
|
||||||
@ -10,7 +11,8 @@
|
|||||||
#include "core/memory.h"
|
#include "core/memory.h"
|
||||||
|
|
||||||
TEST_CASE("Memory::IsValidVirtualAddress", "[core][memory]") {
|
TEST_CASE("Memory::IsValidVirtualAddress", "[core][memory]") {
|
||||||
CoreTiming::Init();
|
// HACK: see comments of member timing
|
||||||
|
Core::System::GetInstance().timing = std::make_unique<Core::Timing>();
|
||||||
Kernel::KernelSystem kernel(0);
|
Kernel::KernelSystem kernel(0);
|
||||||
SECTION("these regions should not be mapped on an empty process") {
|
SECTION("these regions should not be mapped on an empty process") {
|
||||||
auto process = kernel.CreateProcess(kernel.CreateCodeSet("", 0));
|
auto process = kernel.CreateProcess(kernel.CreateCodeSet("", 0));
|
||||||
@ -51,6 +53,4 @@ TEST_CASE("Memory::IsValidVirtualAddress", "[core][memory]") {
|
|||||||
process->vm_manager.UnmapRange(Memory::CONFIG_MEMORY_VADDR, Memory::CONFIG_MEMORY_SIZE);
|
process->vm_manager.UnmapRange(Memory::CONFIG_MEMORY_VADDR, Memory::CONFIG_MEMORY_SIZE);
|
||||||
CHECK(Memory::IsValidVirtualAddress(*process, Memory::CONFIG_MEMORY_VADDR) == false);
|
CHECK(Memory::IsValidVirtualAddress(*process, Memory::CONFIG_MEMORY_VADDR) == false);
|
||||||
}
|
}
|
||||||
|
|
||||||
CoreTiming::Shutdown();
|
|
||||||
}
|
}
|
||||||
|
@ -146,7 +146,8 @@ void RendererOpenGL::SwapBuffers() {
|
|||||||
render_window.PollEvents();
|
render_window.PollEvents();
|
||||||
render_window.SwapBuffers();
|
render_window.SwapBuffers();
|
||||||
|
|
||||||
Core::System::GetInstance().frame_limiter.DoFrameLimiting(CoreTiming::GetGlobalTimeUs());
|
Core::System::GetInstance().frame_limiter.DoFrameLimiting(
|
||||||
|
Core::System::GetInstance().CoreTiming().GetGlobalTimeUs());
|
||||||
Core::System::GetInstance().perf_stats.BeginSystemFrame();
|
Core::System::GetInstance().perf_stats.BeginSystemFrame();
|
||||||
|
|
||||||
prev_state.Apply();
|
prev_state.Apply();
|
||||||
|
Loading…
Reference in New Issue
Block a user