IOS: Implement MIOS functionality
This implements MIOS's PPC bootstrapping functionality, which enables users to start a GameCube game from the Wii System Menu. Because we aren't doing Starlet LLE (and don't have a boot1), we can just jump to MIOS when the emulated software does an ES_LAUNCH or uses ioctlv 0x25 to launch BC. Note that the process is more complex on a real Wii and goes through several more steps before getting to MIOS: * The System Menu detects a GameCube disc and launches BC (1-100) instead of the game. [Dolphin does this too.] * BC, which is reportedly very similar to boot1, lowers the Hollywood clock speed to the Flipper's and then launches boot2. * boot2 sees the lowered clock speed and launches MIOS (1-101) instead of the System Menu. MIOS runs instead of IOS in GC mode and has an embedded GC IPL (which is the code actually responsible for loading the disc game) and a PPC bootstrap code. To get things working properly, we simply need to load both to memory, then jump to the bootstrap code at 0x3400. Obviously, because of the way this works, a real MIOS is required.
This commit is contained in:
parent
4662e25cbb
commit
fdfe57a49b
|
@ -35,6 +35,7 @@ public:
|
||||||
// Returns true if a map file exists, false if none could be found.
|
// Returns true if a map file exists, false if none could be found.
|
||||||
static bool FindMapFile(std::string* existing_map_file, std::string* writable_map_file,
|
static bool FindMapFile(std::string* existing_map_file, std::string* writable_map_file,
|
||||||
std::string* title_id = nullptr);
|
std::string* title_id = nullptr);
|
||||||
|
static bool LoadMapFromFilename();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static bool DVDRead(u64 dvd_offset, u32 output_address, u32 length, bool decrypt);
|
static bool DVDRead(u64 dvd_offset, u32 output_address, u32 length, bool decrypt);
|
||||||
|
@ -42,7 +43,6 @@ private:
|
||||||
|
|
||||||
static void UpdateDebugger_MapLoaded();
|
static void UpdateDebugger_MapLoaded();
|
||||||
|
|
||||||
static bool LoadMapFromFilename();
|
|
||||||
static bool Boot_ELF(const std::string& filename);
|
static bool Boot_ELF(const std::string& filename);
|
||||||
static bool Boot_WiiWAD(const std::string& filename);
|
static bool Boot_WiiWAD(const std::string& filename);
|
||||||
|
|
||||||
|
|
|
@ -102,7 +102,7 @@ const char* ElfReader::GetSectionName(int section) const
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is just a simple elf loader, good enough to load elfs generated by devkitPPC
|
// This is just a simple elf loader, good enough to load elfs generated by devkitPPC
|
||||||
bool ElfReader::LoadIntoMemory()
|
bool ElfReader::LoadIntoMemory(bool only_in_mem1)
|
||||||
{
|
{
|
||||||
INFO_LOG(MASTER_LOG, "String section: %i", header->e_shstrndx);
|
INFO_LOG(MASTER_LOG, "String section: %i", header->e_shstrndx);
|
||||||
|
|
||||||
|
@ -132,6 +132,9 @@ bool ElfReader::LoadIntoMemory()
|
||||||
u32 srcSize = p->p_filesz;
|
u32 srcSize = p->p_filesz;
|
||||||
u32 dstSize = p->p_memsz;
|
u32 dstSize = p->p_memsz;
|
||||||
|
|
||||||
|
if (only_in_mem1 && p->p_vaddr >= Memory::REALRAM_SIZE)
|
||||||
|
continue;
|
||||||
|
|
||||||
Memory::CopyToEmu(writeAddr, src, srcSize);
|
Memory::CopyToEmu(writeAddr, src, srcSize);
|
||||||
if (srcSize < dstSize)
|
if (srcSize < dstSize)
|
||||||
Memory::Memset(writeAddr + srcSize, 0, dstSize - srcSize); // zero out bss
|
Memory::Memset(writeAddr + srcSize, 0, dstSize - srcSize); // zero out bss
|
||||||
|
|
|
@ -39,7 +39,7 @@ public:
|
||||||
ElfMachine GetMachine() const { return (ElfMachine)(header->e_machine); }
|
ElfMachine GetMachine() const { return (ElfMachine)(header->e_machine); }
|
||||||
u32 GetEntryPoint() const { return entryPoint; }
|
u32 GetEntryPoint() const { return entryPoint; }
|
||||||
u32 GetFlags() const { return (u32)(header->e_flags); }
|
u32 GetFlags() const { return (u32)(header->e_flags); }
|
||||||
bool LoadIntoMemory();
|
bool LoadIntoMemory(bool only_in_mem1 = false);
|
||||||
bool LoadSymbols();
|
bool LoadSymbols();
|
||||||
|
|
||||||
int GetNumSegments() const { return (int)(header->e_phnum); }
|
int GetNumSegments() const { return (int)(header->e_phnum); }
|
||||||
|
|
|
@ -140,6 +140,7 @@ set(SRCS ActionReplay.cpp
|
||||||
IOS/Device.cpp
|
IOS/Device.cpp
|
||||||
IOS/DeviceStub.cpp
|
IOS/DeviceStub.cpp
|
||||||
IOS/IPC.cpp
|
IOS/IPC.cpp
|
||||||
|
IOS/MIOS.cpp
|
||||||
IOS/DI/DI.cpp
|
IOS/DI/DI.cpp
|
||||||
IOS/ES/ES.cpp
|
IOS/ES/ES.cpp
|
||||||
IOS/ES/Formats.cpp
|
IOS/ES/Formats.cpp
|
||||||
|
|
|
@ -188,6 +188,7 @@ struct SConfig : NonCopyable
|
||||||
BOOT_ELF,
|
BOOT_ELF,
|
||||||
BOOT_DOL,
|
BOOT_DOL,
|
||||||
BOOT_WII_NAND,
|
BOOT_WII_NAND,
|
||||||
|
BOOT_MIOS,
|
||||||
BOOT_BS2,
|
BOOT_BS2,
|
||||||
BOOT_DFF
|
BOOT_DFF
|
||||||
};
|
};
|
||||||
|
|
|
@ -634,10 +634,6 @@ void EmuThread()
|
||||||
|
|
||||||
FileMon::Close();
|
FileMon::Close();
|
||||||
|
|
||||||
// Stop audio thread - Actually this does nothing when using HLE
|
|
||||||
// emulation, but stops the DSP Interpreter when using LLE emulation.
|
|
||||||
DSP::GetDSPEmulator()->DSP_StopSoundStream();
|
|
||||||
|
|
||||||
// We must set up this flag before executing HW::Shutdown()
|
// We must set up this flag before executing HW::Shutdown()
|
||||||
s_hardware_initialized = false;
|
s_hardware_initialized = false;
|
||||||
INFO_LOG(CONSOLE, "%s", StopMessage(false, "Shutting down HW").c_str());
|
INFO_LOG(CONSOLE, "%s", StopMessage(false, "Shutting down HW").c_str());
|
||||||
|
|
|
@ -172,6 +172,7 @@
|
||||||
<ClCompile Include="IOS\Device.cpp" />
|
<ClCompile Include="IOS\Device.cpp" />
|
||||||
<ClCompile Include="IOS\DeviceStub.cpp" />
|
<ClCompile Include="IOS\DeviceStub.cpp" />
|
||||||
<ClCompile Include="IOS\IPC.cpp" />
|
<ClCompile Include="IOS\IPC.cpp" />
|
||||||
|
<ClCompile Include="IOS\MIOS.cpp" />
|
||||||
<ClCompile Include="IOS\DI\DI.cpp" />
|
<ClCompile Include="IOS\DI\DI.cpp" />
|
||||||
<ClCompile Include="IOS\ES\ES.cpp" />
|
<ClCompile Include="IOS\ES\ES.cpp" />
|
||||||
<ClCompile Include="IOS\ES\Formats.cpp" />
|
<ClCompile Include="IOS\ES\Formats.cpp" />
|
||||||
|
@ -408,6 +409,7 @@
|
||||||
<ClInclude Include="IOS\Device.h" />
|
<ClInclude Include="IOS\Device.h" />
|
||||||
<ClInclude Include="IOS\DeviceStub.h" />
|
<ClInclude Include="IOS\DeviceStub.h" />
|
||||||
<ClInclude Include="IOS\IPC.h" />
|
<ClInclude Include="IOS\IPC.h" />
|
||||||
|
<ClInclude Include="IOS\MIOS.h" />
|
||||||
<ClInclude Include="IOS\DI\DI.h" />
|
<ClInclude Include="IOS\DI\DI.h" />
|
||||||
<ClInclude Include="IOS\ES\ES.h" />
|
<ClInclude Include="IOS\ES\ES.h" />
|
||||||
<ClInclude Include="IOS\ES\Formats.h" />
|
<ClInclude Include="IOS\ES\Formats.h" />
|
||||||
|
|
|
@ -752,6 +752,9 @@
|
||||||
<ClCompile Include="IOS\IPC.cpp">
|
<ClCompile Include="IOS\IPC.cpp">
|
||||||
<Filter>IOS</Filter>
|
<Filter>IOS</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="IOS\MIOS.cpp">
|
||||||
|
<Filter>IOS</Filter>
|
||||||
|
</ClCompile>
|
||||||
<ClCompile Include="IOS\Network\Net.cpp">
|
<ClCompile Include="IOS\Network\Net.cpp">
|
||||||
<Filter>IOS\Network</Filter>
|
<Filter>IOS\Network</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
@ -1419,6 +1422,9 @@
|
||||||
<ClInclude Include="IOS\IPC.h">
|
<ClInclude Include="IOS\IPC.h">
|
||||||
<Filter>IOS</Filter>
|
<Filter>IOS</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="IOS\MIOS.h">
|
||||||
|
<Filter>IOS</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Text Include="CMakeLists.txt" />
|
<Text Include="CMakeLists.txt" />
|
||||||
|
|
|
@ -177,6 +177,13 @@ DSPEmulator* GetDSPEmulator()
|
||||||
}
|
}
|
||||||
|
|
||||||
void Init(bool hle)
|
void Init(bool hle)
|
||||||
|
{
|
||||||
|
Reinit(hle);
|
||||||
|
s_et_GenerateDSPInterrupt = CoreTiming::RegisterEvent("DSPint", GenerateDSPInterrupt);
|
||||||
|
s_et_CompleteARAM = CoreTiming::RegisterEvent("ARAMint", CompleteARAM);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Reinit(bool hle)
|
||||||
{
|
{
|
||||||
s_dsp_emulator = CreateDSPEmulator(hle);
|
s_dsp_emulator = CreateDSPEmulator(hle);
|
||||||
s_dsp_is_lle = s_dsp_emulator->IsLLE();
|
s_dsp_is_lle = s_dsp_emulator->IsLLE();
|
||||||
|
@ -206,9 +213,6 @@ void Init(bool hle)
|
||||||
s_ARAM_Info.Hex = 0;
|
s_ARAM_Info.Hex = 0;
|
||||||
s_AR_MODE = 1; // ARAM Controller has init'd
|
s_AR_MODE = 1; // ARAM Controller has init'd
|
||||||
s_AR_REFRESH = 156; // 156MHz
|
s_AR_REFRESH = 156; // 156MHz
|
||||||
|
|
||||||
s_et_GenerateDSPInterrupt = CoreTiming::RegisterEvent("DSPint", GenerateDSPInterrupt);
|
|
||||||
s_et_CompleteARAM = CoreTiming::RegisterEvent("ARAMint", CompleteARAM);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Shutdown()
|
void Shutdown()
|
||||||
|
|
|
@ -60,6 +60,7 @@ union UDSPControl
|
||||||
};
|
};
|
||||||
|
|
||||||
void Init(bool hle);
|
void Init(bool hle);
|
||||||
|
void Reinit(bool hle);
|
||||||
void Shutdown();
|
void Shutdown();
|
||||||
|
|
||||||
void RegisterMMIO(MMIO::Mapping* mmio, u32 base);
|
void RegisterMMIO(MMIO::Mapping* mmio, u32 base);
|
||||||
|
|
|
@ -37,6 +37,12 @@ static bool s_request_disable_thread;
|
||||||
|
|
||||||
DSPLLE::DSPLLE() = default;
|
DSPLLE::DSPLLE() = default;
|
||||||
|
|
||||||
|
DSPLLE::~DSPLLE()
|
||||||
|
{
|
||||||
|
DSPCore_Shutdown();
|
||||||
|
DSP_StopSoundStream();
|
||||||
|
}
|
||||||
|
|
||||||
void DSPLLE::DoState(PointerWrap& p)
|
void DSPLLE::DoState(PointerWrap& p)
|
||||||
{
|
{
|
||||||
bool is_hle = false;
|
bool is_hle = false;
|
||||||
|
|
|
@ -22,6 +22,7 @@ class DSPLLE : public DSPEmulator
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
DSPLLE();
|
DSPLLE();
|
||||||
|
~DSPLLE();
|
||||||
|
|
||||||
bool Initialize(bool wii, bool dsp_thread) override;
|
bool Initialize(bool wii, bool dsp_thread) override;
|
||||||
void Shutdown() override;
|
void Shutdown() override;
|
||||||
|
|
|
@ -419,8 +419,24 @@ void Init()
|
||||||
{
|
{
|
||||||
DVDThread::Start();
|
DVDThread::Start();
|
||||||
|
|
||||||
s_DISR.Hex = 0;
|
Reset();
|
||||||
s_DICVR.Hex = 1; // Disc Channel relies on cover being open when no disc is inserted
|
s_DICVR.Hex = 1; // Disc Channel relies on cover being open when no disc is inserted
|
||||||
|
s_disc_inside = false;
|
||||||
|
|
||||||
|
s_eject_disc = CoreTiming::RegisterEvent("EjectDisc", EjectDiscCallback);
|
||||||
|
s_insert_disc = CoreTiming::RegisterEvent("InsertDisc", InsertDiscCallback);
|
||||||
|
|
||||||
|
s_finish_executing_command =
|
||||||
|
CoreTiming::RegisterEvent("FinishExecutingCommand", FinishExecutingCommandCallback);
|
||||||
|
|
||||||
|
u64 userdata = PackFinishExecutingCommandUserdata(ReplyType::DTK, DIInterruptType::INT_TCINT);
|
||||||
|
CoreTiming::ScheduleEvent(0, s_finish_executing_command, userdata);
|
||||||
|
}
|
||||||
|
|
||||||
|
// This doesn't reset any inserted disc or the cover state.
|
||||||
|
void Reset()
|
||||||
|
{
|
||||||
|
s_DISR.Hex = 0;
|
||||||
s_DICMDBUF[0].Hex = 0;
|
s_DICMDBUF[0].Hex = 0;
|
||||||
s_DICMDBUF[1].Hex = 0;
|
s_DICMDBUF[1].Hex = 0;
|
||||||
s_DICMDBUF[2].Hex = 0;
|
s_DICMDBUF[2].Hex = 0;
|
||||||
|
@ -441,7 +457,6 @@ void Init()
|
||||||
s_pending_samples = 0;
|
s_pending_samples = 0;
|
||||||
|
|
||||||
s_error_code = 0;
|
s_error_code = 0;
|
||||||
s_disc_inside = false;
|
|
||||||
|
|
||||||
// The buffer is empty at start
|
// The buffer is empty at start
|
||||||
s_read_buffer_start_offset = 0;
|
s_read_buffer_start_offset = 0;
|
||||||
|
@ -450,15 +465,6 @@ void Init()
|
||||||
s_read_buffer_end_time = 0;
|
s_read_buffer_end_time = 0;
|
||||||
|
|
||||||
s_disc_path_to_insert.clear();
|
s_disc_path_to_insert.clear();
|
||||||
|
|
||||||
s_eject_disc = CoreTiming::RegisterEvent("EjectDisc", EjectDiscCallback);
|
|
||||||
s_insert_disc = CoreTiming::RegisterEvent("InsertDisc", InsertDiscCallback);
|
|
||||||
|
|
||||||
s_finish_executing_command =
|
|
||||||
CoreTiming::RegisterEvent("FinishExecutingCommand", FinishExecutingCommandCallback);
|
|
||||||
|
|
||||||
u64 userdata = PackFinishExecutingCommandUserdata(ReplyType::DTK, DIInterruptType::INT_TCINT);
|
|
||||||
CoreTiming::ScheduleEvent(0, s_finish_executing_command, userdata);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Shutdown()
|
void Shutdown()
|
||||||
|
|
|
@ -102,6 +102,7 @@ enum class ReplyType : u32
|
||||||
};
|
};
|
||||||
|
|
||||||
void Init();
|
void Init();
|
||||||
|
void Reset();
|
||||||
void Shutdown();
|
void Shutdown();
|
||||||
void DoState(PointerWrap& p);
|
void DoState(PointerWrap& p);
|
||||||
|
|
||||||
|
|
|
@ -232,7 +232,10 @@ void CEXIIPL::SetCS(int _iCS)
|
||||||
|
|
||||||
void CEXIIPL::UpdateRTC()
|
void CEXIIPL::UpdateRTC()
|
||||||
{
|
{
|
||||||
u32 epoch = SConfig::GetInstance().bWii ? WII_EPOCH : GC_EPOCH;
|
u32 epoch =
|
||||||
|
(SConfig::GetInstance().bWii || SConfig::GetInstance().m_BootType == SConfig::BOOT_MIOS) ?
|
||||||
|
WII_EPOCH :
|
||||||
|
GC_EPOCH;
|
||||||
u32 rtc = Common::swap32(GetEmulatedTime(epoch));
|
u32 rtc = Common::swap32(GetEmulatedTime(epoch));
|
||||||
std::memcpy(m_RTC, &rtc, sizeof(u32));
|
std::memcpy(m_RTC, &rtc, sizeof(u32));
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,12 +61,11 @@ void Init()
|
||||||
|
|
||||||
void Shutdown()
|
void Shutdown()
|
||||||
{
|
{
|
||||||
|
// IOS should always be shut down regardless of bWii because it can be running in GC mode (MIOS).
|
||||||
|
IOS::HLE::Shutdown(); // Depends on Memory
|
||||||
|
IOS::Shutdown();
|
||||||
if (SConfig::GetInstance().bWii)
|
if (SConfig::GetInstance().bWii)
|
||||||
{
|
|
||||||
IOS::HLE::Shutdown(); // Depends on Memory
|
|
||||||
IOS::Shutdown();
|
|
||||||
Core::ShutdownWiiRoot();
|
Core::ShutdownWiiRoot();
|
||||||
}
|
|
||||||
|
|
||||||
SystemTimers::Shutdown();
|
SystemTimers::Shutdown();
|
||||||
CPU::Shutdown();
|
CPU::Shutdown();
|
||||||
|
|
|
@ -223,7 +223,12 @@ static void ThrottleCallback(u64 last_time, s64 cyclesLate)
|
||||||
// SystemTimers::Init
|
// SystemTimers::Init
|
||||||
void PreInit()
|
void PreInit()
|
||||||
{
|
{
|
||||||
if (SConfig::GetInstance().bWii)
|
ChangePPCClock(SConfig::GetInstance().bWii ? Mode::Wii : Mode::GC);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ChangePPCClock(Mode mode)
|
||||||
|
{
|
||||||
|
if (mode == Mode::Wii)
|
||||||
s_cpu_core_clock = 729000000u;
|
s_cpu_core_clock = 729000000u;
|
||||||
else
|
else
|
||||||
s_cpu_core_clock = 486000000u;
|
s_cpu_core_clock = 486000000u;
|
||||||
|
|
|
@ -33,10 +33,17 @@ enum
|
||||||
TIMER_RATIO = 12
|
TIMER_RATIO = 12
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class Mode
|
||||||
|
{
|
||||||
|
GC,
|
||||||
|
Wii,
|
||||||
|
};
|
||||||
|
|
||||||
u32 GetTicksPerSecond();
|
u32 GetTicksPerSecond();
|
||||||
void PreInit();
|
void PreInit();
|
||||||
void Init();
|
void Init();
|
||||||
void Shutdown();
|
void Shutdown();
|
||||||
|
void ChangePPCClock(Mode mode);
|
||||||
|
|
||||||
// Notify timing system that somebody wrote to the decrementer
|
// Notify timing system that somebody wrote to the decrementer
|
||||||
void DecrementerSet();
|
void DecrementerSet();
|
||||||
|
|
|
@ -1113,6 +1113,9 @@ IPCCommandResult ES::Launch(const IOCtlVRequest& request)
|
||||||
u64 titleid = Memory::Read_U64(request.in_vectors[1].address + 16);
|
u64 titleid = Memory::Read_U64(request.in_vectors[1].address + 16);
|
||||||
u16 access = Memory::Read_U16(request.in_vectors[1].address + 24);
|
u16 access = Memory::Read_U16(request.in_vectors[1].address + 24);
|
||||||
|
|
||||||
|
NOTICE_LOG(IOS_ES, "IOCTL_ES_LAUNCH %016" PRIx64 " %08x %016" PRIx64 " %08x %016" PRIx64 " %04x",
|
||||||
|
TitleID, view, ticketid, devicetype, titleid, access);
|
||||||
|
|
||||||
// ES_LAUNCH should probably reset thw whole state, which at least means closing all open files.
|
// ES_LAUNCH should probably reset thw whole state, which at least means closing all open files.
|
||||||
// leaving them open through ES_LAUNCH may cause hangs and other funky behavior
|
// leaving them open through ES_LAUNCH may cause hangs and other funky behavior
|
||||||
// (supposedly when trying to re-open those files).
|
// (supposedly when trying to re-open those files).
|
||||||
|
@ -1173,9 +1176,6 @@ IPCCommandResult ES::Launch(const IOCtlVRequest& request)
|
||||||
SetDefaultContentFile(tContentFile);
|
SetDefaultContentFile(tContentFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
ERROR_LOG(IOS_ES, "IOCTL_ES_LAUNCH %016" PRIx64 " %08x %016" PRIx64 " %08x %016" PRIx64 " %04x",
|
|
||||||
TitleID, view, ticketid, devicetype, titleid, access);
|
|
||||||
|
|
||||||
// Generate a "reply" to the IPC command. ES_LAUNCH is unique because it
|
// Generate a "reply" to the IPC command. ES_LAUNCH is unique because it
|
||||||
// involves restarting IOS; IOS generates two acknowledgements in a row.
|
// involves restarting IOS; IOS generates two acknowledgements in a row.
|
||||||
// Note: If we just reset the PPC, don't write anything to the command buffer. This
|
// Note: If we just reset the PPC, don't write anything to the command buffer. This
|
||||||
|
|
|
@ -42,6 +42,7 @@
|
||||||
#include "Core/IOS/FS/FS.h"
|
#include "Core/IOS/FS/FS.h"
|
||||||
#include "Core/IOS/FS/FileIO.h"
|
#include "Core/IOS/FS/FileIO.h"
|
||||||
#include "Core/IOS/IPC.h"
|
#include "Core/IOS/IPC.h"
|
||||||
|
#include "Core/IOS/MIOS.h"
|
||||||
#include "Core/IOS/Network/Net.h"
|
#include "Core/IOS/Network/Net.h"
|
||||||
#include "Core/IOS/Network/SSL.h"
|
#include "Core/IOS/Network/SSL.h"
|
||||||
#include "Core/IOS/Network/Socket.h"
|
#include "Core/IOS/Network/Socket.h"
|
||||||
|
@ -111,6 +112,7 @@ struct IosMemoryValues
|
||||||
u32 ram_vendor;
|
u32 ram_vendor;
|
||||||
u32 unknown_begin;
|
u32 unknown_begin;
|
||||||
u32 unknown_end;
|
u32 unknown_end;
|
||||||
|
u32 sysmenu_sync;
|
||||||
};
|
};
|
||||||
|
|
||||||
constexpr u32 ADDR_MEM1_SIZE = 0x3100;
|
constexpr u32 ADDR_MEM1_SIZE = 0x3100;
|
||||||
|
@ -162,210 +164,210 @@ constexpr std::array<IosMemoryValues, 31> ios_memory_values = {
|
||||||
MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END,
|
MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END,
|
||||||
MEM2_SIZE, MEM2_SIZE, 0x93400000, MEM2_ARENA_BEGIN,
|
MEM2_SIZE, MEM2_SIZE, 0x93400000, MEM2_ARENA_BEGIN,
|
||||||
0x933E0000, 0x933E0000, 0x93400000, HOLLYWOOD_REVISION,
|
0x933E0000, 0x933E0000, 0x93400000, HOLLYWOOD_REVISION,
|
||||||
RAM_VENDOR, PLACEHOLDER, PLACEHOLDER,
|
RAM_VENDOR, PLACEHOLDER, PLACEHOLDER, 0,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
12, 0xc020e, 0x030110, MEM1_SIZE,
|
12, 0xc020e, 0x030110, MEM1_SIZE,
|
||||||
MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END,
|
MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END,
|
||||||
MEM2_SIZE, MEM2_SIZE, 0x93400000, MEM2_ARENA_BEGIN,
|
MEM2_SIZE, MEM2_SIZE, 0x93400000, MEM2_ARENA_BEGIN,
|
||||||
0x933E0000, 0x933E0000, 0x93400000, HOLLYWOOD_REVISION,
|
0x933E0000, 0x933E0000, 0x93400000, HOLLYWOOD_REVISION,
|
||||||
RAM_VENDOR, PLACEHOLDER, PLACEHOLDER,
|
RAM_VENDOR, PLACEHOLDER, PLACEHOLDER, 0,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
13, 0xd0408, 0x030110, MEM1_SIZE,
|
13, 0xd0408, 0x030110, MEM1_SIZE,
|
||||||
MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END,
|
MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END,
|
||||||
MEM2_SIZE, MEM2_SIZE, 0x93400000, MEM2_ARENA_BEGIN,
|
MEM2_SIZE, MEM2_SIZE, 0x93400000, MEM2_ARENA_BEGIN,
|
||||||
0x933E0000, 0x933E0000, 0x93400000, HOLLYWOOD_REVISION,
|
0x933E0000, 0x933E0000, 0x93400000, HOLLYWOOD_REVISION,
|
||||||
RAM_VENDOR, PLACEHOLDER, PLACEHOLDER,
|
RAM_VENDOR, PLACEHOLDER, PLACEHOLDER, 0,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
14, 0xe0408, 0x030110, MEM1_SIZE,
|
14, 0xe0408, 0x030110, MEM1_SIZE,
|
||||||
MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END,
|
MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END,
|
||||||
MEM2_SIZE, MEM2_SIZE, 0x93400000, MEM2_ARENA_BEGIN,
|
MEM2_SIZE, MEM2_SIZE, 0x93400000, MEM2_ARENA_BEGIN,
|
||||||
0x933E0000, 0x933E0000, 0x93400000, HOLLYWOOD_REVISION,
|
0x933E0000, 0x933E0000, 0x93400000, HOLLYWOOD_REVISION,
|
||||||
RAM_VENDOR, PLACEHOLDER, PLACEHOLDER,
|
RAM_VENDOR, PLACEHOLDER, PLACEHOLDER, 0,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
15, 0xf0408, 0x030110, MEM1_SIZE,
|
15, 0xf0408, 0x030110, MEM1_SIZE,
|
||||||
MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END,
|
MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END,
|
||||||
MEM2_SIZE, MEM2_SIZE, 0x93400000, MEM2_ARENA_BEGIN,
|
MEM2_SIZE, MEM2_SIZE, 0x93400000, MEM2_ARENA_BEGIN,
|
||||||
0x933E0000, 0x933E0000, 0x93400000, HOLLYWOOD_REVISION,
|
0x933E0000, 0x933E0000, 0x93400000, HOLLYWOOD_REVISION,
|
||||||
RAM_VENDOR, PLACEHOLDER, PLACEHOLDER,
|
RAM_VENDOR, PLACEHOLDER, PLACEHOLDER, 0,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
17, 0x110408, 0x030110, MEM1_SIZE,
|
17, 0x110408, 0x030110, MEM1_SIZE,
|
||||||
MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END,
|
MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END,
|
||||||
MEM2_SIZE, MEM2_SIZE, 0x93400000, MEM2_ARENA_BEGIN,
|
MEM2_SIZE, MEM2_SIZE, 0x93400000, MEM2_ARENA_BEGIN,
|
||||||
0x933E0000, 0x933E0000, 0x93400000, HOLLYWOOD_REVISION,
|
0x933E0000, 0x933E0000, 0x93400000, HOLLYWOOD_REVISION,
|
||||||
RAM_VENDOR, PLACEHOLDER, PLACEHOLDER,
|
RAM_VENDOR, PLACEHOLDER, PLACEHOLDER, 0,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
21, 0x15040f, 0x030110, MEM1_SIZE,
|
21, 0x15040f, 0x030110, MEM1_SIZE,
|
||||||
MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END,
|
MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END,
|
||||||
MEM2_SIZE, MEM2_SIZE, 0x93400000, MEM2_ARENA_BEGIN,
|
MEM2_SIZE, MEM2_SIZE, 0x93400000, MEM2_ARENA_BEGIN,
|
||||||
0x933E0000, 0x933E0000, 0x93400000, HOLLYWOOD_REVISION,
|
0x933E0000, 0x933E0000, 0x93400000, HOLLYWOOD_REVISION,
|
||||||
RAM_VENDOR, PLACEHOLDER, PLACEHOLDER,
|
RAM_VENDOR, PLACEHOLDER, PLACEHOLDER, 0,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
22, 0x16050e, 0x030110, MEM1_SIZE,
|
22, 0x16050e, 0x030110, MEM1_SIZE,
|
||||||
MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END,
|
MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END,
|
||||||
MEM2_SIZE, MEM2_SIZE, 0x93400000, MEM2_ARENA_BEGIN,
|
MEM2_SIZE, MEM2_SIZE, 0x93400000, MEM2_ARENA_BEGIN,
|
||||||
0x933E0000, 0x933E0000, 0x93400000, HOLLYWOOD_REVISION,
|
0x933E0000, 0x933E0000, 0x93400000, HOLLYWOOD_REVISION,
|
||||||
RAM_VENDOR, PLACEHOLDER, PLACEHOLDER,
|
RAM_VENDOR, PLACEHOLDER, PLACEHOLDER, 0,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
28, 0x1c070f, 0x030110, MEM1_SIZE,
|
28, 0x1c070f, 0x030110, MEM1_SIZE,
|
||||||
MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END,
|
MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END,
|
||||||
MEM2_SIZE, MEM2_SIZE, 0x93800000, MEM2_ARENA_BEGIN,
|
MEM2_SIZE, MEM2_SIZE, 0x93800000, MEM2_ARENA_BEGIN,
|
||||||
0x937E0000, 0x937E0000, 0x93800000, HOLLYWOOD_REVISION,
|
0x937E0000, 0x937E0000, 0x93800000, HOLLYWOOD_REVISION,
|
||||||
RAM_VENDOR, 0x93800000, 0x93820000,
|
RAM_VENDOR, 0x93800000, 0x93820000, 0,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
31, 0x1f0e18, 0x030110, MEM1_SIZE,
|
31, 0x1f0e18, 0x030110, MEM1_SIZE,
|
||||||
MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END,
|
MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END,
|
||||||
MEM2_SIZE, MEM2_SIZE, 0x93600000, MEM2_ARENA_BEGIN,
|
MEM2_SIZE, MEM2_SIZE, 0x93600000, MEM2_ARENA_BEGIN,
|
||||||
0x935E0000, 0x935E0000, 0x93600000, HOLLYWOOD_REVISION,
|
0x935E0000, 0x935E0000, 0x93600000, HOLLYWOOD_REVISION,
|
||||||
RAM_VENDOR, 0x93600000, 0x93620000,
|
RAM_VENDOR, 0x93600000, 0x93620000, 0,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
33, 0x210e18, 0x030110, MEM1_SIZE,
|
33, 0x210e18, 0x030110, MEM1_SIZE,
|
||||||
MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END,
|
MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END,
|
||||||
MEM2_SIZE, MEM2_SIZE, 0x93600000, MEM2_ARENA_BEGIN,
|
MEM2_SIZE, MEM2_SIZE, 0x93600000, MEM2_ARENA_BEGIN,
|
||||||
0x935E0000, 0x935E0000, 0x93600000, HOLLYWOOD_REVISION,
|
0x935E0000, 0x935E0000, 0x93600000, HOLLYWOOD_REVISION,
|
||||||
RAM_VENDOR, 0x93600000, 0x93620000,
|
RAM_VENDOR, 0x93600000, 0x93620000, 0,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
34, 0x220e18, 0x030110, MEM1_SIZE,
|
34, 0x220e18, 0x030110, MEM1_SIZE,
|
||||||
MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END,
|
MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END,
|
||||||
MEM2_SIZE, MEM2_SIZE, 0x93600000, MEM2_ARENA_BEGIN,
|
MEM2_SIZE, MEM2_SIZE, 0x93600000, MEM2_ARENA_BEGIN,
|
||||||
0x935E0000, 0x935E0000, 0x93600000, HOLLYWOOD_REVISION,
|
0x935E0000, 0x935E0000, 0x93600000, HOLLYWOOD_REVISION,
|
||||||
RAM_VENDOR, 0x93600000, 0x93620000,
|
RAM_VENDOR, 0x93600000, 0x93620000, 0,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
35, 0x230e18, 0x030110, MEM1_SIZE,
|
35, 0x230e18, 0x030110, MEM1_SIZE,
|
||||||
MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END,
|
MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END,
|
||||||
MEM2_SIZE, MEM2_SIZE, 0x93600000, MEM2_ARENA_BEGIN,
|
MEM2_SIZE, MEM2_SIZE, 0x93600000, MEM2_ARENA_BEGIN,
|
||||||
0x935E0000, 0x935E0000, 0x93600000, HOLLYWOOD_REVISION,
|
0x935E0000, 0x935E0000, 0x93600000, HOLLYWOOD_REVISION,
|
||||||
RAM_VENDOR, 0x93600000, 0x93620000,
|
RAM_VENDOR, 0x93600000, 0x93620000, 0,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
36, 0x240e18, 0x030110, MEM1_SIZE,
|
36, 0x240e18, 0x030110, MEM1_SIZE,
|
||||||
MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END,
|
MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END,
|
||||||
MEM2_SIZE, MEM2_SIZE, 0x93600000, MEM2_ARENA_BEGIN,
|
MEM2_SIZE, MEM2_SIZE, 0x93600000, MEM2_ARENA_BEGIN,
|
||||||
0x935E0000, 0x935E0000, 0x93600000, HOLLYWOOD_REVISION,
|
0x935E0000, 0x935E0000, 0x93600000, HOLLYWOOD_REVISION,
|
||||||
RAM_VENDOR, 0x93600000, 0x93620000,
|
RAM_VENDOR, 0x93600000, 0x93620000, 0,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
37, 0x25161f, 0x030110, MEM1_SIZE,
|
37, 0x25161f, 0x030110, MEM1_SIZE,
|
||||||
MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END,
|
MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END,
|
||||||
MEM2_SIZE, MEM2_SIZE, 0x93600000, MEM2_ARENA_BEGIN,
|
MEM2_SIZE, MEM2_SIZE, 0x93600000, MEM2_ARENA_BEGIN,
|
||||||
0x935E0000, 0x935E0000, 0x93600000, HOLLYWOOD_REVISION,
|
0x935E0000, 0x935E0000, 0x93600000, HOLLYWOOD_REVISION,
|
||||||
RAM_VENDOR, 0x93600000, 0x93620000,
|
RAM_VENDOR, 0x93600000, 0x93620000, 0,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
38, 0x26101c, 0x030110, MEM1_SIZE,
|
38, 0x26101c, 0x030110, MEM1_SIZE,
|
||||||
MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END,
|
MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END,
|
||||||
MEM2_SIZE, MEM2_SIZE, 0x93600000, MEM2_ARENA_BEGIN,
|
MEM2_SIZE, MEM2_SIZE, 0x93600000, MEM2_ARENA_BEGIN,
|
||||||
0x935E0000, 0x935E0000, 0x93600000, HOLLYWOOD_REVISION,
|
0x935E0000, 0x935E0000, 0x93600000, HOLLYWOOD_REVISION,
|
||||||
RAM_VENDOR, 0x93600000, 0x93620000,
|
RAM_VENDOR, 0x93600000, 0x93620000, 0,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
41, 0x290e17, 0x030110, MEM1_SIZE,
|
41, 0x290e17, 0x030110, MEM1_SIZE,
|
||||||
MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END,
|
MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END,
|
||||||
MEM2_SIZE, MEM2_SIZE, 0x93600000, MEM2_ARENA_BEGIN,
|
MEM2_SIZE, MEM2_SIZE, 0x93600000, MEM2_ARENA_BEGIN,
|
||||||
0x935E0000, 0x935E0000, 0x93600000, HOLLYWOOD_REVISION,
|
0x935E0000, 0x935E0000, 0x93600000, HOLLYWOOD_REVISION,
|
||||||
RAM_VENDOR, 0x93600000, 0x93620000,
|
RAM_VENDOR, 0x93600000, 0x93620000, 0,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
43, 0x2b0e17, 0x030110, MEM1_SIZE,
|
43, 0x2b0e17, 0x030110, MEM1_SIZE,
|
||||||
MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END,
|
MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END,
|
||||||
MEM2_SIZE, MEM2_SIZE, 0x93600000, MEM2_ARENA_BEGIN,
|
MEM2_SIZE, MEM2_SIZE, 0x93600000, MEM2_ARENA_BEGIN,
|
||||||
0x935E0000, 0x935E0000, 0x93600000, HOLLYWOOD_REVISION,
|
0x935E0000, 0x935E0000, 0x93600000, HOLLYWOOD_REVISION,
|
||||||
RAM_VENDOR, 0x93600000, 0x93620000,
|
RAM_VENDOR, 0x93600000, 0x93620000, 0,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
45, 0x2d0e17, 0x030110, MEM1_SIZE,
|
45, 0x2d0e17, 0x030110, MEM1_SIZE,
|
||||||
MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END,
|
MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END,
|
||||||
MEM2_SIZE, MEM2_SIZE, 0x93600000, MEM2_ARENA_BEGIN,
|
MEM2_SIZE, MEM2_SIZE, 0x93600000, MEM2_ARENA_BEGIN,
|
||||||
0x935E0000, 0x935E0000, 0x93600000, HOLLYWOOD_REVISION,
|
0x935E0000, 0x935E0000, 0x93600000, HOLLYWOOD_REVISION,
|
||||||
RAM_VENDOR, 0x93600000, 0x93620000,
|
RAM_VENDOR, 0x93600000, 0x93620000, 0,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
46, 0x2e0e17, 0x030110, MEM1_SIZE,
|
46, 0x2e0e17, 0x030110, MEM1_SIZE,
|
||||||
MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END,
|
MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END,
|
||||||
MEM2_SIZE, MEM2_SIZE, 0x93600000, MEM2_ARENA_BEGIN,
|
MEM2_SIZE, MEM2_SIZE, 0x93600000, MEM2_ARENA_BEGIN,
|
||||||
0x935E0000, 0x935E0000, 0x93600000, HOLLYWOOD_REVISION,
|
0x935E0000, 0x935E0000, 0x93600000, HOLLYWOOD_REVISION,
|
||||||
RAM_VENDOR, 0x93600000, 0x93620000,
|
RAM_VENDOR, 0x93600000, 0x93620000, 0,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
48, 0x30101c, 0x030110, MEM1_SIZE,
|
48, 0x30101c, 0x030110, MEM1_SIZE,
|
||||||
MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END,
|
MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END,
|
||||||
MEM2_SIZE, MEM2_SIZE, 0x93600000, MEM2_ARENA_BEGIN,
|
MEM2_SIZE, MEM2_SIZE, 0x93600000, MEM2_ARENA_BEGIN,
|
||||||
0x935E0000, 0x935E0000, 0x93600000, HOLLYWOOD_REVISION,
|
0x935E0000, 0x935E0000, 0x93600000, HOLLYWOOD_REVISION,
|
||||||
RAM_VENDOR, 0x93600000, 0x93620000,
|
RAM_VENDOR, 0x93600000, 0x93620000, 0,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
53, 0x35161f, 0x030110, MEM1_SIZE,
|
53, 0x35161f, 0x030110, MEM1_SIZE,
|
||||||
MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END,
|
MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END,
|
||||||
MEM2_SIZE, MEM2_SIZE, 0x93600000, MEM2_ARENA_BEGIN,
|
MEM2_SIZE, MEM2_SIZE, 0x93600000, MEM2_ARENA_BEGIN,
|
||||||
0x935E0000, 0x935E0000, 0x93600000, HOLLYWOOD_REVISION,
|
0x935E0000, 0x935E0000, 0x93600000, HOLLYWOOD_REVISION,
|
||||||
RAM_VENDOR, 0x93600000, 0x93620000,
|
RAM_VENDOR, 0x93600000, 0x93620000, 0,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
55, 0x37161f, 0x030110, MEM1_SIZE,
|
55, 0x37161f, 0x030110, MEM1_SIZE,
|
||||||
MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END,
|
MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END,
|
||||||
MEM2_SIZE, MEM2_SIZE, 0x93600000, MEM2_ARENA_BEGIN,
|
MEM2_SIZE, MEM2_SIZE, 0x93600000, MEM2_ARENA_BEGIN,
|
||||||
0x935E0000, 0x935E0000, 0x93600000, HOLLYWOOD_REVISION,
|
0x935E0000, 0x935E0000, 0x93600000, HOLLYWOOD_REVISION,
|
||||||
RAM_VENDOR, 0x93600000, 0x93620000,
|
RAM_VENDOR, 0x93600000, 0x93620000, 0,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
56, 0x38161e, 0x030110, MEM1_SIZE,
|
56, 0x38161e, 0x030110, MEM1_SIZE,
|
||||||
MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END,
|
MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END,
|
||||||
MEM2_SIZE, MEM2_SIZE, 0x93600000, MEM2_ARENA_BEGIN,
|
MEM2_SIZE, MEM2_SIZE, 0x93600000, MEM2_ARENA_BEGIN,
|
||||||
0x935E0000, 0x935E0000, 0x93600000, HOLLYWOOD_REVISION,
|
0x935E0000, 0x935E0000, 0x93600000, HOLLYWOOD_REVISION,
|
||||||
RAM_VENDOR, 0x93600000, 0x93620000,
|
RAM_VENDOR, 0x93600000, 0x93620000, 0,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
57, 0x39171f, 0x030110, MEM1_SIZE,
|
57, 0x39171f, 0x030110, MEM1_SIZE,
|
||||||
MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END,
|
MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END,
|
||||||
MEM2_SIZE, MEM2_SIZE, 0x93600000, MEM2_ARENA_BEGIN,
|
MEM2_SIZE, MEM2_SIZE, 0x93600000, MEM2_ARENA_BEGIN,
|
||||||
0x935E0000, 0x935E0000, 0x93600000, HOLLYWOOD_REVISION,
|
0x935E0000, 0x935E0000, 0x93600000, HOLLYWOOD_REVISION,
|
||||||
RAM_VENDOR, 0x93600000, 0x93620000,
|
RAM_VENDOR, 0x93600000, 0x93620000, 0,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
58, 0x3a1820, 0x030110, MEM1_SIZE,
|
58, 0x3a1820, 0x030110, MEM1_SIZE,
|
||||||
MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END,
|
MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END,
|
||||||
MEM2_SIZE, MEM2_SIZE, 0x93600000, MEM2_ARENA_BEGIN,
|
MEM2_SIZE, MEM2_SIZE, 0x93600000, MEM2_ARENA_BEGIN,
|
||||||
0x935E0000, 0x935E0000, 0x93600000, HOLLYWOOD_REVISION,
|
0x935E0000, 0x935E0000, 0x93600000, HOLLYWOOD_REVISION,
|
||||||
RAM_VENDOR, 0x93600000, 0x93620000,
|
RAM_VENDOR, 0x93600000, 0x93620000, 0,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
59, 0x3b1c21, 0x101811, MEM1_SIZE,
|
59, 0x3b1c21, 0x101811, MEM1_SIZE,
|
||||||
MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END,
|
MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END,
|
||||||
MEM2_SIZE, MEM2_SIZE, 0x93600000, MEM2_ARENA_BEGIN,
|
MEM2_SIZE, MEM2_SIZE, 0x93600000, MEM2_ARENA_BEGIN,
|
||||||
0x935E0000, 0x935E0000, 0x93600000, HOLLYWOOD_REVISION,
|
0x935E0000, 0x935E0000, 0x93600000, HOLLYWOOD_REVISION,
|
||||||
RAM_VENDOR, 0x93600000, 0x93620000,
|
RAM_VENDOR, 0x93600000, 0x93620000, 0,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
61, 0x3d161e, 0x030110, MEM1_SIZE,
|
61, 0x3d161e, 0x030110, MEM1_SIZE,
|
||||||
MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END,
|
MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END,
|
||||||
MEM2_SIZE, MEM2_SIZE, 0x93600000, MEM2_ARENA_BEGIN,
|
MEM2_SIZE, MEM2_SIZE, 0x93600000, MEM2_ARENA_BEGIN,
|
||||||
0x935E0000, 0x935E0000, 0x93600000, HOLLYWOOD_REVISION,
|
0x935E0000, 0x935E0000, 0x93600000, HOLLYWOOD_REVISION,
|
||||||
RAM_VENDOR, 0x93600000, 0x93620000,
|
RAM_VENDOR, 0x93600000, 0x93620000, 0,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
62, 0x3e191e, 0x022712, MEM1_SIZE,
|
62, 0x3e191e, 0x022712, MEM1_SIZE,
|
||||||
MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END,
|
MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END,
|
||||||
MEM2_SIZE, MEM2_SIZE, 0x93600000, MEM2_ARENA_BEGIN,
|
MEM2_SIZE, MEM2_SIZE, 0x93600000, MEM2_ARENA_BEGIN,
|
||||||
0x935E0000, 0x935E0000, 0x93600000, HOLLYWOOD_REVISION,
|
0x935E0000, 0x935E0000, 0x93600000, HOLLYWOOD_REVISION,
|
||||||
RAM_VENDOR, 0x93600000, 0x93620000,
|
RAM_VENDOR, 0x93600000, 0x93620000, 0,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
80, 0x501b20, 0x030310, MEM1_SIZE,
|
80, 0x501b20, 0x030310, MEM1_SIZE,
|
||||||
MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END,
|
MEM1_SIZE, MEM1_END, MEM1_ARENA_BEGIN, MEM1_ARENA_END,
|
||||||
MEM2_SIZE, MEM2_SIZE, 0x93600000, MEM2_ARENA_BEGIN,
|
MEM2_SIZE, MEM2_SIZE, 0x93600000, MEM2_ARENA_BEGIN,
|
||||||
0x935E0000, 0x935E0000, 0x93600000, HOLLYWOOD_REVISION,
|
0x935E0000, 0x935E0000, 0x93600000, HOLLYWOOD_REVISION,
|
||||||
RAM_VENDOR, 0x93600000, 0x93620000,
|
RAM_VENDOR, 0x93600000, 0x93620000, 0,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
257,
|
257,
|
||||||
|
@ -387,6 +389,7 @@ constexpr std::array<IosMemoryValues, 31> ios_memory_values = {
|
||||||
RAM_VENDOR_MIOS,
|
RAM_VENDOR_MIOS,
|
||||||
PLACEHOLDER,
|
PLACEHOLDER,
|
||||||
PLACEHOLDER,
|
PLACEHOLDER,
|
||||||
|
PLACEHOLDER,
|
||||||
}}};
|
}}};
|
||||||
|
|
||||||
static void EnqueueEvent(u64 userdata, s64 cycles_late = 0)
|
static void EnqueueEvent(u64 userdata, s64 cycles_late = 0)
|
||||||
|
@ -459,7 +462,7 @@ static bool SetupMemory(u64 ios_title_id)
|
||||||
Memory::Write_U8(0xDE, ADDR_BOOT_FLAG);
|
Memory::Write_U8(0xDE, ADDR_BOOT_FLAG);
|
||||||
Memory::Write_U8(0xAD, ADDR_APPLOADER_FLAG);
|
Memory::Write_U8(0xAD, ADDR_APPLOADER_FLAG);
|
||||||
Memory::Write_U16(0xBEEF, ADDR_DEVKIT_BOOT_PROGRAM_VERSION);
|
Memory::Write_U16(0xBEEF, ADDR_DEVKIT_BOOT_PROGRAM_VERSION);
|
||||||
Memory::Write_U32(0x00000000, ADDR_SYSMENU_SYNC);
|
Memory::Write_U32(target_imv->sysmenu_sync, ADDR_SYSMENU_SYNC);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -517,7 +520,6 @@ static void AddStaticDevices()
|
||||||
|
|
||||||
void Init()
|
void Init()
|
||||||
{
|
{
|
||||||
AddStaticDevices();
|
|
||||||
s_event_enqueue = CoreTiming::RegisterEvent("IPCEvent", EnqueueEvent);
|
s_event_enqueue = CoreTiming::RegisterEvent("IPCEvent", EnqueueEvent);
|
||||||
s_event_sdio_notify = CoreTiming::RegisterEvent("SDIO_EventNotify", SDIO_EventNotify_CPUThread);
|
s_event_sdio_notify = CoreTiming::RegisterEvent("SDIO_EventNotify", SDIO_EventNotify_CPUThread);
|
||||||
}
|
}
|
||||||
|
@ -552,14 +554,31 @@ void Shutdown()
|
||||||
Reset(true);
|
Reset(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
constexpr u64 BC_TITLE_ID = 0x0000000100000100;
|
||||||
|
constexpr u64 MIOS_TITLE_ID = 0x0000000100000101;
|
||||||
|
|
||||||
bool Reload(const u64 ios_title_id)
|
bool Reload(const u64 ios_title_id)
|
||||||
{
|
{
|
||||||
|
// A real Wii goes through several steps before getting to MIOS.
|
||||||
|
//
|
||||||
|
// * The System Menu detects a GameCube disc and launches BC (1-100) instead of the game.
|
||||||
|
// * BC (similar to boot1) lowers the clock speed to the Flipper's and then launches boot2.
|
||||||
|
// * boot2 sees the lowered clock speed and launches MIOS (1-101) instead of the System Menu.
|
||||||
|
//
|
||||||
|
// Because we currently don't have boot1 and boot2, and BC is only ever used to launch MIOS
|
||||||
|
// (indirectly via boot2), we can just launch MIOS when BC is launched.
|
||||||
|
if (ios_title_id == BC_TITLE_ID)
|
||||||
|
return Reload(MIOS_TITLE_ID);
|
||||||
|
|
||||||
if (!SetupMemory(ios_title_id))
|
if (!SetupMemory(ios_title_id))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
s_active_title_id = ios_title_id;
|
s_active_title_id = ios_title_id;
|
||||||
Reset(true);
|
Reset(true);
|
||||||
|
|
||||||
|
if (ios_title_id == MIOS_TITLE_ID)
|
||||||
|
return MIOS::Load();
|
||||||
|
|
||||||
AddStaticDevices();
|
AddStaticDevices();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -629,6 +648,9 @@ void DoState(PointerWrap& p)
|
||||||
p.Do(s_last_reply_time);
|
p.Do(s_last_reply_time);
|
||||||
p.Do(s_active_title_id);
|
p.Do(s_active_title_id);
|
||||||
|
|
||||||
|
if (s_active_title_id == MIOS_TITLE_ID)
|
||||||
|
return;
|
||||||
|
|
||||||
// We need to make sure all file handles are closed so IOS::HLE::Device::FS::DoState can
|
// We need to make sure all file handles are closed so IOS::HLE::Device::FS::DoState can
|
||||||
// successfully save or re-create /tmp
|
// successfully save or re-create /tmp
|
||||||
for (auto& descriptor : s_fdmap)
|
for (auto& descriptor : s_fdmap)
|
||||||
|
|
|
@ -0,0 +1,195 @@
|
||||||
|
// Copyright 2017 Dolphin Emulator Project
|
||||||
|
// Licensed under GPLv2+
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#include <cstring>
|
||||||
|
#include <utility>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "Common/CommonFuncs.h"
|
||||||
|
#include "Common/CommonTypes.h"
|
||||||
|
#include "Common/FileUtil.h"
|
||||||
|
#include "Common/Logging/Log.h"
|
||||||
|
#include "Common/MsgHandler.h"
|
||||||
|
#include "Common/NandPaths.h"
|
||||||
|
#include "Core/Boot/Boot.h"
|
||||||
|
#include "Core/Boot/ElfReader.h"
|
||||||
|
#include "Core/ConfigManager.h"
|
||||||
|
#include "Core/Core.h"
|
||||||
|
#include "Core/DSPEmulator.h"
|
||||||
|
#include "Core/HLE/HLE.h"
|
||||||
|
#include "Core/HW/DSP.h"
|
||||||
|
#include "Core/HW/DVDInterface.h"
|
||||||
|
#include "Core/HW/DVDThread.h"
|
||||||
|
#include "Core/HW/Memmap.h"
|
||||||
|
#include "Core/HW/SystemTimers.h"
|
||||||
|
#include "Core/IOS/MIOS.h"
|
||||||
|
#include "Core/PowerPC/PPCSymbolDB.h"
|
||||||
|
#include "Core/PowerPC/PowerPC.h"
|
||||||
|
#include "DiscIO/NANDContentLoader.h"
|
||||||
|
#include "DiscIO/Volume.h"
|
||||||
|
|
||||||
|
namespace IOS
|
||||||
|
{
|
||||||
|
namespace HLE
|
||||||
|
{
|
||||||
|
namespace MIOS
|
||||||
|
{
|
||||||
|
constexpr u64 MIOS_TITLE_ID = 0x0000000100000101;
|
||||||
|
|
||||||
|
// Source: https://wiibrew.org/wiki/ARM_Binaries
|
||||||
|
struct ARMBinary final
|
||||||
|
{
|
||||||
|
explicit ARMBinary(const std::vector<u8>& bytes);
|
||||||
|
explicit ARMBinary(std::vector<u8>&& bytes);
|
||||||
|
|
||||||
|
bool IsValid() const;
|
||||||
|
std::vector<u8> GetElf() const;
|
||||||
|
u32 GetHeaderSize() const;
|
||||||
|
u32 GetElfOffset() const;
|
||||||
|
u32 GetElfSize() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<u8> m_bytes;
|
||||||
|
};
|
||||||
|
|
||||||
|
ARMBinary::ARMBinary(const std::vector<u8>& bytes) : m_bytes(bytes)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ARMBinary::ARMBinary(std::vector<u8>&& bytes) : m_bytes(std::move(bytes))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ARMBinary::IsValid() const
|
||||||
|
{
|
||||||
|
// The header is at least 0x10.
|
||||||
|
if (m_bytes.size() < 0x10)
|
||||||
|
return false;
|
||||||
|
return m_bytes.size() >= (GetHeaderSize() + GetElfOffset() + GetElfSize());
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<u8> ARMBinary::GetElf() const
|
||||||
|
{
|
||||||
|
const auto iterator = m_bytes.cbegin() + GetHeaderSize() + GetElfOffset();
|
||||||
|
return std::vector<u8>(iterator, iterator + GetElfSize());
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 ARMBinary::GetHeaderSize() const
|
||||||
|
{
|
||||||
|
return Common::swap32(m_bytes.data());
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 ARMBinary::GetElfOffset() const
|
||||||
|
{
|
||||||
|
return Common::swap32(m_bytes.data() + 0x4);
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 ARMBinary::GetElfSize() const
|
||||||
|
{
|
||||||
|
return Common::swap32(m_bytes.data() + 0x8);
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::vector<u8> GetMIOSBinary()
|
||||||
|
{
|
||||||
|
const auto& loader =
|
||||||
|
DiscIO::CNANDContentManager::Access().GetNANDLoader(MIOS_TITLE_ID, Common::FROM_SESSION_ROOT);
|
||||||
|
if (!loader.IsValid())
|
||||||
|
return {};
|
||||||
|
|
||||||
|
const auto* content = loader.GetContentByIndex(loader.GetBootIndex());
|
||||||
|
if (!content)
|
||||||
|
return {};
|
||||||
|
|
||||||
|
return content->m_Data->Get();
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
// MIOS appears to only reset the DI and the PPC.
|
||||||
|
DVDInterface::Reset();
|
||||||
|
PowerPC::Reset();
|
||||||
|
// Note: this is specific to Dolphin and is required because we initialised it in Wii mode.
|
||||||
|
DSP::Reinit(SConfig::GetInstance().bDSPHLE);
|
||||||
|
DSP::GetDSPEmulator()->Initialize(SConfig::GetInstance().bWii, SConfig::GetInstance().bDSPThread);
|
||||||
|
|
||||||
|
SystemTimers::ChangePPCClock(SystemTimers::Mode::GC);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void UpdateRunningGame()
|
||||||
|
{
|
||||||
|
DVDThread::WaitUntilIdle();
|
||||||
|
const DiscIO::IVolume& volume = DVDInterface::GetVolume();
|
||||||
|
SConfig::GetInstance().m_BootType = SConfig::BOOT_MIOS;
|
||||||
|
SConfig::GetInstance().m_strName = volume.GetInternalName();
|
||||||
|
SConfig::GetInstance().m_strGameID = volume.GetGameID();
|
||||||
|
SConfig::GetInstance().m_revision = volume.GetRevision();
|
||||||
|
|
||||||
|
g_symbolDB.Clear();
|
||||||
|
CBoot::LoadMapFromFilename();
|
||||||
|
::HLE::Clear();
|
||||||
|
::HLE::PatchFunctions();
|
||||||
|
|
||||||
|
NOTICE_LOG(IOS, "Running game: %s (%s)", SConfig::GetInstance().m_strName.c_str(),
|
||||||
|
SConfig::GetInstance().m_strGameID.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr u32 ADDRESS_INIT_SEMAPHORE = 0x30f8;
|
||||||
|
|
||||||
|
bool Load()
|
||||||
|
{
|
||||||
|
Memory::Write_U32(0x00000000, ADDRESS_INIT_SEMAPHORE);
|
||||||
|
Memory::Write_U32(0x09142001, 0x3180);
|
||||||
|
|
||||||
|
ARMBinary mios{GetMIOSBinary()};
|
||||||
|
if (!mios.IsValid())
|
||||||
|
{
|
||||||
|
PanicAlertT("Failed to load MIOS. It is required for launching GameCube titles from Wii mode.");
|
||||||
|
Core::QueueHostJob(Core::Stop);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<u8> elf_bytes = mios.GetElf();
|
||||||
|
ElfReader elf{elf_bytes.data()};
|
||||||
|
if (!elf.LoadIntoMemory(true))
|
||||||
|
{
|
||||||
|
PanicAlertT("Failed to load MIOS ELF into memory.");
|
||||||
|
Core::QueueHostJob(Core::Stop);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ReinitHardware();
|
||||||
|
NOTICE_LOG(IOS, "Reinitialised hardware.");
|
||||||
|
|
||||||
|
// Load symbols for the IPL if they exist.
|
||||||
|
g_symbolDB.Clear();
|
||||||
|
if (g_symbolDB.LoadMap(File::GetUserPath(D_MAPS_IDX) + "mios-ipl.map"))
|
||||||
|
{
|
||||||
|
::HLE::Clear();
|
||||||
|
::HLE::PatchFunctions();
|
||||||
|
}
|
||||||
|
|
||||||
|
const PowerPC::CoreMode core_mode = PowerPC::GetMode();
|
||||||
|
PowerPC::SetMode(PowerPC::CoreMode::Interpreter);
|
||||||
|
MSR = 0;
|
||||||
|
PC = 0x3400;
|
||||||
|
NOTICE_LOG(IOS, "Loaded MIOS and bootstrapped PPC.");
|
||||||
|
|
||||||
|
// IOS writes 0 to 0x30f8 before bootstrapping the PPC. Once started, the IPL eventually writes
|
||||||
|
// 0xdeadbeef there, then waits for it to be cleared by IOS before continuing.
|
||||||
|
while (Memory::Read_U32(ADDRESS_INIT_SEMAPHORE) != 0xdeadbeef)
|
||||||
|
PowerPC::SingleStep();
|
||||||
|
PowerPC::SetMode(core_mode);
|
||||||
|
|
||||||
|
Memory::Write_U32(0x00000000, ADDRESS_INIT_SEMAPHORE);
|
||||||
|
NOTICE_LOG(IOS, "IPL ready.");
|
||||||
|
UpdateRunningGame();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} // namespace MIOS
|
||||||
|
} // namespace HLE
|
||||||
|
} // namespace IOS
|
|
@ -0,0 +1,16 @@
|
||||||
|
// Copyright 2017 Dolphin Emulator Project
|
||||||
|
// Licensed under GPLv2+
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace IOS
|
||||||
|
{
|
||||||
|
namespace HLE
|
||||||
|
{
|
||||||
|
namespace MIOS
|
||||||
|
{
|
||||||
|
bool Load();
|
||||||
|
} // namespace MIOS
|
||||||
|
} // namespace HLE
|
||||||
|
} // namespace IOS
|
|
@ -189,11 +189,7 @@ void Init(int cpu_core)
|
||||||
s_invalidate_cache_thread_safe =
|
s_invalidate_cache_thread_safe =
|
||||||
CoreTiming::RegisterEvent("invalidateEmulatedCache", InvalidateCacheThreadSafe);
|
CoreTiming::RegisterEvent("invalidateEmulatedCache", InvalidateCacheThreadSafe);
|
||||||
|
|
||||||
ppcState.pagetable_base = 0;
|
Reset();
|
||||||
ppcState.pagetable_hashmask = 0;
|
|
||||||
ppcState.tlb = {};
|
|
||||||
|
|
||||||
ResetRegisters();
|
|
||||||
|
|
||||||
InitializeCPUCore(cpu_core);
|
InitializeCPUCore(cpu_core);
|
||||||
ppcState.iCache.Init();
|
ppcState.iCache.Init();
|
||||||
|
@ -202,6 +198,16 @@ void Init(int cpu_core)
|
||||||
breakpoints.ClearAllTemporary();
|
breakpoints.ClearAllTemporary();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Reset()
|
||||||
|
{
|
||||||
|
ppcState.pagetable_base = 0;
|
||||||
|
ppcState.pagetable_hashmask = 0;
|
||||||
|
ppcState.tlb = {};
|
||||||
|
|
||||||
|
ResetRegisters();
|
||||||
|
ppcState.iCache.Reset();
|
||||||
|
}
|
||||||
|
|
||||||
void ScheduleInvalidateCacheThreadSafe(u32 address)
|
void ScheduleInvalidateCacheThreadSafe(u32 address)
|
||||||
{
|
{
|
||||||
if (CPU::GetState() == CPU::State::CPU_RUNNING)
|
if (CPU::GetState() == CPU::State::CPU_RUNNING)
|
||||||
|
|
|
@ -136,6 +136,7 @@ extern MemChecks memchecks;
|
||||||
extern PPCDebugInterface debug_interface;
|
extern PPCDebugInterface debug_interface;
|
||||||
|
|
||||||
void Init(int cpu_core);
|
void Init(int cpu_core);
|
||||||
|
void Reset();
|
||||||
void Shutdown();
|
void Shutdown();
|
||||||
void DoState(PointerWrap& p);
|
void DoState(PointerWrap& p);
|
||||||
void ScheduleInvalidateCacheThreadSafe(u32 address);
|
void ScheduleInvalidateCacheThreadSafe(u32 address);
|
||||||
|
|
|
@ -156,6 +156,19 @@ static std::string DoState(PointerWrap& p)
|
||||||
return version_created_by;
|
return version_created_by;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool is_wii =
|
||||||
|
SConfig::GetInstance().bWii || SConfig::GetInstance().m_BootType == SConfig::BOOT_MIOS;
|
||||||
|
const bool is_wii_currently = is_wii;
|
||||||
|
p.Do(is_wii);
|
||||||
|
if (is_wii != is_wii_currently)
|
||||||
|
{
|
||||||
|
OSD::AddMessage(StringFromFormat("Cannot load a savestate created under %s mode in %s mode",
|
||||||
|
is_wii ? "Wii" : "GC", is_wii_currently ? "Wii" : "GC"),
|
||||||
|
OSD::Duration::NORMAL, OSD::Color::RED);
|
||||||
|
p.SetMode(PointerWrap::MODE_MEASURE);
|
||||||
|
return version_created_by;
|
||||||
|
}
|
||||||
|
|
||||||
// Begin with video backend, so that it gets a chance to clear its caches and writeback modified
|
// Begin with video backend, so that it gets a chance to clear its caches and writeback modified
|
||||||
// things to RAM
|
// things to RAM
|
||||||
g_video_backend->DoState(p);
|
g_video_backend->DoState(p);
|
||||||
|
|
Loading…
Reference in New Issue