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; };