Add CPU Clock Frequency slider
This slider affects the number of cycles that the guest cpu emulation reports that have passed since the last time slice. This option scales the result returned by a percentage that the user selects. In some games underclocking the CPU can give a major speedup. Exposing this as an option will give users something to toy with for performance, while also potentially enhancing games that experience lag on the real console
This commit is contained in:
parent
55ec7031cc
commit
276d56ca9b
|
@ -104,6 +104,8 @@ void Config::ReadValues() {
|
||||||
|
|
||||||
// Core
|
// Core
|
||||||
Settings::values.use_cpu_jit = sdl2_config->GetBoolean("Core", "use_cpu_jit", true);
|
Settings::values.use_cpu_jit = sdl2_config->GetBoolean("Core", "use_cpu_jit", true);
|
||||||
|
Settings::values.cpu_clock_percentage =
|
||||||
|
sdl2_config->GetInteger("Core", "cpu_clock_percentage", 100);
|
||||||
|
|
||||||
// Renderer
|
// Renderer
|
||||||
Settings::values.use_gles = sdl2_config->GetBoolean("Renderer", "use_gles", false);
|
Settings::values.use_gles = sdl2_config->GetBoolean("Renderer", "use_gles", false);
|
||||||
|
|
|
@ -91,6 +91,12 @@ udp_pad_index=
|
||||||
# 0: Interpreter (slow), 1 (default): JIT (fast)
|
# 0: Interpreter (slow), 1 (default): JIT (fast)
|
||||||
use_cpu_jit =
|
use_cpu_jit =
|
||||||
|
|
||||||
|
# Change the Clock Frequency of the emulated 3DS CPU.
|
||||||
|
# Underclocking can increase the performance of the game at the risk of freezing.
|
||||||
|
# Overclocking may fix lag that happens on console, but also comes with the risk of freezing.
|
||||||
|
# Range is any positive integer (but we suspect 25 - 400 is a good idea) Default is 100
|
||||||
|
cpu_clock_percentage =
|
||||||
|
|
||||||
[Renderer]
|
[Renderer]
|
||||||
# Whether to render using GLES or OpenGL
|
# Whether to render using GLES or OpenGL
|
||||||
# 0 (default): OpenGL, 1: GLES
|
# 0 (default): OpenGL, 1: GLES
|
||||||
|
|
|
@ -253,6 +253,8 @@ void Config::ReadCoreValues() {
|
||||||
qt_config->beginGroup(QStringLiteral("Core"));
|
qt_config->beginGroup(QStringLiteral("Core"));
|
||||||
|
|
||||||
Settings::values.use_cpu_jit = ReadSetting(QStringLiteral("use_cpu_jit"), true).toBool();
|
Settings::values.use_cpu_jit = ReadSetting(QStringLiteral("use_cpu_jit"), true).toBool();
|
||||||
|
Settings::values.cpu_clock_percentage =
|
||||||
|
ReadSetting(QStringLiteral("cpu_clock_percentage"), 100).toInt();
|
||||||
|
|
||||||
qt_config->endGroup();
|
qt_config->endGroup();
|
||||||
}
|
}
|
||||||
|
@ -730,6 +732,8 @@ void Config::SaveCoreValues() {
|
||||||
qt_config->beginGroup(QStringLiteral("Core"));
|
qt_config->beginGroup(QStringLiteral("Core"));
|
||||||
|
|
||||||
WriteSetting(QStringLiteral("use_cpu_jit"), Settings::values.use_cpu_jit, true);
|
WriteSetting(QStringLiteral("use_cpu_jit"), Settings::values.use_cpu_jit, true);
|
||||||
|
WriteSetting(QStringLiteral("cpu_clock_percentage"), Settings::values.cpu_clock_percentage,
|
||||||
|
100);
|
||||||
|
|
||||||
qt_config->endGroup();
|
qt_config->endGroup();
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>345</width>
|
<width>345</width>
|
||||||
<height>357</height>
|
<height>358</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="windowTitle">
|
<property name="windowTitle">
|
||||||
|
@ -68,6 +68,13 @@
|
||||||
<string>Emulation</string>
|
<string>Emulation</string>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QGridLayout" name="gridLayout">
|
<layout class="QGridLayout" name="gridLayout">
|
||||||
|
<item row="1" column="0">
|
||||||
|
<widget class="QCheckBox" name="toggle_frame_limit">
|
||||||
|
<property name="text">
|
||||||
|
<string>Limit Speed Percent</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
<item row="0" column="0">
|
<item row="0" column="0">
|
||||||
<widget class="QLabel" name="label">
|
<widget class="QLabel" name="label">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
|
@ -119,13 +126,6 @@
|
||||||
</item>
|
</item>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="1" column="0">
|
|
||||||
<widget class="QCheckBox" name="toggle_frame_limit">
|
|
||||||
<property name="text">
|
|
||||||
<string>Limit Speed Percent</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="1" column="1">
|
<item row="1" column="1">
|
||||||
<widget class="QSpinBox" name="frame_limit">
|
<widget class="QSpinBox" name="frame_limit">
|
||||||
<property name="suffix">
|
<property name="suffix">
|
||||||
|
|
|
@ -217,6 +217,17 @@ static const std::array<const char*, 187> country_names = {
|
||||||
QT_TRANSLATE_NOOP("ConfigureSystem", "Bermuda"), // 180-186
|
QT_TRANSLATE_NOOP("ConfigureSystem", "Bermuda"), // 180-186
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// The QSlider doesn't have an easy way to set a custom step amount,
|
||||||
|
// so we can just convert from the sliders range (0 - 79) to the expected
|
||||||
|
// settings range (5 - 400) with simple math.
|
||||||
|
static constexpr int SliderToSettings(int value) {
|
||||||
|
return 5 * value + 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr int SettingsToSlider(int value) {
|
||||||
|
return (value - 5) / 5;
|
||||||
|
}
|
||||||
|
|
||||||
ConfigureSystem::ConfigureSystem(QWidget* parent) : QWidget(parent), ui(new Ui::ConfigureSystem) {
|
ConfigureSystem::ConfigureSystem(QWidget* parent) : QWidget(parent), ui(new Ui::ConfigureSystem) {
|
||||||
ui->setupUi(this);
|
ui->setupUi(this);
|
||||||
connect(ui->combo_birthmonth,
|
connect(ui->combo_birthmonth,
|
||||||
|
@ -233,6 +244,10 @@ ConfigureSystem::ConfigureSystem(QWidget* parent) : QWidget(parent), ui(new Ui::
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
connect(ui->slider_clock_speed, &QSlider::valueChanged, [&](int value) {
|
||||||
|
ui->clock_display_label->setText(QStringLiteral("%1%").arg(SliderToSettings(value)));
|
||||||
|
});
|
||||||
|
|
||||||
ConfigureTime();
|
ConfigureTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -258,6 +273,10 @@ void ConfigureSystem::SetConfiguration() {
|
||||||
|
|
||||||
ui->label_disable_info->hide();
|
ui->label_disable_info->hide();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ui->slider_clock_speed->setValue(SettingsToSlider(Settings::values.cpu_clock_percentage));
|
||||||
|
ui->clock_display_label->setText(
|
||||||
|
QStringLiteral("%1%").arg(Settings::values.cpu_clock_percentage));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConfigureSystem::ReadSystemSettings() {
|
void ConfigureSystem::ReadSystemSettings() {
|
||||||
|
@ -299,65 +318,65 @@ void ConfigureSystem::ReadSystemSettings() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConfigureSystem::ApplyConfiguration() {
|
void ConfigureSystem::ApplyConfiguration() {
|
||||||
if (!enabled) {
|
if (enabled) {
|
||||||
return;
|
bool modified = false;
|
||||||
|
|
||||||
|
// apply username
|
||||||
|
// TODO(wwylele): Use this when we move to Qt 5.5
|
||||||
|
// std::u16string new_username = ui->edit_username->text().toStdU16String();
|
||||||
|
std::u16string new_username(
|
||||||
|
reinterpret_cast<const char16_t*>(ui->edit_username->text().utf16()));
|
||||||
|
if (new_username != username) {
|
||||||
|
cfg->SetUsername(new_username);
|
||||||
|
modified = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// apply birthday
|
||||||
|
int new_birthmonth = ui->combo_birthmonth->currentIndex() + 1;
|
||||||
|
int new_birthday = ui->combo_birthday->currentIndex() + 1;
|
||||||
|
if (birthmonth != new_birthmonth || birthday != new_birthday) {
|
||||||
|
cfg->SetBirthday(new_birthmonth, new_birthday);
|
||||||
|
modified = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// apply language
|
||||||
|
int new_language = ui->combo_language->currentIndex();
|
||||||
|
if (language_index != new_language) {
|
||||||
|
cfg->SetSystemLanguage(static_cast<Service::CFG::SystemLanguage>(new_language));
|
||||||
|
modified = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// apply sound
|
||||||
|
int new_sound = ui->combo_sound->currentIndex();
|
||||||
|
if (sound_index != new_sound) {
|
||||||
|
cfg->SetSoundOutputMode(static_cast<Service::CFG::SoundOutputMode>(new_sound));
|
||||||
|
modified = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// apply country
|
||||||
|
u8 new_country = static_cast<u8>(ui->combo_country->currentData().toInt());
|
||||||
|
if (country_code != new_country) {
|
||||||
|
cfg->SetCountryCode(new_country);
|
||||||
|
modified = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// apply play coin
|
||||||
|
u16 new_play_coin = static_cast<u16>(ui->spinBox_play_coins->value());
|
||||||
|
if (play_coin != new_play_coin) {
|
||||||
|
Service::PTM::Module::SetPlayCoins(new_play_coin);
|
||||||
|
}
|
||||||
|
|
||||||
|
// update the config savegame if any item is modified.
|
||||||
|
if (modified) {
|
||||||
|
cfg->UpdateConfigNANDSavegame();
|
||||||
|
}
|
||||||
|
|
||||||
|
Settings::values.init_clock =
|
||||||
|
static_cast<Settings::InitClock>(ui->combo_init_clock->currentIndex());
|
||||||
|
Settings::values.init_time = ui->edit_init_time->dateTime().toTime_t();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool modified = false;
|
Settings::values.cpu_clock_percentage = SliderToSettings(ui->slider_clock_speed->value());
|
||||||
|
|
||||||
// apply username
|
|
||||||
// TODO(wwylele): Use this when we move to Qt 5.5
|
|
||||||
// std::u16string new_username = ui->edit_username->text().toStdU16String();
|
|
||||||
std::u16string new_username(
|
|
||||||
reinterpret_cast<const char16_t*>(ui->edit_username->text().utf16()));
|
|
||||||
if (new_username != username) {
|
|
||||||
cfg->SetUsername(new_username);
|
|
||||||
modified = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// apply birthday
|
|
||||||
int new_birthmonth = ui->combo_birthmonth->currentIndex() + 1;
|
|
||||||
int new_birthday = ui->combo_birthday->currentIndex() + 1;
|
|
||||||
if (birthmonth != new_birthmonth || birthday != new_birthday) {
|
|
||||||
cfg->SetBirthday(new_birthmonth, new_birthday);
|
|
||||||
modified = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// apply language
|
|
||||||
int new_language = ui->combo_language->currentIndex();
|
|
||||||
if (language_index != new_language) {
|
|
||||||
cfg->SetSystemLanguage(static_cast<Service::CFG::SystemLanguage>(new_language));
|
|
||||||
modified = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// apply sound
|
|
||||||
int new_sound = ui->combo_sound->currentIndex();
|
|
||||||
if (sound_index != new_sound) {
|
|
||||||
cfg->SetSoundOutputMode(static_cast<Service::CFG::SoundOutputMode>(new_sound));
|
|
||||||
modified = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// apply country
|
|
||||||
u8 new_country = static_cast<u8>(ui->combo_country->currentData().toInt());
|
|
||||||
if (country_code != new_country) {
|
|
||||||
cfg->SetCountryCode(new_country);
|
|
||||||
modified = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// apply play coin
|
|
||||||
u16 new_play_coin = static_cast<u16>(ui->spinBox_play_coins->value());
|
|
||||||
if (play_coin != new_play_coin) {
|
|
||||||
Service::PTM::Module::SetPlayCoins(new_play_coin);
|
|
||||||
}
|
|
||||||
|
|
||||||
// update the config savegame if any item is modified.
|
|
||||||
if (modified) {
|
|
||||||
cfg->UpdateConfigNANDSavegame();
|
|
||||||
}
|
|
||||||
|
|
||||||
Settings::values.init_clock =
|
|
||||||
static_cast<Settings::InitClock>(ui->combo_init_clock->currentIndex());
|
|
||||||
Settings::values.init_time = ui->edit_init_time->dateTime().toTime_t();
|
|
||||||
Settings::Apply();
|
Settings::Apply();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,8 +6,8 @@
|
||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>360</width>
|
<width>471</width>
|
||||||
<height>377</height>
|
<height>555</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="windowTitle">
|
<property name="windowTitle">
|
||||||
|
@ -228,8 +228,7 @@
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="4" column="1">
|
<item row="4" column="1">
|
||||||
<widget class="QComboBox" name="combo_country">
|
<widget class="QComboBox" name="combo_country"/>
|
||||||
</widget>
|
|
||||||
</item>
|
</item>
|
||||||
<item row="5" column="0">
|
<item row="5" column="0">
|
||||||
<widget class="QLabel" name="label_init_clock">
|
<widget class="QLabel" name="label_init_clock">
|
||||||
|
@ -306,6 +305,63 @@
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QGroupBox" name="groupBox">
|
||||||
|
<property name="title">
|
||||||
|
<string>Advanced</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QGridLayout" name="gridLayout_2">
|
||||||
|
<item row="0" column="0">
|
||||||
|
<widget class="QLabel" name="label_3">
|
||||||
|
<property name="text">
|
||||||
|
<string>CPU Clock Speed</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="2">
|
||||||
|
<widget class="QSlider" name="slider_clock_speed">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string><html><body>Changes the emulated CPU clock frequency.<br>Underclocking can increase performance but may cause the game to freeze.<br>Overclocking may reduce in game lag but also might cause freezes</body></html></string>
|
||||||
|
</property>
|
||||||
|
<property name="minimum">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="maximum">
|
||||||
|
<number>79</number>
|
||||||
|
</property>
|
||||||
|
<property name="singleStep">
|
||||||
|
<number>5</number>
|
||||||
|
</property>
|
||||||
|
<property name="pageStep">
|
||||||
|
<number>15</number>
|
||||||
|
</property>
|
||||||
|
<property name="value">
|
||||||
|
<number>25</number>
|
||||||
|
</property>
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="tickPosition">
|
||||||
|
<enum>QSlider::TicksBelow</enum>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="1">
|
||||||
|
<widget class="QLabel" name="clock_display_label">
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_2"/>
|
||||||
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QLabel" name="label_disable_info">
|
<widget class="QLabel" name="label_disable_info">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
|
@ -316,6 +372,16 @@
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_cpu_clock_info">
|
||||||
|
<property name="text">
|
||||||
|
<string><html><head/><body><p>CPU Clock Speed Information<br/>Underclocking can increase performance but may cause the game to freeze.<br/>Overclocking may reduce in game lag but also might cause freezes</p></body></html></string>
|
||||||
|
</property>
|
||||||
|
<property name="textFormat">
|
||||||
|
<enum>Qt::RichText</enum>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<spacer name="verticalSpacer">
|
<spacer name="verticalSpacer">
|
||||||
<property name="orientation">
|
<property name="orientation">
|
||||||
|
|
|
@ -256,7 +256,7 @@ System::ResultStatus System::Init(Frontend::EmuWindow& emu_window, u32 system_mo
|
||||||
|
|
||||||
memory = std::make_unique<Memory::MemorySystem>();
|
memory = std::make_unique<Memory::MemorySystem>();
|
||||||
|
|
||||||
timing = std::make_unique<Timing>(num_cores);
|
timing = std::make_unique<Timing>(num_cores, Settings::values.cpu_clock_percentage);
|
||||||
|
|
||||||
kernel = std::make_unique<Kernel::KernelSystem>(
|
kernel = std::make_unique<Kernel::KernelSystem>(
|
||||||
*memory, *timing, [this] { PrepareReschedule(); }, system_mode, num_cores);
|
*memory, *timing, [this] { PrepareReschedule(); }, system_mode, num_cores);
|
||||||
|
|
|
@ -20,14 +20,20 @@ bool Timing::Event::operator<(const Timing::Event& right) const {
|
||||||
return std::tie(time, fifo_order) < std::tie(right.time, right.fifo_order);
|
return std::tie(time, fifo_order) < std::tie(right.time, right.fifo_order);
|
||||||
}
|
}
|
||||||
|
|
||||||
Timing::Timing(std::size_t num_cores) {
|
Timing::Timing(std::size_t num_cores, u32 cpu_clock_percentage) {
|
||||||
timers.resize(num_cores);
|
timers.resize(num_cores);
|
||||||
for (std::size_t i = 0; i < num_cores; ++i) {
|
for (std::size_t i = 0; i < num_cores; ++i) {
|
||||||
timers[i] = std::make_shared<Timer>();
|
timers[i] = std::make_shared<Timer>(100.0 / cpu_clock_percentage);
|
||||||
}
|
}
|
||||||
current_timer = timers[0];
|
current_timer = timers[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Timing::UpdateClockSpeed(u32 cpu_clock_percentage) {
|
||||||
|
for (auto& timer : timers) {
|
||||||
|
timer->cpu_clock_scale = 100.0 / cpu_clock_percentage;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
TimingEventType* Timing::RegisterEvent(const std::string& name, TimedCallback callback) {
|
TimingEventType* Timing::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.
|
||||||
|
@ -117,6 +123,8 @@ std::shared_ptr<Timing::Timer> Timing::GetTimer(std::size_t cpu_id) {
|
||||||
return timers[cpu_id];
|
return timers[cpu_id];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Timing::Timer::Timer(double cpu_clock_scale_) : cpu_clock_scale(cpu_clock_scale_) {}
|
||||||
|
|
||||||
Timing::Timer::~Timer() {
|
Timing::Timer::~Timer() {
|
||||||
MoveEvents();
|
MoveEvents();
|
||||||
}
|
}
|
||||||
|
@ -130,7 +138,7 @@ u64 Timing::Timer::GetTicks() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Timing::Timer::AddTicks(u64 ticks) {
|
void Timing::Timer::AddTicks(u64 ticks) {
|
||||||
downcount -= ticks;
|
downcount -= static_cast<u64>(ticks * cpu_clock_scale);
|
||||||
}
|
}
|
||||||
|
|
||||||
u64 Timing::Timer::GetIdleTicks() const {
|
u64 Timing::Timer::GetIdleTicks() const {
|
||||||
|
|
|
@ -148,6 +148,7 @@ public:
|
||||||
|
|
||||||
class Timer {
|
class Timer {
|
||||||
public:
|
public:
|
||||||
|
Timer(double cpu_clock_scale);
|
||||||
~Timer();
|
~Timer();
|
||||||
|
|
||||||
s64 GetMaxSliceLength() const;
|
s64 GetMaxSliceLength() const;
|
||||||
|
@ -190,10 +191,13 @@ public:
|
||||||
s64 slice_length = MAX_SLICE_LENGTH;
|
s64 slice_length = MAX_SLICE_LENGTH;
|
||||||
s64 downcount = MAX_SLICE_LENGTH;
|
s64 downcount = MAX_SLICE_LENGTH;
|
||||||
s64 executed_ticks = 0;
|
s64 executed_ticks = 0;
|
||||||
u64 idled_cycles;
|
u64 idled_cycles = 0;
|
||||||
|
// Stores a scaling for the internal clockspeed. Changing this number results in
|
||||||
|
// under/overclocking the guest cpu
|
||||||
|
double cpu_clock_scale = 1.0;
|
||||||
};
|
};
|
||||||
|
|
||||||
explicit Timing(std::size_t num_cores);
|
explicit Timing(std::size_t num_cores, u32 cpu_clock_percentage);
|
||||||
|
|
||||||
~Timing(){};
|
~Timing(){};
|
||||||
|
|
||||||
|
@ -220,6 +224,11 @@ public:
|
||||||
global_timer += ticks;
|
global_timer += ticks;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the value of the cpu clock scaling to the new percentage.
|
||||||
|
*/
|
||||||
|
void UpdateClockSpeed(u32 cpu_clock_percentage);
|
||||||
|
|
||||||
std::chrono::microseconds GetGlobalTimeUs() const;
|
std::chrono::microseconds GetGlobalTimeUs() const;
|
||||||
|
|
||||||
std::shared_ptr<Timer> GetTimer(std::size_t cpu_id);
|
std::shared_ptr<Timer> GetTimer(std::size_t cpu_id);
|
||||||
|
@ -229,10 +238,14 @@ private:
|
||||||
|
|
||||||
// unordered_map stores each element separately as a linked list node so pointers to
|
// unordered_map stores each element separately as a linked list node so pointers to
|
||||||
// elements remain stable regardless of rehashes/resizing.
|
// elements remain stable regardless of rehashes/resizing.
|
||||||
std::unordered_map<std::string, TimingEventType> event_types;
|
std::unordered_map<std::string, TimingEventType> event_types = {};
|
||||||
|
|
||||||
std::vector<std::shared_ptr<Timer>> timers;
|
std::vector<std::shared_ptr<Timer>> timers;
|
||||||
std::shared_ptr<Timer> current_timer;
|
std::shared_ptr<Timer> current_timer;
|
||||||
|
|
||||||
|
// Stores a scaling for the internal clockspeed. Changing this number results in
|
||||||
|
// under/overclocking the guest cpu
|
||||||
|
double cpu_clock_scale = 1.0;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Core
|
} // namespace Core
|
||||||
|
|
|
@ -40,6 +40,7 @@ void Apply() {
|
||||||
|
|
||||||
auto& system = Core::System::GetInstance();
|
auto& system = Core::System::GetInstance();
|
||||||
if (system.IsPoweredOn()) {
|
if (system.IsPoweredOn()) {
|
||||||
|
system.CoreTiming().UpdateClockSpeed(values.cpu_clock_percentage);
|
||||||
Core::DSP().SetSink(values.sink_id, values.audio_device_id);
|
Core::DSP().SetSink(values.sink_id, values.audio_device_id);
|
||||||
Core::DSP().EnableStretching(values.enable_audio_stretching);
|
Core::DSP().EnableStretching(values.enable_audio_stretching);
|
||||||
|
|
||||||
|
|
|
@ -128,6 +128,7 @@ struct Values {
|
||||||
|
|
||||||
// Core
|
// Core
|
||||||
bool use_cpu_jit;
|
bool use_cpu_jit;
|
||||||
|
int cpu_clock_percentage;
|
||||||
|
|
||||||
// Data Storage
|
// Data Storage
|
||||||
bool use_virtual_sd;
|
bool use_virtual_sd;
|
||||||
|
|
|
@ -15,7 +15,7 @@ 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)) {
|
||||||
|
|
||||||
timing = std::make_unique<Core::Timing>(1);
|
timing = std::make_unique<Core::Timing>(1, 100);
|
||||||
memory = std::make_unique<Memory::MemorySystem>();
|
memory = std::make_unique<Memory::MemorySystem>();
|
||||||
kernel = std::make_unique<Kernel::KernelSystem>(*memory, *timing, [] {}, 0, 1);
|
kernel = std::make_unique<Kernel::KernelSystem>(*memory, *timing, [] {}, 0, 1);
|
||||||
|
|
||||||
|
|
|
@ -43,7 +43,7 @@ static void AdvanceAndCheck(Core::Timing& timing, u32 idx, int downcount, int ex
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("CoreTiming[BasicOrder]", "[core]") {
|
TEST_CASE("CoreTiming[BasicOrder]", "[core]") {
|
||||||
Core::Timing timing(1);
|
Core::Timing timing(1, 100);
|
||||||
|
|
||||||
Core::TimingEventType* cb_a = timing.RegisterEvent("callbackA", CallbackTemplate<0>);
|
Core::TimingEventType* cb_a = timing.RegisterEvent("callbackA", CallbackTemplate<0>);
|
||||||
Core::TimingEventType* cb_b = timing.RegisterEvent("callbackB", CallbackTemplate<1>);
|
Core::TimingEventType* cb_b = timing.RegisterEvent("callbackB", CallbackTemplate<1>);
|
||||||
|
@ -90,7 +90,7 @@ void FifoCallback(u64 userdata, s64 cycles_late) {
|
||||||
TEST_CASE("CoreTiming[SharedSlot]", "[core]") {
|
TEST_CASE("CoreTiming[SharedSlot]", "[core]") {
|
||||||
using namespace SharedSlotTest;
|
using namespace SharedSlotTest;
|
||||||
|
|
||||||
Core::Timing timing(1);
|
Core::Timing timing(1, 100);
|
||||||
|
|
||||||
Core::TimingEventType* cb_a = timing.RegisterEvent("callbackA", FifoCallback<0>);
|
Core::TimingEventType* cb_a = timing.RegisterEvent("callbackA", FifoCallback<0>);
|
||||||
Core::TimingEventType* cb_b = timing.RegisterEvent("callbackB", FifoCallback<1>);
|
Core::TimingEventType* cb_b = timing.RegisterEvent("callbackB", FifoCallback<1>);
|
||||||
|
@ -118,7 +118,7 @@ TEST_CASE("CoreTiming[SharedSlot]", "[core]") {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("CoreTiming[PredictableLateness]", "[core]") {
|
TEST_CASE("CoreTiming[PredictableLateness]", "[core]") {
|
||||||
Core::Timing timing(1);
|
Core::Timing timing(1, 100);
|
||||||
|
|
||||||
Core::TimingEventType* cb_a = timing.RegisterEvent("callbackA", CallbackTemplate<0>);
|
Core::TimingEventType* cb_a = timing.RegisterEvent("callbackA", CallbackTemplate<0>);
|
||||||
Core::TimingEventType* cb_b = timing.RegisterEvent("callbackB", CallbackTemplate<1>);
|
Core::TimingEventType* cb_b = timing.RegisterEvent("callbackB", CallbackTemplate<1>);
|
||||||
|
@ -149,7 +149,7 @@ static void RescheduleCallback(Core::Timing& timing, u64 userdata, s64 cycles_la
|
||||||
TEST_CASE("CoreTiming[ChainScheduling]", "[core]") {
|
TEST_CASE("CoreTiming[ChainScheduling]", "[core]") {
|
||||||
using namespace ChainSchedulingTest;
|
using namespace ChainSchedulingTest;
|
||||||
|
|
||||||
Core::Timing timing(1);
|
Core::Timing timing(1, 100);
|
||||||
|
|
||||||
Core::TimingEventType* cb_a = timing.RegisterEvent("callbackA", CallbackTemplate<0>);
|
Core::TimingEventType* cb_a = timing.RegisterEvent("callbackA", CallbackTemplate<0>);
|
||||||
Core::TimingEventType* cb_b = timing.RegisterEvent("callbackB", CallbackTemplate<1>);
|
Core::TimingEventType* cb_b = timing.RegisterEvent("callbackB", CallbackTemplate<1>);
|
||||||
|
|
|
@ -21,7 +21,7 @@ static std::shared_ptr<Object> MakeObject(Kernel::KernelSystem& kernel) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("HLERequestContext::PopulateFromIncomingCommandBuffer", "[core][kernel]") {
|
TEST_CASE("HLERequestContext::PopulateFromIncomingCommandBuffer", "[core][kernel]") {
|
||||||
Core::Timing timing(1);
|
Core::Timing timing(1, 100);
|
||||||
Memory::MemorySystem memory;
|
Memory::MemorySystem memory;
|
||||||
Kernel::KernelSystem kernel(memory, timing, [] {}, 0, 1);
|
Kernel::KernelSystem kernel(memory, timing, [] {}, 0, 1);
|
||||||
auto [server, client] = kernel.CreateSessionPair();
|
auto [server, client] = kernel.CreateSessionPair();
|
||||||
|
@ -233,7 +233,7 @@ TEST_CASE("HLERequestContext::PopulateFromIncomingCommandBuffer", "[core][kernel
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("HLERequestContext::WriteToOutgoingCommandBuffer", "[core][kernel]") {
|
TEST_CASE("HLERequestContext::WriteToOutgoingCommandBuffer", "[core][kernel]") {
|
||||||
Core::Timing timing(1);
|
Core::Timing timing(1, 100);
|
||||||
Memory::MemorySystem memory;
|
Memory::MemorySystem memory;
|
||||||
Kernel::KernelSystem kernel(memory, timing, [] {}, 0, 1);
|
Kernel::KernelSystem kernel(memory, timing, [] {}, 0, 1);
|
||||||
auto [server, client] = kernel.CreateSessionPair();
|
auto [server, client] = kernel.CreateSessionPair();
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
#include "core/memory.h"
|
#include "core/memory.h"
|
||||||
|
|
||||||
TEST_CASE("Memory::IsValidVirtualAddress", "[core][memory]") {
|
TEST_CASE("Memory::IsValidVirtualAddress", "[core][memory]") {
|
||||||
Core::Timing timing(1);
|
Core::Timing timing(1, 100);
|
||||||
Memory::MemorySystem memory;
|
Memory::MemorySystem memory;
|
||||||
Kernel::KernelSystem kernel(memory, timing, [] {}, 0, 1);
|
Kernel::KernelSystem kernel(memory, timing, [] {}, 0, 1);
|
||||||
SECTION("these regions should not be mapped on an empty process") {
|
SECTION("these regions should not be mapped on an empty process") {
|
||||||
|
|
Loading…
Reference in New Issue