From 5ba28325b262d44fcd7721aa00074955bd794015 Mon Sep 17 00:00:00 2001
From: FernandoS27 <fsahmkow27@gmail.com>
Date: Sun, 6 Jun 2021 09:57:24 +0200
Subject: [PATCH] General: Add settings for fastmem and disabling adress space
 check.

---
 src/common/settings.cpp                        |  8 ++++++++
 src/common/settings.h                          |  4 ++++
 src/core/arm/dynarmic/arm_dynarmic_32.cpp      |  5 ++++-
 src/core/arm/dynarmic/arm_dynarmic_64.cpp      |  8 +++++++-
 src/core/memory.cpp                            | 14 ++++++++++----
 src/yuzu/configuration/config.cpp              |  7 +++++++
 src/yuzu/configuration/configure_cpu.cpp       |  9 +++++++++
 src/yuzu/configuration/configure_cpu.h         |  1 +
 src/yuzu/configuration/configure_cpu.ui        | 12 ++++++++++++
 src/yuzu/configuration/configure_cpu_debug.cpp |  3 +++
 src/yuzu/configuration/configure_cpu_debug.ui  | 14 ++++++++++++++
 src/yuzu_cmd/default_ini.h                     |  4 ++++
 12 files changed, 83 insertions(+), 6 deletions(-)

diff --git a/src/common/settings.cpp b/src/common/settings.cpp
index bcb4e4be1a..360e878d60 100644
--- a/src/common/settings.cpp
+++ b/src/common/settings.cpp
@@ -90,6 +90,13 @@ bool IsGPULevelHigh() {
            values.gpu_accuracy.GetValue() == GPUAccuracy::High;
 }
 
+bool IsFastmemEnabled() {
+    if (values.cpu_accuracy.GetValue() == CPUAccuracy::DebugMode) {
+        return values.cpuopt_fastmem;
+    }
+    return true;
+}
+
 float Volume() {
     if (values.audio_muted) {
         return 0.0f;
@@ -115,6 +122,7 @@ void RestoreGlobalState(bool is_powered_on) {
     values.cpuopt_unsafe_unfuse_fma.SetGlobal(true);
     values.cpuopt_unsafe_reduce_fp_error.SetGlobal(true);
     values.cpuopt_unsafe_inaccurate_nan.SetGlobal(true);
+    values.cpuopt_unsafe_fastmem_check.SetGlobal(true);
 
     // Renderer
     values.renderer_backend.SetGlobal(true);
diff --git a/src/common/settings.h b/src/common/settings.h
index 48085b9a95..1af8c5ac2e 100644
--- a/src/common/settings.h
+++ b/src/common/settings.h
@@ -125,10 +125,12 @@ struct Values {
     bool cpuopt_const_prop;
     bool cpuopt_misc_ir;
     bool cpuopt_reduce_misalign_checks;
+    bool cpuopt_fastmem;
 
     Setting<bool> cpuopt_unsafe_unfuse_fma;
     Setting<bool> cpuopt_unsafe_reduce_fp_error;
     Setting<bool> cpuopt_unsafe_inaccurate_nan;
+    Setting<bool> cpuopt_unsafe_fastmem_check;
 
     // Renderer
     Setting<RendererBackend> renderer_backend;
@@ -249,6 +251,8 @@ void SetConfiguringGlobal(bool is_global);
 bool IsGPULevelExtreme();
 bool IsGPULevelHigh();
 
+bool IsFastmemEnabled();
+
 float Volume();
 
 std::string GetTimeZoneString();
diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.cpp b/src/core/arm/dynarmic/arm_dynarmic_32.cpp
index fb128f7358..c8f6dc7653 100644
--- a/src/core/arm/dynarmic/arm_dynarmic_32.cpp
+++ b/src/core/arm/dynarmic/arm_dynarmic_32.cpp
@@ -144,7 +144,7 @@ std::shared_ptr<Dynarmic::A32::Jit> ARM_Dynarmic_32::MakeJit(Common::PageTable*
 
     // Code cache size
     config.code_cache_size = 512 * 1024 * 1024;
-    config.far_code_offset = 256 * 1024 * 1024;
+    config.far_code_offset = 400 * 1024 * 1024;
 
     // Safe optimizations
     if (Settings::values.cpu_accuracy.GetValue() == Settings::CPUAccuracy::DebugMode) {
@@ -172,6 +172,9 @@ std::shared_ptr<Dynarmic::A32::Jit> ARM_Dynarmic_32::MakeJit(Common::PageTable*
         if (!Settings::values.cpuopt_reduce_misalign_checks) {
             config.only_detect_misalignment_via_page_table_on_page_boundary = false;
         }
+        if (!Settings::values.cpuopt_fastmem) {
+            config.fastmem_pointer = nullptr;
+        }
     }
 
     // Unsafe optimizations
diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.cpp b/src/core/arm/dynarmic/arm_dynarmic_64.cpp
index b0ac8cf8ac..ba524cd058 100644
--- a/src/core/arm/dynarmic/arm_dynarmic_64.cpp
+++ b/src/core/arm/dynarmic/arm_dynarmic_64.cpp
@@ -185,7 +185,7 @@ std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic_64::MakeJit(Common::PageTable*
 
     // Code cache size
     config.code_cache_size = 512 * 1024 * 1024;
-    config.far_code_offset = 256 * 1024 * 1024;
+    config.far_code_offset = 400 * 1024 * 1024;
 
     // Safe optimizations
     if (Settings::values.cpu_accuracy.GetValue() == Settings::CPUAccuracy::DebugMode) {
@@ -213,6 +213,9 @@ std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic_64::MakeJit(Common::PageTable*
         if (!Settings::values.cpuopt_reduce_misalign_checks) {
             config.only_detect_misalignment_via_page_table_on_page_boundary = false;
         }
+        if (!Settings::values.cpuopt_fastmem) {
+            config.fastmem_pointer = nullptr;
+        }
     }
 
     // Unsafe optimizations
@@ -227,6 +230,9 @@ std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic_64::MakeJit(Common::PageTable*
         if (Settings::values.cpuopt_unsafe_inaccurate_nan.GetValue()) {
             config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_InaccurateNaN;
         }
+        if (Settings::values.cpuopt_unsafe_fastmem_check.GetValue()) {
+            config.fastmem_address_space_bits = 64;
+        }
     }
 
     return std::make_shared<Dynarmic::A64::Jit>(config);
diff --git a/src/core/memory.cpp b/src/core/memory.cpp
index 79468e4dc7..f285c6f639 100644
--- a/src/core/memory.cpp
+++ b/src/core/memory.cpp
@@ -47,7 +47,9 @@ struct Memory::Impl {
                    "Out of bounds target: {:016X}", target);
         MapPages(page_table, base / PAGE_SIZE, size / PAGE_SIZE, target, Common::PageType::Memory);
 
-        system.DeviceMemory().buffer.Map(base, target - DramMemoryMap::Base, size);
+        if (Settings::IsFastmemEnabled()) {
+            system.DeviceMemory().buffer.Map(base, target - DramMemoryMap::Base, size);
+        }
     }
 
     void UnmapRegion(Common::PageTable& page_table, VAddr base, u64 size) {
@@ -55,7 +57,9 @@ struct Memory::Impl {
         ASSERT_MSG((base & PAGE_MASK) == 0, "non-page aligned base: {:016X}", base);
         MapPages(page_table, base / PAGE_SIZE, size / PAGE_SIZE, 0, Common::PageType::Unmapped);
 
-        system.DeviceMemory().buffer.Unmap(base, size);
+        if (Settings::IsFastmemEnabled()) {
+            system.DeviceMemory().buffer.Unmap(base, size);
+        }
     }
 
     bool IsValidVirtualAddress(const Kernel::KProcess& process, const VAddr vaddr) const {
@@ -475,8 +479,10 @@ struct Memory::Impl {
             return;
         }
 
-        const bool is_read_enable = Settings::IsGPULevelHigh() || !cached;
-        system.DeviceMemory().buffer.Protect(vaddr, size, is_read_enable, !cached);
+        if (Settings::IsFastmemEnabled()) {
+            const bool is_read_enable = Settings::IsGPULevelHigh() || !cached;
+            system.DeviceMemory().buffer.Protect(vaddr, size, is_read_enable, !cached);
+        }
 
         // Iterate over a contiguous CPU address space, which corresponds to the specified GPU
         // address space, marking the region as un/cached. The region is marked un/cached at a
diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp
index e9d4bef607..a59b36e138 100644
--- a/src/yuzu/configuration/config.cpp
+++ b/src/yuzu/configuration/config.cpp
@@ -756,6 +756,8 @@ void Config::ReadCpuValues() {
                       QStringLiteral("cpuopt_unsafe_reduce_fp_error"), true);
     ReadSettingGlobal(Settings::values.cpuopt_unsafe_inaccurate_nan,
                       QStringLiteral("cpuopt_unsafe_inaccurate_nan"), true);
+    ReadSettingGlobal(Settings::values.cpuopt_unsafe_fastmem_check,
+                      QStringLiteral("cpuopt_unsafe_fastmem_check"), true);
 
     if (global) {
         Settings::values.cpuopt_page_tables =
@@ -774,6 +776,8 @@ void Config::ReadCpuValues() {
             ReadSetting(QStringLiteral("cpuopt_misc_ir"), true).toBool();
         Settings::values.cpuopt_reduce_misalign_checks =
             ReadSetting(QStringLiteral("cpuopt_reduce_misalign_checks"), true).toBool();
+        Settings::values.cpuopt_fastmem =
+            ReadSetting(QStringLiteral("cpuopt_fastmem"), true).toBool();
     }
 
     qt_config->endGroup();
@@ -1332,6 +1336,8 @@ void Config::SaveCpuValues() {
                        Settings::values.cpuopt_unsafe_reduce_fp_error, true);
     WriteSettingGlobal(QStringLiteral("cpuopt_unsafe_inaccurate_nan"),
                        Settings::values.cpuopt_unsafe_inaccurate_nan, true);
+    WriteSettingGlobal(QStringLiteral("cpuopt_unsafe_fastmem_check"),
+                       Settings::values.cpuopt_unsafe_fastmem_check, true);
 
     if (global) {
         WriteSetting(QStringLiteral("cpuopt_page_tables"), Settings::values.cpuopt_page_tables,
@@ -1348,6 +1354,7 @@ void Config::SaveCpuValues() {
         WriteSetting(QStringLiteral("cpuopt_misc_ir"), Settings::values.cpuopt_misc_ir, true);
         WriteSetting(QStringLiteral("cpuopt_reduce_misalign_checks"),
                      Settings::values.cpuopt_reduce_misalign_checks, true);
+        WriteSetting(QStringLiteral("cpuopt_fastmem"), Settings::values.cpuopt_fastmem, true);
     }
 
     qt_config->endGroup();
diff --git a/src/yuzu/configuration/configure_cpu.cpp b/src/yuzu/configuration/configure_cpu.cpp
index 525c42ff0d..22219cbada 100644
--- a/src/yuzu/configuration/configure_cpu.cpp
+++ b/src/yuzu/configuration/configure_cpu.cpp
@@ -35,12 +35,15 @@ void ConfigureCpu::SetConfiguration() {
     ui->cpuopt_unsafe_unfuse_fma->setEnabled(runtime_lock);
     ui->cpuopt_unsafe_reduce_fp_error->setEnabled(runtime_lock);
     ui->cpuopt_unsafe_inaccurate_nan->setEnabled(runtime_lock);
+    ui->cpuopt_unsafe_fastmem_check->setEnabled(runtime_lock);
 
     ui->cpuopt_unsafe_unfuse_fma->setChecked(Settings::values.cpuopt_unsafe_unfuse_fma.GetValue());
     ui->cpuopt_unsafe_reduce_fp_error->setChecked(
         Settings::values.cpuopt_unsafe_reduce_fp_error.GetValue());
     ui->cpuopt_unsafe_inaccurate_nan->setChecked(
         Settings::values.cpuopt_unsafe_inaccurate_nan.GetValue());
+    ui->cpuopt_unsafe_fastmem_check->setChecked(
+        Settings::values.cpuopt_unsafe_fastmem_check.GetValue());
 
     if (Settings::IsConfiguringGlobal()) {
         ui->accuracy->setCurrentIndex(static_cast<int>(Settings::values.cpu_accuracy.GetValue()));
@@ -84,6 +87,9 @@ void ConfigureCpu::ApplyConfiguration() {
     ConfigurationShared::ApplyPerGameSetting(&Settings::values.cpuopt_unsafe_inaccurate_nan,
                                              ui->cpuopt_unsafe_inaccurate_nan,
                                              cpuopt_unsafe_inaccurate_nan);
+    ConfigurationShared::ApplyPerGameSetting(&Settings::values.cpuopt_unsafe_fastmem_check,
+                                             ui->cpuopt_unsafe_fastmem_check,
+                                             cpuopt_unsafe_fastmem_check);
 
     if (Settings::IsConfiguringGlobal()) {
         // Guard if during game and set to game-specific value
@@ -134,4 +140,7 @@ void ConfigureCpu::SetupPerGameUI() {
     ConfigurationShared::SetColoredTristate(ui->cpuopt_unsafe_inaccurate_nan,
                                             Settings::values.cpuopt_unsafe_inaccurate_nan,
                                             cpuopt_unsafe_inaccurate_nan);
+    ConfigurationShared::SetColoredTristate(ui->cpuopt_unsafe_fastmem_check,
+                                            Settings::values.cpuopt_unsafe_fastmem_check,
+                                            cpuopt_unsafe_fastmem_check);
 }
diff --git a/src/yuzu/configuration/configure_cpu.h b/src/yuzu/configuration/configure_cpu.h
index 8e2eeb7a68..57ff2772a6 100644
--- a/src/yuzu/configuration/configure_cpu.h
+++ b/src/yuzu/configuration/configure_cpu.h
@@ -41,4 +41,5 @@ private:
     ConfigurationShared::CheckState cpuopt_unsafe_unfuse_fma;
     ConfigurationShared::CheckState cpuopt_unsafe_reduce_fp_error;
     ConfigurationShared::CheckState cpuopt_unsafe_inaccurate_nan;
+    ConfigurationShared::CheckState cpuopt_unsafe_fastmem_check;
 };
diff --git a/src/yuzu/configuration/configure_cpu.ui b/src/yuzu/configuration/configure_cpu.ui
index 99b5736405..31ef9e3f54 100644
--- a/src/yuzu/configuration/configure_cpu.ui
+++ b/src/yuzu/configuration/configure_cpu.ui
@@ -123,6 +123,18 @@
           </property>
          </widget>
         </item>
+        <item>
+         <widget class="QCheckBox" name="cpuopt_unsafe_fastmem_check">
+          <property name="toolTip">
+           <string>
+            &lt;div&gt;This option improves speed by eliminating a safety check before every memory read/write in guest. Disabling it may allow a game to read/write the emulator's memory.&lt;/div&gt;
+           </string>
+          </property>
+          <property name="text">
+           <string>Disable address space checks</string>
+          </property>
+         </widget>
+        </item>
        </layout>
       </widget>
      </item>
diff --git a/src/yuzu/configuration/configure_cpu_debug.cpp b/src/yuzu/configuration/configure_cpu_debug.cpp
index c925c023c4..e25c52baf4 100644
--- a/src/yuzu/configuration/configure_cpu_debug.cpp
+++ b/src/yuzu/configuration/configure_cpu_debug.cpp
@@ -39,6 +39,8 @@ void ConfigureCpuDebug::SetConfiguration() {
     ui->cpuopt_misc_ir->setChecked(Settings::values.cpuopt_misc_ir);
     ui->cpuopt_reduce_misalign_checks->setEnabled(runtime_lock);
     ui->cpuopt_reduce_misalign_checks->setChecked(Settings::values.cpuopt_reduce_misalign_checks);
+    ui->cpuopt_fastmem->setEnabled(runtime_lock);
+    ui->cpuopt_fastmem->setChecked(Settings::values.cpuopt_fastmem);
 }
 
 void ConfigureCpuDebug::ApplyConfiguration() {
@@ -50,6 +52,7 @@ void ConfigureCpuDebug::ApplyConfiguration() {
     Settings::values.cpuopt_const_prop = ui->cpuopt_const_prop->isChecked();
     Settings::values.cpuopt_misc_ir = ui->cpuopt_misc_ir->isChecked();
     Settings::values.cpuopt_reduce_misalign_checks = ui->cpuopt_reduce_misalign_checks->isChecked();
+    Settings::values.cpuopt_fastmem = ui->cpuopt_fastmem->isChecked();
 }
 
 void ConfigureCpuDebug::changeEvent(QEvent* event) {
diff --git a/src/yuzu/configuration/configure_cpu_debug.ui b/src/yuzu/configuration/configure_cpu_debug.ui
index a90dc64fed..11ee19a128 100644
--- a/src/yuzu/configuration/configure_cpu_debug.ui
+++ b/src/yuzu/configuration/configure_cpu_debug.ui
@@ -139,6 +139,20 @@
           </property>
          </widget>
         </item>
+        <item>
+         <widget class="QCheckBox" name="cpuopt_fastmem">
+          <property name="text">
+           <string>Enable Host MMU Emulation</string>
+          </property>
+          <property name="toolTip">
+           <string>
+            &lt;div style="white-space: nowrap"&gt;This optimization speeds up memory accesses by the guest program.&lt;/div&gt;
+            &lt;div style="white-space: nowrap"&gt;Enabling it causes guest memory reads/writes to be done directly into memory and make use of Host's MMU.&lt;/div&gt;
+            &lt;div style="white-space: nowrap"&gt;Disabling this forces all memory accesses to use Software MMU Emulation.&lt;/div&gt;
+           </string>
+          </property>
+         </widget>
+        </item>
        </layout>
       </widget>
      </item>
diff --git a/src/yuzu_cmd/default_ini.h b/src/yuzu_cmd/default_ini.h
index 8ce2967ac2..f48d935a1f 100644
--- a/src/yuzu_cmd/default_ini.h
+++ b/src/yuzu_cmd/default_ini.h
@@ -150,6 +150,10 @@ cpuopt_misc_ir =
 # 0: Disabled, 1 (default): Enabled
 cpuopt_reduce_misalign_checks =
 
+# Enable Host MMU Emulation (faster guest memory access)
+# 0: Disabled, 1 (default): Enabled
+cpuopt_fastmem =
+
 [Renderer]
 # Which backend API to use.
 # 0 (default): OpenGL, 1: Vulkan