From 3eb504d67cd3a78ece552c86377479577b669da5 Mon Sep 17 00:00:00 2001 From: ApfelTeeSaft <91074565+ApfelTeeSaft@users.noreply.github.com> Date: Mon, 6 Jul 2026 17:46:23 +0200 Subject: [PATCH] feat: make per instruction cycle table optional makes the nov 2022 change regarding the instruction cycle table thing toggleable inside Debug->CPU Settings. --- CMakeModules/GenerateSettingKeys.cmake | 1 + src/audio_core/hle/source.cpp | 11 +++ src/citra_qt/configuration/config.cpp | 2 + .../configuration/configure_debug.cpp | 11 +++ src/citra_qt/configuration/configure_debug.h | 7 +- src/citra_qt/configuration/configure_debug.ui | 80 +++++++++++-------- src/common/settings.cpp | 2 + src/common/settings.h | 2 + src/core/arm/dynarmic/arm_dynarmic.cpp | 4 + 9 files changed, 84 insertions(+), 36 deletions(-) diff --git a/CMakeModules/GenerateSettingKeys.cmake b/CMakeModules/GenerateSettingKeys.cmake index b7be40f51..986682059 100644 --- a/CMakeModules/GenerateSettingKeys.cmake +++ b/CMakeModules/GenerateSettingKeys.cmake @@ -9,6 +9,7 @@ foreach(KEY IN ITEMS "use_artic_base_controller" "enable_gamemode" "use_cpu_jit" + "cpu_legacy_instruction_ticks" "cpu_clock_percentage" "is_new_3ds" "lle_applets" diff --git a/src/audio_core/hle/source.cpp b/src/audio_core/hle/source.cpp index 018368704..968552fce 100644 --- a/src/audio_core/hle/source.cpp +++ b/src/audio_core/hle/source.cpp @@ -436,6 +436,17 @@ bool Source::DequeueBuffer() { // Because our interpolation consumes samples instead of using an index, // let's just consume the samples up to the current sample number. + // Guard like the partial-embedded-buffer path in ParseConfig: a play_position + // beyond the decoded length would otherwise erase past the end (undefined + // behavior). Log when this triggers so affected titles can be identified. + if (state.current_sample_number > state.current_buffer.size()) { + LOG_WARNING(Audio_DSP, + "source_id={} buffer_id={} play_position={} exceeds decoded buffer " + "size={}; resetting to 0", + source_id, buf.buffer_id, state.current_sample_number, + state.current_buffer.size()); + state.current_sample_number = 0; + } state.current_buffer.erase( state.current_buffer.begin(), std::next(state.current_buffer.begin(), state.current_sample_number)); diff --git a/src/citra_qt/configuration/config.cpp b/src/citra_qt/configuration/config.cpp index 61045e12a..eca7d4a28 100644 --- a/src/citra_qt/configuration/config.cpp +++ b/src/citra_qt/configuration/config.cpp @@ -474,6 +474,7 @@ void QtConfig::ReadCoreValues() { qt_config->beginGroup(QStringLiteral("Core")); ReadGlobalSetting(Settings::values.cpu_clock_percentage); + ReadGlobalSetting(Settings::values.cpu_legacy_instruction_ticks); if (global) { ReadBasicSetting(Settings::values.use_cpu_jit); @@ -1071,6 +1072,7 @@ void QtConfig::SaveCoreValues() { qt_config->beginGroup(QStringLiteral("Core")); WriteGlobalSetting(Settings::values.cpu_clock_percentage); + WriteGlobalSetting(Settings::values.cpu_legacy_instruction_ticks); if (global) { WriteBasicSetting(Settings::values.use_cpu_jit); diff --git a/src/citra_qt/configuration/configure_debug.cpp b/src/citra_qt/configuration/configure_debug.cpp index 73bc2483d..1162837ca 100644 --- a/src/citra_qt/configuration/configure_debug.cpp +++ b/src/citra_qt/configuration/configure_debug.cpp @@ -143,6 +143,8 @@ void ConfigureDebug::SetConfiguration() { ui->toggle_renderer_debug->setChecked(Settings::values.renderer_debug.GetValue()); ui->toggle_pica_debugging->setChecked(Settings::values.pica_debugging.GetValue()); ui->toggle_dump_command_buffers->setChecked(Settings::values.dump_command_buffers.GetValue()); + ui->toggle_cpu_legacy_instruction_ticks->setChecked( + Settings::values.cpu_legacy_instruction_ticks.GetValue()); if (!Settings::IsConfiguringGlobal()) { if (Settings::values.cpu_clock_percentage.UsingGlobal()) { @@ -192,6 +194,9 @@ void ConfigureDebug::ApplyConfiguration() { Settings::values.dump_command_buffers = ui->toggle_dump_command_buffers->isChecked(); Settings::values.instant_debug_log = ui->instant_debug_log->isChecked(); + ConfigurationShared::ApplyPerGameSetting(&Settings::values.cpu_legacy_instruction_ticks, + ui->toggle_cpu_legacy_instruction_ticks, + cpu_legacy_instruction_ticks); ConfigurationShared::ApplyPerGameSetting( &Settings::values.cpu_clock_percentage, ui->clock_speed_combo, [this](s32) { return SliderToSettings(ui->slider_clock_speed->value()); }); @@ -201,9 +206,15 @@ void ConfigureDebug::SetupPerGameUI() { // Block the global settings if a game is currently running that overrides them if (Settings::IsConfiguringGlobal()) { ui->slider_clock_speed->setEnabled(Settings::values.cpu_clock_percentage.UsingGlobal()); + ui->toggle_cpu_legacy_instruction_ticks->setEnabled( + Settings::values.cpu_legacy_instruction_ticks.UsingGlobal()); return; } + ConfigurationShared::SetColoredTristate(ui->toggle_cpu_legacy_instruction_ticks, + Settings::values.cpu_legacy_instruction_ticks, + cpu_legacy_instruction_ticks); + connect(ui->clock_speed_combo, qOverload(&QComboBox::activated), this, [this](int index) { ui->slider_clock_speed->setEnabled(index == 1); ConfigurationShared::SetHighlight(ui->clock_speed_widget, index == 1); diff --git a/src/citra_qt/configuration/configure_debug.h b/src/citra_qt/configuration/configure_debug.h index f511e260e..adc2b5cea 100644 --- a/src/citra_qt/configuration/configure_debug.h +++ b/src/citra_qt/configuration/configure_debug.h @@ -7,8 +7,12 @@ #include #include +namespace ConfigurationShared { + enum class CheckState; +} + namespace Ui { -class ConfigureDebug; + class ConfigureDebug; } class ConfigureDebug : public QWidget { @@ -26,4 +30,5 @@ public: private: std::unique_ptr ui; bool is_powered_on; + ConfigurationShared::CheckState cpu_legacy_instruction_ticks; }; diff --git a/src/citra_qt/configuration/configure_debug.ui b/src/citra_qt/configuration/configure_debug.ui index e5fac44b1..80a75332d 100644 --- a/src/citra_qt/configuration/configure_debug.ui +++ b/src/citra_qt/configuration/configure_debug.ui @@ -61,11 +61,11 @@ - - - Pause next non-sysmodule process at start - - + + + Pause next non-sysmodule process at start + + @@ -125,14 +125,14 @@ - - - Flush log output on every message - - - <html><body>Immediately commits the debug log to file. Use this if Azahar crashes and the log output is being cut.<br>Enabling this feature will decrease performance, only use it for debugging purposes.</body></html> - - + + + Flush log output on every message + + + <html><body>Immediately commits the debug log to file. Use this if Azahar crashes and the log output is being cut.<br>Enabling this feature will decrease performance, only use it for debugging purposes.</body></html> + + @@ -226,13 +226,13 @@ - <html><head/><body>Underclocking can increase performance but may cause the application to freeze.<br/>Overclocking may reduce lag in applications but also might cause freezes</p></body></html> - - - Qt::RichText - - - + <html><head/><body>Underclocking can increase performance but may cause the application to freeze.<br/>Overclocking may reduce lag in applications but also might cause freezes</p></body></html> + + + Qt::RichText + + + @@ -243,6 +243,16 @@ + + + + <html><head/><body><p>Counts every ARM instruction as a single cycle instead of using the per-instruction timing table. A few applications contain scripted logic that is sensitive to the emulated CPU speed and only progresses correctly with this enabled (e.g. the rooftop chase in LEGO City Undercover: The Chase Begins). Leave unchecked unless an application misbehaves. Requires restarting the application to fully apply.</p></body></html> + + + Use legacy CPU cycle timing (1 tick per instruction) + + + @@ -250,13 +260,13 @@ - - - - Enable PICA200 debugging - - - + + + + Enable PICA200 debugging + + + @@ -304,14 +314,14 @@ - - - Enable RPC server - - - <html><head/><body><p>Enables the RPC server on port 45987. This allows remotely reading/writing guest memory, do not enable if you don't know what you are doing.</p></body></html> - - + + + Enable RPC server + + + <html><head/><body><p>Enables the RPC server on port 45987. This allows remotely reading/writing guest memory, do not enable if you don't know what you are doing.</p></body></html> + + diff --git a/src/common/settings.cpp b/src/common/settings.cpp index f2327ea5a..209a35407 100644 --- a/src/common/settings.cpp +++ b/src/common/settings.cpp @@ -88,6 +88,8 @@ void LogSettings() { LOG_INFO(Config, "Azahar Configuration:"); log_setting("Core_UseCpuJit", values.use_cpu_jit.GetValue()); log_setting("Core_CPUClockPercentage", values.cpu_clock_percentage.GetValue()); + log_setting("Core_CpuLegacyInstructionTicks", + values.cpu_legacy_instruction_ticks.GetValue()); log_setting("Controller_UseArticController", values.use_artic_base_controller.GetValue()); log_setting("Renderer_UseGLES", values.use_gles.GetValue()); log_setting("Renderer_GraphicsAPI", GetGraphicsAPIName(values.graphics_api.GetValue())); diff --git a/src/common/settings.h b/src/common/settings.h index e481d761f..37ce5fb17 100644 --- a/src/common/settings.h +++ b/src/common/settings.h @@ -482,6 +482,8 @@ struct Values { // Core Setting use_cpu_jit{true, Keys::use_cpu_jit}; SwitchableSetting cpu_clock_percentage{100, 5, 400, Keys::cpu_clock_percentage}; + SwitchableSetting cpu_legacy_instruction_ticks{false, + Keys::cpu_legacy_instruction_ticks}; SwitchableSetting is_new_3ds{true, Keys::is_new_3ds}; SwitchableSetting lle_applets{true, Keys::lle_applets}; SwitchableSetting deterministic_async_operations{false, diff --git a/src/core/arm/dynarmic/arm_dynarmic.cpp b/src/core/arm/dynarmic/arm_dynarmic.cpp index 64b740569..da3fddf13 100644 --- a/src/core/arm/dynarmic/arm_dynarmic.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic.cpp @@ -8,6 +8,7 @@ #include #include "common/assert.h" #include "common/microprofile.h" +#include "common/settings.h" #include "core/arm/dynarmic/arm_dynarmic.h" #include "core/arm/dynarmic/arm_dynarmic_cp15.h" #include "core/arm/dynarmic/arm_exclusive_monitor.h" @@ -159,6 +160,9 @@ public: return static_cast(ticks <= 0 ? 0 : ticks); } std::uint64_t GetTicksForCode(bool is_thumb, VAddr, std::uint32_t instruction) override { + if (Settings::values.cpu_legacy_instruction_ticks.GetValue()) [[unlikely]] { + return 1; + } return Core::TicksForInstruction(is_thumb, instruction); }