mirror of
https://github.com/citra-emu/citra.git
synced 2024-11-30 16:20:07 +00:00
CoreTiming: Fix ARM11 clock rate, add ability to use nanoseconds in core timing, add overflow handling
This commit is contained in:
parent
b6dd8ef874
commit
e4d51b8ff4
@ -5,7 +5,7 @@ cache:
|
|||||||
- C:\ProgramData\chocolatey\bin -> appveyor.yml
|
- C:\ProgramData\chocolatey\bin -> appveyor.yml
|
||||||
- C:\ProgramData\chocolatey\lib -> appveyor.yml
|
- C:\ProgramData\chocolatey\lib -> appveyor.yml
|
||||||
|
|
||||||
os: Previous Visual Studio 2017
|
os: Visual Studio 2017
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
# Tell msys2 to add mingw64 to the path
|
# Tell msys2 to add mingw64 to the path
|
||||||
|
@ -5,8 +5,10 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
#include <limits>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
|
#include "common/logging/log.h"
|
||||||
|
|
||||||
// This is a system to schedule events into the emulated machine's future. Time is measured
|
// This is a system to schedule events into the emulated machine's future. Time is measured
|
||||||
// in main CPU clock cycles.
|
// in main CPU clock cycles.
|
||||||
@ -21,35 +23,87 @@
|
|||||||
// inside callback:
|
// inside callback:
|
||||||
// ScheduleEvent(periodInCycles - cycles_late, callback, "whatever")
|
// ScheduleEvent(periodInCycles - cycles_late, callback, "whatever")
|
||||||
|
|
||||||
constexpr int BASE_CLOCK_RATE_ARM11 = 268123480;
|
// The actual timing is 268,111,855.956 Hz
|
||||||
|
constexpr s64 BASE_CLOCK_RATE_ARM11 = 268111856;
|
||||||
|
|
||||||
|
constexpr u64 MAX_VALUE_TO_MULTIPLY = std::numeric_limits<s64>::max() / 268111856;
|
||||||
extern int g_clock_rate_arm11;
|
extern int g_clock_rate_arm11;
|
||||||
|
|
||||||
inline s64 msToCycles(int ms) {
|
inline s64 msToCycles(int ms) {
|
||||||
return (s64)g_clock_rate_arm11 / 1000 * ms;
|
// since mx is int there is no way to overflow
|
||||||
|
return g_clock_rate_arm11 * static_cast<s64>(ms) / 1000;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline s64 msToCycles(float ms) {
|
inline s64 msToCycles(float ms) {
|
||||||
return (s64)(g_clock_rate_arm11 * ms * (0.001f));
|
return static_cast<s64>(g_clock_rate_arm11 * ms * (0.001f));
|
||||||
}
|
}
|
||||||
|
|
||||||
inline s64 msToCycles(double ms) {
|
inline s64 msToCycles(double ms) {
|
||||||
return (s64)(g_clock_rate_arm11 * ms * (0.001));
|
return static_cast<s64>(g_clock_rate_arm11 * ms * (0.001));
|
||||||
}
|
}
|
||||||
|
|
||||||
inline s64 usToCycles(float us) {
|
inline s64 usToCycles(float us) {
|
||||||
return (s64)(g_clock_rate_arm11 * us * (0.000001f));
|
return static_cast<s64>(g_clock_rate_arm11 * us * (0.000001f));
|
||||||
}
|
}
|
||||||
|
|
||||||
inline s64 usToCycles(int us) {
|
inline s64 usToCycles(int us) {
|
||||||
return (g_clock_rate_arm11 / 1000000 * (s64)us);
|
return (g_clock_rate_arm11 * static_cast<s64>(us) / 1000000);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline s64 usToCycles(s64 us) {
|
inline s64 usToCycles(s64 us) {
|
||||||
return (g_clock_rate_arm11 / 1000000 * us);
|
if ((us / 1000000) > MAX_VALUE_TO_MULTIPLY) {
|
||||||
|
LOG_ERROR(Core_Timing, "Integer overflow, use max value");
|
||||||
|
return std::numeric_limits<s64>::max();
|
||||||
|
} else if (us > MAX_VALUE_TO_MULTIPLY) {
|
||||||
|
LOG_DEBUG(Core_Timing, "Time very big, do rounding");
|
||||||
|
return (g_clock_rate_arm11 * (us / 1000000));
|
||||||
|
}
|
||||||
|
return (g_clock_rate_arm11 * us / 1000000);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline s64 usToCycles(u64 us) {
|
inline s64 usToCycles(u64 us) {
|
||||||
return (s64)(g_clock_rate_arm11 / 1000000 * us);
|
if ((us / 1000000) > MAX_VALUE_TO_MULTIPLY) {
|
||||||
|
LOG_ERROR(Core_Timing, "Integer overflow, use max value");
|
||||||
|
return std::numeric_limits<s64>::max();
|
||||||
|
} else if (us > MAX_VALUE_TO_MULTIPLY) {
|
||||||
|
LOG_DEBUG(Core_Timing, "Time very big, do rounding");
|
||||||
|
return (g_clock_rate_arm11 * static_cast<s64>(us / 1000000));
|
||||||
|
}
|
||||||
|
return (g_clock_rate_arm11 * static_cast<s64>(us) / 1000000);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline s64 nsToCycles(float ns) {
|
||||||
|
return static_cast<s64>(g_clock_rate_arm11 * ns * (0.000000001f));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline s64 nsToCycles(int ns) {
|
||||||
|
return (g_clock_rate_arm11 * static_cast<s64>(ns) / 1000000000);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline s64 nsToCycles(s64 ns) {
|
||||||
|
if ((ns / 1000000000) > MAX_VALUE_TO_MULTIPLY) {
|
||||||
|
LOG_ERROR(Core_Timing, "Integer overflow, use max value");
|
||||||
|
return std::numeric_limits<s64>::max();
|
||||||
|
} else if (ns > MAX_VALUE_TO_MULTIPLY) {
|
||||||
|
LOG_DEBUG(Core_Timing, "Time very big, do rounding");
|
||||||
|
return (g_clock_rate_arm11 * (ns / 1000000000));
|
||||||
|
}
|
||||||
|
return (g_clock_rate_arm11 * ns / 1000000000);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline s64 nsToCycles(u64 ns) {
|
||||||
|
if ((ns / 1000000000) > MAX_VALUE_TO_MULTIPLY) {
|
||||||
|
LOG_ERROR(Core_Timing, "Integer overflow, use max value");
|
||||||
|
return std::numeric_limits<s64>::max();
|
||||||
|
} else if (ns > MAX_VALUE_TO_MULTIPLY) {
|
||||||
|
LOG_DEBUG(Core_Timing, "Time very big, do rounding");
|
||||||
|
return (g_clock_rate_arm11 * static_cast<s64>(ns / 1000000000));
|
||||||
|
}
|
||||||
|
return (g_clock_rate_arm11 * static_cast<s64>(ns) / 1000000000);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline u64 cyclesToNs(s64 cycles) {
|
||||||
|
return cycles / (g_clock_rate_arm11 / 1000000000);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline s64 cyclesToUs(s64 cycles) {
|
inline s64 cyclesToUs(s64 cycles) {
|
||||||
|
@ -266,8 +266,7 @@ void Thread::WakeAfterDelay(s64 nanoseconds) {
|
|||||||
if (nanoseconds == -1)
|
if (nanoseconds == -1)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
u64 microseconds = nanoseconds / 1000;
|
CoreTiming::ScheduleEvent(nsToCycles(nanoseconds), ThreadWakeupEventType, callback_handle);
|
||||||
CoreTiming::ScheduleEvent(usToCycles(microseconds), ThreadWakeupEventType, callback_handle);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Thread::ResumeFromWait() {
|
void Thread::ResumeFromWait() {
|
||||||
|
@ -57,8 +57,7 @@ void Timer::Set(s64 initial, s64 interval) {
|
|||||||
// Immediately invoke the callback
|
// Immediately invoke the callback
|
||||||
Signal(0);
|
Signal(0);
|
||||||
} else {
|
} else {
|
||||||
u64 initial_microseconds = initial / 1000;
|
CoreTiming::ScheduleEvent(nsToCycles(initial), timer_callback_event_type,
|
||||||
CoreTiming::ScheduleEvent(usToCycles(initial_microseconds), timer_callback_event_type,
|
|
||||||
callback_handle);
|
callback_handle);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -88,8 +87,7 @@ void Timer::Signal(int cycles_late) {
|
|||||||
|
|
||||||
if (interval_delay != 0) {
|
if (interval_delay != 0) {
|
||||||
// Reschedule the timer with the interval delay
|
// Reschedule the timer with the interval delay
|
||||||
u64 interval_microseconds = interval_delay / 1000;
|
CoreTiming::ScheduleEvent(nsToCycles(interval_delay) - cycles_late,
|
||||||
CoreTiming::ScheduleEvent(usToCycles(interval_microseconds) - cycles_late,
|
|
||||||
timer_callback_event_type, callback_handle);
|
timer_callback_event_type, callback_handle);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user