From cc858c63b8d04c5ce407c7efd0ae8abc654e73a0 Mon Sep 17 00:00:00 2001 From: Minty-Meeo <45425365+Minty-Meeo@users.noreply.github.com> Date: Tue, 28 Apr 2020 12:10:50 -0500 Subject: [PATCH] Configurable MEM1 and MEM2 sizes at runtime via Dolphin.ini Changed several enums from Memmap.h to be static vars and implemented Get functions to query them. This seems to have boosted speed a bit in some titles? The new variables and some previously statically initialized items are now initialized via Memory::Init() and the new AddressSpace::Init(). s_ram_size_real and the new s_exram_size_real in particular are initialized from new OnionConfig values "MAIN_MEM1_SIZE" and "MAIN_MEM2_SIZE", only if "MAIN_RAM_OVERRIDE_ENABLE" is true. GUI features have been added to Config > Advanced to adjust the new OnionConfig values. A check has been added to State::doState to ensure savestates with memory configurations different from the current settings aren't loaded. The STATE_VERSION is now 115. FIFO Files have been updated from version 4 to version 5, now including the MEM1 and MEM2 sizes from the time of DFF creation. FIFO Logs not using the new features (OnionConfig MAIN_RAM_OVERRIDE_ENABLE is false) are still backwards compatible. FIFO Logs that do use the new features have a MIN_LOADER_VERSION of 5. Thanks to the order of function calls, FIFO logs are able to automatically configure the new OnionConfig settings to match what is needed. This is a bit hacky, though, so I also threw in a failsafe for if the conditions that allow this to work ever go away. I took the liberty of adding a log message to explain why the core fails to initialize if the MIN_LOADER_VERSION is too great. Some IOS code has had the function "RAMOverrideForIOSMemoryValues" appended to it to recalculate IOS Memory Values from retail IOSes/apploaders to fit the extended memory sizes. Worry not, if MAIN_RAM_OVERRIDE_ENABLE is false, this function does absolutely nothing. A hotfix in DolphinQt/MenuBar.cpp has been implemented for RAM Override. --- Source/Core/Core/Boot/Boot_BS2Emu.cpp | 35 ++--- Source/Core/Core/Boot/DolReader.cpp | 4 +- Source/Core/Core/Boot/ElfReader.cpp | 2 +- Source/Core/Core/Config/MainSettings.cpp | 4 + Source/Core/Core/Config/MainSettings.h | 3 + .../Core/ConfigLoaders/IsSettingSaveable.cpp | 6 +- Source/Core/Core/FifoPlayer/FifoDataFile.cpp | 65 ++++++++- Source/Core/Core/FifoPlayer/FifoDataFile.h | 5 + Source/Core/Core/FifoPlayer/FifoPlayer.cpp | 4 +- Source/Core/Core/FifoPlayer/FifoRecorder.cpp | 12 +- Source/Core/Core/HW/AddressSpace.cpp | 25 ++-- Source/Core/Core/HW/AddressSpace.h | 2 + Source/Core/Core/HW/DSP.cpp | 6 +- Source/Core/Core/HW/DSPHLE/UCodes/UCodes.cpp | 28 ++-- Source/Core/Core/HW/HW.cpp | 4 +- Source/Core/Core/HW/Memmap.cpp | 128 +++++++++++++++--- Source/Core/Core/HW/Memmap.h | 35 ++--- Source/Core/Core/IOS/IOS.cpp | 71 ++++++++-- Source/Core/Core/IOS/IOS.h | 8 ++ Source/Core/Core/IOS/MIOS.cpp | 2 +- Source/Core/Core/IOS/VersionInfo.h | 4 +- Source/Core/Core/PowerPC/MMU.cpp | 37 ++--- Source/Core/Core/State.cpp | 21 ++- Source/Core/DolphinQt/CheatsManager.cpp | 2 +- Source/Core/DolphinQt/MenuBar.cpp | 13 +- .../Core/DolphinQt/Settings/AdvancedPane.cpp | 87 ++++++++++++ Source/Core/DolphinQt/Settings/AdvancedPane.h | 7 + 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 MAIN_ACCURATE_NANS{{System::Main, "Core", "AccurateNaNs"} const ConfigInfo MAIN_EMULATION_SPEED{{System::Main, "Core", "EmulationSpeed"}, 1.0f}; const ConfigInfo MAIN_OVERCLOCK{{System::Main, "Core", "Overclock"}, 1.0f}; const ConfigInfo MAIN_OVERCLOCK_ENABLE{{System::Main, "Core", "OverclockEnable"}, false}; +const ConfigInfo MAIN_RAM_OVERRIDE_ENABLE{{System::Main, "Core", "RAMOverrideEnable"}, false}; +const ConfigInfo MAIN_MEM1_SIZE{{System::Main, "Core", "MEM1Size"}, Memory::MEM1_SIZE_RETAIL}; +const ConfigInfo MAIN_MEM2_SIZE{{System::Main, "Core", "MEM2Size"}, Memory::MEM2_SIZE_RETAIL}; const ConfigInfo MAIN_GFX_BACKEND{{System::Main, "Core", "GFXBackend"}, ""}; const ConfigInfo 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 MAIN_ACCURATE_NANS; extern const ConfigInfo MAIN_EMULATION_SPEED; extern const ConfigInfo MAIN_OVERCLOCK; extern const ConfigInfo MAIN_OVERCLOCK_ENABLE; +extern const ConfigInfo MAIN_RAM_OVERRIDE_ENABLE; +extern const ConfigInfo MAIN_MEM1_SIZE; +extern const ConfigInfo MAIN_MEM2_SIZE; // Should really be part of System::GFX, but again, we're stuck with past mistakes. extern const ConfigInfo MAIN_GFX_BACKEND; extern const ConfigInfo 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 s_setting_saveable = { + static constexpr std::array 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 #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::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(); dataFile->m_Flags = header.flags; @@ -209,10 +238,36 @@ std::unique_ptr 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(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::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(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 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 +#include #include #include @@ -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; @@ -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 physical_regions; static std::vector 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; 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(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& 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; };