mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2026-03-21 17:49:58 -05:00
Triforce: Optimized code
Removed unneeded code Removed unused code Added EINPROGRESS to fix networking on Linux systems Added function NetworkBufferCheck and NetworkCMDBufferCheck to verify buffer sizes Added NetworkCMDBufferRead/NetworkCMDBufferWrite/NetworkBufferRead/NetworkBufferWrite Added multiply buffer size checks Rewrote GetGameType() Moved AMMediaboard::Shutdown to DVDInterface::Shutdown() Changed JVSIOMessage overrun check Changed SwapBuffers function to be a member function Added sanity checks for buffer sizes Added translation prefix for Triforce buttons Updated text for misconfigurations when trying to boot normal games with Triforce hardware connected Fixed NAMCAM for Mario Kart GP
This commit is contained in:
parent
be2da8dc7b
commit
ce802f1e62
|
|
@ -289,13 +289,6 @@ void Stop(Core::System& system) // - Hammertime!
|
|||
// Stop the CPU
|
||||
INFO_LOG_FMT(CONSOLE, "{}", StopMessage(true, "Stop CPU"));
|
||||
system.GetCPU().Stop();
|
||||
|
||||
const ExpansionInterface::EXIDeviceType type = Config::Get(Config::MAIN_SERIAL_PORT_1);
|
||||
|
||||
if ((type == ExpansionInterface::EXIDeviceType::Baseboard))
|
||||
{
|
||||
AMMediaboard::Shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
void DeclareAsCPUThread()
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -52,6 +52,12 @@ enum InquiryType
|
|||
Version2 = 0x29484100,
|
||||
};
|
||||
|
||||
namespace Core
|
||||
{
|
||||
class CPUThreadGuard;
|
||||
class System;
|
||||
} // namespace Core
|
||||
|
||||
namespace AMMediaboard
|
||||
{
|
||||
|
||||
|
|
@ -148,10 +154,13 @@ enum MediaBoardAddress : u32
|
|||
|
||||
DIMMCommandVersion1 = 0x1F900000,
|
||||
DIMMCommandVersion2 = 0x84000000,
|
||||
DIMMCommandVersion2_1 = 0x84000020,
|
||||
DIMMCommandVersion2_2 = 0x89000000,
|
||||
DIMMCommandVersion2_2_1 = 0x89000200,
|
||||
DIMMCommandExecute1 = 0x84000040,
|
||||
DIMMCommandExecute2 = 0x88000000,
|
||||
|
||||
NetworkCommandAddress = 0x1F800200,
|
||||
NetworkCommandAddress1 = 0x1F800200,
|
||||
NetworkCommandAddress2 = 0x89040200,
|
||||
|
||||
NetworkBufferAddress1 = 0x1FA00000,
|
||||
|
|
@ -217,4 +226,5 @@ u32 GetGameType();
|
|||
u32 GetMediaType();
|
||||
bool GetTestMenu();
|
||||
void Shutdown();
|
||||
|
||||
}; // namespace AMMediaboard
|
||||
|
|
|
|||
|
|
@ -341,6 +341,11 @@ void DVDInterface::ResetDrive(bool spinup)
|
|||
void DVDInterface::Shutdown()
|
||||
{
|
||||
m_system.GetDVDThread().Stop();
|
||||
|
||||
if (m_system.IsTriforce())
|
||||
{
|
||||
AMMediaboard::Shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
static u64 GetDiscEndOffset(const DiscIO::VolumeDisc& disc)
|
||||
|
|
|
|||
|
|
@ -105,7 +105,6 @@ CEXIBaseboard::CEXIBaseboard(Core::System& system) : IEXIDevice(system)
|
|||
|
||||
CEXIBaseboard::~CEXIBaseboard()
|
||||
{
|
||||
m_backup.Close();
|
||||
}
|
||||
|
||||
void CEXIBaseboard::SetCS(int cs)
|
||||
|
|
|
|||
|
|
@ -54,6 +54,6 @@ private:
|
|||
File::IOFile m_backup;
|
||||
|
||||
protected:
|
||||
void TransferByte(u8& _uByte) override;
|
||||
void TransferByte(u8& byte) override;
|
||||
};
|
||||
} // namespace ExpansionInterface
|
||||
|
|
|
|||
|
|
@ -72,9 +72,9 @@ public:
|
|||
static constexpr const char* START_BUTTON = "Start";
|
||||
|
||||
// Special Triforce buttons
|
||||
static constexpr const char* TEST_BUTTON = "Test";
|
||||
static constexpr const char* SERVICE_BUTTON = "Service";
|
||||
static constexpr const char* COIN_BUTTON = "Coin";
|
||||
static constexpr const char* TEST_BUTTON = _trans("Test");
|
||||
static constexpr const char* SERVICE_BUTTON = _trans("Service");
|
||||
static constexpr const char* COIN_BUTTON = _trans("Coin");
|
||||
|
||||
// i18n: The left trigger button (labeled L on real controllers)
|
||||
static constexpr const char* L_DIGITAL = _trans("L");
|
||||
|
|
|
|||
|
|
@ -52,6 +52,12 @@ void JVSIOMessage::Start(int node)
|
|||
|
||||
void JVSIOMessage::AddData(const u8* dst, std::size_t len, int sync = 0)
|
||||
{
|
||||
if (m_ptr + len >= 0x80)
|
||||
{
|
||||
PanicAlertFmt("JVSIOMessage overrun!");
|
||||
return;
|
||||
}
|
||||
|
||||
while (len--)
|
||||
{
|
||||
const u8 c = *dst++;
|
||||
|
|
@ -68,8 +74,6 @@ void JVSIOMessage::AddData(const u8* dst, std::size_t len, int sync = 0)
|
|||
if (!sync)
|
||||
m_csum += c;
|
||||
sync = 0;
|
||||
if (m_ptr >= 0x80)
|
||||
PanicAlertFmt("JVSIOMessage overrun!");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -96,33 +100,18 @@ void JVSIOMessage::End()
|
|||
AddData(m_csum + len - 2);
|
||||
}
|
||||
|
||||
static u8 CheckSumXOR(u8* Data, u32 Length)
|
||||
static u8 CheckSumXOR(u8* data, u32 length)
|
||||
{
|
||||
u8 check = 0;
|
||||
|
||||
for (u32 i = 0; i < Length; i++)
|
||||
for (u32 i = 0; i < length; i++)
|
||||
{
|
||||
check ^= Data[i];
|
||||
check ^= data[i];
|
||||
}
|
||||
|
||||
return check;
|
||||
}
|
||||
|
||||
// Reply has to be delayed due a bug in the parser
|
||||
static void swap_buffers(u8* buffer, u32* buffer_length)
|
||||
{
|
||||
static u8 last[2][0x80];
|
||||
static u32 lastptr[2];
|
||||
|
||||
memcpy(last[1], buffer, 0x80); // Save current buffer
|
||||
memcpy(buffer, last[0], 0x80); // Load previous buffer
|
||||
memcpy(last[0], last[1], 0x80); // Update history
|
||||
|
||||
lastptr[1] = *buffer_length; // Swap lengths
|
||||
*buffer_length = lastptr[0];
|
||||
lastptr[0] = lastptr[1];
|
||||
}
|
||||
|
||||
static const char s_cdr_program_version[] = {" Version 1.22,2003/09/19,171-8213B"};
|
||||
static const char s_cdr_boot_version[] = {" Version 1.04,2003/06/17,171-8213B"};
|
||||
static const u8 s_cdr_card_data[] = {
|
||||
|
|
@ -236,6 +225,17 @@ void CSIDevice_AMBaseboard::ICCardSendReply(ICCommand* iccommand, u8* buffer, u3
|
|||
buffer[(*length)++] = crc;
|
||||
}
|
||||
|
||||
void CSIDevice_AMBaseboard::SwapBuffers(u8* buffer, u32* buffer_length)
|
||||
{
|
||||
memcpy(m_last[1], buffer, 0x80); // Save current buffer
|
||||
memcpy(buffer, m_last[0], 0x80); // Load previous buffer
|
||||
memcpy(m_last[0], m_last[1], 0x80); // Update history
|
||||
|
||||
m_lastptr[1] = *buffer_length; // Swap lengths
|
||||
*buffer_length = m_lastptr[0];
|
||||
m_lastptr[0] = m_lastptr[1];
|
||||
}
|
||||
|
||||
int CSIDevice_AMBaseboard::RunBuffer(u8* buffer, int request_length)
|
||||
{
|
||||
const auto& serial_interface = m_system.GetSerialInterface();
|
||||
|
|
@ -526,15 +526,7 @@ int CSIDevice_AMBaseboard::RunBuffer(u8* buffer, int request_length)
|
|||
{
|
||||
const u32 size = data_in[1];
|
||||
|
||||
char logptr[1024];
|
||||
char* log = logptr;
|
||||
|
||||
for (u32 i = 0; i < (u32)(data_in[1] + 2); ++i)
|
||||
{
|
||||
log += sprintf(log, "%02X ", data_in[i]);
|
||||
}
|
||||
|
||||
INFO_LOG_FMT(SERIALINTERFACE_CARD, "Command: {}", logptr);
|
||||
DEBUG_LOG_FMT(SERIALINTERFACE_CARD, "Command: {}", HexDump(data_in, size + 2));
|
||||
|
||||
INFO_LOG_FMT(
|
||||
SERIALINTERFACE_CARD,
|
||||
|
|
@ -624,7 +616,7 @@ int CSIDevice_AMBaseboard::RunBuffer(u8* buffer, int request_length)
|
|||
case ICCARDCommand::ReadPage:
|
||||
case ICCARDCommand::ReadUseCount:
|
||||
{
|
||||
const u16 page = Common::swap16(data_in + 6);
|
||||
const u16 page = Common::swap16(data_in + 6) & 0xFF; // 255 is max page
|
||||
|
||||
icco.extlen = 8;
|
||||
icco.length += icco.extlen;
|
||||
|
|
@ -638,7 +630,7 @@ int CSIDevice_AMBaseboard::RunBuffer(u8* buffer, int request_length)
|
|||
}
|
||||
case ICCARDCommand::WritePage:
|
||||
{
|
||||
const u16 page = Common::swap16(data_in + 8);
|
||||
const u16 page = Common::swap16(data_in + 8) & 0xFF; // 255 is max page
|
||||
|
||||
// Write only one page
|
||||
if (page == 4)
|
||||
|
|
@ -656,7 +648,7 @@ int CSIDevice_AMBaseboard::RunBuffer(u8* buffer, int request_length)
|
|||
}
|
||||
case ICCARDCommand::DecreaseUseCount:
|
||||
{
|
||||
const u16 page = Common::swap16(data_in + 6);
|
||||
const u16 page = Common::swap16(data_in + 6) & 0xFF; // 255 is max page
|
||||
|
||||
icco.extlen = 2;
|
||||
icco.length += icco.extlen;
|
||||
|
|
@ -675,7 +667,7 @@ int CSIDevice_AMBaseboard::RunBuffer(u8* buffer, int request_length)
|
|||
}
|
||||
case ICCARDCommand::ReadPages:
|
||||
{
|
||||
const u16 page = Common::swap16(data_in + 6);
|
||||
const u16 page = Common::swap16(data_in + 6) & 0xFF; // 255 is max page
|
||||
const u16 count = Common::swap16(data_in + 8);
|
||||
|
||||
const u32 offs = page * 8;
|
||||
|
|
@ -701,7 +693,7 @@ int CSIDevice_AMBaseboard::RunBuffer(u8* buffer, int request_length)
|
|||
{
|
||||
const u16 pksize = length;
|
||||
const u16 size = Common::swap16(data_in + 2);
|
||||
const u16 page = Common::swap16(data_in + 6);
|
||||
const u16 page = Common::swap16(data_in + 6) & 0xFF; // 255 is max page
|
||||
const u16 count = Common::swap16(data_in + 8);
|
||||
|
||||
// We got a complete packet
|
||||
|
|
@ -713,7 +705,17 @@ int CSIDevice_AMBaseboard::RunBuffer(u8* buffer, int request_length)
|
|||
}
|
||||
else
|
||||
{
|
||||
memcpy(m_ic_card_data + page * 8, data_in + 13, count * 8);
|
||||
if (page * 8 + count * 8 > sizeof(m_ic_card_data))
|
||||
{
|
||||
ERROR_LOG_FMT(
|
||||
SERIALINTERFACE_CARD,
|
||||
"GC-AM: Command 0x31 (IC-CARD) Data overflow: Pages:{} Count:{}({:x})",
|
||||
page, count, size);
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(m_ic_card_data + page * 8, data_in + 13, count * 8);
|
||||
}
|
||||
}
|
||||
|
||||
INFO_LOG_FMT(SERIALINTERFACE_CARD,
|
||||
|
|
@ -877,14 +879,8 @@ int CSIDevice_AMBaseboard::RunBuffer(u8* buffer, int request_length)
|
|||
INFO_LOG_FMT(SERIALINTERFACE_AMBB, "GC-AM: Command 0x31 (SERIAL) Command:{:06x}",
|
||||
serial_command);
|
||||
|
||||
if (/*command == 0xf43200 || */ serial_command == 0x801000)
|
||||
if (serial_command == 0x801000)
|
||||
{
|
||||
// u32 PC = m_system.GetPowerPC().GetPPCState().pc;
|
||||
|
||||
// INFO_LOG_FMT(SERIALINTERFACE_AMBB, "GCAM: PC:{:08x}", PC);
|
||||
|
||||
// m_system.GetPowerPC().GetBreakPoints().Add(PC + 8, true, true, std::nullopt);
|
||||
|
||||
data_out[data_offset++] = 0x31;
|
||||
data_out[data_offset++] = 0x02;
|
||||
data_out[data_offset++] = 0xFF;
|
||||
|
|
@ -1025,7 +1021,7 @@ int CSIDevice_AMBaseboard::RunBuffer(u8* buffer, int request_length)
|
|||
const u32 command_length_offset = data_offset;
|
||||
data_out[data_offset++] = 0x00; // len
|
||||
|
||||
data_out[data_offset++] = 0x02; //
|
||||
data_out[data_offset++] = 0x02;
|
||||
const u32 checksum_start = data_offset;
|
||||
|
||||
data_out[data_offset++] = 0x00; // 0x00 len
|
||||
|
|
@ -1382,12 +1378,16 @@ int CSIDevice_AMBaseboard::RunBuffer(u8* buffer, int request_length)
|
|||
static int delay = 0;
|
||||
|
||||
const u8* frame = &data_in[0];
|
||||
const u8 nr_bytes = frame[3]; // Byte after E0 xx
|
||||
const u32 frame_len = nr_bytes + 3; // Header(2) + length byte + payload + checksum
|
||||
|
||||
// TODO: frame_len isn't checked for buffer overflow.
|
||||
const u8 nr_bytes = frame[3]; // Byte after E0 xx
|
||||
u32 frame_len = nr_bytes + 3; // Header(2) + length byte + payload + checksum
|
||||
|
||||
u8 jvs_buf[0x80];
|
||||
|
||||
if (frame_len > sizeof(jvs_buf))
|
||||
{
|
||||
frame_len = sizeof(jvs_buf);
|
||||
}
|
||||
|
||||
memcpy(jvs_buf, frame, frame_len);
|
||||
|
||||
// Extract node and payload pointers
|
||||
|
|
@ -2123,18 +2123,15 @@ int CSIDevice_AMBaseboard::RunBuffer(u8* buffer, int request_length)
|
|||
data_in = buffer;
|
||||
data_out[1] = data_offset - 2;
|
||||
checksum = 0;
|
||||
char logptr[1024];
|
||||
char* log = logptr;
|
||||
|
||||
for (int i = 0; i < 0x7F; ++i)
|
||||
{
|
||||
checksum += data_in[i] = data_out[i];
|
||||
log += sprintf(log, "%02X", data_in[i]);
|
||||
}
|
||||
data_in[0x7f] = ~checksum;
|
||||
DEBUG_LOG_FMT(SERIALINTERFACE_AMBB, "Command send back: {}", logptr);
|
||||
DEBUG_LOG_FMT(SERIALINTERFACE_AMBB, "Command send back: {}", HexDump(data_out.data(), 0x7F));
|
||||
|
||||
swap_buffers(buffer, &buffer_length);
|
||||
SwapBuffers(buffer, &buffer_length);
|
||||
|
||||
buffer_position = buffer_length;
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -19,22 +19,90 @@ namespace SerialInterface
|
|||
class JVSIOMessage
|
||||
{
|
||||
public:
|
||||
u32 m_ptr = 0;
|
||||
u32 m_last_start = 0;
|
||||
u32 m_csum = 0;
|
||||
std::array<u8, 0x80> m_msg;
|
||||
|
||||
void Start(int node);
|
||||
void AddData(const u8* dst, std::size_t len, int sync);
|
||||
void AddData(const void* data, std::size_t len);
|
||||
void AddData(const char* data);
|
||||
void AddData(u32 n);
|
||||
void End();
|
||||
|
||||
u32 m_ptr = 0;
|
||||
std::array<u8, 0x80> m_msg;
|
||||
|
||||
private:
|
||||
u32 m_last_start = 0;
|
||||
u32 m_csum = 0;
|
||||
};
|
||||
|
||||
// Triforce (GC-AM) baseboard
|
||||
class CSIDevice_AMBaseboard : public ISIDevice
|
||||
{
|
||||
enum EButtonCombo
|
||||
{
|
||||
COMBO_NONE = 0,
|
||||
COMBO_ORIGIN,
|
||||
COMBO_RESET
|
||||
};
|
||||
|
||||
public:
|
||||
// constructor
|
||||
CSIDevice_AMBaseboard(Core::System& system, SIDevices device, int device_number);
|
||||
|
||||
// run the SI Buffer
|
||||
int RunBuffer(u8* buffer, int request_length) override;
|
||||
|
||||
// Reply has to be delayed due a bug in the parser
|
||||
void SwapBuffers(u8* buffer, u32* buffer_length);
|
||||
|
||||
// return true on new data
|
||||
DataResponse GetData(u32& hi, u32& low) override;
|
||||
|
||||
// send a command directly
|
||||
void SendCommand(u32 command, u8 poll) override;
|
||||
|
||||
virtual GCPadStatus GetPadStatus();
|
||||
virtual u32 MapPadStatus(const GCPadStatus& pad_status);
|
||||
virtual EButtonCombo HandleButtonCombos(const GCPadStatus& pad_status);
|
||||
|
||||
static void HandleMoviePadStatus(Movie::MovieManager& movie, int device_number,
|
||||
GCPadStatus* pad_status);
|
||||
|
||||
// Send and Receive pad input from network
|
||||
static bool NetPlay_GetInput(int pad_num, GCPadStatus* status);
|
||||
static int NetPlay_InGamePadToLocalPad(int pad_num);
|
||||
|
||||
protected:
|
||||
struct SOrigin
|
||||
{
|
||||
u16 button;
|
||||
u8 origin_stick_x;
|
||||
u8 origin_stick_y;
|
||||
u8 substick_x;
|
||||
u8 substick_y;
|
||||
u8 trigger_left;
|
||||
u8 trigger_right;
|
||||
u8 unk_4;
|
||||
u8 unk_5;
|
||||
};
|
||||
|
||||
// struct to compare input against
|
||||
// Set on connection to perfect neutral values
|
||||
// (standard pad only) Set on button combo to current input state
|
||||
SOrigin m_origin = {};
|
||||
|
||||
// PADAnalogMode
|
||||
// Dunno if we need to do this, game/lib should set it?
|
||||
u8 m_mode = 0x3;
|
||||
|
||||
// Timer to track special button combos:
|
||||
// y, X, start for 3 seconds updates origin with current status
|
||||
// Technically, the above is only on standard pad, wavebird does not support it for example
|
||||
// b, x, start for 3 seconds triggers reset (PI reset button interrupt)
|
||||
u64 m_timer_button_combo_start = 0;
|
||||
// Type of button combo from the last/current poll
|
||||
EButtonCombo m_last_button_combo = COMBO_NONE;
|
||||
void SetOrigin(const GCPadStatus& pad_status);
|
||||
|
||||
private:
|
||||
enum BaseBoardCommand
|
||||
{
|
||||
|
|
@ -190,6 +258,9 @@ private:
|
|||
};
|
||||
};
|
||||
|
||||
u8 m_last[2][0x80];
|
||||
u32 m_lastptr[2];
|
||||
|
||||
u16 m_coin[2];
|
||||
u32 m_coin_pressed[2];
|
||||
|
||||
|
|
@ -238,71 +309,6 @@ private:
|
|||
bool m_fzcc_service;
|
||||
|
||||
void ICCardSendReply(ICCommand* iccommand, u8* buffer, u32* length);
|
||||
|
||||
protected:
|
||||
struct SOrigin
|
||||
{
|
||||
u16 button;
|
||||
u8 origin_stick_x;
|
||||
u8 origin_stick_y;
|
||||
u8 substick_x;
|
||||
u8 substick_y;
|
||||
u8 trigger_left;
|
||||
u8 trigger_right;
|
||||
u8 unk_4;
|
||||
u8 unk_5;
|
||||
};
|
||||
|
||||
enum EButtonCombo
|
||||
{
|
||||
COMBO_NONE = 0,
|
||||
COMBO_ORIGIN,
|
||||
COMBO_RESET
|
||||
};
|
||||
|
||||
// struct to compare input against
|
||||
// Set on connection to perfect neutral values
|
||||
// (standard pad only) Set on button combo to current input state
|
||||
SOrigin m_origin = {};
|
||||
|
||||
// PADAnalogMode
|
||||
// Dunno if we need to do this, game/lib should set it?
|
||||
u8 m_mode = 0x3;
|
||||
|
||||
// Timer to track special button combos:
|
||||
// y, X, start for 3 seconds updates origin with current status
|
||||
// Technically, the above is only on standard pad, wavebird does not support it for example
|
||||
// b, x, start for 3 seconds triggers reset (PI reset button interrupt)
|
||||
u64 m_timer_button_combo_start = 0;
|
||||
// Type of button combo from the last/current poll
|
||||
EButtonCombo m_last_button_combo = COMBO_NONE;
|
||||
|
||||
public:
|
||||
// constructor
|
||||
CSIDevice_AMBaseboard(Core::System& system, SIDevices device, int device_number);
|
||||
|
||||
// run the SI Buffer
|
||||
int RunBuffer(u8* buffer, int request_length) override;
|
||||
|
||||
// return true on new data
|
||||
DataResponse GetData(u32& hi, u32& low) override;
|
||||
|
||||
// send a command directly
|
||||
void SendCommand(u32 command, u8 poll) override;
|
||||
|
||||
virtual GCPadStatus GetPadStatus();
|
||||
virtual u32 MapPadStatus(const GCPadStatus& pad_status);
|
||||
virtual EButtonCombo HandleButtonCombos(const GCPadStatus& pad_status);
|
||||
|
||||
static void HandleMoviePadStatus(Movie::MovieManager& movie, int device_number,
|
||||
GCPadStatus* pad_status);
|
||||
|
||||
// Send and Receive pad input from network
|
||||
static bool NetPlay_GetInput(int pad_num, GCPadStatus* status);
|
||||
static int NetPlay_InGamePadToLocalPad(int pad_num);
|
||||
|
||||
protected:
|
||||
void SetOrigin(const GCPadStatus& pad_status);
|
||||
};
|
||||
|
||||
} // namespace SerialInterface
|
||||
|
|
|
|||
|
|
@ -516,8 +516,6 @@ void MainWindow::CreateComponents()
|
|||
});
|
||||
connect(m_breakpoint_widget, &BreakpointWidget::ShowMemory, m_memory_widget,
|
||||
&MemoryWidget::SetAddress);
|
||||
connect(m_cheats_manager, &CheatsManager::ShowMemory, m_memory_widget, &MemoryWidget::SetAddress);
|
||||
connect(m_cheats_manager, &CheatsManager::RequestWatch, request_watch);
|
||||
}
|
||||
|
||||
void MainWindow::ConnectMenuBar()
|
||||
|
|
@ -1159,9 +1157,7 @@ void MainWindow::StartGame(std::unique_ptr<BootParameters>&& parameters)
|
|||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
When booting Triforce games, we need to ensure that the hardware is set up correctly.
|
||||
*/
|
||||
// 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();
|
||||
|
||||
|
|
@ -1184,15 +1180,20 @@ void MainWindow::StartGame(std::unique_ptr<BootParameters>&& parameters)
|
|||
}
|
||||
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)
|
||||
// Some Triforce tools don't include a boot.id file, but they can still be launched.
|
||||
if (triforce_hardware_sp1)
|
||||
{
|
||||
ModalMessageBox::warning(
|
||||
this, tr("Warning"),
|
||||
tr("Non-Triforce games cannot be booted with Triforce hardware attached."),
|
||||
QMessageBox::Ok);
|
||||
ModalMessageBox::warning(this, tr("Warning"),
|
||||
tr("Non-Triforce games cannot be booted with Triforce hardware "
|
||||
"attached.\nPlease remove the Triforce Baseboard from SP1."),
|
||||
QMessageBox::Ok);
|
||||
}
|
||||
if (triforce_hardware_port_1)
|
||||
{
|
||||
ModalMessageBox::warning(this, tr("Warning"),
|
||||
tr("Non-Triforce games cannot be booted with Triforce hardware "
|
||||
"attached.\nPlease remove the Triforce Baseboard from Port 1."),
|
||||
QMessageBox::Ok);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user