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:
crediar 2025-11-06 23:44:17 +01:00 committed by Jordan Woyak
parent be2da8dc7b
commit ce802f1e62
10 changed files with 512 additions and 436 deletions

View File

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

View File

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

View File

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

View File

@ -105,7 +105,6 @@ CEXIBaseboard::CEXIBaseboard(Core::System& system) : IEXIDevice(system)
CEXIBaseboard::~CEXIBaseboard()
{
m_backup.Close();
}
void CEXIBaseboard::SetCS(int cs)

View File

@ -54,6 +54,6 @@ private:
File::IOFile m_backup;
protected:
void TransferByte(u8& _uByte) override;
void TransferByte(u8& byte) override;
};
} // namespace ExpansionInterface

View File

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

View File

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

View File

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

View File

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