code handler super extended

This commit is contained in:
Nayla Hanegan 2024-08-22 22:50:57 -04:00
parent 69e75c6cfd
commit 11413bf234
9 changed files with 231 additions and 187 deletions

View file

@ -162,6 +162,8 @@
#define GECKO_CODE_HANDLER_MPN "codehandler-mpn.bin"
#define GECKO_CODE_HANDLER_MPN_SUPER "codehandler-mpn.bin"
// Subdirs in Sys
#define GC_SYS_DIR "GC"
#define WII_SYS_DIR "Wii"

View file

@ -67,7 +67,6 @@ extern const Info<bool> MAIN_CPU_THREAD;
extern const Info<bool> MAIN_SYNC_ON_SKIP_IDLE;
extern const Info<std::string> MAIN_DEFAULT_ISO;
extern const Info<bool> MAIN_ENABLE_CHEATS;
extern const Info<bool> MAIN_CODE_HANDLER;
extern const Info<int> MAIN_GC_LANGUAGE;
extern const Info<bool> MAIN_OVERRIDE_REGION_SETTINGS;
extern const Info<bool> MAIN_DPL2_DECODER;

View file

@ -89,8 +89,7 @@ SConfig::~SConfig()
namespace Config
{
// Initialize the configuration option
const Info<bool> MAIN_CODE_HANDLER{{System::Main, "CodeHandler", "UseMPN"}, false};
const Info<int> MAIN_CODE_HANDLER{{System::Main, "CodeHandler", "CodeHandlerValue"}, 0};
}
void SConfig::SaveSettings()

View file

@ -34,13 +34,11 @@ enum class Region;
struct Partition;
class Volume;
} // namespace DiscIO
namespace Config
{
// Define the configuration option
extern const Info<bool> MAIN_CODE_HANDLER;
}
// Define the configuration option
extern const Info<int> MAIN_CODE_HANDLER;
} // namespace Config
namespace IOS::ES
{
class TMDReader;
@ -52,7 +50,7 @@ struct SConfig
{
// Settings
bool bBootToPause = false;
bool bJITNoBlockCache = false;
bool bJITNoBlockLinking = false;

View file

@ -122,19 +122,27 @@ std::vector<GeckoCode> SetAndReturnActiveCodes(std::span<const GeckoCode> gcodes
const char* GetGeckoCodeHandlerPath()
{
return Config::Get(Config::MAIN_CODE_HANDLER) ?
GECKO_CODE_HANDLER_MPN : GECKO_CODE_HANDLER;
int code_handler_value = Config::Get(Config::MAIN_CODE_HANDLER); // Get the integer value
switch (code_handler_value)
{
case 0: return GECKO_CODE_HANDLER; // Dolphin (Stock)
case 1: return GECKO_CODE_HANDLER_MPN; // MPN (Extended)
case 2: return GECKO_CODE_HANDLER_MPN_SUPER; // MPN (Super Extended)
default: return GECKO_CODE_HANDLER; // Fallback
}
}
bool IsGeckoCodeHandlerEnabled()
{
return Config::Get(Config::MAIN_CODE_HANDLER);
int code_handler_value = Config::Get(Config::MAIN_CODE_HANDLER); // Get the integer value
return code_handler_value == 1 || code_handler_value == 2; // Return true for 1 and 2
}
const char* code_handler_file = GetGeckoCodeHandlerPath();
const bool is_mpn_handler = (code_handler_file = GECKO_CODE_HANDLER_MPN);
bool IsGeckoCodeHandlerSUPER()
{
int code_handler_value = Config::Get(Config::MAIN_CODE_HANDLER); // Get the integer value
return code_handler_value == 2; // Return true for 1 and 2
}
// Requires s_active_codes_lock
// NOTE: Refer to "codehandleronly.s" from Gecko OS.
@ -159,187 +167,117 @@ static Installation InstallCodeHandlerLocked(const Core::CPUThreadGuard& guard)
mmio_addr = 0xCD;
}
auto free_memory_base_address = Core::getGameFreeMemory();
bool use_free_memory = free_memory_base_address.has_value();
if (use_free_memory && is_mpn_handler == true)
// Install code handler
for (u32 i = 0; i < data.size(); ++i)
PowerPC::MMU::HostWrite_U8(guard, data[i], INSTALLER_BASE_ADDRESS + i);
// Patch the code handler to the current system type (Gamecube/Wii)
for (u32 h = 0; h < data.length(); h += 4)
{
// Move Gecko code handler to the free mem region
u32 codelist_base_address = free_memory_base_address.value().first;
u32 codelist_end_address = free_memory_base_address.value().second;
u32 codelist_start_address = free_memory_base_address.value().first;
// Install code handler
for (u32 i = 0; i < data.size(); ++i)
PowerPC::MMU::HostWrite_U8(guard, data[i], codelist_base_address + i);
// Patch the code handler to the current system type (Gamecube/Wii)
for (u32 h = 0; h < data.length(); h += 4)
// Patch MMIO address
if (PowerPC::MMU::HostRead_U32(guard, INSTALLER_BASE_ADDRESS + h) ==
(0x3f000000u | ((mmio_addr ^ 1) << 8)))
{
// Patch MMIO address
if (PowerPC::MMU::HostRead_U32(guard, codelist_base_address + h) ==
(0x3f000000u | ((mmio_addr ^ 1) << 8)))
{
NOTICE_LOG_FMT(ACTIONREPLAY, "Patching MMIO access at {:08x}", codelist_base_address + h);
PowerPC::MMU::HostWrite_U32(guard, 0x3f000000u | mmio_addr << 8, codelist_base_address + h);
}
NOTICE_LOG_FMT(ACTIONREPLAY, "Patching MMIO access at {:08x}", INSTALLER_BASE_ADDRESS + h);
PowerPC::MMU::HostWrite_U32(guard, 0x3f000000u | mmio_addr << 8, INSTALLER_BASE_ADDRESS + h);
}
}
const bool is_mpn_handler_and_game_id_gp7e01 =
IsGeckoCodeHandlerSUPER() && (SConfig::GetInstance().GetGameID() == "GP7E01");
const bool is_mpn_handler_and_game_id_gp6e01 =
IsGeckoCodeHandlerSUPER() && (SConfig::GetInstance().GetGameID() == "GP6E01");
const bool is_mpn_handler_and_game_id_gp5e01 =
IsGeckoCodeHandlerSUPER() && (SConfig::GetInstance().GetGameID() == "GP5E01");
u32 codelist_base_address =
is_mpn_handler_and_game_id_gp7e01 ? INSTALLER_BASE_ADDRESS_MP7 :
is_mpn_handler_and_game_id_gp6e01 ? INSTALLER_BASE_ADDRESS_MP6 :
is_mpn_handler_and_game_id_gp5e01 ? INSTALLER_BASE_ADDRESS_MP5 :
INSTALLER_BASE_ADDRESS + static_cast<u32>(data.size()) -
CODE_SIZE;
u32 codelist_end_address = is_mpn_handler_and_game_id_gp7e01 ? INSTALLER_END_ADDRESS_MP7 :
is_mpn_handler_and_game_id_gp6e01 ? INSTALLER_END_ADDRESS_MP6 :
is_mpn_handler_and_game_id_gp5e01 ? INSTALLER_END_ADDRESS_MP5 :
INSTALLER_END_ADDRESS;
if (is_mpn_handler_and_game_id_gp7e01 || is_mpn_handler_and_game_id_gp6e01 ||
is_mpn_handler_and_game_id_gp5e01)
{
// Move Gecko code handler to the free mem region
for (u32 addr = codelist_base_address; addr < codelist_end_address; addr += 4)
{
PowerPC::MMU::HostWrite_U32(guard, 0x00000000, addr);
}
PowerPC::MMU::HostWrite_U32(guard, ((codelist_base_address & 0xFFFF0000) >> 16) + 0x3DE00000,
0x80001904);
PowerPC::MMU::HostWrite_U32(guard, (codelist_base_address & 0x0000FFFF) + 0x61EF0000,
0x80001908);
}
// Write a magic value to 'gameid' (codehandleronly does not actually read this).
// This value will be read back and modified over time by HLE_Misc::GeckoCodeHandlerICacheFlush.
PowerPC::MMU::HostWrite_U32(guard, MAGIC_GAMEID, codelist_start_address);
// Write a magic value to 'gameid' (codehandleronly does not actually read this).
// This value will be read back and modified over time by HLE_Misc::GeckoCodeHandlerICacheFlush.
PowerPC::MMU::HostWrite_U32(guard, MAGIC_GAMEID, codelist_base_address);
// Create GCT in memory
PowerPC::MMU::HostWrite_U32(guard, 0x00d0c0de, codelist_base_address);
PowerPC::MMU::HostWrite_U32(guard, 0x00d0c0de, codelist_base_address + 4);
// Create GCT in memory
PowerPC::MMU::HostWrite_U32(guard, 0x00d0c0de, codelist_base_address);
PowerPC::MMU::HostWrite_U32(guard, 0x00d0c0de, codelist_base_address + 4);
// Each code is 8 bytes (2 words) wide. There is a starter code and an end code.
const u32 start_address = codelist_base_address + CODE_SIZE;
const u32 end_address = codelist_end_address - CODE_SIZE;
u32 next_address = start_address;
// Each code is 8 bytes (2 words) wide. There is a starter code and an end code.
const u32 start_address = codelist_base_address + CODE_SIZE;
const u32 end_address = codelist_end_address - CODE_SIZE;
u32 next_address = start_address;
// NOTE: Only active codes are in the list
for (const GeckoCode& active_code : s_active_codes)
// NOTE: Only active codes are in the list
for (const GeckoCode& active_code : s_active_codes)
{
// If the code is not going to fit in the space we have left then we have to skip it
if (next_address + active_code.codes.size() * CODE_SIZE > end_address)
{
// If the code is not going to fit in the space we have left then we have to skip it
if (next_address + active_code.codes.size() * CODE_SIZE > end_address)
{
NOTICE_LOG_FMT(ACTIONREPLAY,
"Too many GeckoCodes! Ran out of storage space in Game RAM. Could "
"not write: \"{}\". Need {} bytes, only {} remain.",
active_code.name, active_code.codes.size() * CODE_SIZE,
end_address - next_address);
OSD::AddMessage(
fmt::format("Too many GeckoCodes! Ran out of storage space in Game RAM. Could "
"not write: \"{}\". Need {} bytes, only {} remain.",
active_code.name, active_code.codes.size() * CODE_SIZE,
end_address - next_address),
OSD::Duration::VERY_LONG);
continue;
}
for (const GeckoCode::Code& code : active_code.codes)
{
PowerPC::MMU::HostWrite_U32(guard, code.address, next_address);
PowerPC::MMU::HostWrite_U32(guard, code.data, next_address + 4);
next_address += CODE_SIZE;
}
NOTICE_LOG_FMT(ACTIONREPLAY,
"Too many GeckoCodes! Ran out of storage space in Game RAM. Could "
"not write: \"{}\". Need {} bytes, only {} remain.",
active_code.name, active_code.codes.size() * CODE_SIZE,
end_address - next_address);
OSD::AddMessage(fmt::format("Too many GeckoCodes! Ran out of storage space in Game RAM. Could "
"not write: \"{}\". Need {} bytes, only {} remain.",
active_code.name, active_code.codes.size() * CODE_SIZE,
end_address - next_address),
OSD::Duration::VERY_LONG);
continue;
}
WARN_LOG_FMT(ACTIONREPLAY, "GeckoCodes: Using {} of {} bytes", next_address - start_address,
end_address - start_address);
OSD::AddMessage(fmt::format("Gecko Codes: Using {} of {} bytes", next_address - start_address,
end_address - start_address));
// Stop code. Tells the handler that this is the end of the list.
PowerPC::MMU::HostWrite_U32(guard, 0xF0000000, next_address);
PowerPC::MMU::HostWrite_U32(guard, 0x00000000, next_address + 4);
PowerPC::MMU::HostWrite_U32(guard, 0, HLE_TRAMPOLINE_ADDRESS);
// Turn on codes
PowerPC::MMU::HostWrite_U8(guard, 1, codelist_start_address + 7);
// Invalidate the icache and any asm codes
auto& ppc_state = guard.GetSystem().GetPPCState();
auto& memory = guard.GetSystem().GetMemory();
auto& jit_interface = guard.GetSystem().GetJitInterface();
for (u32 j = 0; j < (INSTALLER_END_ADDRESS - codelist_start_address); j += 32)
for (const GeckoCode::Code& code : active_code.codes)
{
ppc_state.iCache.Invalidate(memory, jit_interface, codelist_start_address + j);
PowerPC::MMU::HostWrite_U32(guard, code.address, next_address);
PowerPC::MMU::HostWrite_U32(guard, code.data, next_address + 4);
next_address += CODE_SIZE;
}
}
else
WARN_LOG_FMT(ACTIONREPLAY, "GeckoCodes: Using {} of {} bytes", next_address - start_address,
end_address - start_address);
OSD::AddMessage(fmt::format("Gecko Codes: Using {} of {} bytes", next_address - start_address,
end_address - start_address));
// Stop code. Tells the handler that this is the end of the list.
PowerPC::MMU::HostWrite_U32(guard, 0xF0000000, next_address);
PowerPC::MMU::HostWrite_U32(guard, 0x00000000, next_address + 4);
PowerPC::MMU::HostWrite_U32(guard, 0, HLE_TRAMPOLINE_ADDRESS);
// Turn on codes
PowerPC::MMU::HostWrite_U8(guard, 1, INSTALLER_BASE_ADDRESS + 7);
// Invalidate the icache and any asm codes
auto& ppc_state = guard.GetSystem().GetPPCState();
auto& memory = guard.GetSystem().GetMemory();
auto& jit_interface = guard.GetSystem().GetJitInterface();
for (u32 j = 0; j < (codelist_end_address - codelist_base_address); j += 32)
{
u32 codelist_base_address = INSTALLER_BASE_ADDRESS + static_cast<u32>(data.size()) - CODE_SIZE;
u32 codelist_end_address = INSTALLER_END_ADDRESS;
u32 codelist_start_address = INSTALLER_BASE_ADDRESS;
// Install code handler
for (u32 i = 0; i < data.size(); ++i)
PowerPC::MMU::HostWrite_U8(guard, data[i], INSTALLER_BASE_ADDRESS + i);
// Patch the code handler to the current system type (Gamecube/Wii)
for (u32 h = 0; h < data.length(); h += 4)
{
// Patch MMIO address
if (PowerPC::MMU::HostRead_U32(guard, INSTALLER_BASE_ADDRESS + h) ==
(0x3f000000u | ((mmio_addr ^ 1) << 8)))
{
NOTICE_LOG_FMT(ACTIONREPLAY, "Patching MMIO access at {:08x}", INSTALLER_BASE_ADDRESS + h);
PowerPC::MMU::HostWrite_U32(guard, 0x3f000000u | mmio_addr << 8,
INSTALLER_BASE_ADDRESS + h);
}
}
// Write a magic value to 'gameid' (codehandleronly does not actually read this).
// This value will be read back and modified over time by HLE_Misc::GeckoCodeHandlerICacheFlush.
PowerPC::MMU::HostWrite_U32(guard, MAGIC_GAMEID, codelist_start_address);
// Create GCT in memory
PowerPC::MMU::HostWrite_U32(guard, 0x00d0c0de, codelist_base_address);
PowerPC::MMU::HostWrite_U32(guard, 0x00d0c0de, codelist_base_address + 4);
// Each code is 8 bytes (2 words) wide. There is a starter code and an end code.
const u32 start_address = codelist_base_address + CODE_SIZE;
const u32 end_address = codelist_end_address - CODE_SIZE;
u32 next_address = start_address;
// NOTE: Only active codes are in the list
for (const GeckoCode& active_code : s_active_codes)
{
// If the code is not going to fit in the space we have left then we have to skip it
if (next_address + active_code.codes.size() * CODE_SIZE > end_address)
{
NOTICE_LOG_FMT(ACTIONREPLAY,
"Too many GeckoCodes! Ran out of storage space in Game RAM. Could "
"not write: \"{}\". Need {} bytes, only {} remain.",
active_code.name, active_code.codes.size() * CODE_SIZE,
end_address - next_address);
OSD::AddMessage(
fmt::format("Too many GeckoCodes! Ran out of storage space in Game RAM. Could "
"not write: \"{}\". Need {} bytes, only {} remain.",
active_code.name, active_code.codes.size() * CODE_SIZE,
end_address - next_address),
OSD::Duration::VERY_LONG);
continue;
}
for (const GeckoCode::Code& code : active_code.codes)
{
PowerPC::MMU::HostWrite_U32(guard, code.address, next_address);
PowerPC::MMU::HostWrite_U32(guard, code.data, next_address + 4);
next_address += CODE_SIZE;
}
}
WARN_LOG_FMT(ACTIONREPLAY, "GeckoCodes: Using {} of {} bytes", next_address - start_address,
end_address - start_address);
OSD::AddMessage(fmt::format("Gecko Codes: Using {} of {} bytes", next_address - start_address,
end_address - start_address));
// Stop code. Tells the handler that this is the end of the list.
PowerPC::MMU::HostWrite_U32(guard, 0xF0000000, next_address);
PowerPC::MMU::HostWrite_U32(guard, 0x00000000, next_address + 4);
PowerPC::MMU::HostWrite_U32(guard, 0, HLE_TRAMPOLINE_ADDRESS);
// Turn on codes
PowerPC::MMU::HostWrite_U8(guard, 1, codelist_start_address + 7);
// Invalidate the icache and any asm codes
auto& ppc_state = guard.GetSystem().GetPPCState();
auto& memory = guard.GetSystem().GetMemory();
auto& jit_interface = guard.GetSystem().GetJitInterface();
for (u32 j = 0; j < (INSTALLER_END_ADDRESS - codelist_start_address); j += 32)
{
ppc_state.iCache.Invalidate(memory, jit_interface, codelist_start_address + j);
}
ppc_state.iCache.Invalidate(memory, jit_interface, codelist_base_address + j);
}
return Installation::Installed;
}

View file

@ -49,7 +49,28 @@ bool operator!=(const GeckoCode::Code& lhs, const GeckoCode::Code& rhs);
// Installation address for codehandler.bin in the Game's RAM
constexpr u32 INSTALLER_BASE_ADDRESS = 0x80001800;
constexpr u32 INSTALLER_END_ADDRESS = 0x80003000;
// Override kerjump to 0x8023CF6C location for CodeHandler
constexpr u32 INSTALLER_BASE_ADDRESS_MP7 = 0x8023CF6C;
constexpr u32 INSTALLER_END_ADDRESS_MP7 = 0x8023F9D0;
// Override kerjump to 0x80213974 location for CodeHandler
constexpr u32 INSTALLER_BASE_ADDRESS_MP6 = 0x817611C0;
constexpr u32 INSTALLER_END_ADDRESS_MP6 = 0x817611C0;
// Override kerjump to 0x801A811C location for CodeHandler
constexpr u32 INSTALLER_BASE_ADDRESS_MP5 = 0x81788000;
constexpr u32 INSTALLER_END_ADDRESS_MP5 = 0x817F0000;
// Override kerjump to 0x8011CCC4 location for CodeHandler
constexpr u32 INSTALLER_BASE_ADDRESS_MP4 = 0x81792D00;
constexpr u32 INSTALLER_END_ADDRESS_MP4 = 0x817F0000;
constexpr u32 ENTRY_POINT = INSTALLER_BASE_ADDRESS + 0xA8;
constexpr u32 ENTRY_POINT_MP7 = INSTALLER_BASE_ADDRESS_MP7 + 0xA8;
constexpr u32 ENTRY_POINT_MP6 = INSTALLER_BASE_ADDRESS_MP6 + 0xA8;
constexpr u32 ENTRY_POINT_MP5 = INSTALLER_BASE_ADDRESS_MP5 + 0xA8;
// If the GCT is max-length then this is the second word of the End code (0xF0000000 0x00000000)
// If the table is shorter than the max-length then this address is unused / contains trash.
constexpr u32 HLE_TRAMPOLINE_ADDRESS = INSTALLER_END_ADDRESS - 4;
@ -72,5 +93,4 @@ void RunCodeHandler(const Core::CPUThreadGuard& guard);
void Shutdown();
void DoState(PointerWrap&);
} // namespace Gecko

View file

@ -8,8 +8,10 @@
#include <map>
#include "Common/CommonTypes.h"
#include "Common/CommonPaths.h"
#include "Common/Config/Config.h"
#include "Core/ConfigManager.h"
#include "Core/Config/MainSettings.h"
#include "Core/Core.h"
#include "Core/GeckoCode.h"
@ -79,6 +81,30 @@ void Patch(Core::System& system, u32 addr, std::string_view func_name)
}
}
const char* GetGeckoCodeHandlerPath()
{
int code_handler_value = Config::Get(Config::MAIN_CODE_HANDLER); // Get the integer value
switch (code_handler_value)
{
case 0: return GECKO_CODE_HANDLER; // Dolphin (Stock)
case 1: return GECKO_CODE_HANDLER_MPN; // MPN (Extended)
case 2: return GECKO_CODE_HANDLER_MPN_SUPER; // MPN (Super Extended)
default: return GECKO_CODE_HANDLER; // Fallback
}
}
bool IsGeckoCodeHandlerEnabled()
{
int code_handler_value = Config::Get(Config::MAIN_CODE_HANDLER); // Get the integer value
return code_handler_value == 1 || code_handler_value == 2; // Return true for 1 and 2
}
bool IsGeckoCodeHandlerSUPER()
{
int code_handler_value = Config::Get(Config::MAIN_CODE_HANDLER); // Get the integer value
return code_handler_value == 2; // Return true for 1 and 2
}
void PatchFixedFunctions(Core::System& system)
{
// MIOS puts patch data in low MEM1 (0x1800-0x3000) for its own use.
@ -100,7 +126,28 @@ void PatchFixedFunctions(Core::System& system)
// Not part of the binary itself, but either we or Gecko OS might insert
// this, and it doesn't clear the icache properly.
Patch(system, Gecko::ENTRY_POINT, "GeckoCodehandler");
const bool is_mpn_handler_and_game_id_gp7e01 =
IsGeckoCodeHandlerSUPER() && (SConfig::GetInstance().GetGameID() == "GP7E01");
const bool is_mpn_handler_and_game_id_gp6e01 =
IsGeckoCodeHandlerSUPER() && (SConfig::GetInstance().GetGameID() == "GP6E01");
const bool is_mpn_handler_and_game_id_gp5e01 =
IsGeckoCodeHandlerSUPER() && (SConfig::GetInstance().GetGameID() == "GP5E01");
u32 codelist_hook = is_mpn_handler_and_game_id_gp7e01 ?
Gecko::ENTRY_POINT_MP7 :
is_mpn_handler_and_game_id_gp6e01 ?
Gecko::ENTRY_POINT_MP6 :
is_mpn_handler_and_game_id_gp5e01 ?
Gecko::ENTRY_POINT_MP5 :
Gecko::ENTRY_POINT;
Patch(system, codelist_hook, "GeckoCodehandler");
// This has to always be installed even if cheats are not enabled because of the possiblity of
// loading a savestate where PC is inside the code handler while cheats are disabled.
Patch(system, Gecko::HLE_TRAMPOLINE_ADDRESS, "GeckoHandlerReturnTrampoline");

View file

@ -12,6 +12,8 @@
#include "Core/PowerPC/MMU.h"
#include "Core/PowerPC/PowerPC.h"
#include "Core/System.h"
#include <Common/CommonPaths.h>
#include <Core/ConfigManager.h>
namespace HLE_Misc
{
@ -24,6 +26,31 @@ void UnimplementedFunction(const Core::CPUThreadGuard& guard)
ppc_state.npc = LR(ppc_state);
}
const char* GetGeckoCodeHandlerPath()
{
int code_handler_value = Config::Get(Config::MAIN_CODE_HANDLER); // Get the integer value
switch (code_handler_value)
{
case 0: return GECKO_CODE_HANDLER; // Dolphin (Stock)
case 1: return GECKO_CODE_HANDLER_MPN; // MPN (Extended)
case 2: return GECKO_CODE_HANDLER_MPN_SUPER; // MPN (Super Extended)
default: return GECKO_CODE_HANDLER; // Fallback
}
}
bool IsGeckoCodeHandlerEnabled()
{
int code_handler_value = Config::Get(Config::MAIN_CODE_HANDLER); // Get the integer value
return code_handler_value == 1 || code_handler_value == 2; // Return true for 1 and 2
}
bool IsGeckoCodeHandlerSUPER()
{
int code_handler_value = Config::Get(Config::MAIN_CODE_HANDLER); // Get the integer value
return code_handler_value == 2; // Return true for 1 and 2
}
void HBReload(const Core::CPUThreadGuard& guard)
{
// There isn't much we can do. Just stop cleanly.
@ -44,7 +71,20 @@ void GeckoCodeHandlerICacheFlush(const Core::CPUThreadGuard& guard)
// been read into memory, or such, so we do the first 5 frames. More
// robust alternative would be to actually detect memory writes, but that
// would be even uglier.)
u32 gch_gameid = PowerPC::MMU::HostRead_U32(guard, Gecko::INSTALLER_BASE_ADDRESS);
const bool is_mpn_handler_and_game_id_gp7e01 =
IsGeckoCodeHandlerSUPER() && (SConfig::GetInstance().GetGameID() == "GP7E01");
const bool is_mpn_handler_and_game_id_gp6e01 =
IsGeckoCodeHandlerSUPER() && (SConfig::GetInstance().GetGameID() == "GP6E01");
const bool is_mpn_handler_and_game_id_gp5e01 =
IsGeckoCodeHandlerSUPER() && (SConfig::GetInstance().GetGameID() == "GP5E01");
u32 codelist_hook = is_mpn_handler_and_game_id_gp7e01 ? Gecko::INSTALLER_BASE_ADDRESS_MP7 :
is_mpn_handler_and_game_id_gp6e01 ? Gecko::INSTALLER_BASE_ADDRESS_MP6 :
is_mpn_handler_and_game_id_gp5e01 ? Gecko::INSTALLER_BASE_ADDRESS_MP5 :
Gecko::INSTALLER_BASE_ADDRESS;
u32 gch_gameid = PowerPC::MMU::HostRead_U32(guard, codelist_hook);
if (gch_gameid - Gecko::MAGIC_GAMEID == 5)
{
return;
@ -53,7 +93,7 @@ void GeckoCodeHandlerICacheFlush(const Core::CPUThreadGuard& guard)
{
gch_gameid = Gecko::MAGIC_GAMEID;
}
PowerPC::MMU::HostWrite_U32(guard, gch_gameid + 1, Gecko::INSTALLER_BASE_ADDRESS);
PowerPC::MMU::HostWrite_U32(guard, gch_gameid + 1, codelist_hook);
ppc_state.iCache.Reset(jit_interface);
}

View file

@ -225,8 +225,9 @@ void GeneralPane::CreateCheats()
auto* code_handler_layout = new QFormLayout();
auto* code_handler_label = new QLabel(tr("Code Handler:"));
m_combobox_codehandler = new QComboBox();
m_combobox_codehandler->addItem(tr("Dolphin (Stock)"), QVariant(false));
m_combobox_codehandler->addItem(tr("MPN (Extended)"), QVariant(true));
m_combobox_codehandler->addItem(tr("Dolphin (Stock)"), QVariant(0));
m_combobox_codehandler->addItem(tr("MPN (Extended)"), QVariant(1));
m_combobox_codehandler->addItem(tr("MPN (Super Extended)"), QVariant(2));
code_handler_layout->addRow(code_handler_label, m_combobox_codehandler);
@ -248,7 +249,7 @@ void GeneralPane::LoadConfig()
#endif
SignalBlocking(m_checkbox_dualcore)->setChecked(Config::Get(Config::MAIN_CPU_THREAD));
SignalBlocking(m_checkbox_cheats)->setChecked(Settings::Instance().GetCheatsEnabled());
SignalBlocking(m_combobox_codehandler)->setCurrentIndex(Config::Get(Config::MAIN_CODE_HANDLER) ? 1 : 0);
SignalBlocking(m_combobox_codehandler)->setCurrentIndex(Config::Get(Config::MAIN_CODE_HANDLER));
SignalBlocking(m_checkbox_override_region_settings)
->setChecked(Config::Get(Config::MAIN_OVERRIDE_REGION_SETTINGS));
SignalBlocking(m_checkbox_auto_disc_change)
@ -367,7 +368,7 @@ void GeneralPane::GenerateNewIdentity()
void GeneralPane::OnCodeHandlerChanged(int index)
{
bool use_mpn = m_combobox_codehandler->itemData(index).toBool();
Config::SetBaseOrCurrent(Config::MAIN_CODE_HANDLER, use_mpn); // Ensure correct usage
int code_handler_value = m_combobox_codehandler->itemData(index).toInt();
Config::SetBaseOrCurrent(Config::MAIN_CODE_HANDLER, code_handler_value);
Config::Save();
}