Added support to boot the Triforce IPL

Added handling of dev region for Triforce IPL
This commit is contained in:
crediar 2025-07-17 23:38:08 +02:00
commit 49541626ff
7 changed files with 49 additions and 30 deletions

View file

@ -41,6 +41,7 @@
#define USA_DIR "USA" #define USA_DIR "USA"
#define JAP_DIR "JAP" #define JAP_DIR "JAP"
#define JPN_DIR "JPN" #define JPN_DIR "JPN"
#define DEV_DIR "DEV"
// Subdirs in the User dir returned by GetUserPath(D_USER_IDX) // Subdirs in the User dir returned by GetUserPath(D_USER_IDX)
#define GC_USER_DIR "GC" #define GC_USER_DIR "GC"

View file

@ -38,6 +38,7 @@
#include "Core/FifoPlayer/FifoPlayer.h" #include "Core/FifoPlayer/FifoPlayer.h"
#include "Core/HLE/HLE.h" #include "Core/HLE/HLE.h"
#include "Core/HW/DVD/DVDInterface.h" #include "Core/HW/DVD/DVDInterface.h"
#include "Core/HW/DVD/AMMediaboard.h"
#include "Core/HW/EXI/EXI_DeviceIPL.h" #include "Core/HW/EXI/EXI_DeviceIPL.h"
#include "Core/HW/Memmap.h" #include "Core/HW/Memmap.h"
#include "Core/HW/VideoInterface.h" #include "Core/HW/VideoInterface.h"
@ -408,6 +409,7 @@ bool CBoot::Load_BS2(Core::System& system, const std::string& boot_rom_filename)
break; break;
case Triforce: case Triforce:
known_ipl = true; known_ipl = true;
break;
default: default:
PanicAlertFmtT("The IPL file is not a known good dump. (CRC32: {0:x})", ipl_hash); PanicAlertFmtT("The IPL file is not a known good dump. (CRC32: {0:x})", ipl_hash);
break; break;
@ -458,6 +460,14 @@ bool CBoot::Load_BS2(Core::System& system, const std::string& boot_rom_filename)
ppc_state.spr[SPR_DBAT3L] = 0xfff00001; ppc_state.spr[SPR_DBAT3L] = 0xfff00001;
SetupBAT(system, /*is_wii*/ false); SetupBAT(system, /*is_wii*/ false);
if (ipl_hash == Triforce)
{
HLE::Patch(system, 0x813048B8, "OSReport");
HLE::Patch(system, 0x8130095C, "OSReport"); // Apploader
AMMediaboard::FirmwareMap(true);
}
ppc_state.pc = 0x81200150; ppc_state.pc = 0x81200150;
PowerPC::MSRUpdated(ppc_state); PowerPC::MSRUpdated(ppc_state);

View file

@ -640,6 +640,9 @@ const char* GetDirectoryForRegion(DiscIO::Region region, RegionDirectoryStyle st
ASSERT_MSG(BOOT, false, "NTSC-K is not a valid GameCube region"); ASSERT_MSG(BOOT, false, "NTSC-K is not a valid GameCube region");
return style == RegionDirectoryStyle::Legacy ? JAP_DIR : JPN_DIR; return style == RegionDirectoryStyle::Legacy ? JAP_DIR : JPN_DIR;
case DiscIO::Region::DEV:
return DEV_DIR;
default: default:
ASSERT_MSG(BOOT, false, "Default case should not be reached"); ASSERT_MSG(BOOT, false, "Default case should not be reached");
return EUR_DIR; return EUR_DIR;

View file

@ -48,7 +48,8 @@ enum class Region
NTSC_U = 1, // Mainly North America NTSC_U = 1, // Mainly North America
PAL = 2, // Mainly Europe and Oceania PAL = 2, // Mainly Europe and Oceania
Unknown = 3, // Nintendo uses this to mean region free, but we also use it for unknown regions Unknown = 3, // Nintendo uses this to mean region free, but we also use it for unknown regions
NTSC_K = 4 // South Korea (Wii only) NTSC_K = 4, // South Korea (Wii only)
DEV = 5, // Workaround for Triforce IPL
}; };
// Languages 0 - 9 match Nintendo's Wii language numbering. // Languages 0 - 9 match Nintendo's Wii language numbering.

View file

@ -1145,40 +1145,40 @@ void MainWindow::StartGame(std::unique_ptr<BootParameters>&& parameters)
if (!NKitWarningDialog::ShowUnlessDisabled()) if (!NKitWarningDialog::ShowUnlessDisabled())
return; return;
} }
}
/*
When booting Triforce games, we need to ensure that the hardware is set up correctly.
*/
const auto volume_type =
std::get<BootParameters::Disc>(parameters->parameters).volume->GetVolumeType();
const bool triforce_hardware_sp1 = Config::Get(Config::MAIN_SERIAL_PORT_1) == ExpansionInterface::EXIDeviceType::Baseboard;
const bool triforce_hardware_port_1 = Config::Get(Config::GetInfoForSIDevice(0)) == SerialInterface::SIDevices::SIDEVICE_AM_BASEBOARD;
if (volume_type == DiscIO::Platform::Triforce)
{
if (!triforce_hardware_sp1 || !triforce_hardware_port_1)
{
ModalMessageBox::critical(
this, tr("Error"), tr("To boot a Triforce game, SP1 and Port 1 must be set to Triforce Baseboard."),
QMessageBox::Ok);
HideRenderWidget();
return;
}
}
else
{
/* /*
Some Triforce tools don't include a boot.id file, but they can still be launched. When booting Triforce games, we need to ensure that the hardware is set up correctly.
*/ */
if (triforce_hardware_sp1 || triforce_hardware_port_1) const auto volume_type =
std::get<BootParameters::Disc>(parameters->parameters).volume->GetVolumeType();
const bool triforce_hardware_sp1 = Config::Get(Config::MAIN_SERIAL_PORT_1) == ExpansionInterface::EXIDeviceType::Baseboard;
const bool triforce_hardware_port_1 = Config::Get(Config::GetInfoForSIDevice(0)) == SerialInterface::SIDevices::SIDEVICE_AM_BASEBOARD;
if (volume_type == DiscIO::Platform::Triforce)
{ {
ModalMessageBox::warning( if (!triforce_hardware_sp1 || !triforce_hardware_port_1)
this, tr("Warning"), tr("Non-Triforce games cannot be booted with Triforce hardware attached."), {
QMessageBox::Ok); ModalMessageBox::critical(
this, tr("Error"), tr("To boot a Triforce game, SP1 and Port 1 must be set to Triforce Baseboard."),
QMessageBox::Ok);
HideRenderWidget();
return;
}
} }
} else
{
/*
Some Triforce tools don't include a boot.id file, but they can still be launched.
*/
if (triforce_hardware_sp1 || triforce_hardware_port_1)
{
ModalMessageBox::warning(
this, tr("Warning"), tr("Non-Triforce games cannot be booted with Triforce hardware attached."),
QMessageBox::Ok);
}
}
}
// If we're running, only start a new game once we've stopped the last. // If we're running, only start a new game once we've stopped the last.
if (!Core::IsUninitialized(m_system)) if (!Core::IsUninitialized(m_system))

View file

@ -310,6 +310,9 @@ void MenuBar::AddToolsMenu()
m_pal_ipl = m_pal_ipl =
gc_ipl->addAction(tr("PAL"), this, [this] { emit BootGameCubeIPL(DiscIO::Region::PAL); }); gc_ipl->addAction(tr("PAL"), this, [this] { emit BootGameCubeIPL(DiscIO::Region::PAL); });
m_dev_ipl =
gc_ipl->addAction(tr("Triforce"), this, [this] { emit BootGameCubeIPL(DiscIO::Region::DEV); });
tools_menu->addAction(tr("Memory Card Manager"), this, [this] { emit ShowMemcardManager(); }); tools_menu->addAction(tr("Memory Card Manager"), this, [this] { emit ShowMemcardManager(); });
tools_menu->addSeparator(); tools_menu->addSeparator();

View file

@ -217,6 +217,7 @@ private:
QAction* m_ntscj_ipl; QAction* m_ntscj_ipl;
QAction* m_ntscu_ipl; QAction* m_ntscu_ipl;
QAction* m_pal_ipl; QAction* m_pal_ipl;
QAction* m_dev_ipl;
QMenu* m_manage_nand_menu; QMenu* m_manage_nand_menu;
QAction* m_import_backup; QAction* m_import_backup;
QAction* m_check_nand; QAction* m_check_nand;