diff --git a/appveyor.yml b/appveyor.yml index 7e749d774..5f6b35847 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -5,7 +5,7 @@ cache: - C:\ProgramData\chocolatey\bin -> appveyor.yml - C:\ProgramData\chocolatey\lib -> appveyor.yml -os: Previous Visual Studio 2017 +os: Visual Studio 2017 environment: # Tell msys2 to add mingw64 to the path diff --git a/src/core/core_timing.h b/src/core/core_timing.h index 897350801..3d82b49c0 100644 --- a/src/core/core_timing.h +++ b/src/core/core_timing.h @@ -5,8 +5,10 @@ #pragma once #include +#include #include #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 // in main CPU clock cycles. @@ -21,35 +23,87 @@ // inside callback: // 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::max() / 268111856; extern int g_clock_rate_arm11; 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(ms) / 1000; } inline s64 msToCycles(float ms) { - return (s64)(g_clock_rate_arm11 * ms * (0.001f)); + return static_cast(g_clock_rate_arm11 * ms * (0.001f)); } inline s64 msToCycles(double ms) { - return (s64)(g_clock_rate_arm11 * ms * (0.001)); + return static_cast(g_clock_rate_arm11 * ms * (0.001)); } inline s64 usToCycles(float us) { - return (s64)(g_clock_rate_arm11 * us * (0.000001f)); + return static_cast(g_clock_rate_arm11 * us * (0.000001f)); } inline s64 usToCycles(int us) { - return (g_clock_rate_arm11 / 1000000 * (s64)us); + return (g_clock_rate_arm11 * static_cast(us) / 1000000); } 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::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) { - 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::max(); + } else if (us > MAX_VALUE_TO_MULTIPLY) { + LOG_DEBUG(Core_Timing, "Time very big, do rounding"); + return (g_clock_rate_arm11 * static_cast(us / 1000000)); + } + return (g_clock_rate_arm11 * static_cast(us) / 1000000); +} + +inline s64 nsToCycles(float ns) { + return static_cast(g_clock_rate_arm11 * ns * (0.000000001f)); +} + +inline s64 nsToCycles(int ns) { + return (g_clock_rate_arm11 * static_cast(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::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::max(); + } else if (ns > MAX_VALUE_TO_MULTIPLY) { + LOG_DEBUG(Core_Timing, "Time very big, do rounding"); + return (g_clock_rate_arm11 * static_cast(ns / 1000000000)); + } + return (g_clock_rate_arm11 * static_cast(ns) / 1000000000); +} + +inline u64 cyclesToNs(s64 cycles) { + return cycles / (g_clock_rate_arm11 / 1000000000); } inline s64 cyclesToUs(s64 cycles) { diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index 1d77fb582..42997f360 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -266,8 +266,7 @@ void Thread::WakeAfterDelay(s64 nanoseconds) { if (nanoseconds == -1) return; - u64 microseconds = nanoseconds / 1000; - CoreTiming::ScheduleEvent(usToCycles(microseconds), ThreadWakeupEventType, callback_handle); + CoreTiming::ScheduleEvent(nsToCycles(nanoseconds), ThreadWakeupEventType, callback_handle); } void Thread::ResumeFromWait() { diff --git a/src/core/hle/kernel/timer.cpp b/src/core/hle/kernel/timer.cpp index d7ec93672..35524807a 100644 --- a/src/core/hle/kernel/timer.cpp +++ b/src/core/hle/kernel/timer.cpp @@ -57,8 +57,7 @@ void Timer::Set(s64 initial, s64 interval) { // Immediately invoke the callback Signal(0); } else { - u64 initial_microseconds = initial / 1000; - CoreTiming::ScheduleEvent(usToCycles(initial_microseconds), timer_callback_event_type, + CoreTiming::ScheduleEvent(nsToCycles(initial), timer_callback_event_type, callback_handle); } } @@ -88,8 +87,7 @@ void Timer::Signal(int cycles_late) { if (interval_delay != 0) { // Reschedule the timer with the interval delay - u64 interval_microseconds = interval_delay / 1000; - CoreTiming::ScheduleEvent(usToCycles(interval_microseconds) - cycles_late, + CoreTiming::ScheduleEvent(nsToCycles(interval_delay) - cycles_late, timer_callback_event_type, callback_handle); } }