summaryrefslogtreecommitdiff
path: root/Source/Core
diff options
context:
space:
mode:
authorLéo Lam <leo@leolam.fr>2020-04-28 22:11:12 +0200
committerGitHub <noreply@github.com>2020-04-28 22:11:12 +0200
commit4b00ddf9aaeda9b8781ede7ddb2ccccc055aa76b (patch)
tree5dedb95c2d9a53d6b807f97e0516aab14c0b8c15 /Source/Core
parent54b85f6034d3f5a8b16a918f5cba34e9c6cad1a9 (diff)
parentcc858c63b8d04c5ce407c7efd0ae8abc654e73a0 (diff)
Merge pull request #8722 from Minty-Meeo/master
Configurable MEM1 and MEM2 sizes at runtime via Dolphin.ini
Diffstat (limited to 'Source/Core')
-rw-r--r--Source/Core/Core/Boot/Boot_BS2Emu.cpp35
-rw-r--r--Source/Core/Core/Boot/DolReader.cpp4
-rw-r--r--Source/Core/Core/Boot/ElfReader.cpp2
-rw-r--r--Source/Core/Core/Config/MainSettings.cpp4
-rw-r--r--Source/Core/Core/Config/MainSettings.h3
-rw-r--r--Source/Core/Core/ConfigLoaders/IsSettingSaveable.cpp6
-rw-r--r--Source/Core/Core/FifoPlayer/FifoDataFile.cpp65
-rw-r--r--Source/Core/Core/FifoPlayer/FifoDataFile.h5
-rw-r--r--Source/Core/Core/FifoPlayer/FifoPlayer.cpp4
-rw-r--r--Source/Core/Core/FifoPlayer/FifoRecorder.cpp12
-rw-r--r--Source/Core/Core/HW/AddressSpace.cpp25
-rw-r--r--Source/Core/Core/HW/AddressSpace.h2
-rw-r--r--Source/Core/Core/HW/DSP.cpp6
-rw-r--r--Source/Core/Core/HW/DSPHLE/UCodes/UCodes.cpp28
-rw-r--r--Source/Core/Core/HW/HW.cpp4
-rw-r--r--Source/Core/Core/HW/Memmap.cpp128
-rw-r--r--Source/Core/Core/HW/Memmap.h35
-rw-r--r--Source/Core/Core/IOS/IOS.cpp71
-rw-r--r--Source/Core/Core/IOS/IOS.h8
-rw-r--r--Source/Core/Core/IOS/MIOS.cpp2
-rw-r--r--Source/Core/Core/IOS/VersionInfo.h4
-rw-r--r--Source/Core/Core/PowerPC/MMU.cpp37
-rw-r--r--Source/Core/Core/State.cpp21
-rw-r--r--Source/Core/DolphinQt/CheatsManager.cpp2
-rw-r--r--Source/Core/DolphinQt/MenuBar.cpp13
-rw-r--r--Source/Core/DolphinQt/Settings/AdvancedPane.cpp87
-rw-r--r--Source/Core/DolphinQt/Settings/AdvancedPane.h7
27 files changed, 487 insertions, 133 deletions
diff --git a/Source/Core/Core/Boot/Boot_BS2Emu.cpp b/Source/Core/Core/Boot/Boot_BS2Emu.cpp
index 7ef205225d..33e004598b 100644
--- a/Source/Core/Core/Boot/Boot_BS2Emu.cpp
+++ b/Source/Core/Core/Boot/Boot_BS2Emu.cpp
@@ -172,7 +172,7 @@ void CBoot::SetupGCMemory()
PowerPC::HostWrite_U32(0x0D15EA5E, 0x80000020);
// Physical Memory Size (24MB on retail)
- PowerPC::HostWrite_U32(Memory::REALRAM_SIZE, 0x80000028);
+ PowerPC::HostWrite_U32(Memory::GetRamSizeReal(), 0x80000028);
// Console type - DevKit (retail ID == 0x00000003) see YAGCD 4.2.1.1.2
// TODO: determine why some games fail when using a retail ID.
@@ -369,26 +369,26 @@ bool CBoot::SetupWiiMemory(IOS::HLE::IOSC::ConsoleType console_type)
0x80000060 Copyright code
*/
- Memory::Write_U32(0x0D15EA5E, 0x00000020); // Another magic word
- Memory::Write_U32(0x00000001, 0x00000024); // Unknown
- Memory::Write_U32(Memory::REALRAM_SIZE, 0x00000028); // MEM1 size 24MB
+ Memory::Write_U32(0x0D15EA5E, 0x00000020); // Another magic word
+ Memory::Write_U32(0x00000001, 0x00000024); // Unknown
+ Memory::Write_U32(Memory::GetRamSizeReal(), 0x00000028); // MEM1 size 24MB
u32 board_model = console_type == IOS::HLE::IOSC::ConsoleType::RVT ? 0x10000021 : 0x00000023;
Memory::Write_U32(board_model, 0x0000002c); // Board Model
Memory::Write_U32(0x00000000, 0x00000030); // Init
Memory::Write_U32(0x817FEC60, 0x00000034); // Init
// 38, 3C should get start, size of FST through apploader
- Memory::Write_U32(0x8008f7b8, 0x000000e4); // Thread Init
- Memory::Write_U32(Memory::REALRAM_SIZE, 0x000000f0); // "Simulated memory size" (debug mode?)
- Memory::Write_U32(0x8179b500, 0x000000f4); // __start
- Memory::Write_U32(0x0e7be2c0, 0x000000f8); // Bus speed
- Memory::Write_U32(0x2B73A840, 0x000000fc); // CPU speed
- Memory::Write_U16(0x0000, 0x000030e6); // Console type
- Memory::Write_U32(0x00000000, 0x000030c0); // EXI
- Memory::Write_U32(0x00000000, 0x000030c4); // EXI
- Memory::Write_U32(0x00000000, 0x000030dc); // Time
- Memory::Write_U32(0xffffffff, 0x000030d8); // Unknown, set by any official NAND title
- Memory::Write_U16(0x8201, 0x000030e6); // Dev console / debug capable
- Memory::Write_U32(0x00000000, 0x000030f0); // Apploader
+ Memory::Write_U32(0x8008f7b8, 0x000000e4); // Thread Init
+ Memory::Write_U32(Memory::GetRamSizeReal(), 0x000000f0); // "Simulated memory size" (debug mode?)
+ Memory::Write_U32(0x8179b500, 0x000000f4); // __start
+ Memory::Write_U32(0x0e7be2c0, 0x000000f8); // Bus speed
+ Memory::Write_U32(0x2B73A840, 0x000000fc); // CPU speed
+ Memory::Write_U16(0x0000, 0x000030e6); // Console type
+ Memory::Write_U32(0x00000000, 0x000030c0); // EXI
+ Memory::Write_U32(0x00000000, 0x000030c4); // EXI
+ Memory::Write_U32(0x00000000, 0x000030dc); // Time
+ Memory::Write_U32(0xffffffff, 0x000030d8); // Unknown, set by any official NAND title
+ Memory::Write_U16(0x8201, 0x000030e6); // Dev console / debug capable
+ Memory::Write_U32(0x00000000, 0x000030f0); // Apploader
// During the boot process, 0x315c is first set to 0xdeadbeef by IOS
// in the boot_ppc syscall. The value is then partly overwritten by SDK titles.
@@ -493,6 +493,9 @@ bool CBoot::EmulatedBS2_Wii(const DiscIO::VolumeDisc& volume)
if (!RunApploader(/*is_wii*/ true, volume))
return false;
+ // The Apploader probably just overwrote values needed for RAM Override. Run this again!
+ IOS::HLE::RAMOverrideForIOSMemoryValues(IOS::HLE::MemorySetupType::IOSReload);
+
// Warning: This call will set incorrect running game metadata if our volume parameter
// doesn't point to the same disc as the one that's inserted in the emulated disc drive!
IOS::HLE::GetIOS()->GetES()->DIVerify(tmd, volume.GetTicket(partition));
diff --git a/Source/Core/Core/Boot/DolReader.cpp b/Source/Core/Core/Boot/DolReader.cpp
index 1fd03fd9a1..54c010013e 100644
--- a/Source/Core/Core/Boot/DolReader.cpp
+++ b/Source/Core/Core/Boot/DolReader.cpp
@@ -102,7 +102,7 @@ bool DolReader::LoadIntoMemory(bool only_in_mem1) const
for (size_t i = 0; i < m_text_sections.size(); ++i)
if (!m_text_sections[i].empty() &&
!(only_in_mem1 &&
- m_dolheader.textAddress[i] + m_text_sections[i].size() >= Memory::REALRAM_SIZE))
+ m_dolheader.textAddress[i] + m_text_sections[i].size() >= Memory::GetRamSizeReal()))
{
Memory::CopyToEmu(m_dolheader.textAddress[i], m_text_sections[i].data(),
m_text_sections[i].size());
@@ -112,7 +112,7 @@ bool DolReader::LoadIntoMemory(bool only_in_mem1) const
for (size_t i = 0; i < m_data_sections.size(); ++i)
if (!m_data_sections[i].empty() &&
!(only_in_mem1 &&
- m_dolheader.dataAddress[i] + m_data_sections[i].size() >= Memory::REALRAM_SIZE))
+ m_dolheader.dataAddress[i] + m_data_sections[i].size() >= Memory::GetRamSizeReal()))
{
Memory::CopyToEmu(m_dolheader.dataAddress[i], m_data_sections[i].data(),
m_data_sections[i].size());
diff --git a/Source/Core/Core/Boot/ElfReader.cpp b/Source/Core/Core/Boot/ElfReader.cpp
index 979a309ac3..12a5e76874 100644
--- a/Source/Core/Core/Boot/ElfReader.cpp
+++ b/Source/Core/Core/Boot/ElfReader.cpp
@@ -151,7 +151,7 @@ bool ElfReader::LoadIntoMemory(bool only_in_mem1) const
u32 srcSize = p->p_filesz;
u32 dstSize = p->p_memsz;
- if (only_in_mem1 && p->p_vaddr >= Memory::REALRAM_SIZE)
+ if (only_in_mem1 && p->p_vaddr >= Memory::GetRamSizeReal())
continue;
Memory::CopyToEmu(writeAddr, src, srcSize);
diff --git a/Source/Core/Core/Config/MainSettings.cpp b/Source/Core/Core/Config/MainSettings.cpp
index fd1fde1277..577878df2b 100644
--- a/Source/Core/Core/Config/MainSettings.cpp
+++ b/Source/Core/Core/Config/MainSettings.cpp
@@ -9,6 +9,7 @@
#include "AudioCommon/AudioCommon.h"
#include "Common/Config/Config.h"
#include "Core/HW/EXI/EXI_Device.h"
+#include "Core/HW/Memmap.h"
#include "Core/HW/SI/SI_Device.h"
#include "Core/PowerPC/PowerPC.h"
@@ -98,6 +99,9 @@ const ConfigInfo<bool> MAIN_ACCURATE_NANS{{System::Main, "Core", "AccurateNaNs"}
const ConfigInfo<float> MAIN_EMULATION_SPEED{{System::Main, "Core", "EmulationSpeed"}, 1.0f};
const ConfigInfo<float> MAIN_OVERCLOCK{{System::Main, "Core", "Overclock"}, 1.0f};
const ConfigInfo<bool> MAIN_OVERCLOCK_ENABLE{{System::Main, "Core", "OverclockEnable"}, false};
+const ConfigInfo<bool> MAIN_RAM_OVERRIDE_ENABLE{{System::Main, "Core", "RAMOverrideEnable"}, false};
+const ConfigInfo<u32> MAIN_MEM1_SIZE{{System::Main, "Core", "MEM1Size"}, Memory::MEM1_SIZE_RETAIL};
+const ConfigInfo<u32> MAIN_MEM2_SIZE{{System::Main, "Core", "MEM2Size"}, Memory::MEM2_SIZE_RETAIL};
const ConfigInfo<std::string> MAIN_GFX_BACKEND{{System::Main, "Core", "GFXBackend"}, ""};
const ConfigInfo<std::string> MAIN_GPU_DETERMINISM_MODE{
{System::Main, "Core", "GPUDeterminismMode"}, "auto"};
diff --git a/Source/Core/Core/Config/MainSettings.h b/Source/Core/Core/Config/MainSettings.h
index 8278578a9c..60b197d784 100644
--- a/Source/Core/Core/Config/MainSettings.h
+++ b/Source/Core/Core/Config/MainSettings.h
@@ -76,6 +76,9 @@ extern const ConfigInfo<bool> MAIN_ACCURATE_NANS;
extern const ConfigInfo<float> MAIN_EMULATION_SPEED;
extern const ConfigInfo<float> MAIN_OVERCLOCK;
extern const ConfigInfo<bool> MAIN_OVERCLOCK_ENABLE;
+extern const ConfigInfo<bool> MAIN_RAM_OVERRIDE_ENABLE;
+extern const ConfigInfo<u32> MAIN_MEM1_SIZE;
+extern const ConfigInfo<u32> MAIN_MEM2_SIZE;
// Should really be part of System::GFX, but again, we're stuck with past mistakes.
extern const ConfigInfo<std::string> MAIN_GFX_BACKEND;
extern const ConfigInfo<std::string> MAIN_GPU_DETERMINISM_MODE;
diff --git a/Source/Core/Core/ConfigLoaders/IsSettingSaveable.cpp b/Source/Core/Core/ConfigLoaders/IsSettingSaveable.cpp
index f58aec2cd4..8e62ccfcce 100644
--- a/Source/Core/Core/ConfigLoaders/IsSettingSaveable.cpp
+++ b/Source/Core/Core/ConfigLoaders/IsSettingSaveable.cpp
@@ -28,7 +28,7 @@ bool IsSettingSaveable(const Config::ConfigLocation& config_location)
return true;
}
- static constexpr std::array<const Config::ConfigLocation*, 93> s_setting_saveable = {
+ static constexpr std::array<const Config::ConfigLocation*, 96> s_setting_saveable = {
// Main.Core
&Config::MAIN_DEFAULT_ISO.location,
@@ -37,8 +37,12 @@ bool IsSettingSaveable(const Config::ConfigLocation& config_location)
&Config::MAIN_AUTO_DISC_CHANGE.location,
&Config::MAIN_DPL2_DECODER.location,
&Config::MAIN_DPL2_QUALITY.location,
+ &Config::MAIN_RAM_OVERRIDE_ENABLE.location,
+ &Config::MAIN_MEM1_SIZE.location,
+ &Config::MAIN_MEM2_SIZE.location,
// Main.Display
+
&Config::MAIN_FULLSCREEN_DISPLAY_RES.location,
&Config::MAIN_FULLSCREEN.location,
&Config::MAIN_RENDER_TO_MAIN.location,
diff --git a/Source/Core/Core/FifoPlayer/FifoDataFile.cpp b/Source/Core/Core/FifoPlayer/FifoDataFile.cpp
index 9b3d03d69a..0c2d36d10d 100644
--- a/Source/Core/Core/FifoPlayer/FifoDataFile.cpp
+++ b/Source/Core/Core/FifoPlayer/FifoDataFile.cpp
@@ -11,12 +11,18 @@
#include <vector>
#include "Common/File.h"
+#include "Common/MsgHandler.h"
+#include "Core/Config/MainSettings.h"
+#include "Core/HW/Memmap.h"
enum
{
FILE_ID = 0x0d01f1f0,
- VERSION_NUMBER = 4,
+ VERSION_NUMBER = 5,
MIN_LOADER_VERSION = 1,
+ // This value is only used if the DFF file was created with overridden RAM sizes.
+ // If the MIN_LOADER_VERSION ever exceeds this, it's alright to remove it.
+ MIN_LOADER_VERSION_FOR_RAM_OVERRIDE = 5,
};
#pragma pack(push, 1)
@@ -39,7 +45,11 @@ struct FileHeader
u32 flags;
u64 texMemOffset;
u32 texMemSize;
- u8 reserved[40];
+ // These are for overriden RAM sizes. Otherwise the FIFO Player
+ // will crash and burn with mismatched settings. See PR #8722.
+ u32 mem1_size;
+ u32 mem2_size;
+ u8 reserved[32];
};
static_assert(sizeof(FileHeader) == 128, "FileHeader should be 128 bytes");
@@ -129,7 +139,11 @@ bool FifoDataFile::Save(const std::string& filename)
FileHeader header;
header.fileId = FILE_ID;
header.file_version = VERSION_NUMBER;
- header.min_loader_version = MIN_LOADER_VERSION;
+ // Maintain backwards compatability so long as the RAM sizes aren't overridden.
+ if (Config::Get(Config::MAIN_RAM_OVERRIDE_ENABLE))
+ header.min_loader_version = MIN_LOADER_VERSION_FOR_RAM_OVERRIDE;
+ else
+ header.min_loader_version = MIN_LOADER_VERSION;
header.bpMemOffset = bpMemOffset;
header.bpMemSize = BP_MEM_SIZE;
@@ -151,6 +165,9 @@ bool FifoDataFile::Save(const std::string& filename)
header.flags = m_Flags;
+ header.mem1_size = Memory::GetRamSizeReal();
+ header.mem2_size = Memory::GetExRamSizeReal();
+
file.Seek(0, SEEK_SET);
file.WriteBytes(&header, sizeof(FileHeader));
@@ -198,10 +215,22 @@ std::unique_ptr<FifoDataFile> FifoDataFile::Load(const std::string& filename, bo
if (header.fileId != FILE_ID || header.min_loader_version > VERSION_NUMBER)
{
+ CriticalAlertT(
+ "The DFF's minimum loader version (%d) exceeds the version of this FIFO Player (%d)",
+ header.min_loader_version, VERSION_NUMBER);
file.Close();
return nullptr;
}
+ // Official support for overridden RAM sizes was added in version 5.
+ if (header.file_version < 5)
+ {
+ // It's safe to assume FIFO Logs before PR #8722 weren't using this
+ // obscure feature, so load up these header values with the old defaults.
+ header.mem1_size = Memory::MEM1_SIZE_RETAIL;
+ header.mem2_size = Memory::MEM2_SIZE_RETAIL;
+ }
+
auto dataFile = std::make_unique<FifoDataFile>();
dataFile->m_Flags = header.flags;
@@ -209,10 +238,36 @@ std::unique_ptr<FifoDataFile> FifoDataFile::Load(const std::string& filename, bo
if (flagsOnly)
{
+ // Force settings to match those used when the DFF was created. This is sort of a hack.
+ // It only works because this function gets called twice, and the first time (flagsOnly mode)
+ // happens to be before HW::Init(). But the convenience is hard to deny!
+ Config::SetCurrent(Config::MAIN_RAM_OVERRIDE_ENABLE, true);
+ Config::SetCurrent(Config::MAIN_MEM1_SIZE, header.mem1_size);
+ Config::SetCurrent(Config::MAIN_MEM2_SIZE, header.mem2_size);
+
file.Close();
return dataFile;
}
+ // To make up for such a hacky thing, here is a catch-all failsafe in case if the above code
+ // stops working or is otherwise removed. As it is, this should never end up running.
+ // It should be noted, however, that Dolphin *will still crash* from the nullptr being returned
+ // in a non-flagsOnly context, so if this code becomes necessary, it should be moved above the
+ // prior conditional.
+ if (header.mem1_size != Memory::GetRamSizeReal() ||
+ header.mem2_size != Memory::GetExRamSizeReal())
+ {
+ CriticalAlertT("Emulated memory size mismatch!\n"
+ "Current | MEM1 %08X (%3dMB) MEM2 %08X (%3dMB)\n"
+ "DFF | MEM1 %08X (%3dMB) MEM2 %08X (%3dMB)",
+ Memory::GetRamSizeReal(), Memory::GetRamSizeReal() / 0x100000,
+ Memory::GetExRamSizeReal(), Memory::GetExRamSizeReal() / 0x100000,
+ header.mem1_size, header.mem1_size / 0x100000, header.mem2_size,
+ header.mem2_size / 0x100000);
+ file.Close();
+ return nullptr;
+ }
+
u32 size = std::min<u32>(BP_MEM_SIZE, header.bpMemSize);
file.Seek(header.bpMemOffset, SEEK_SET);
file.ReadArray(dataFile->m_BPMem, size);
@@ -238,6 +293,10 @@ std::unique_ptr<FifoDataFile> FifoDataFile::Load(const std::string& filename, bo
file.ReadArray(dataFile->m_TexMem, size);
}
+ // idk what else these could be used for, but it'd be a shame to not make them available.
+ dataFile->m_ram_size_real = header.mem1_size;
+ dataFile->m_exram_size_real = header.mem2_size;
+
// Read frames
for (u32 i = 0; i < header.frameCount; ++i)
{
diff --git a/Source/Core/Core/FifoPlayer/FifoDataFile.h b/Source/Core/Core/FifoPlayer/FifoDataFile.h
index 33042f3c6c..58dd8098b2 100644
--- a/Source/Core/Core/FifoPlayer/FifoDataFile.h
+++ b/Source/Core/Core/FifoPlayer/FifoDataFile.h
@@ -69,6 +69,9 @@ public:
u32* GetXFMem() { return m_XFMem; }
u32* GetXFRegs() { return m_XFRegs; }
u8* GetTexMem() { return m_TexMem; }
+ u32 GetRamSizeReal() { return m_ram_size_real; }
+ u32 GetExRamSizeReal() { return m_exram_size_real; }
+
void AddFrame(const FifoFrameInfo& frameInfo);
const FifoFrameInfo& GetFrame(u32 frame) const { return m_Frames[frame]; }
u32 GetFrameCount() const { return static_cast<u32>(m_Frames.size()); }
@@ -96,6 +99,8 @@ private:
u32 m_XFMem[XF_MEM_SIZE];
u32 m_XFRegs[XF_REGS_SIZE];
u8 m_TexMem[TEX_MEM_SIZE];
+ u32 m_ram_size_real;
+ u32 m_exram_size_real;
u32 m_Flags = 0;
u32 m_Version = 0;
diff --git a/Source/Core/Core/FifoPlayer/FifoPlayer.cpp b/Source/Core/Core/FifoPlayer/FifoPlayer.cpp
index 3bf070acb5..7761abea48 100644
--- a/Source/Core/Core/FifoPlayer/FifoPlayer.cpp
+++ b/Source/Core/Core/FifoPlayer/FifoPlayer.cpp
@@ -356,9 +356,9 @@ void FifoPlayer::WriteMemory(const MemoryUpdate& memUpdate)
u8* mem = nullptr;
if (memUpdate.address & 0x10000000)
- mem = &Memory::m_pEXRAM[memUpdate.address & Memory::EXRAM_MASK];
+ mem = &Memory::m_pEXRAM[memUpdate.address & Memory::GetExRamMask()];
else
- mem = &Memory::m_pRAM[memUpdate.address & Memory::RAM_MASK];
+ mem = &Memory::m_pRAM[memUpdate.address & Memory::GetRamMask()];
std::copy(memUpdate.data.begin(), memUpdate.data.end(), mem);
}
diff --git a/Source/Core/Core/FifoPlayer/FifoRecorder.cpp b/Source/Core/Core/FifoPlayer/FifoRecorder.cpp
index 96329d695b..8d042727ad 100644
--- a/Source/Core/Core/FifoPlayer/FifoRecorder.cpp
+++ b/Source/Core/Core/FifoPlayer/FifoRecorder.cpp
@@ -36,8 +36,8 @@ void FifoRecorder::StartRecording(s32 numFrames, CallbackFunc finishedCb)
// - Global variables suck
// - Multithreading with the above two sucks
//
- m_Ram.resize(Memory::RAM_SIZE);
- m_ExRam.resize(Memory::EXRAM_SIZE);
+ m_Ram.resize(Memory::GetRamSize());
+ m_ExRam.resize(Memory::GetExRamSize());
std::fill(m_Ram.begin(), m_Ram.end(), 0);
std::fill(m_ExRam.begin(), m_ExRam.end(), 0);
@@ -121,13 +121,13 @@ void FifoRecorder::UseMemory(u32 address, u32 size, MemoryUpdate::Type type, boo
u8* newData;
if (address & 0x10000000)
{
- curData = &m_ExRam[address & Memory::EXRAM_MASK];
- newData = &Memory::m_pEXRAM[address & Memory::EXRAM_MASK];
+ curData = &m_ExRam[address & Memory::GetExRamMask()];
+ newData = &Memory::m_pEXRAM[address & Memory::GetExRamMask()];
}
else
{
- curData = &m_Ram[address & Memory::RAM_MASK];
- newData = &Memory::m_pRAM[address & Memory::RAM_MASK];
+ curData = &m_Ram[address & Memory::GetRamMask()];
+ newData = &Memory::m_pRAM[address & Memory::GetRamMask()];
}
if (!dynamicUpdate && memcmp(curData, newData, size) != 0)
diff --git a/Source/Core/Core/HW/AddressSpace.cpp b/Source/Core/Core/HW/AddressSpace.cpp
index c84f62a7ef..0506db7687 100644
--- a/Source/Core/Core/HW/AddressSpace.cpp
+++ b/Source/Core/Core/HW/AddressSpace.cpp
@@ -234,6 +234,7 @@ struct AccessorMapping
struct CompositeAddressSpaceAccessors : Accessors
{
+ CompositeAddressSpaceAccessors() = default;
CompositeAddressSpaceAccessors(std::initializer_list<AccessorMapping> accessors)
: m_accessor_mappings(accessors.begin(), accessors.end())
{
@@ -303,6 +304,7 @@ private:
struct SmallBlockAccessors : Accessors
{
+ SmallBlockAccessors() = default;
SmallBlockAccessors(u8** alloc_base_, u32 size_) : alloc_base{alloc_base_}, size{size_} {}
bool IsValidAddress(u32 address) const override
@@ -366,14 +368,11 @@ struct NullAccessors : Accessors
static EffectiveAddressSpaceAccessors s_effective_address_space_accessors;
static AuxiliaryAddressSpaceAccessors s_auxiliary_address_space_accessors;
-static SmallBlockAccessors s_mem1_address_space_accessors{&Memory::m_pRAM, Memory::REALRAM_SIZE};
-static SmallBlockAccessors s_mem2_address_space_accessors{&Memory::m_pEXRAM, Memory::EXRAM_SIZE};
-static SmallBlockAccessors s_fake_address_space_accessors{&Memory::m_pFakeVMEM,
- Memory::FAKEVMEM_SIZE};
-static CompositeAddressSpaceAccessors s_physical_address_space_accessors_gcn{
- {0x00000000, &s_mem1_address_space_accessors}};
-static CompositeAddressSpaceAccessors s_physical_address_space_accessors_wii{
- {0x00000000, &s_mem1_address_space_accessors}, {0x10000000, &s_mem2_address_space_accessors}};
+static SmallBlockAccessors s_mem1_address_space_accessors;
+static SmallBlockAccessors s_mem2_address_space_accessors;
+static SmallBlockAccessors s_fake_address_space_accessors;
+static CompositeAddressSpaceAccessors s_physical_address_space_accessors_gcn;
+static CompositeAddressSpaceAccessors s_physical_address_space_accessors_wii;
static NullAccessors s_null_accessors;
Accessors* GetAccessors(Type address_space)
@@ -413,4 +412,14 @@ Accessors* GetAccessors(Type address_space)
return &s_null_accessors;
}
+void Init()
+{
+ s_mem1_address_space_accessors = {&Memory::m_pRAM, Memory::GetRamSizeReal()};
+ s_mem2_address_space_accessors = {&Memory::m_pEXRAM, Memory::GetExRamSizeReal()};
+ s_fake_address_space_accessors = {&Memory::m_pFakeVMEM, Memory::GetFakeVMemSize()};
+ s_physical_address_space_accessors_gcn = {{0x00000000, &s_mem1_address_space_accessors}};
+ s_physical_address_space_accessors_wii = {{0x00000000, &s_mem1_address_space_accessors},
+ {0x10000000, &s_mem2_address_space_accessors}};
+}
+
} // namespace AddressSpace
diff --git a/Source/Core/Core/HW/AddressSpace.h b/Source/Core/Core/HW/AddressSpace.h
index 9577669bdc..c1ed71ed20 100644
--- a/Source/Core/Core/HW/AddressSpace.h
+++ b/Source/Core/Core/HW/AddressSpace.h
@@ -47,4 +47,6 @@ struct Accessors
Accessors* GetAccessors(Type address_space);
+void Init();
+
} // namespace AddressSpace
diff --git a/Source/Core/Core/HW/DSP.cpp b/Source/Core/Core/HW/DSP.cpp
index d1b96e4c11..4e431ddce5 100644
--- a/Source/Core/Core/HW/DSP.cpp
+++ b/Source/Core/Core/HW/DSP.cpp
@@ -193,8 +193,8 @@ void Reinit(bool hle)
if (SConfig::GetInstance().bWii)
{
s_ARAM.wii_mode = true;
- s_ARAM.size = Memory::EXRAM_SIZE;
- s_ARAM.mask = Memory::EXRAM_MASK;
+ s_ARAM.size = Memory::GetExRamSizeReal();
+ s_ARAM.mask = Memory::GetExRamMask();
s_ARAM.ptr = Memory::m_pEXRAM;
}
else
@@ -589,7 +589,7 @@ u8 ReadARAM(u32 address)
if (address & 0x10000000)
return s_ARAM.ptr[address & s_ARAM.mask];
else
- return Memory::Read_U8(address & Memory::RAM_MASK);
+ return Memory::Read_U8(address & Memory::GetRamMask());
}
else
{
diff --git a/Source/Core/Core/HW/DSPHLE/UCodes/UCodes.cpp b/Source/Core/Core/HW/DSPHLE/UCodes/UCodes.cpp
index edc3a7a876..79e95b4296 100644
--- a/Source/Core/Core/HW/DSPHLE/UCodes/UCodes.cpp
+++ b/Source/Core/Core/HW/DSPHLE/UCodes/UCodes.cpp
@@ -39,17 +39,17 @@ constexpr bool ExramRead(u32 address)
u8 HLEMemory_Read_U8(u32 address)
{
if (ExramRead(address))
- return Memory::m_pEXRAM[address & Memory::EXRAM_MASK];
+ return Memory::m_pEXRAM[address & Memory::GetExRamMask()];
- return Memory::m_pRAM[address & Memory::RAM_MASK];
+ return Memory::m_pRAM[address & Memory::GetRamMask()];
}
void HLEMemory_Write_U8(u32 address, u8 value)
{
if (ExramRead(address))
- Memory::m_pEXRAM[address & Memory::EXRAM_MASK] = value;
+ Memory::m_pEXRAM[address & Memory::GetExRamMask()] = value;
else
- Memory::m_pRAM[address & Memory::RAM_MASK] = value;
+ Memory::m_pRAM[address & Memory::GetRamMask()] = value;
}
u16 HLEMemory_Read_U16LE(u32 address)
@@ -57,9 +57,9 @@ u16 HLEMemory_Read_U16LE(u32 address)
u16 value;
if (ExramRead(address))
- std::memcpy(&value, &Memory::m_pEXRAM[address & Memory::EXRAM_MASK], sizeof(u16));
+ std::memcpy(&value, &Memory::m_pEXRAM[address & Memory::GetExRamMask()], sizeof(u16));
else
- std::memcpy(&value, &Memory::m_pRAM[address & Memory::RAM_MASK], sizeof(u16));
+ std::memcpy(&value, &Memory::m_pRAM[address & Memory::GetRamMask()], sizeof(u16));
return value;
}
@@ -72,9 +72,9 @@ u16 HLEMemory_Read_U16(u32 address)
void HLEMemory_Write_U16LE(u32 address, u16 value)
{
if (ExramRead(address))
- std::memcpy(&Memory::m_pEXRAM[address & Memory::EXRAM_MASK], &value, sizeof(u16));
+ std::memcpy(&Memory::m_pEXRAM[address & Memory::GetExRamMask()], &value, sizeof(u16));
else
- std::memcpy(&Memory::m_pRAM[address & Memory::RAM_MASK], &value, sizeof(u16));
+ std::memcpy(&Memory::m_pRAM[address & Memory::GetRamMask()], &value, sizeof(u16));
}
void HLEMemory_Write_U16(u32 address, u16 value)
@@ -87,9 +87,9 @@ u32 HLEMemory_Read_U32LE(u32 address)
u32 value;
if (ExramRead(address))
- std::memcpy(&value, &Memory::m_pEXRAM[address & Memory::EXRAM_MASK], sizeof(u32));
+ std::memcpy(&value, &Memory::m_pEXRAM[address & Memory::GetExRamMask()], sizeof(u32));
else
- std::memcpy(&value, &Memory::m_pRAM[address & Memory::RAM_MASK], sizeof(u32));
+ std::memcpy(&value, &Memory::m_pRAM[address & Memory::GetRamMask()], sizeof(u32));
return value;
}
@@ -102,9 +102,9 @@ u32 HLEMemory_Read_U32(u32 address)
void HLEMemory_Write_U32LE(u32 address, u32 value)
{
if (ExramRead(address))
- std::memcpy(&Memory::m_pEXRAM[address & Memory::EXRAM_MASK], &value, sizeof(u32));
+ std::memcpy(&Memory::m_pEXRAM[address & Memory::GetExRamMask()], &value, sizeof(u32));
else
- std::memcpy(&Memory::m_pRAM[address & Memory::RAM_MASK], &value, sizeof(u32));
+ std::memcpy(&Memory::m_pRAM[address & Memory::GetRamMask()], &value, sizeof(u32));
}
void HLEMemory_Write_U32(u32 address, u32 value)
@@ -115,9 +115,9 @@ void HLEMemory_Write_U32(u32 address, u32 value)
void* HLEMemory_Get_Pointer(u32 address)
{
if (ExramRead(address))
- return &Memory::m_pEXRAM[address & Memory::EXRAM_MASK];
+ return &Memory::m_pEXRAM[address & Memory::GetExRamMask()];
- return &Memory::m_pRAM[address & Memory::RAM_MASK];
+ return &Memory::m_pRAM[address & Memory::GetRamMask()];
}
UCodeInterface::UCodeInterface(DSPHLE* dsphle, u32 crc)
diff --git a/Source/Core/Core/HW/HW.cpp b/Source/Core/Core/HW/HW.cpp
index 2cf194d9da..3fcaebe863 100644
--- a/Source/Core/Core/HW/HW.cpp
+++ b/Source/Core/Core/HW/HW.cpp
@@ -10,6 +10,7 @@
#include "Core/ConfigManager.h"
#include "Core/Core.h"
#include "Core/CoreTiming.h"
+#include "Core/HW/AddressSpace.h"
#include "Core/HW/AudioInterface.h"
#include "Core/HW/CPU.h"
#include "Core/HW/DSP.h"
@@ -41,7 +42,8 @@ void Init()
SerialInterface::Init();
ProcessorInterface::Init();
ExpansionInterface::Init(); // Needs to be initialized before Memory
- Memory::Init();
+ Memory::Init(); // Needs to be initialized before AddressSpace
+ AddressSpace::Init();
DSP::Init(SConfig::GetInstance().bDSPHLE);
DVDInterface::Init();
GPFifo::Init();
diff --git a/Source/Core/Core/HW/Memmap.cpp b/Source/Core/Core/HW/Memmap.cpp
index 3adebdc700..bc64f242ab 100644
--- a/Source/Core/Core/HW/Memmap.cpp
+++ b/Source/Core/Core/HW/Memmap.cpp
@@ -10,6 +10,7 @@
#include "Core/HW/Memmap.h"
#include <algorithm>
+#include <array>
#include <cstring>
#include <memory>
@@ -18,6 +19,7 @@
#include "Common/Logging/Log.h"
#include "Common/MemArena.h"
#include "Common/Swap.h"
+#include "Core/Config/MainSettings.h"
#include "Core/ConfigManager.h"
#include "Core/HW/AudioInterface.h"
#include "Core/HW/DSP.h"
@@ -57,6 +59,70 @@ u8* m_pL1Cache;
u8* m_pEXRAM;
u8* m_pFakeVMEM;
+// s_ram_size is the amount allocated by the emulator, whereas s_ram_size_real
+// is what will be reported in lowmem, and thus used by emulated software.
+// Note: Writing to lowmem is done by IPL. If using retail IPL, it will
+// always be set to 24MB.
+static u32 s_ram_size_real;
+static u32 s_ram_size;
+static u32 s_ram_mask;
+static u32 s_fakevmem_size;
+static u32 s_fakevmem_mask;
+static u32 s_L1_cache_size;
+static u32 s_L1_cache_mask;
+static u32 s_io_size;
+// s_exram_size is the amount allocated by the emulator, whereas s_exram_size_real
+// is what gets used by emulated software. If using retail IOS, it will
+// always be set to 64MB.
+static u32 s_exram_size_real;
+static u32 s_exram_size;
+static u32 s_exram_mask;
+
+u32 GetRamSizeReal()
+{
+ return s_ram_size_real;
+}
+u32 GetRamSize()
+{
+ return s_ram_size;
+}
+u32 GetRamMask()
+{
+ return s_ram_mask;
+}
+u32 GetFakeVMemSize()
+{
+ return s_fakevmem_size;
+}
+u32 GetFakeVMemMask()
+{
+ return s_fakevmem_mask;
+}
+u32 GetL1CacheSize()
+{
+ return s_L1_cache_size;
+}
+u32 GetL1CacheMask()
+{
+ return s_L1_cache_mask;
+}
+u32 GetIOSize()
+{
+ return s_io_size;
+}
+u32 GetExRamSizeReal()
+{
+ return s_exram_size_real;
+}
+u32 GetExRamSize()
+{
+ return s_exram_size;
+}
+u32 GetExRamMask()
+{
+ return s_exram_mask;
+}
+
// MMIO mapping object.
std::unique_ptr<MMIO::Mapping> mmio_mapping;
@@ -154,15 +220,9 @@ struct LogicalMemoryView
//
// Dolphin doesn't emulate the difference between cached and uncached access.
//
-// TODO: The actual size of RAM is REALRAM_SIZE (24MB); the other 8MB shouldn't
-// be backed by actual memory.
+// TODO: The actual size of RAM is 24MB; the other 8MB shouldn't be backed by actual memory.
// TODO: Do we want to handle the mirrors of the GC RAM?
-static PhysicalMemoryRegion physical_regions[] = {
- {&m_pRAM, 0x00000000, RAM_SIZE, PhysicalMemoryRegion::ALWAYS},
- {&m_pL1Cache, 0xE0000000, L1_CACHE_SIZE, PhysicalMemoryRegion::ALWAYS},
- {&m_pFakeVMEM, 0x7E000000, FAKEVMEM_SIZE, PhysicalMemoryRegion::FAKE_VMEM},
- {&m_pEXRAM, 0x10000000, EXRAM_SIZE, PhysicalMemoryRegion::WII_ONLY},
-};
+static std::array<PhysicalMemoryRegion, 4> physical_regions;
static std::vector<LogicalMemoryView> logical_mapped_entries;
@@ -189,6 +249,34 @@ static u32 GetFlags()
void Init()
{
+ const auto get_mem1_size = [] {
+ if (Config::Get(Config::MAIN_RAM_OVERRIDE_ENABLE))
+ return Config::Get(Config::MAIN_MEM1_SIZE);
+ return Memory::MEM1_SIZE_RETAIL;
+ };
+ const auto get_mem2_size = [] {
+ if (Config::Get(Config::MAIN_RAM_OVERRIDE_ENABLE))
+ return Config::Get(Config::MAIN_MEM2_SIZE);
+ return Memory::MEM2_SIZE_RETAIL;
+ };
+ s_ram_size_real = get_mem1_size();
+ s_ram_size = MathUtil::NextPowerOf2(GetRamSizeReal());
+ s_ram_mask = GetRamSize() - 1;
+ s_fakevmem_size = 0x02000000;
+ s_fakevmem_mask = GetFakeVMemSize() - 1;
+ s_L1_cache_size = 0x00040000;
+ s_L1_cache_mask = GetL1CacheSize() - 1;
+ s_io_size = 0x00010000;
+ s_exram_size_real = get_mem2_size();
+ s_exram_size = MathUtil::NextPowerOf2(GetExRamSizeReal());
+ s_exram_mask = GetExRamSize() - 1;
+
+ physical_regions[0] = {&m_pRAM, 0x00000000, GetRamSize(), PhysicalMemoryRegion::ALWAYS};
+ physical_regions[1] = {&m_pL1Cache, 0xE0000000, GetL1CacheSize(), PhysicalMemoryRegion::ALWAYS};
+ physical_regions[2] = {&m_pFakeVMEM, 0x7E000000, GetFakeVMemSize(),
+ PhysicalMemoryRegion::FAKE_VMEM};
+ physical_regions[3] = {&m_pEXRAM, 0x10000000, GetExRamSize(), PhysicalMemoryRegion::WII_ONLY};
+
bool wii = SConfig::GetInstance().bWii;
u32 flags = GetFlags();
u32 mem_size = 0;
@@ -304,14 +392,14 @@ void UpdateLogicalMemory(const PowerPC::BatTable& dbat_table)
void DoState(PointerWrap& p)
{
bool wii = SConfig::GetInstance().bWii;
- p.DoArray(m_pRAM, RAM_SIZE);
- p.DoArray(m_pL1Cache, L1_CACHE_SIZE);
+ p.DoArray(m_pRAM, GetRamSize());
+ p.DoArray(m_pL1Cache, GetL1CacheSize());
p.DoMarker("Memory RAM");
if (m_pFakeVMEM)
- p.DoArray(m_pFakeVMEM, FAKEVMEM_SIZE);
+ p.DoArray(m_pFakeVMEM, GetFakeVMemSize());
p.DoMarker("Memory FakeVMEM");
if (wii)
- p.DoArray(m_pEXRAM, EXRAM_SIZE);
+ p.DoArray(m_pEXRAM, GetExRamSize());
p.DoMarker("Memory EXRAM");
}
@@ -363,19 +451,19 @@ void ShutdownFastmemArena()
void Clear()
{
if (m_pRAM)
- memset(m_pRAM, 0, RAM_SIZE);
+ memset(m_pRAM, 0, GetRamSize());
if (m_pL1Cache)
- memset(m_pL1Cache, 0, L1_CACHE_SIZE);
+ memset(m_pL1Cache, 0, GetL1CacheSize());
if (m_pFakeVMEM)
- memset(m_pFakeVMEM, 0, FAKEVMEM_SIZE);
+ memset(m_pFakeVMEM, 0, GetFakeVMemSize());
if (m_pEXRAM)
- memset(m_pEXRAM, 0, EXRAM_SIZE);
+ memset(m_pEXRAM, 0, GetExRamSize());
}
static inline u8* GetPointerForRange(u32 address, size_t size)
{
// Make sure we don't have a range spanning 2 separate banks
- if (size >= EXRAM_SIZE)
+ if (size >= GetExRamSizeReal())
return nullptr;
// Check that the beginning and end of the range are valid
@@ -450,13 +538,13 @@ u8* GetPointer(u32 address)
// TODO: Should we be masking off more bits here? Can all devices access
// EXRAM?
address &= 0x3FFFFFFF;
- if (address < REALRAM_SIZE)
+ if (address < GetRamSizeReal())
return m_pRAM + address;
if (m_pEXRAM)
{
- if ((address >> 28) == 0x1 && (address & 0x0fffffff) < EXRAM_SIZE)
- return m_pEXRAM + (address & EXRAM_MASK);
+ if ((address >> 28) == 0x1 && (address & 0x0fffffff) < GetExRamSizeReal())
+ return m_pEXRAM + (address & GetExRamMask());
}
PanicAlert("Unknown Pointer 0x%08x PC 0x%08x LR 0x%08x", address, PC, LR);
diff --git a/Source/Core/Core/HW/Memmap.h b/Source/Core/Core/HW/Memmap.h
index ae98bbc7ef..7399697bef 100644
--- a/Source/Core/Core/HW/Memmap.h
+++ b/Source/Core/Core/HW/Memmap.h
@@ -37,23 +37,24 @@ extern u8* m_pEXRAM;
extern u8* m_pL1Cache;
extern u8* m_pFakeVMEM;
-enum
-{
- // RAM_SIZE is the amount allocated by the emulator, whereas REALRAM_SIZE is
- // what will be reported in lowmem, and thus used by emulated software.
- // Note: Writing to lowmem is done by IPL. If using retail IPL, it will
- // always be set to 24MB.
- REALRAM_SIZE = 0x01800000,
- RAM_SIZE = MathUtil::NextPowerOf2(REALRAM_SIZE),
- RAM_MASK = RAM_SIZE - 1,
- FAKEVMEM_SIZE = 0x02000000,
- FAKEVMEM_MASK = FAKEVMEM_SIZE - 1,
- L1_CACHE_SIZE = 0x00040000,
- L1_CACHE_MASK = L1_CACHE_SIZE - 1,
- IO_SIZE = 0x00010000,
- EXRAM_SIZE = 0x04000000,
- EXRAM_MASK = EXRAM_SIZE - 1,
-};
+u32 GetRamSizeReal();
+u32 GetRamSize();
+u32 GetRamMask();
+u32 GetFakeVMemSize();
+u32 GetFakeVMemMask();
+u32 GetL1CacheSize();
+u32 GetL1CacheMask();
+u32 GetIOSize();
+u32 GetExRamSizeReal();
+u32 GetExRamSize();
+u32 GetExRamMask();
+
+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 MEM2_SIZE_RETAIL = 0x04000000U;
+constexpr u32 MEM2_SIZE_NDEV = 0x08000000U;
// MMIO mapping object.
extern std::unique_ptr<MMIO::Mapping> mmio_mapping;
diff --git a/Source/Core/Core/IOS/IOS.cpp b/Source/Core/Core/IOS/IOS.cpp
index 7ce51f2338..ede48baf1b 100644
--- a/Source/Core/Core/IOS/IOS.cpp
+++ b/Source/Core/Core/IOS/IOS.cpp
@@ -22,6 +22,7 @@
#include "Core/Boot/DolReader.h"
#include "Core/Boot/ElfReader.h"
#include "Core/CommonTitles.h"
+#include "Core/Config/MainSettings.h"
#include "Core/ConfigManager.h"
#include "Core/Core.h"
#include "Core/CoreTiming.h"
@@ -85,8 +86,8 @@ constexpr u32 ADDR_HOLLYWOOD_REVISION = 0x3138;
constexpr u32 ADDR_PH3 = 0x313c;
constexpr u32 ADDR_IOS_VERSION = 0x3140;
constexpr u32 ADDR_IOS_DATE = 0x3144;
-constexpr u32 ADDR_UNKNOWN_BEGIN = 0x3148;
-constexpr u32 ADDR_UNKNOWN_END = 0x314c;
+constexpr u32 ADDR_IOS_RESERVED_BEGIN = 0x3148;
+constexpr u32 ADDR_IOS_RESERVED_END = 0x314c;
constexpr u32 ADDR_PH4 = 0x3150;
constexpr u32 ADDR_PH5 = 0x3154;
constexpr u32 ADDR_RAM_VENDOR = 0x3158;
@@ -96,12 +97,6 @@ constexpr u32 ADDR_DEVKIT_BOOT_PROGRAM_VERSION = 0x315e;
constexpr u32 ADDR_SYSMENU_SYNC = 0x3160;
constexpr u32 PLACEHOLDER = 0xDEADBEEF;
-enum class MemorySetupType
-{
- IOSReload,
- Full,
-};
-
static bool SetupMemory(u64 ios_title_id, MemorySetupType setup_type)
{
auto target_imv = std::find_if(
@@ -134,8 +129,10 @@ static bool SetupMemory(u64 ios_title_id, MemorySetupType setup_type)
Memory::Write_U32(target_imv->mem2_arena_end, ADDR_MEM2_ARENA_END);
Memory::Write_U32(target_imv->ipc_buffer_begin, ADDR_IPC_BUFFER_BEGIN);
Memory::Write_U32(target_imv->ipc_buffer_end, ADDR_IPC_BUFFER_END);
- Memory::Write_U32(target_imv->unknown_begin, ADDR_UNKNOWN_BEGIN);
- Memory::Write_U32(target_imv->unknown_end, ADDR_UNKNOWN_END);
+ Memory::Write_U32(target_imv->ios_reserved_begin, ADDR_IOS_RESERVED_BEGIN);
+ Memory::Write_U32(target_imv->ios_reserved_end, ADDR_IOS_RESERVED_END);
+
+ RAMOverrideForIOSMemoryValues(setup_type);
return true;
}
@@ -158,8 +155,8 @@ static bool SetupMemory(u64 ios_title_id, MemorySetupType setup_type)
Memory::Write_U32(PLACEHOLDER, ADDR_PH3);
Memory::Write_U32(target_imv->ios_version, ADDR_IOS_VERSION);
Memory::Write_U32(target_imv->ios_date, ADDR_IOS_DATE);
- Memory::Write_U32(target_imv->unknown_begin, ADDR_UNKNOWN_BEGIN);
- Memory::Write_U32(target_imv->unknown_end, ADDR_UNKNOWN_END);
+ Memory::Write_U32(target_imv->ios_reserved_begin, ADDR_IOS_RESERVED_BEGIN);
+ Memory::Write_U32(target_imv->ios_reserved_end, ADDR_IOS_RESERVED_END);
Memory::Write_U32(PLACEHOLDER, ADDR_PH4);
Memory::Write_U32(PLACEHOLDER, ADDR_PH5);
Memory::Write_U32(target_imv->ram_vendor, ADDR_RAM_VENDOR);
@@ -167,9 +164,59 @@ static bool SetupMemory(u64 ios_title_id, MemorySetupType setup_type)
Memory::Write_U8(0xAD, ADDR_APPLOADER_FLAG);
Memory::Write_U16(0xBEEF, ADDR_DEVKIT_BOOT_PROGRAM_VERSION);
Memory::Write_U32(target_imv->sysmenu_sync, ADDR_SYSMENU_SYNC);
+
+ RAMOverrideForIOSMemoryValues(setup_type);
+
return true;
}
+void RAMOverrideForIOSMemoryValues(MemorySetupType setup_type)
+{
+ // Don't touch anything if the feature isn't enabled.
+ if (!Config::Get(Config::MAIN_RAM_OVERRIDE_ENABLE))
+ return;
+
+ // Some unstated constants that can be inferred.
+ const u32 ipc_buffer_size =
+ Memory::Read_U32(ADDR_IPC_BUFFER_END) - Memory::Read_U32(ADDR_IPC_BUFFER_BEGIN);
+ const u32 ios_reserved_size =
+ Memory::Read_U32(ADDR_IOS_RESERVED_END) - Memory::Read_U32(ADDR_IOS_RESERVED_BEGIN);
+
+ const u32 mem1_physical_size = Memory::GetRamSizeReal();
+ const u32 mem1_simulated_size = Memory::GetRamSizeReal();
+ const u32 mem1_end = Memory::MEM1_BASE_ADDR + mem1_simulated_size;
+ const u32 mem1_arena_begin = 0;
+ const u32 mem1_arena_end = mem1_end;
+ const u32 mem2_physical_size = Memory::GetExRamSizeReal();
+ const u32 mem2_simulated_size = Memory::GetExRamSizeReal();
+ const u32 mem2_end = Memory::MEM2_BASE_ADDR + mem2_simulated_size - ios_reserved_size;
+ const u32 mem2_arena_begin = Memory::MEM2_BASE_ADDR + 0x800U;
+ const u32 mem2_arena_end = mem2_end - ipc_buffer_size;
+ const u32 ipc_buffer_begin = mem2_arena_end;
+ const u32 ipc_buffer_end = mem2_end;
+ const u32 ios_reserved_begin = mem2_end;
+ const u32 ios_reserved_end = Memory::MEM2_BASE_ADDR + mem2_simulated_size;
+
+ if (setup_type == MemorySetupType::Full)
+ {
+ // Overwriting these after the game's apploader sets them would be bad
+ Memory::Write_U32(mem1_physical_size, ADDR_MEM1_SIZE);
+ Memory::Write_U32(mem1_simulated_size, ADDR_MEM1_SIM_SIZE);
+ Memory::Write_U32(mem1_end, ADDR_MEM1_END);
+ Memory::Write_U32(mem1_arena_begin, ADDR_MEM1_ARENA_BEGIN);
+ Memory::Write_U32(mem1_arena_end, ADDR_MEM1_ARENA_END);
+ }
+ Memory::Write_U32(mem2_physical_size, ADDR_MEM2_SIZE);
+ Memory::Write_U32(mem2_simulated_size, ADDR_MEM2_SIM_SIZE);
+ Memory::Write_U32(mem2_end, ADDR_MEM2_END);
+ Memory::Write_U32(mem2_arena_begin, ADDR_MEM2_ARENA_BEGIN);
+ Memory::Write_U32(mem2_arena_end, ADDR_MEM2_ARENA_END);
+ Memory::Write_U32(ipc_buffer_begin, ADDR_IPC_BUFFER_BEGIN);
+ Memory::Write_U32(ipc_buffer_end, ADDR_IPC_BUFFER_END);
+ Memory::Write_U32(ios_reserved_begin, ADDR_IOS_RESERVED_BEGIN);
+ Memory::Write_U32(ios_reserved_end, ADDR_IOS_RESERVED_END);
+}
+
void WriteReturnValue(s32 value, u32 address)
{
Memory::Write_U32(static_cast<u32>(value), address);
diff --git a/Source/Core/Core/IOS/IOS.h b/Source/Core/Core/IOS/IOS.h
index 419e0ab542..daf53585ab 100644
--- a/Source/Core/Core/IOS/IOS.h
+++ b/Source/Core/Core/IOS/IOS.h
@@ -55,6 +55,14 @@ enum IPCCommandType : u32
IPC_REPLY = 8,
};
+enum class MemorySetupType
+{
+ IOSReload,
+ Full,
+};
+
+void RAMOverrideForIOSMemoryValues(MemorySetupType setup_type);
+
void WriteReturnValue(s32 value, u32 address);
// HLE for the IOS kernel: IPC, device management, syscalls, and Dolphin-specific, IOS-wide calls.
diff --git a/Source/Core/Core/IOS/MIOS.cpp b/Source/Core/Core/IOS/MIOS.cpp
index e5bb987ea5..9148619977 100644
--- a/Source/Core/Core/IOS/MIOS.cpp
+++ b/Source/Core/Core/IOS/MIOS.cpp
@@ -32,7 +32,7 @@ static void ReinitHardware()
SConfig::GetInstance().bWii = false;
// IOS clears mem2 and overwrites it with pseudo-random data (for security).
- std::memset(Memory::m_pEXRAM, 0, Memory::EXRAM_SIZE);
+ std::memset(Memory::m_pEXRAM, 0, Memory::GetExRamSizeReal());
// MIOS appears to only reset the DI and the PPC.
// HACK However, resetting DI will reset the DTK config, which is set by the system menu
// (and not by MIOS), causing games that use DTK to break. Perhaps MIOS doesn't actually
diff --git a/Source/Core/Core/IOS/VersionInfo.h b/Source/Core/Core/IOS/VersionInfo.h
index 0dd7f0c256..eb88e67938 100644
--- a/Source/Core/Core/IOS/VersionInfo.h
+++ b/Source/Core/Core/IOS/VersionInfo.h
@@ -29,8 +29,8 @@ struct MemoryValues
u32 ipc_buffer_end;
u32 hollywood_revision;
u32 ram_vendor;
- u32 unknown_begin;
- u32 unknown_end;
+ u32 ios_reserved_begin;
+ u32 ios_reserved_end;
u32 sysmenu_sync;
};
diff --git a/Source/Core/Core/PowerPC/MMU.cpp b/Source/Core/Core/PowerPC/MMU.cpp
index 952556ddea..5a008f92fc 100644
--- a/Source/Core/Core/PowerPC/MMU.cpp
+++ b/Source/Core/Core/PowerPC/MMU.cpp
@@ -211,14 +211,14 @@ static T ReadFromHardware(u32 em_address)
{
// Handle RAM; the masking intentionally discards bits (essentially creating
// mirrors of memory).
- // TODO: Only the first REALRAM_SIZE is supposed to be backed by actual memory.
+ // TODO: Only the first GetRamSizeReal() is supposed to be backed by actual memory.
T value;
- std::memcpy(&value, &Memory::m_pRAM[em_address & Memory::RAM_MASK], sizeof(T));
+ std::memcpy(&value, &Memory::m_pRAM[em_address & Memory::GetRamMask()], sizeof(T));
return bswap(value);
}
if (Memory::m_pEXRAM && (em_address >> 28) == 0x1 &&
- (em_address & 0x0FFFFFFF) < Memory::EXRAM_SIZE)
+ (em_address & 0x0FFFFFFF) < Memory::GetExRamSizeReal())
{
T value;
std::memcpy(&value, &Memory::m_pEXRAM[em_address & 0x0FFFFFFF], sizeof(T));
@@ -226,7 +226,7 @@ static T ReadFromHardware(u32 em_address)
}
// Locked L1 technically doesn't have a fixed address, but games all use 0xE0000000.
- if ((em_address >> 28) == 0xE && (em_address < (0xE0000000 + Memory::L1_CACHE_SIZE)))
+ if ((em_address >> 28) == 0xE && (em_address < (0xE0000000 + Memory::GetL1CacheSize())))
{
T value;
std::memcpy(&value, &Memory::m_pL1Cache[em_address & 0x0FFFFFFF], sizeof(T));
@@ -238,7 +238,7 @@ static T ReadFromHardware(u32 em_address)
if (Memory::m_pFakeVMEM && ((em_address & 0xFE000000) == 0x7E000000))
{
T value;
- std::memcpy(&value, &Memory::m_pFakeVMEM[em_address & Memory::RAM_MASK], sizeof(T));
+ std::memcpy(&value, &Memory::m_pFakeVMEM[em_address & Memory::GetRamMask()], sizeof(T));
return bswap(value);
}
@@ -300,14 +300,14 @@ static void WriteToHardware(u32 em_address, const T data)
{
// Handle RAM; the masking intentionally discards bits (essentially creating
// mirrors of memory).
- // TODO: Only the first REALRAM_SIZE is supposed to be backed by actual memory.
+ // TODO: Only the first GetRamSizeReal() is supposed to be backed by actual memory.
const T swapped_data = bswap(data);
- std::memcpy(&Memory::m_pRAM[em_address & Memory::RAM_MASK], &swapped_data, sizeof(T));
+ std::memcpy(&Memory::m_pRAM[em_address & Memory::GetRamMask()], &swapped_data, sizeof(T));
return;
}
if (Memory::m_pEXRAM && (em_address >> 28) == 0x1 &&
- (em_address & 0x0FFFFFFF) < Memory::EXRAM_SIZE)
+ (em_address & 0x0FFFFFFF) < Memory::GetExRamSizeReal())
{
const T swapped_data = bswap(data);
std::memcpy(&Memory::m_pEXRAM[em_address & 0x0FFFFFFF], &swapped_data, sizeof(T));
@@ -315,7 +315,7 @@ static void WriteToHardware(u32 em_address, const T data)
}
// Locked L1 technically doesn't have a fixed address, but games all use 0xE0000000.
- if ((em_address >> 28 == 0xE) && (em_address < (0xE0000000 + Memory::L1_CACHE_SIZE)))
+ if ((em_address >> 28 == 0xE) && (em_address < (0xE0000000 + Memory::GetL1CacheSize())))
{
const T swapped_data = bswap(data);
std::memcpy(&Memory::m_pL1Cache[em_address & 0x0FFFFFFF], &swapped_data, sizeof(T));
@@ -328,7 +328,7 @@ static void WriteToHardware(u32 em_address, const T data)
if (Memory::m_pFakeVMEM && ((em_address & 0xFE000000) == 0x7E000000))
{
const T swapped_data = bswap(data);
- std::memcpy(&Memory::m_pFakeVMEM[em_address & Memory::RAM_MASK], &swapped_data, sizeof(T));
+ std::memcpy(&Memory::m_pFakeVMEM[em_address & Memory::GetRamMask()], &swapped_data, sizeof(T));
return;
}
@@ -412,7 +412,7 @@ TryReadInstResult TryReadInstruction(u32 address)
// TODO: Refactor this. This icache implementation is totally wrong if used with the fake vmem.
if (Memory::m_pFakeVMEM && ((address & 0xFE000000) == 0x7E000000))
{
- hex = Common::swap32(&Memory::m_pFakeVMEM[address & Memory::FAKEVMEM_MASK]);
+ hex = Common::swap32(&Memory::m_pFakeVMEM[address & Memory::GetFakeVMemMask()]);
}
else
{
@@ -667,13 +667,14 @@ static bool IsRAMAddress(u32 address, bool translate)
}
u32 segment = address >> 28;
- if (segment == 0x0 && (address & 0x0FFFFFFF) < Memory::REALRAM_SIZE)
+ if (segment == 0x0 && (address & 0x0FFFFFFF) < Memory::GetRamSizeReal())
return true;
- else if (Memory::m_pEXRAM && segment == 0x1 && (address & 0x0FFFFFFF) < Memory::EXRAM_SIZE)
+ else if (Memory::m_pEXRAM && segment == 0x1 &&
+ (address & 0x0FFFFFFF) < Memory::GetExRamSizeReal())
return true;
else if (Memory::m_pFakeVMEM && ((address & 0xFE000000) == 0x7E000000))
return true;
- else if (segment == 0xE && (address < (0xE0000000 + Memory::L1_CACHE_SIZE)))
+ else if (segment == 0xE && (address < (0xE0000000 + Memory::GetL1CacheSize())))
return true;
return false;
}
@@ -1212,13 +1213,13 @@ static void UpdateBATs(BatTable& bat_table, u32 base_spr)
u32 valid_bit = BAT_MAPPED_BIT;
if (Memory::m_pFakeVMEM && (physical_address & 0xFE000000) == 0x7E000000)
valid_bit |= BAT_PHYSICAL_BIT;
- else if (physical_address < Memory::REALRAM_SIZE)
+ else if (physical_address < Memory::GetRamSizeReal())
valid_bit |= BAT_PHYSICAL_BIT;
else if (Memory::m_pEXRAM && physical_address >> 28 == 0x1 &&
- (physical_address & 0x0FFFFFFF) < Memory::EXRAM_SIZE)
+ (physical_address & 0x0FFFFFFF) < Memory::GetExRamSizeReal())
valid_bit |= BAT_PHYSICAL_BIT;
else if (physical_address >> 28 == 0xE &&
- physical_address < 0xE0000000 + Memory::L1_CACHE_SIZE)
+ physical_address < 0xE0000000 + Memory::GetL1CacheSize())
valid_bit |= BAT_PHYSICAL_BIT;
// Fastmem doesn't support memchecks, so disable it for all overlapping virtual pages.
@@ -1239,7 +1240,7 @@ static void UpdateFakeMMUBat(BatTable& bat_table, u32 start_addr)
// Map from 0x4XXXXXXX or 0x7XXXXXXX to the range
// [0x7E000000,0x80000000).
u32 e_address = i + (start_addr >> BAT_INDEX_SHIFT);
- u32 p_address = 0x7E000000 | (i << BAT_INDEX_SHIFT & Memory::FAKEVMEM_MASK);
+ u32 p_address = 0x7E000000 | (i << BAT_INDEX_SHIFT & Memory::GetFakeVMemMask());
u32 flags = BAT_MAPPED_BIT | BAT_PHYSICAL_BIT;
if (PowerPC::memchecks.OverlapsMemcheck(e_address << BAT_INDEX_SHIFT, BAT_PAGE_SIZE))
diff --git a/Source/Core/Core/State.cpp b/Source/Core/Core/State.cpp
index c8bc970315..84de8d864b 100644
--- a/Source/Core/Core/State.cpp
+++ b/Source/Core/Core/State.cpp
@@ -30,6 +30,7 @@
#include "Core/CoreTiming.h"
#include "Core/GeckoCode.h"
#include "Core/HW/HW.h"
+#include "Core/HW/Memmap.h"
#include "Core/HW/Wiimote.h"
#include "Core/Host.h"
#include "Core/Movie.h"
@@ -73,7 +74,7 @@ static Common::Event g_compressAndDumpStateSyncEvent;
static std::thread g_save_thread;
// Don't forget to increase this after doing changes on the savestate system
-constexpr u32 STATE_VERSION = 114; // Last changed in PR 8394
+constexpr u32 STATE_VERSION = 115; // Last changed in PR 8722
// Maps savestate versions to Dolphin versions.
// Versions after 42 don't need to be added to this list,
@@ -171,6 +172,24 @@ static void DoState(PointerWrap& p)
return;
}
+ // Check to make sure the emulated memory sizes are the same as the savestate
+ u32 state_mem1_size = Memory::GetRamSizeReal();
+ u32 state_mem2_size = Memory::GetExRamSizeReal();
+ p.Do(state_mem1_size);
+ p.Do(state_mem2_size);
+ if (state_mem1_size != Memory::GetRamSizeReal() || state_mem2_size != Memory::GetExRamSizeReal())
+ {
+ OSD::AddMessage(fmt::format("Memory size mismatch!\n"
+ "Current | MEM1 {:08X} ({:3}MB) MEM2 {:08X} ({:3}MB)\n"
+ "State | MEM1 {:08X} ({:3}MB) MEM2 {:08X} ({:3}MB)",
+ Memory::GetRamSizeReal(), Memory::GetRamSizeReal() / 0x100000U,
+ Memory::GetExRamSizeReal(), Memory::GetExRamSizeReal() / 0x100000U,
+ state_mem1_size, state_mem1_size / 0x100000U, state_mem2_size,
+ state_mem2_size / 0x100000U));
+ p.SetMode(PointerWrap::MODE_MEASURE);
+ return;
+ }
+
// Movie must be done before the video backend, because the window is redrawn in the video backend
// state load, and the frame number must be up-to-date.
Movie::DoState(p);
diff --git a/Source/Core/DolphinQt/CheatsManager.cpp b/Source/Core/DolphinQt/CheatsManager.cpp
index 649fa1e685..edb9537c86 100644
--- a/Source/Core/DolphinQt/CheatsManager.cpp
+++ b/Source/Core/DolphinQt/CheatsManager.cpp
@@ -571,7 +571,7 @@ void CheatsManager::NewSearch()
return;
Core::RunAsCPUThread([&] {
- for (u32 i = 0; i < Memory::REALRAM_SIZE - GetTypeSize(); i++)
+ for (u32 i = 0; i < Memory::GetRamSizeReal() - GetTypeSize(); i++)
{
if (PowerPC::HostIsRAMAddress(base_address + i) && matches_func(base_address + i))
m_results.push_back(
diff --git a/Source/Core/DolphinQt/MenuBar.cpp b/Source/Core/DolphinQt/MenuBar.cpp
index 3f4564c27f..25a7a1dd5b 100644
--- a/Source/Core/DolphinQt/MenuBar.cpp
+++ b/Source/Core/DolphinQt/MenuBar.cpp
@@ -26,6 +26,7 @@
#include "Core/Debugger/RSO.h"
#include "Core/HLE/HLE.h"
#include "Core/HW/AddressSpace.h"
+#include "Core/HW/Memmap.h"
#include "Core/HW/WiiSave.h"
#include "Core/HW/Wiimote.h"
#include "Core/IOS/ES/ES.h"
@@ -1178,13 +1179,15 @@ void MenuBar::ClearSymbols()
void MenuBar::GenerateSymbolsFromAddress()
{
- PPCAnalyst::FindFunctions(0x80000000, 0x81800000, &g_symbolDB);
+ PPCAnalyst::FindFunctions(Memory::MEM1_BASE_ADDR,
+ Memory::MEM1_BASE_ADDR + Memory::GetRamSizeReal(), &g_symbolDB);
emit NotifySymbolsUpdated();
}
void MenuBar::GenerateSymbolsFromSignatureDB()
{
- PPCAnalyst::FindFunctions(0x80000000, 0x81800000, &g_symbolDB);
+ PPCAnalyst::FindFunctions(Memory::MEM1_BASE_ADDR,
+ Memory::MEM1_BASE_ADDR + Memory::GetRamSizeReal(), &g_symbolDB);
SignatureDB db(SignatureDB::HandlerType::DSY);
if (db.Load(File::GetSysDirectory() + TOTALDB))
{
@@ -1315,7 +1318,8 @@ void MenuBar::LoadSymbolMap()
if (!map_exists)
{
g_symbolDB.Clear();
- PPCAnalyst::FindFunctions(0x81300000, 0x81800000, &g_symbolDB);
+ PPCAnalyst::FindFunctions(Memory::MEM1_BASE_ADDR + 0x1300000,
+ Memory::MEM1_BASE_ADDR + Memory::GetRamSizeReal(), &g_symbolDB);
SignatureDB db(SignatureDB::HandlerType::DSY);
if (db.Load(File::GetSysDirectory() + TOTALDB))
db.Apply(&g_symbolDB);
@@ -1554,7 +1558,8 @@ void MenuBar::SearchInstruction()
return;
bool found = false;
- for (u32 addr = 0x80000000; addr < 0x81800000; addr += 4)
+ for (u32 addr = Memory::MEM1_BASE_ADDR; addr < Memory::MEM1_BASE_ADDR + Memory::GetRamSizeReal();
+ addr += 4)
{
auto ins_name =
QString::fromStdString(PPCTables::GetInstructionName(PowerPC::HostRead_U32(addr)));
diff --git a/Source/Core/DolphinQt/Settings/AdvancedPane.cpp b/Source/Core/DolphinQt/Settings/AdvancedPane.cpp
index 8f87d4fe14..191684ec71 100644
--- a/Source/Core/DolphinQt/Settings/AdvancedPane.cpp
+++ b/Source/Core/DolphinQt/Settings/AdvancedPane.cpp
@@ -96,6 +96,44 @@ void AdvancedPane::CreateLayout()
cpu_clock_override_description->setWordWrap(true);
clock_override_layout->addWidget(cpu_clock_override_description);
+ auto* ram_override = new QGroupBox(tr("Memory Override"));
+ auto* ram_override_layout = new QVBoxLayout();
+ ram_override->setLayout(ram_override_layout);
+ main_layout->addWidget(ram_override);
+
+ m_ram_override_checkbox = new QCheckBox(tr("Enable Emulated Memory Size Override"));
+ ram_override_layout->addWidget(m_ram_override_checkbox);
+
+ auto* mem1_override_slider_layout = new QHBoxLayout();
+ mem1_override_slider_layout->setContentsMargins(0, 0, 0, 0);
+ ram_override_layout->addLayout(mem1_override_slider_layout);
+
+ m_mem1_override_slider = new QSlider(Qt::Horizontal);
+ m_mem1_override_slider->setRange(24, 64);
+ mem1_override_slider_layout->addWidget(m_mem1_override_slider);
+
+ m_mem1_override_slider_label = new QLabel();
+ mem1_override_slider_layout->addWidget(m_mem1_override_slider_label);
+
+ auto* mem2_override_slider_layout = new QHBoxLayout();
+ mem2_override_slider_layout->setContentsMargins(0, 0, 0, 0);
+ ram_override_layout->addLayout(mem2_override_slider_layout);
+
+ m_mem2_override_slider = new QSlider(Qt::Horizontal);
+ m_mem2_override_slider->setRange(64, 128);
+ mem2_override_slider_layout->addWidget(m_mem2_override_slider);
+
+ m_mem2_override_slider_label = new QLabel();
+ mem2_override_slider_layout->addWidget(m_mem2_override_slider_label);
+
+ auto* ram_override_description =
+ new QLabel(tr("Adjusts the emulated sizes of MEM1 and MEM2.\n\n"
+ "Some titles may recognize the larger memory arena(s) and take "
+ "advantage of it, though retail titles should be optimized for "
+ "the retail memory limitations."));
+ ram_override_description->setWordWrap(true);
+ ram_override_layout->addWidget(ram_override_description);
+
auto* rtc_options = new QGroupBox(tr("Custom RTC Options"));
rtc_options->setLayout(new QVBoxLayout());
main_layout->addWidget(rtc_options);
@@ -154,6 +192,24 @@ void AdvancedPane::ConnectLayout()
Update();
});
+ m_ram_override_checkbox->setChecked(Config::Get(Config::MAIN_RAM_OVERRIDE_ENABLE));
+ connect(m_ram_override_checkbox, &QCheckBox::toggled, [this](bool enable_ram_override) {
+ Config::SetBaseOrCurrent(Config::MAIN_RAM_OVERRIDE_ENABLE, enable_ram_override);
+ Update();
+ });
+
+ connect(m_mem1_override_slider, &QSlider::valueChanged, [this](int slider_value) {
+ const u32 mem1_size = m_mem1_override_slider->value() * 0x100000;
+ Config::SetBaseOrCurrent(Config::MAIN_MEM1_SIZE, mem1_size);
+ Update();
+ });
+
+ connect(m_mem2_override_slider, &QSlider::valueChanged, [this](int slider_value) {
+ const u32 mem2_size = m_mem2_override_slider->value() * 0x100000;
+ Config::SetBaseOrCurrent(Config::MAIN_MEM2_SIZE, mem2_size);
+ Update();
+ });
+
m_custom_rtc_checkbox->setChecked(SConfig::GetInstance().bEnableCustomRTC);
connect(m_custom_rtc_checkbox, &QCheckBox::toggled, [this](bool enable_custom_rtc) {
SConfig::GetInstance().bEnableCustomRTC = enable_custom_rtc;
@@ -173,6 +229,7 @@ void AdvancedPane::Update()
{
const bool running = Core::GetState() != Core::State::Uninitialized;
const bool enable_cpu_clock_override_widgets = SConfig::GetInstance().m_OCEnable;
+ const bool enable_ram_override_widgets = Config::Get(Config::MAIN_RAM_OVERRIDE_ENABLE);
const bool enable_custom_rtc_widgets = SConfig::GetInstance().bEnableCustomRTC && !running;
const std::vector<PowerPC::CPUCore>& available_cpu_cores = PowerPC::AvailableCPUCores();
@@ -208,6 +265,36 @@ void AdvancedPane::Update()
return tr("%1 % (%2 MHz)").arg(QString::number(percent), QString::number(clock));
}());
+ m_ram_override_checkbox->setEnabled(!running);
+
+ m_mem1_override_slider->setEnabled(enable_ram_override_widgets && !running);
+ m_mem1_override_slider_label->setEnabled(enable_ram_override_widgets && !running);
+
+ {
+ const QSignalBlocker blocker(m_mem1_override_slider);
+ const u32 mem1_size = Config::Get(Config::MAIN_MEM1_SIZE) / 0x100000;
+ m_mem1_override_slider->setValue(mem1_size);
+ }
+
+ m_mem1_override_slider_label->setText([] {
+ const u32 mem1_size = Config::Get(Config::MAIN_MEM1_SIZE) / 0x100000;
+ return tr("%1MB (MEM1)").arg(QString::number(mem1_size));
+ }());
+
+ m_mem2_override_slider->setEnabled(enable_ram_override_widgets && !running);
+ m_mem2_override_slider_label->setEnabled(enable_ram_override_widgets && !running);
+
+ {
+ const QSignalBlocker blocker(m_mem2_override_slider);
+ const u32 mem2_size = Config::Get(Config::MAIN_MEM2_SIZE) / 0x100000;
+ m_mem2_override_slider->setValue(mem2_size);
+ }
+
+ m_mem2_override_slider_label->setText([] {
+ const u32 mem2_size = Config::Get(Config::MAIN_MEM2_SIZE) / 0x100000;
+ return tr("%1MB (MEM2)").arg(QString::number(mem2_size));
+ }());
+
m_custom_rtc_checkbox->setEnabled(!running);
m_custom_rtc_datetime->setEnabled(enable_custom_rtc_widgets);
}
diff --git a/Source/Core/DolphinQt/Settings/AdvancedPane.h b/Source/Core/DolphinQt/Settings/AdvancedPane.h
index a625038a12..acaae7a7dd 100644
--- a/Source/Core/DolphinQt/Settings/AdvancedPane.h
+++ b/Source/Core/DolphinQt/Settings/AdvancedPane.h
@@ -40,4 +40,11 @@ private:
QCheckBox* m_custom_rtc_checkbox;
QDateTimeEdit* m_custom_rtc_datetime;
+
+ QCheckBox* m_ram_override_checkbox;
+ QSlider* m_mem1_override_slider;
+ QLabel* m_mem1_override_slider_label;
+ QSlider* m_mem2_override_slider;
+ QLabel* m_mem2_override_slider_label;
+ QLabel* m_ram_override_description;
};