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.
This commit is contained in:
Minty-Meeo 2020-04-28 12:10:50 -05:00
parent 116cef572b
commit cc858c63b8
27 changed files with 487 additions and 133 deletions

View file

@ -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));

View file

@ -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());

View file

@ -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);

View file

@ -9,6 +9,7 @@
#include "AudioCommon/AudioCommon.h"
#include "Common/Config/Config.h"
#include "Core/HW/EXI/EXI_Device.h"
#include "Core/HW/Memmap.h"
#include "Core/HW/SI/SI_Device.h"
#include "Core/PowerPC/PowerPC.h"
@ -98,6 +99,9 @@ const ConfigInfo<bool> MAIN_ACCURATE_NANS{{System::Main, "Core", "AccurateNaNs"}
const ConfigInfo<float> MAIN_EMULATION_SPEED{{System::Main, "Core", "EmulationSpeed"}, 1.0f};
const ConfigInfo<float> MAIN_OVERCLOCK{{System::Main, "Core", "Overclock"}, 1.0f};
const ConfigInfo<bool> MAIN_OVERCLOCK_ENABLE{{System::Main, "Core", "OverclockEnable"}, false};
const ConfigInfo<bool> MAIN_RAM_OVERRIDE_ENABLE{{System::Main, "Core", "RAMOverrideEnable"}, false};
const ConfigInfo<u32> MAIN_MEM1_SIZE{{System::Main, "Core", "MEM1Size"}, Memory::MEM1_SIZE_RETAIL};
const ConfigInfo<u32> MAIN_MEM2_SIZE{{System::Main, "Core", "MEM2Size"}, Memory::MEM2_SIZE_RETAIL};
const ConfigInfo<std::string> MAIN_GFX_BACKEND{{System::Main, "Core", "GFXBackend"}, ""};
const ConfigInfo<std::string> MAIN_GPU_DETERMINISM_MODE{
{System::Main, "Core", "GPUDeterminismMode"}, "auto"};

View file

@ -76,6 +76,9 @@ extern const ConfigInfo<bool> MAIN_ACCURATE_NANS;
extern const ConfigInfo<float> MAIN_EMULATION_SPEED;
extern const ConfigInfo<float> MAIN_OVERCLOCK;
extern const ConfigInfo<bool> MAIN_OVERCLOCK_ENABLE;
extern const ConfigInfo<bool> MAIN_RAM_OVERRIDE_ENABLE;
extern const ConfigInfo<u32> MAIN_MEM1_SIZE;
extern const ConfigInfo<u32> MAIN_MEM2_SIZE;
// Should really be part of System::GFX, but again, we're stuck with past mistakes.
extern const ConfigInfo<std::string> MAIN_GFX_BACKEND;
extern const ConfigInfo<std::string> MAIN_GPU_DETERMINISM_MODE;

View file

@ -28,7 +28,7 @@ bool IsSettingSaveable(const Config::ConfigLocation& config_location)
return true;
}
static constexpr std::array<const Config::ConfigLocation*, 93> s_setting_saveable = {
static constexpr std::array<const Config::ConfigLocation*, 96> s_setting_saveable = {
// Main.Core
&Config::MAIN_DEFAULT_ISO.location,
@ -37,8 +37,12 @@ bool IsSettingSaveable(const Config::ConfigLocation& config_location)
&Config::MAIN_AUTO_DISC_CHANGE.location,
&Config::MAIN_DPL2_DECODER.location,
&Config::MAIN_DPL2_QUALITY.location,
&Config::MAIN_RAM_OVERRIDE_ENABLE.location,
&Config::MAIN_MEM1_SIZE.location,
&Config::MAIN_MEM2_SIZE.location,
// Main.Display
&Config::MAIN_FULLSCREEN_DISPLAY_RES.location,
&Config::MAIN_FULLSCREEN.location,
&Config::MAIN_RENDER_TO_MAIN.location,

View file

@ -11,12 +11,18 @@
#include <vector>
#include "Common/File.h"
#include "Common/MsgHandler.h"
#include "Core/Config/MainSettings.h"
#include "Core/HW/Memmap.h"
enum
{
FILE_ID = 0x0d01f1f0,
VERSION_NUMBER = 4,
VERSION_NUMBER = 5,
MIN_LOADER_VERSION = 1,
// This value is only used if the DFF file was created with overridden RAM sizes.
// If the MIN_LOADER_VERSION ever exceeds this, it's alright to remove it.
MIN_LOADER_VERSION_FOR_RAM_OVERRIDE = 5,
};
#pragma pack(push, 1)
@ -39,7 +45,11 @@ struct FileHeader
u32 flags;
u64 texMemOffset;
u32 texMemSize;
u8 reserved[40];
// These are for overriden RAM sizes. Otherwise the FIFO Player
// will crash and burn with mismatched settings. See PR #8722.
u32 mem1_size;
u32 mem2_size;
u8 reserved[32];
};
static_assert(sizeof(FileHeader) == 128, "FileHeader should be 128 bytes");
@ -129,7 +139,11 @@ bool FifoDataFile::Save(const std::string& filename)
FileHeader header;
header.fileId = FILE_ID;
header.file_version = VERSION_NUMBER;
header.min_loader_version = MIN_LOADER_VERSION;
// Maintain backwards compatability so long as the RAM sizes aren't overridden.
if (Config::Get(Config::MAIN_RAM_OVERRIDE_ENABLE))
header.min_loader_version = MIN_LOADER_VERSION_FOR_RAM_OVERRIDE;
else
header.min_loader_version = MIN_LOADER_VERSION;
header.bpMemOffset = bpMemOffset;
header.bpMemSize = BP_MEM_SIZE;
@ -151,6 +165,9 @@ bool FifoDataFile::Save(const std::string& filename)
header.flags = m_Flags;
header.mem1_size = Memory::GetRamSizeReal();
header.mem2_size = Memory::GetExRamSizeReal();
file.Seek(0, SEEK_SET);
file.WriteBytes(&header, sizeof(FileHeader));
@ -198,10 +215,22 @@ std::unique_ptr<FifoDataFile> FifoDataFile::Load(const std::string& filename, bo
if (header.fileId != FILE_ID || header.min_loader_version > VERSION_NUMBER)
{
CriticalAlertT(
"The DFF's minimum loader version (%d) exceeds the version of this FIFO Player (%d)",
header.min_loader_version, VERSION_NUMBER);
file.Close();
return nullptr;
}
// Official support for overridden RAM sizes was added in version 5.
if (header.file_version < 5)
{
// It's safe to assume FIFO Logs before PR #8722 weren't using this
// obscure feature, so load up these header values with the old defaults.
header.mem1_size = Memory::MEM1_SIZE_RETAIL;
header.mem2_size = Memory::MEM2_SIZE_RETAIL;
}
auto dataFile = std::make_unique<FifoDataFile>();
dataFile->m_Flags = header.flags;
@ -209,10 +238,36 @@ std::unique_ptr<FifoDataFile> FifoDataFile::Load(const std::string& filename, bo
if (flagsOnly)
{
// Force settings to match those used when the DFF was created. This is sort of a hack.
// It only works because this function gets called twice, and the first time (flagsOnly mode)
// happens to be before HW::Init(). But the convenience is hard to deny!
Config::SetCurrent(Config::MAIN_RAM_OVERRIDE_ENABLE, true);
Config::SetCurrent(Config::MAIN_MEM1_SIZE, header.mem1_size);
Config::SetCurrent(Config::MAIN_MEM2_SIZE, header.mem2_size);
file.Close();
return dataFile;
}
// To make up for such a hacky thing, here is a catch-all failsafe in case if the above code
// stops working or is otherwise removed. As it is, this should never end up running.
// It should be noted, however, that Dolphin *will still crash* from the nullptr being returned
// in a non-flagsOnly context, so if this code becomes necessary, it should be moved above the
// prior conditional.
if (header.mem1_size != Memory::GetRamSizeReal() ||
header.mem2_size != Memory::GetExRamSizeReal())
{
CriticalAlertT("Emulated memory size mismatch!\n"
"Current | MEM1 %08X (%3dMB) MEM2 %08X (%3dMB)\n"
"DFF | MEM1 %08X (%3dMB) MEM2 %08X (%3dMB)",
Memory::GetRamSizeReal(), Memory::GetRamSizeReal() / 0x100000,
Memory::GetExRamSizeReal(), Memory::GetExRamSizeReal() / 0x100000,
header.mem1_size, header.mem1_size / 0x100000, header.mem2_size,
header.mem2_size / 0x100000);
file.Close();
return nullptr;
}
u32 size = std::min<u32>(BP_MEM_SIZE, header.bpMemSize);
file.Seek(header.bpMemOffset, SEEK_SET);
file.ReadArray(dataFile->m_BPMem, size);
@ -238,6 +293,10 @@ std::unique_ptr<FifoDataFile> FifoDataFile::Load(const std::string& filename, bo
file.ReadArray(dataFile->m_TexMem, size);
}
// idk what else these could be used for, but it'd be a shame to not make them available.
dataFile->m_ram_size_real = header.mem1_size;
dataFile->m_exram_size_real = header.mem2_size;
// Read frames
for (u32 i = 0; i < header.frameCount; ++i)
{

View file

@ -69,6 +69,9 @@ public:
u32* GetXFMem() { return m_XFMem; }
u32* GetXFRegs() { return m_XFRegs; }
u8* GetTexMem() { return m_TexMem; }
u32 GetRamSizeReal() { return m_ram_size_real; }
u32 GetExRamSizeReal() { return m_exram_size_real; }
void AddFrame(const FifoFrameInfo& frameInfo);
const FifoFrameInfo& GetFrame(u32 frame) const { return m_Frames[frame]; }
u32 GetFrameCount() const { return static_cast<u32>(m_Frames.size()); }
@ -96,6 +99,8 @@ private:
u32 m_XFMem[XF_MEM_SIZE];
u32 m_XFRegs[XF_REGS_SIZE];
u8 m_TexMem[TEX_MEM_SIZE];
u32 m_ram_size_real;
u32 m_exram_size_real;
u32 m_Flags = 0;
u32 m_Version = 0;

View file

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

View file

@ -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)

View file

@ -234,6 +234,7 @@ struct AccessorMapping
struct CompositeAddressSpaceAccessors : Accessors
{
CompositeAddressSpaceAccessors() = default;
CompositeAddressSpaceAccessors(std::initializer_list<AccessorMapping> accessors)
: m_accessor_mappings(accessors.begin(), accessors.end())
{
@ -303,6 +304,7 @@ private:
struct SmallBlockAccessors : Accessors
{
SmallBlockAccessors() = default;
SmallBlockAccessors(u8** alloc_base_, u32 size_) : alloc_base{alloc_base_}, size{size_} {}
bool IsValidAddress(u32 address) const override
@ -366,14 +368,11 @@ struct NullAccessors : Accessors
static EffectiveAddressSpaceAccessors s_effective_address_space_accessors;
static AuxiliaryAddressSpaceAccessors s_auxiliary_address_space_accessors;
static SmallBlockAccessors s_mem1_address_space_accessors{&Memory::m_pRAM, Memory::REALRAM_SIZE};
static SmallBlockAccessors s_mem2_address_space_accessors{&Memory::m_pEXRAM, Memory::EXRAM_SIZE};
static SmallBlockAccessors s_fake_address_space_accessors{&Memory::m_pFakeVMEM,
Memory::FAKEVMEM_SIZE};
static CompositeAddressSpaceAccessors s_physical_address_space_accessors_gcn{
{0x00000000, &s_mem1_address_space_accessors}};
static CompositeAddressSpaceAccessors s_physical_address_space_accessors_wii{
{0x00000000, &s_mem1_address_space_accessors}, {0x10000000, &s_mem2_address_space_accessors}};
static SmallBlockAccessors s_mem1_address_space_accessors;
static SmallBlockAccessors s_mem2_address_space_accessors;
static SmallBlockAccessors s_fake_address_space_accessors;
static CompositeAddressSpaceAccessors s_physical_address_space_accessors_gcn;
static CompositeAddressSpaceAccessors s_physical_address_space_accessors_wii;
static NullAccessors s_null_accessors;
Accessors* GetAccessors(Type address_space)
@ -413,4 +412,14 @@ Accessors* GetAccessors(Type address_space)
return &s_null_accessors;
}
void Init()
{
s_mem1_address_space_accessors = {&Memory::m_pRAM, Memory::GetRamSizeReal()};
s_mem2_address_space_accessors = {&Memory::m_pEXRAM, Memory::GetExRamSizeReal()};
s_fake_address_space_accessors = {&Memory::m_pFakeVMEM, Memory::GetFakeVMemSize()};
s_physical_address_space_accessors_gcn = {{0x00000000, &s_mem1_address_space_accessors}};
s_physical_address_space_accessors_wii = {{0x00000000, &s_mem1_address_space_accessors},
{0x10000000, &s_mem2_address_space_accessors}};
}
} // namespace AddressSpace

View file

@ -47,4 +47,6 @@ struct Accessors
Accessors* GetAccessors(Type address_space);
void Init();
} // namespace AddressSpace

View file

@ -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
{

View file

@ -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)

View file

@ -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();

View file

@ -10,6 +10,7 @@
#include "Core/HW/Memmap.h"
#include <algorithm>
#include <array>
#include <cstring>
#include <memory>
@ -18,6 +19,7 @@
#include "Common/Logging/Log.h"
#include "Common/MemArena.h"
#include "Common/Swap.h"
#include "Core/Config/MainSettings.h"
#include "Core/ConfigManager.h"
#include "Core/HW/AudioInterface.h"
#include "Core/HW/DSP.h"
@ -57,6 +59,70 @@ u8* m_pL1Cache;
u8* m_pEXRAM;
u8* m_pFakeVMEM;
// s_ram_size is the amount allocated by the emulator, whereas s_ram_size_real
// is what will be reported in lowmem, and thus used by emulated software.
// Note: Writing to lowmem is done by IPL. If using retail IPL, it will
// always be set to 24MB.
static u32 s_ram_size_real;
static u32 s_ram_size;
static u32 s_ram_mask;
static u32 s_fakevmem_size;
static u32 s_fakevmem_mask;
static u32 s_L1_cache_size;
static u32 s_L1_cache_mask;
static u32 s_io_size;
// s_exram_size is the amount allocated by the emulator, whereas s_exram_size_real
// is what gets used by emulated software. If using retail IOS, it will
// always be set to 64MB.
static u32 s_exram_size_real;
static u32 s_exram_size;
static u32 s_exram_mask;
u32 GetRamSizeReal()
{
return s_ram_size_real;
}
u32 GetRamSize()
{
return s_ram_size;
}
u32 GetRamMask()
{
return s_ram_mask;
}
u32 GetFakeVMemSize()
{
return s_fakevmem_size;
}
u32 GetFakeVMemMask()
{
return s_fakevmem_mask;
}
u32 GetL1CacheSize()
{
return s_L1_cache_size;
}
u32 GetL1CacheMask()
{
return s_L1_cache_mask;
}
u32 GetIOSize()
{
return s_io_size;
}
u32 GetExRamSizeReal()
{
return s_exram_size_real;
}
u32 GetExRamSize()
{
return s_exram_size;
}
u32 GetExRamMask()
{
return s_exram_mask;
}
// MMIO mapping object.
std::unique_ptr<MMIO::Mapping> mmio_mapping;
@ -154,15 +220,9 @@ struct LogicalMemoryView
//
// Dolphin doesn't emulate the difference between cached and uncached access.
//
// TODO: The actual size of RAM is REALRAM_SIZE (24MB); the other 8MB shouldn't
// be backed by actual memory.
// TODO: The actual size of RAM is 24MB; the other 8MB shouldn't be backed by actual memory.
// TODO: Do we want to handle the mirrors of the GC RAM?
static PhysicalMemoryRegion physical_regions[] = {
{&m_pRAM, 0x00000000, RAM_SIZE, PhysicalMemoryRegion::ALWAYS},
{&m_pL1Cache, 0xE0000000, L1_CACHE_SIZE, PhysicalMemoryRegion::ALWAYS},
{&m_pFakeVMEM, 0x7E000000, FAKEVMEM_SIZE, PhysicalMemoryRegion::FAKE_VMEM},
{&m_pEXRAM, 0x10000000, EXRAM_SIZE, PhysicalMemoryRegion::WII_ONLY},
};
static std::array<PhysicalMemoryRegion, 4> physical_regions;
static std::vector<LogicalMemoryView> logical_mapped_entries;
@ -189,6 +249,34 @@ static u32 GetFlags()
void Init()
{
const auto get_mem1_size = [] {
if (Config::Get(Config::MAIN_RAM_OVERRIDE_ENABLE))
return Config::Get(Config::MAIN_MEM1_SIZE);
return Memory::MEM1_SIZE_RETAIL;
};
const auto get_mem2_size = [] {
if (Config::Get(Config::MAIN_RAM_OVERRIDE_ENABLE))
return Config::Get(Config::MAIN_MEM2_SIZE);
return Memory::MEM2_SIZE_RETAIL;
};
s_ram_size_real = get_mem1_size();
s_ram_size = MathUtil::NextPowerOf2(GetRamSizeReal());
s_ram_mask = GetRamSize() - 1;
s_fakevmem_size = 0x02000000;
s_fakevmem_mask = GetFakeVMemSize() - 1;
s_L1_cache_size = 0x00040000;
s_L1_cache_mask = GetL1CacheSize() - 1;
s_io_size = 0x00010000;
s_exram_size_real = get_mem2_size();
s_exram_size = MathUtil::NextPowerOf2(GetExRamSizeReal());
s_exram_mask = GetExRamSize() - 1;
physical_regions[0] = {&m_pRAM, 0x00000000, GetRamSize(), PhysicalMemoryRegion::ALWAYS};
physical_regions[1] = {&m_pL1Cache, 0xE0000000, GetL1CacheSize(), PhysicalMemoryRegion::ALWAYS};
physical_regions[2] = {&m_pFakeVMEM, 0x7E000000, GetFakeVMemSize(),
PhysicalMemoryRegion::FAKE_VMEM};
physical_regions[3] = {&m_pEXRAM, 0x10000000, GetExRamSize(), PhysicalMemoryRegion::WII_ONLY};
bool wii = SConfig::GetInstance().bWii;
u32 flags = GetFlags();
u32 mem_size = 0;
@ -304,14 +392,14 @@ void UpdateLogicalMemory(const PowerPC::BatTable& dbat_table)
void DoState(PointerWrap& p)
{
bool wii = SConfig::GetInstance().bWii;
p.DoArray(m_pRAM, RAM_SIZE);
p.DoArray(m_pL1Cache, L1_CACHE_SIZE);
p.DoArray(m_pRAM, GetRamSize());
p.DoArray(m_pL1Cache, GetL1CacheSize());
p.DoMarker("Memory RAM");
if (m_pFakeVMEM)
p.DoArray(m_pFakeVMEM, FAKEVMEM_SIZE);
p.DoArray(m_pFakeVMEM, GetFakeVMemSize());
p.DoMarker("Memory FakeVMEM");
if (wii)
p.DoArray(m_pEXRAM, EXRAM_SIZE);
p.DoArray(m_pEXRAM, GetExRamSize());
p.DoMarker("Memory EXRAM");
}
@ -363,19 +451,19 @@ void ShutdownFastmemArena()
void Clear()
{
if (m_pRAM)
memset(m_pRAM, 0, RAM_SIZE);
memset(m_pRAM, 0, GetRamSize());
if (m_pL1Cache)
memset(m_pL1Cache, 0, L1_CACHE_SIZE);
memset(m_pL1Cache, 0, GetL1CacheSize());
if (m_pFakeVMEM)
memset(m_pFakeVMEM, 0, FAKEVMEM_SIZE);
memset(m_pFakeVMEM, 0, GetFakeVMemSize());
if (m_pEXRAM)
memset(m_pEXRAM, 0, EXRAM_SIZE);
memset(m_pEXRAM, 0, GetExRamSize());
}
static inline u8* GetPointerForRange(u32 address, size_t size)
{
// Make sure we don't have a range spanning 2 separate banks
if (size >= EXRAM_SIZE)
if (size >= GetExRamSizeReal())
return nullptr;
// Check that the beginning and end of the range are valid
@ -450,13 +538,13 @@ u8* GetPointer(u32 address)
// TODO: Should we be masking off more bits here? Can all devices access
// EXRAM?
address &= 0x3FFFFFFF;
if (address < REALRAM_SIZE)
if (address < GetRamSizeReal())
return m_pRAM + address;
if (m_pEXRAM)
{
if ((address >> 28) == 0x1 && (address & 0x0fffffff) < EXRAM_SIZE)
return m_pEXRAM + (address & EXRAM_MASK);
if ((address >> 28) == 0x1 && (address & 0x0fffffff) < GetExRamSizeReal())
return m_pEXRAM + (address & GetExRamMask());
}
PanicAlert("Unknown Pointer 0x%08x PC 0x%08x LR 0x%08x", address, PC, LR);

View file

@ -37,23 +37,24 @@ extern u8* m_pEXRAM;
extern u8* m_pL1Cache;
extern u8* m_pFakeVMEM;
enum
{
// RAM_SIZE is the amount allocated by the emulator, whereas REALRAM_SIZE is
// what will be reported in lowmem, and thus used by emulated software.
// Note: Writing to lowmem is done by IPL. If using retail IPL, it will
// always be set to 24MB.
REALRAM_SIZE = 0x01800000,
RAM_SIZE = MathUtil::NextPowerOf2(REALRAM_SIZE),
RAM_MASK = RAM_SIZE - 1,
FAKEVMEM_SIZE = 0x02000000,
FAKEVMEM_MASK = FAKEVMEM_SIZE - 1,
L1_CACHE_SIZE = 0x00040000,
L1_CACHE_MASK = L1_CACHE_SIZE - 1,
IO_SIZE = 0x00010000,
EXRAM_SIZE = 0x04000000,
EXRAM_MASK = EXRAM_SIZE - 1,
};
u32 GetRamSizeReal();
u32 GetRamSize();
u32 GetRamMask();
u32 GetFakeVMemSize();
u32 GetFakeVMemMask();
u32 GetL1CacheSize();
u32 GetL1CacheMask();
u32 GetIOSize();
u32 GetExRamSizeReal();
u32 GetExRamSize();
u32 GetExRamMask();
constexpr u32 MEM1_BASE_ADDR = 0x80000000U;
constexpr u32 MEM2_BASE_ADDR = 0x90000000U;
constexpr u32 MEM1_SIZE_RETAIL = 0x01800000U;
constexpr u32 MEM1_SIZE_GDEV = 0x04000000U;
constexpr u32 MEM2_SIZE_RETAIL = 0x04000000U;
constexpr u32 MEM2_SIZE_NDEV = 0x08000000U;
// MMIO mapping object.
extern std::unique_ptr<MMIO::Mapping> mmio_mapping;

View file

@ -22,6 +22,7 @@
#include "Core/Boot/DolReader.h"
#include "Core/Boot/ElfReader.h"
#include "Core/CommonTitles.h"
#include "Core/Config/MainSettings.h"
#include "Core/ConfigManager.h"
#include "Core/Core.h"
#include "Core/CoreTiming.h"
@ -85,8 +86,8 @@ constexpr u32 ADDR_HOLLYWOOD_REVISION = 0x3138;
constexpr u32 ADDR_PH3 = 0x313c;
constexpr u32 ADDR_IOS_VERSION = 0x3140;
constexpr u32 ADDR_IOS_DATE = 0x3144;
constexpr u32 ADDR_UNKNOWN_BEGIN = 0x3148;
constexpr u32 ADDR_UNKNOWN_END = 0x314c;
constexpr u32 ADDR_IOS_RESERVED_BEGIN = 0x3148;
constexpr u32 ADDR_IOS_RESERVED_END = 0x314c;
constexpr u32 ADDR_PH4 = 0x3150;
constexpr u32 ADDR_PH5 = 0x3154;
constexpr u32 ADDR_RAM_VENDOR = 0x3158;
@ -96,12 +97,6 @@ constexpr u32 ADDR_DEVKIT_BOOT_PROGRAM_VERSION = 0x315e;
constexpr u32 ADDR_SYSMENU_SYNC = 0x3160;
constexpr u32 PLACEHOLDER = 0xDEADBEEF;
enum class MemorySetupType
{
IOSReload,
Full,
};
static bool SetupMemory(u64 ios_title_id, MemorySetupType setup_type)
{
auto target_imv = std::find_if(
@ -134,8 +129,10 @@ static bool SetupMemory(u64 ios_title_id, MemorySetupType setup_type)
Memory::Write_U32(target_imv->mem2_arena_end, ADDR_MEM2_ARENA_END);
Memory::Write_U32(target_imv->ipc_buffer_begin, ADDR_IPC_BUFFER_BEGIN);
Memory::Write_U32(target_imv->ipc_buffer_end, ADDR_IPC_BUFFER_END);
Memory::Write_U32(target_imv->unknown_begin, ADDR_UNKNOWN_BEGIN);
Memory::Write_U32(target_imv->unknown_end, ADDR_UNKNOWN_END);
Memory::Write_U32(target_imv->ios_reserved_begin, ADDR_IOS_RESERVED_BEGIN);
Memory::Write_U32(target_imv->ios_reserved_end, ADDR_IOS_RESERVED_END);
RAMOverrideForIOSMemoryValues(setup_type);
return true;
}
@ -158,8 +155,8 @@ static bool SetupMemory(u64 ios_title_id, MemorySetupType setup_type)
Memory::Write_U32(PLACEHOLDER, ADDR_PH3);
Memory::Write_U32(target_imv->ios_version, ADDR_IOS_VERSION);
Memory::Write_U32(target_imv->ios_date, ADDR_IOS_DATE);
Memory::Write_U32(target_imv->unknown_begin, ADDR_UNKNOWN_BEGIN);
Memory::Write_U32(target_imv->unknown_end, ADDR_UNKNOWN_END);
Memory::Write_U32(target_imv->ios_reserved_begin, ADDR_IOS_RESERVED_BEGIN);
Memory::Write_U32(target_imv->ios_reserved_end, ADDR_IOS_RESERVED_END);
Memory::Write_U32(PLACEHOLDER, ADDR_PH4);
Memory::Write_U32(PLACEHOLDER, ADDR_PH5);
Memory::Write_U32(target_imv->ram_vendor, ADDR_RAM_VENDOR);
@ -167,9 +164,59 @@ static bool SetupMemory(u64 ios_title_id, MemorySetupType setup_type)
Memory::Write_U8(0xAD, ADDR_APPLOADER_FLAG);
Memory::Write_U16(0xBEEF, ADDR_DEVKIT_BOOT_PROGRAM_VERSION);
Memory::Write_U32(target_imv->sysmenu_sync, ADDR_SYSMENU_SYNC);
RAMOverrideForIOSMemoryValues(setup_type);
return true;
}
void RAMOverrideForIOSMemoryValues(MemorySetupType setup_type)
{
// Don't touch anything if the feature isn't enabled.
if (!Config::Get(Config::MAIN_RAM_OVERRIDE_ENABLE))
return;
// Some unstated constants that can be inferred.
const u32 ipc_buffer_size =
Memory::Read_U32(ADDR_IPC_BUFFER_END) - Memory::Read_U32(ADDR_IPC_BUFFER_BEGIN);
const u32 ios_reserved_size =
Memory::Read_U32(ADDR_IOS_RESERVED_END) - Memory::Read_U32(ADDR_IOS_RESERVED_BEGIN);
const u32 mem1_physical_size = Memory::GetRamSizeReal();
const u32 mem1_simulated_size = Memory::GetRamSizeReal();
const u32 mem1_end = Memory::MEM1_BASE_ADDR + mem1_simulated_size;
const u32 mem1_arena_begin = 0;
const u32 mem1_arena_end = mem1_end;
const u32 mem2_physical_size = Memory::GetExRamSizeReal();
const u32 mem2_simulated_size = Memory::GetExRamSizeReal();
const u32 mem2_end = Memory::MEM2_BASE_ADDR + mem2_simulated_size - ios_reserved_size;
const u32 mem2_arena_begin = Memory::MEM2_BASE_ADDR + 0x800U;
const u32 mem2_arena_end = mem2_end - ipc_buffer_size;
const u32 ipc_buffer_begin = mem2_arena_end;
const u32 ipc_buffer_end = mem2_end;
const u32 ios_reserved_begin = mem2_end;
const u32 ios_reserved_end = Memory::MEM2_BASE_ADDR + mem2_simulated_size;
if (setup_type == MemorySetupType::Full)
{
// Overwriting these after the game's apploader sets them would be bad
Memory::Write_U32(mem1_physical_size, ADDR_MEM1_SIZE);
Memory::Write_U32(mem1_simulated_size, ADDR_MEM1_SIM_SIZE);
Memory::Write_U32(mem1_end, ADDR_MEM1_END);
Memory::Write_U32(mem1_arena_begin, ADDR_MEM1_ARENA_BEGIN);
Memory::Write_U32(mem1_arena_end, ADDR_MEM1_ARENA_END);
}
Memory::Write_U32(mem2_physical_size, ADDR_MEM2_SIZE);
Memory::Write_U32(mem2_simulated_size, ADDR_MEM2_SIM_SIZE);
Memory::Write_U32(mem2_end, ADDR_MEM2_END);
Memory::Write_U32(mem2_arena_begin, ADDR_MEM2_ARENA_BEGIN);
Memory::Write_U32(mem2_arena_end, ADDR_MEM2_ARENA_END);
Memory::Write_U32(ipc_buffer_begin, ADDR_IPC_BUFFER_BEGIN);
Memory::Write_U32(ipc_buffer_end, ADDR_IPC_BUFFER_END);
Memory::Write_U32(ios_reserved_begin, ADDR_IOS_RESERVED_BEGIN);
Memory::Write_U32(ios_reserved_end, ADDR_IOS_RESERVED_END);
}
void WriteReturnValue(s32 value, u32 address)
{
Memory::Write_U32(static_cast<u32>(value), address);

View file

@ -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.

View file

@ -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

View file

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

View file

@ -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))

View file

@ -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);

View file

@ -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(

View file

@ -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)));

View file

@ -96,6 +96,44 @@ void AdvancedPane::CreateLayout()
cpu_clock_override_description->setWordWrap(true);
clock_override_layout->addWidget(cpu_clock_override_description);
auto* ram_override = new QGroupBox(tr("Memory Override"));
auto* ram_override_layout = new QVBoxLayout();
ram_override->setLayout(ram_override_layout);
main_layout->addWidget(ram_override);
m_ram_override_checkbox = new QCheckBox(tr("Enable Emulated Memory Size Override"));
ram_override_layout->addWidget(m_ram_override_checkbox);
auto* mem1_override_slider_layout = new QHBoxLayout();
mem1_override_slider_layout->setContentsMargins(0, 0, 0, 0);
ram_override_layout->addLayout(mem1_override_slider_layout);
m_mem1_override_slider = new QSlider(Qt::Horizontal);
m_mem1_override_slider->setRange(24, 64);
mem1_override_slider_layout->addWidget(m_mem1_override_slider);
m_mem1_override_slider_label = new QLabel();
mem1_override_slider_layout->addWidget(m_mem1_override_slider_label);
auto* mem2_override_slider_layout = new QHBoxLayout();
mem2_override_slider_layout->setContentsMargins(0, 0, 0, 0);
ram_override_layout->addLayout(mem2_override_slider_layout);
m_mem2_override_slider = new QSlider(Qt::Horizontal);
m_mem2_override_slider->setRange(64, 128);
mem2_override_slider_layout->addWidget(m_mem2_override_slider);
m_mem2_override_slider_label = new QLabel();
mem2_override_slider_layout->addWidget(m_mem2_override_slider_label);
auto* ram_override_description =
new QLabel(tr("Adjusts the emulated sizes of MEM1 and MEM2.\n\n"
"Some titles may recognize the larger memory arena(s) and take "
"advantage of it, though retail titles should be optimized for "
"the retail memory limitations."));
ram_override_description->setWordWrap(true);
ram_override_layout->addWidget(ram_override_description);
auto* rtc_options = new QGroupBox(tr("Custom RTC Options"));
rtc_options->setLayout(new QVBoxLayout());
main_layout->addWidget(rtc_options);
@ -154,6 +192,24 @@ void AdvancedPane::ConnectLayout()
Update();
});
m_ram_override_checkbox->setChecked(Config::Get(Config::MAIN_RAM_OVERRIDE_ENABLE));
connect(m_ram_override_checkbox, &QCheckBox::toggled, [this](bool enable_ram_override) {
Config::SetBaseOrCurrent(Config::MAIN_RAM_OVERRIDE_ENABLE, enable_ram_override);
Update();
});
connect(m_mem1_override_slider, &QSlider::valueChanged, [this](int slider_value) {
const u32 mem1_size = m_mem1_override_slider->value() * 0x100000;
Config::SetBaseOrCurrent(Config::MAIN_MEM1_SIZE, mem1_size);
Update();
});
connect(m_mem2_override_slider, &QSlider::valueChanged, [this](int slider_value) {
const u32 mem2_size = m_mem2_override_slider->value() * 0x100000;
Config::SetBaseOrCurrent(Config::MAIN_MEM2_SIZE, mem2_size);
Update();
});
m_custom_rtc_checkbox->setChecked(SConfig::GetInstance().bEnableCustomRTC);
connect(m_custom_rtc_checkbox, &QCheckBox::toggled, [this](bool enable_custom_rtc) {
SConfig::GetInstance().bEnableCustomRTC = enable_custom_rtc;
@ -173,6 +229,7 @@ void AdvancedPane::Update()
{
const bool running = Core::GetState() != Core::State::Uninitialized;
const bool enable_cpu_clock_override_widgets = SConfig::GetInstance().m_OCEnable;
const bool enable_ram_override_widgets = Config::Get(Config::MAIN_RAM_OVERRIDE_ENABLE);
const bool enable_custom_rtc_widgets = SConfig::GetInstance().bEnableCustomRTC && !running;
const std::vector<PowerPC::CPUCore>& available_cpu_cores = PowerPC::AvailableCPUCores();
@ -208,6 +265,36 @@ void AdvancedPane::Update()
return tr("%1 % (%2 MHz)").arg(QString::number(percent), QString::number(clock));
}());
m_ram_override_checkbox->setEnabled(!running);
m_mem1_override_slider->setEnabled(enable_ram_override_widgets && !running);
m_mem1_override_slider_label->setEnabled(enable_ram_override_widgets && !running);
{
const QSignalBlocker blocker(m_mem1_override_slider);
const u32 mem1_size = Config::Get(Config::MAIN_MEM1_SIZE) / 0x100000;
m_mem1_override_slider->setValue(mem1_size);
}
m_mem1_override_slider_label->setText([] {
const u32 mem1_size = Config::Get(Config::MAIN_MEM1_SIZE) / 0x100000;
return tr("%1MB (MEM1)").arg(QString::number(mem1_size));
}());
m_mem2_override_slider->setEnabled(enable_ram_override_widgets && !running);
m_mem2_override_slider_label->setEnabled(enable_ram_override_widgets && !running);
{
const QSignalBlocker blocker(m_mem2_override_slider);
const u32 mem2_size = Config::Get(Config::MAIN_MEM2_SIZE) / 0x100000;
m_mem2_override_slider->setValue(mem2_size);
}
m_mem2_override_slider_label->setText([] {
const u32 mem2_size = Config::Get(Config::MAIN_MEM2_SIZE) / 0x100000;
return tr("%1MB (MEM2)").arg(QString::number(mem2_size));
}());
m_custom_rtc_checkbox->setEnabled(!running);
m_custom_rtc_datetime->setEnabled(enable_custom_rtc_widgets);
}

View file

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