#pragma once #include #include #include #include "helpers.hpp" #include "logger.hpp" struct Scheduler { enum class EventType { VBlank = 0, // End of frame event UpdateTimers = 1, // Update kernel timer objects RunDSP = 2, // Make the emulated DSP run for one audio frame SignalY2R = 3, // Signal that a Y2R conversion has finished Panic = 4, // Dummy event that is always pending and should never be triggered (Timestamp = UINT64_MAX) TotalNumberOfEvents // How many event types do we have in total? }; static constexpr usize totalNumberOfEvents = static_cast(EventType::TotalNumberOfEvents); static constexpr u64 arm11Clock = 268111856; template using EventMap = boost::container::flat_multimap, boost::container::static_vector, size>>; EventMap events; u64 currentTimestamp = 0; u64 nextTimestamp = 0; // Set nextTimestamp to the timestamp of the next event void updateNextTimestamp() { nextTimestamp = events.cbegin()->first; } void addEvent(EventType type, u64 timestamp) { events.emplace(timestamp, type); updateNextTimestamp(); } void removeEvent(EventType type) { for (auto it = events.begin(); it != events.end(); it++) { // Find first event of type "type" and remove it. // Our scheduler shouldn't have duplicate events, so it's safe to exit when an event is found if (it->second == type) { events.erase(it); updateNextTimestamp(); break; } } }; void reset() { currentTimestamp = 0; // Clear any pending events events.clear(); addEvent(Scheduler::EventType::VBlank, arm11Clock / 60); // Add a dummy event to always keep the scheduler non-empty addEvent(EventType::Panic, std::numeric_limits::max()); } private: static constexpr u64 MAX_VALUE_TO_MULTIPLY = std::numeric_limits::max() / arm11Clock; public: // Function for converting time units to cycles for various kernel functions // Thank you Citra static constexpr s64 nsToCycles(float ns) { return s64(arm11Clock * (0.000000001f) * ns); } static constexpr s64 nsToCycles(int ns) { return arm11Clock * s64(ns) / 1000000000; } static constexpr s64 nsToCycles(s64 ns) { if (ns / 1000000000 > static_cast(MAX_VALUE_TO_MULTIPLY)) { return std::numeric_limits::max(); } if (ns > static_cast(MAX_VALUE_TO_MULTIPLY)) { return arm11Clock * (ns / 1000000000); } return (arm11Clock * ns) / 1000000000; } static constexpr s64 nsToCycles(u64 ns) { if (ns / 1000000000 > MAX_VALUE_TO_MULTIPLY) { return std::numeric_limits::max(); } if (ns > MAX_VALUE_TO_MULTIPLY) { return arm11Clock * (s64(ns) / 1000000000); } return (arm11Clock * s64(ns)) / 1000000000; } };