mirror of
https://github.com/citra-mirror/citra.git
synced 2024-08-20 02:13:23 +02:00
Merge remote-tracking branch 'upstream/master' into feature/savestates-2
This commit is contained in:
commit
03379b2072
@ -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();
|
||||||
}
|
}
|
||||||
@ -737,6 +739,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">
|
||||||
|
@ -319,7 +319,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, n3ds_mode);
|
*memory, *timing, [this] { PrepareReschedule(); }, system_mode, num_cores, n3ds_mode);
|
||||||
|
@ -22,14 +22,21 @@ 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>();
|
||||||
}
|
}
|
||||||
|
UpdateClockSpeed(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 +124,8 @@ std::shared_ptr<Timing::Timer> Timing::GetTimer(std::size_t cpu_id) {
|
|||||||
return timers[cpu_id];
|
return timers[cpu_id];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Timing::Timer::Timer() = default;
|
||||||
|
|
||||||
Timing::Timer::~Timer() {
|
Timing::Timer::~Timer() {
|
||||||
MoveEvents();
|
MoveEvents();
|
||||||
}
|
}
|
||||||
@ -130,7 +139,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 {
|
||||||
|
@ -176,6 +176,7 @@ public:
|
|||||||
|
|
||||||
class Timer {
|
class Timer {
|
||||||
public:
|
public:
|
||||||
|
Timer();
|
||||||
~Timer();
|
~Timer();
|
||||||
|
|
||||||
s64 GetMaxSliceLength() const;
|
s64 GetMaxSliceLength() const;
|
||||||
@ -218,7 +219,10 @@ 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;
|
||||||
|
|
||||||
template <class Archive>
|
template <class Archive>
|
||||||
void serialize(Archive& ar, const unsigned int) {
|
void serialize(Archive& ar, const unsigned int) {
|
||||||
@ -234,7 +238,7 @@ public:
|
|||||||
friend class boost::serialization::access;
|
friend class boost::serialization::access;
|
||||||
};
|
};
|
||||||
|
|
||||||
explicit Timing(std::size_t num_cores);
|
explicit Timing(std::size_t num_cores, u32 cpu_clock_percentage);
|
||||||
|
|
||||||
~Timing(){};
|
~Timing(){};
|
||||||
|
|
||||||
@ -261,6 +265,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);
|
||||||
@ -270,11 +279,15 @@ 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;
|
||||||
|
|
||||||
template <class Archive>
|
template <class Archive>
|
||||||
void serialize(Archive& ar, const unsigned int) {
|
void serialize(Archive& ar, const unsigned int) {
|
||||||
// event_types set during initialization of other things
|
// event_types set during initialization of other things
|
||||||
|
@ -152,13 +152,16 @@ ResultCode VMManager::ChangeMemoryState(VAddr target, u32 size, MemoryState expe
|
|||||||
}
|
}
|
||||||
|
|
||||||
CASCADE_RESULT(auto vma, CarveVMARange(target, size));
|
CASCADE_RESULT(auto vma, CarveVMARange(target, size));
|
||||||
ASSERT(vma->second.size == size);
|
|
||||||
|
|
||||||
vma->second.permissions = new_perms;
|
const VMAIter end = vma_map.end();
|
||||||
vma->second.meminfo_state = new_state;
|
// The comparison against the end of the range must be done using addresses since VMAs can be
|
||||||
UpdatePageTableForVMA(vma->second);
|
// merged during this process, causing invalidation of the iterators.
|
||||||
|
while (vma != end && vma->second.base < target_end) {
|
||||||
MergeAdjacent(vma);
|
vma->second.permissions = new_perms;
|
||||||
|
vma->second.meminfo_state = new_state;
|
||||||
|
UpdatePageTableForVMA(vma->second);
|
||||||
|
vma = std::next(MergeAdjacent(vma));
|
||||||
|
}
|
||||||
|
|
||||||
return RESULT_SUCCESS;
|
return RESULT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
@ -46,10 +46,17 @@ static const ResultCode ERROR_NOT_LOADED = // 0xD8A12C0D
|
|||||||
|
|
||||||
static bool VerifyBufferState(Kernel::Process& process, VAddr buffer_ptr, u32 size) {
|
static bool VerifyBufferState(Kernel::Process& process, VAddr buffer_ptr, u32 size) {
|
||||||
auto vma = process.vm_manager.FindVMA(buffer_ptr);
|
auto vma = process.vm_manager.FindVMA(buffer_ptr);
|
||||||
return vma != process.vm_manager.vma_map.end() &&
|
while (vma != process.vm_manager.vma_map.end()) {
|
||||||
vma->second.base + vma->second.size >= buffer_ptr + size &&
|
if (vma->second.permissions != Kernel::VMAPermission::ReadWrite ||
|
||||||
vma->second.permissions == Kernel::VMAPermission::ReadWrite &&
|
vma->second.meminfo_state != Kernel::MemoryState::Private) {
|
||||||
vma->second.meminfo_state == Kernel::MemoryState::Private;
|
return false;
|
||||||
|
}
|
||||||
|
if (vma->second.base + vma->second.size >= buffer_ptr + size) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
vma = std::next(vma);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RO::Initialize(Kernel::HLERequestContext& ctx) {
|
void RO::Initialize(Kernel::HLERequestContext& ctx) {
|
||||||
|
@ -44,6 +44,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 std::shared_ptr<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, 0);
|
kernel = std::make_unique<Kernel::KernelSystem>(*memory, *timing, [] {}, 0, 1, 0);
|
||||||
|
|
||||||
|
@ -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>);
|
||||||
|
@ -24,7 +24,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, 0);
|
Kernel::KernelSystem kernel(memory, timing, [] {}, 0, 1, 0);
|
||||||
auto [server, client] = kernel.CreateSessionPair();
|
auto [server, client] = kernel.CreateSessionPair();
|
||||||
@ -239,7 +239,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, 0);
|
Kernel::KernelSystem kernel(memory, timing, [] {}, 0, 1, 0);
|
||||||
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, 0);
|
Kernel::KernelSystem kernel(memory, timing, [] {}, 0, 1, 0);
|
||||||
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
Block a user