summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorcristian64 <cristian64@gmail.com>2026-04-03 10:58:54 +0100
committercristian64 <cristian64@gmail.com>2026-07-11 23:02:54 +0100
commit0cab1731d61ecb87c7bc388dbd176a4150afbbe3 (patch)
treef30c08837851d9fe32073003cbaff5a4bc418b06
parent03b1f2148b080adc9ed15ecc40e3948404388b61 (diff)
Core: Adjust emulated memory size automatically.
Dolphin now uses the simulated memory size defined in `bi2.bin` to adjust the memory size in the emulated console automatically. If **Enable Emulated Memory Size Override** has been enabled by the user, the fixed memory size specified for **MEM1** and **MEM2** are still used as they were before. Most retail games do not define the simulated memory size (Wii or Triforce games), or define it to a value that matches the default 24 MiB (GameCube games), so, in the general case, there is no behavior change. One game that sets the simulated memory to a non-default value is the debug build of _Mario Kart: Double Dash!!_, where the value is set to 48 MiB. This enhancement is focused mainly to the modding community. Prior to these changes, modded games with extended memory requirements would fail to launch in Dolphin [with no indication of what the problem is] if the user failed to set the emulated memory override to the correct value. Now, modding tools can specify the simulated memory size in the `bi2.bin` file to produce extended games that _just work_ in Dolphin, without cumbersome instructions that can be overlooked by the user.
-rw-r--r--Source/Core/Core/FifoPlayer/FifoDataFile.cpp3
-rw-r--r--Source/Core/Core/HW/Memmap.cpp13
-rw-r--r--Source/Core/Core/HW/Memmap.h2
-rw-r--r--Source/Core/Core/IOS/IOS.cpp5
-rw-r--r--Source/Core/Core/System.cpp1
-rw-r--r--Source/Core/Core/System.h4
-rw-r--r--Source/UnitTests/Core/PowerPC/PageTableHostMappingTest.cpp5
7 files changed, 29 insertions, 4 deletions
diff --git a/Source/Core/Core/FifoPlayer/FifoDataFile.cpp b/Source/Core/Core/FifoPlayer/FifoDataFile.cpp
index f795d5f08a..0e1e44aef9 100644
--- a/Source/Core/Core/FifoPlayer/FifoDataFile.cpp
+++ b/Source/Core/Core/FifoPlayer/FifoDataFile.cpp
@@ -140,7 +140,8 @@ bool FifoDataFile::Save(const std::string& filename)
header.fileId = FILE_ID;
header.file_version = VERSION_NUMBER;
// Maintain backwards compatibility so long as the RAM sizes aren't overridden.
- if (Config::Get(Config::MAIN_RAM_OVERRIDE_ENABLE))
+ if (Config::Get(Config::MAIN_RAM_OVERRIDE_ENABLE) ||
+ SConfig::GetInstance().GetSimulatedMemorySize() > Memory::MEM1_SIZE_RETAIL)
header.min_loader_version = MIN_LOADER_VERSION_FOR_RAM_OVERRIDE;
else
header.min_loader_version = MIN_LOADER_VERSION;
diff --git a/Source/Core/Core/HW/Memmap.cpp b/Source/Core/Core/HW/Memmap.cpp
index e6d8fd56a5..054596e3d8 100644
--- a/Source/Core/Core/HW/Memmap.cpp
+++ b/Source/Core/Core/HW/Memmap.cpp
@@ -25,6 +25,7 @@
#include "Common/MsgHandler.h"
#include "Common/Swap.h"
#include "Core/Config/MainSettings.h"
+#include "Core/ConfigManager.h"
#include "Core/Core.h"
#include "Core/HW/AudioInterface.h"
#include "Core/HW/DSP.h"
@@ -87,10 +88,18 @@ void MemoryManager::InitMMIO(Core::System& system)
void MemoryManager::Init()
{
- const auto get_mem1_size = [] {
+ const auto get_mem1_size = [this] {
if (Config::Get(Config::MAIN_RAM_OVERRIDE_ENABLE))
return Config::Get(Config::MAIN_MEM1_SIZE);
- return Memory::MEM1_SIZE_RETAIL;
+ // The simulated memory size in the game's header was originally used to ask the Apploader to
+ // simulate a smaller memory size than that in development systems. That is, it could make the
+ // 48 MiB devkit act like a 24 MiB retail console during testing, or any other config.
+ //
+ // Dolphin is reusing this as a signal to automatically adjust the emulated memory size. The
+ // upper bound is clamped to 64 MiB (maximum supported by Flipper's memory controller),
+ // reflecting Apploader behaviour of clamping the simulated size to physical memory size. It is
+ // never desired to emulate less than a retail console, so the lower bound is clapped to 24 MiB.
+ return std::clamp(m_system.GetSimulatedMemorySize(), MEM1_SIZE_RETAIL, MEM1_SIZE_MAX);
};
const auto get_mem2_size = [] {
if (Config::Get(Config::MAIN_RAM_OVERRIDE_ENABLE))
diff --git a/Source/Core/Core/HW/Memmap.h b/Source/Core/Core/HW/Memmap.h
index baa910cc70..e9253272f6 100644
--- a/Source/Core/Core/HW/Memmap.h
+++ b/Source/Core/Core/HW/Memmap.h
@@ -34,8 +34,10 @@ constexpr u32 MEM1_BASE_ADDR = 0x80000000U;
constexpr u32 MEM2_BASE_ADDR = 0x90000000U;
constexpr u32 MEM1_SIZE_RETAIL = 0x01800000U;
constexpr u32 MEM1_SIZE_GDEV = 0x04000000U;
+constexpr u32 MEM1_SIZE_MAX = 0x04000000U;
constexpr u32 MEM2_SIZE_RETAIL = 0x04000000U;
constexpr u32 MEM2_SIZE_NDEV = 0x08000000U;
+constexpr u32 MEM2_SIZE_MAX = 0x08000000U;
struct PhysicalMemoryRegion
{
diff --git a/Source/Core/Core/IOS/IOS.cpp b/Source/Core/Core/IOS/IOS.cpp
index d3986775b6..49c0b2bbd3 100644
--- a/Source/Core/Core/IOS/IOS.cpp
+++ b/Source/Core/Core/IOS/IOS.cpp
@@ -221,8 +221,11 @@ static void ReleasePPCAncast(Core::System& system)
void RAMOverrideForIOSMemoryValues(Memory::MemoryManager& memory, MemorySetupType setup_type)
{
// Don't touch anything if the feature isn't enabled.
- if (!Config::Get(Config::MAIN_RAM_OVERRIDE_ENABLE))
+ if (!Config::Get(Config::MAIN_RAM_OVERRIDE_ENABLE) ||
+ SConfig::GetInstance().GetSimulatedMemorySize() <= Memory::MEM1_SIZE_RETAIL)
+ {
return;
+ }
// Some unstated constants that can be inferred.
const u32 ipc_buffer_size =
diff --git a/Source/Core/Core/System.cpp b/Source/Core/Core/System.cpp
index 686d1a3264..12da7dcaea 100644
--- a/Source/Core/Core/System.cpp
+++ b/Source/Core/Core/System.cpp
@@ -119,6 +119,7 @@ void System::Initialize()
m_separate_cpu_and_gpu_threads = Config::Get(Config::MAIN_CPU_THREAD);
m_mmu_enabled = Config::Get(Config::MAIN_MMU);
m_pause_on_panic_enabled = Config::Get(Config::MAIN_PAUSE_ON_PANIC);
+ m_simulated_memory_size = SConfig::GetInstance().GetSimulatedMemorySize();
}
SoundStream* System::GetSoundStream() const
diff --git a/Source/Core/Core/System.h b/Source/Core/Core/System.h
index a170c608ee..8524003400 100644
--- a/Source/Core/Core/System.h
+++ b/Source/Core/Core/System.h
@@ -5,6 +5,8 @@
#include <memory>
+#include "Common/CommonTypes.h"
+
class GeometryShaderManager;
class Interpreter;
class JitInterface;
@@ -147,6 +149,7 @@ public:
bool IsTriforce() const { return m_is_triforce; }
bool IsWii() const { return m_is_wii; }
bool IsBranchWatchIgnoreApploader() { return m_branch_watch_ignore_apploader; }
+ u32 GetSimulatedMemorySize() const { return m_simulated_memory_size; }
void SetIsMIOS(bool is_mios) { m_is_mios = is_mios; }
void SetIsTriforce(bool is_triforce) { m_is_triforce = is_triforce; }
@@ -216,5 +219,6 @@ private:
bool m_is_triforce = false;
bool m_is_wii = false;
bool m_branch_watch_ignore_apploader = false;
+ u32 m_simulated_memory_size{0};
};
} // namespace Core
diff --git a/Source/UnitTests/Core/PowerPC/PageTableHostMappingTest.cpp b/Source/UnitTests/Core/PowerPC/PageTableHostMappingTest.cpp
index 2cfb4b8c8f..c2622cee37 100644
--- a/Source/UnitTests/Core/PowerPC/PageTableHostMappingTest.cpp
+++ b/Source/UnitTests/Core/PowerPC/PageTableHostMappingTest.cpp
@@ -10,6 +10,7 @@
#include "Common/Align.h"
#include "Common/CommonTypes.h"
#include "Common/Swap.h"
+#include "Core/ConfigManager.h"
#include "Core/Core.h"
#include "Core/MemTools.h"
#include "Core/PowerPC/BreakPoints.h"
@@ -131,6 +132,8 @@ public:
if (!EMM::IsExceptionHandlerSupported())
GTEST_SKIP() << "Skipping PageTableHostMappingTest because exception handler is unsupported.";
+ SConfig::Init();
+
auto& system = Core::System::GetInstance();
auto& memory = system.GetMemory();
const u32 host_page_size = memory.GetHostPageSize();
@@ -177,6 +180,8 @@ public:
EMM::UninstallExceptionHandler();
Core::UndeclareAsCPUThread();
system.GetMemory().Shutdown();
+
+ SConfig::Shutdown();
}
static void SetSR(size_t index, u32 vsid)