From 009d8e13dac86ed8f73d58ffd0e9b073c788f628 Mon Sep 17 00:00:00 2001 From: brian218 Date: Wed, 6 Sep 2023 23:10:30 +0800 Subject: [PATCH] USIO: Support up to 4 players for Tekken Tag Tournament 2 Pair Play mode --- rpcs3/Emu/Io/usio.cpp | 90 +++++++++++++++++++++----------------- rpcs3/Emu/Io/usio.h | 14 ++++-- rpcs3/Emu/Io/usio_config.h | 4 +- 3 files changed, 62 insertions(+), 46 deletions(-) diff --git a/rpcs3/Emu/Io/usio.cpp b/rpcs3/Emu/Io/usio.cpp index a5b4348937..668a3685f6 100644 --- a/rpcs3/Emu/Io/usio.cpp +++ b/rpcs3/Emu/Io/usio.cpp @@ -186,7 +186,7 @@ void usb_device_usio::translate_input_taiko() std::lock_guard lock(pad::g_pad_mutex); const auto handler = pad::get_current_handler(); - std::vector input_buf(96); + std::vector input_buf(0x60); constexpr le_t c_hit = 0x1800; le_t digital_input = 0; @@ -204,6 +204,7 @@ void usb_device_usio::translate_input_taiko() } const usz offset = player * 8ULL; + auto& status = m_io_status[0]; const auto& cfg = ::at32(g_cfg_usio.players, pad_number); cfg->handle_input(pad, false, [&](usio_btn btn, u16 /*value*/, bool pressed) @@ -212,15 +213,15 @@ void usb_device_usio::translate_input_taiko() { case usio_btn::test: if (player != 0) break; - if (pressed && !test_key_pressed) // Solve the need to hold the Test key - test_on = !test_on; - test_key_pressed = pressed; + if (pressed && !status.test_key_pressed) // Solve the need to hold the Test key + status.test_on = !status.test_on; + status.test_key_pressed = pressed; break; case usio_btn::coin: if (player != 0) break; - if (pressed && !coin_key_pressed) // Ensure only one coin is inserted each time the Coin key is pressed - coin_counter++; - coin_key_pressed = pressed; + if (pressed && !status.coin_key_pressed) // Ensure only one coin is inserted each time the Coin key is pressed + status.coin_counter++; + status.coin_key_pressed = pressed; break; case usio_btn::service: if (player == 0 && pressed) @@ -258,14 +259,16 @@ void usb_device_usio::translate_input_taiko() break; } }); + + if (player == 0 && status.test_on) + digital_input |= 0x80; }; for (usz i = 0; i < g_cfg_usio.players.size(); i++) translate_from_pad(i, i); - digital_input |= test_on ? 0x80 : 0x00; std::memcpy(input_buf.data(), &digital_input, sizeof(u16)); - std::memcpy(input_buf.data() + 16, &coin_counter, sizeof(u16)); + std::memcpy(input_buf.data() + 16, &m_io_status[0].coin_counter, sizeof(u16)); response = std::move(input_buf); } @@ -275,8 +278,8 @@ void usb_device_usio::translate_input_tekken() std::lock_guard lock(pad::g_pad_mutex); const auto handler = pad::get_current_handler(); - std::vector input_buf(256); - le_t digital_input = 0; + std::vector input_buf(0x180); + le_t digital_input[2]{}; le_t digital_input_lm = 0; auto translate_from_pad = [&](usz pad_number, usz player) @@ -292,7 +295,9 @@ void usb_device_usio::translate_input_tekken() return; } - const usz shift = player * 24ULL; + const usz shift = (player % 2) * 24ULL; + auto& status = m_io_status[player / 2]; + auto& input = digital_input[player / 2]; const auto& cfg = ::at32(g_cfg_usio.players, pad_number); cfg->handle_input(pad, false, [&](usio_btn btn, u16 /*value*/, bool pressed) @@ -300,27 +305,27 @@ void usb_device_usio::translate_input_tekken() switch (btn) { case usio_btn::test: - if (player != 0) + if (player % 2 != 0) break; - if (pressed && !test_key_pressed) // Solve the need to hold the Test button - test_on = !test_on; - test_key_pressed = pressed; + if (pressed && !status.test_key_pressed) // Solve the need to hold the Test button + status.test_on = !status.test_on; + status.test_key_pressed = pressed; break; case usio_btn::coin: - if (player != 0) + if (player % 2 != 0) break; - if (pressed && !coin_key_pressed) // Ensure only one coin is inserted each time the Coin button is pressed - coin_counter++; - coin_key_pressed = pressed; + if (pressed && !status.coin_key_pressed) // Ensure only one coin is inserted each time the Coin button is pressed + status.coin_counter++; + status.coin_key_pressed = pressed; break; case usio_btn::service: - if (player == 0 && pressed) - digital_input |= 0x4000; + if (player % 2 == 0 && pressed) + input |= 0x4000; break; case usio_btn::enter: if (pressed) { - digital_input |= 0x800000ULL << shift; + input |= 0x800000ULL << shift; if (player == 0) digital_input_lm |= 0x800; } @@ -328,7 +333,7 @@ void usb_device_usio::translate_input_tekken() case usio_btn::up: if (pressed) { - digital_input |= 0x200000ULL << shift; + input |= 0x200000ULL << shift; if (player == 0) digital_input_lm |= 0x200; } @@ -336,7 +341,7 @@ void usb_device_usio::translate_input_tekken() case usio_btn::down: if (pressed) { - digital_input |= 0x100000ULL << shift; + input |= 0x100000ULL << shift; if (player == 0) digital_input_lm |= 0x400; } @@ -344,7 +349,7 @@ void usb_device_usio::translate_input_tekken() case usio_btn::left: if (pressed) { - digital_input |= 0x80000ULL << shift; + input |= 0x80000ULL << shift; if (player == 0) digital_input_lm |= 0x2000; } @@ -352,7 +357,7 @@ void usb_device_usio::translate_input_tekken() case usio_btn::right: if (pressed) { - digital_input |= 0x40000ULL << shift; + input |= 0x40000ULL << shift; if (player == 0) digital_input_lm |= 0x4000; } @@ -360,47 +365,52 @@ void usb_device_usio::translate_input_tekken() case usio_btn::tekken_button1: if (pressed) { - digital_input |= 0x20000ULL << shift; + input |= 0x20000ULL << shift; if (player == 0) digital_input_lm |= 0x100; } break; case usio_btn::tekken_button2: if (pressed) - digital_input |= 0x10000ULL << shift; + input |= 0x10000ULL << shift; break; case usio_btn::tekken_button3: if (pressed) - digital_input |= 0x40000000ULL << shift; + input |= 0x40000000ULL << shift; break; case usio_btn::tekken_button4: if (pressed) - digital_input |= 0x20000000ULL << shift; + input |= 0x20000000ULL << shift; break; case usio_btn::tekken_button5: if (pressed) - digital_input |= 0x80000000ULL << shift; + input |= 0x80000000ULL << shift; break; default: break; } }); + + if (player % 2 == 0 && status.test_on) + { + input |= 0x80; + if (player == 0) + digital_input_lm |= 0x1000; + } }; for (usz i = 0; i < g_cfg_usio.players.size(); i++) translate_from_pad(i, i); - if (test_on) + for (usz i = 0; i < 2; i++) { - digital_input |= 0x80; - digital_input_lm |= 0x1000; + std::memcpy(input_buf.data() - i * 0x80 + 0x100, &digital_input[i], sizeof(u64)); + std::memcpy(input_buf.data() - i * 0x80 + 0x100 + 0x10, &m_io_status[i].coin_counter, sizeof(u16)); } - std::memcpy(input_buf.data() + 128, &digital_input, sizeof(u64)); - std::memcpy(input_buf.data() + 128 + 16, &coin_counter, sizeof(u16)); std::memcpy(input_buf.data(), &digital_input_lm, sizeof(u16)); - input_buf[2] = 0b00010000; // DIP Switches, 8 in total + input_buf[2] = 0b00010000; // DIP switches, 8 in total response = std::move(input_buf); } @@ -489,7 +499,7 @@ void usb_device_usio::usio_read(u8 channel, u16 reg, u16 size) // Get Buffer, rarely gives a reply on real HW // First U16 seems to be a timestamp of sort // Purpose seems related to connectivity check - response = {0x7E, 0xE4, 0x00, 0x00, 0x74, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0x00, 0x7E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + response = {0x7E, 0xE4, 0x00, 0x00, 0x74, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0x00, 0x7E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; break; } case 0x0080: @@ -522,7 +532,7 @@ void usb_device_usio::usio_read(u8 channel, u16 reg, u16 size) // Seems to contain a few extra bytes of info in addition to the firmware string // Firmware // "NBGI.;USIO01;Ver1.00;JPN,Multipurpose with PPG." - constexpr std::array info {0x4E, 0x42, 0x47, 0x49, 0x2E, 0x3B, 0x55, 0x53, 0x49, 0x4F, 0x30, 0x31, 0x3B, 0x56, 0x65, 0x72, 0x31, 0x2E, 0x30, 0x30, 0x3B, 0x4A, 0x50, 0x4E, 0x2C, 0x4D, 0x75, 0x6C, 0x74, 0x69, 0x70, 0x75, 0x72, 0x70, 0x6F, 0x73, 0x65, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x50, 0x50, 0x47, 0x2E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4E, 0x42, 0x47, 0x49, 0x2E, 0x3B, 0x55, 0x53, 0x49, 0x4F, 0x30, 0x31, 0x3B, 0x56, 0x65, 0x72, 0x31, 0x2E, 0x30, 0x30, 0x3B, 0x4A, 0x50, 0x4E, 0x2C, 0x4D, 0x75, 0x6C, 0x74, 0x69, 0x70, 0x75, 0x72, 0x70, 0x6F, 0x73, 0x65, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x50, 0x50, 0x47, 0x2E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x13, 0x00, 0x30, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x03, 0x02, 0x00, 0x08, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x03, 0x00, 0x75, 0x6C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + constexpr std::array info {0x4E, 0x42, 0x47, 0x49, 0x2E, 0x3B, 0x55, 0x53, 0x49, 0x4F, 0x30, 0x31, 0x3B, 0x56, 0x65, 0x72, 0x31, 0x2E, 0x30, 0x30, 0x3B, 0x4A, 0x50, 0x4E, 0x2C, 0x4D, 0x75, 0x6C, 0x74, 0x69, 0x70, 0x75, 0x72, 0x70, 0x6F, 0x73, 0x65, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x50, 0x50, 0x47, 0x2E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4E, 0x42, 0x47, 0x49, 0x31, 0x3B, 0x55, 0x53, 0x49, 0x4F, 0x30, 0x31, 0x3B, 0x56, 0x65, 0x72, 0x31, 0x2E, 0x30, 0x30, 0x3B, 0x4A, 0x50, 0x4E, 0x2C, 0x4D, 0x75, 0x6C, 0x74, 0x69, 0x70, 0x75, 0x72, 0x70, 0x6F, 0x73, 0x65, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x50, 0x50, 0x47, 0x2E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x13, 0x00, 0x30, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x03, 0x02, 0x00, 0x08, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x03, 0x00, 0x75, 0x6C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4E, 0x42, 0x47, 0x49, 0x32, 0x3B, 0x55, 0x53, 0x49, 0x4F, 0x30, 0x31, 0x3B, 0x56, 0x65, 0x72, 0x31, 0x2E, 0x30, 0x30, 0x3B, 0x4A, 0x50, 0x4E, 0x2C, 0x4D, 0x75, 0x6C, 0x74, 0x69, 0x70, 0x75, 0x72, 0x70, 0x6F, 0x73, 0x65, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x50, 0x50, 0x47, 0x2E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x13, 0x00, 0x30, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x03, 0x02, 0x00, 0x08, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x03, 0x00, 0x75, 0x6C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; response = {info.begin() + (reg - 0x1800), info.end()}; break; } diff --git a/rpcs3/Emu/Io/usio.h b/rpcs3/Emu/Io/usio.h index 98543fe122..512b33d4b4 100644 --- a/rpcs3/Emu/Io/usio.h +++ b/rpcs3/Emu/Io/usio.h @@ -21,11 +21,17 @@ private: void usio_read(u8 channel, u16 reg, u16 size); private: - bool test_on = false; - bool test_key_pressed = false; - bool coin_key_pressed = false; bool is_used = false; - le_t coin_counter = 0; const std::string usio_backup_path = rpcs3::utils::get_hdd1_dir() + "/caches/usiobackup.bin"; std::vector response; + + struct io_status + { + bool test_on = false; + bool test_key_pressed = false; + bool coin_key_pressed = false; + le_t coin_counter = 0; + }; + + std::array m_io_status; }; diff --git a/rpcs3/Emu/Io/usio_config.h b/rpcs3/Emu/Io/usio_config.h index 91e5f74934..1ca078b2a4 100644 --- a/rpcs3/Emu/Io/usio_config.h +++ b/rpcs3/Emu/Io/usio_config.h @@ -50,9 +50,9 @@ struct cfg_usio final : public emulated_pad_config cfg_pad_btn tekken_button5{this, "Tekken Button 5", usio_btn::tekken_button5, pad_button::R1}; }; -struct cfg_usios final : public emulated_pads_config +struct cfg_usios final : public emulated_pads_config { - cfg_usios() : emulated_pads_config("usio") {}; + cfg_usios() : emulated_pads_config("usio") {}; }; extern cfg_usios g_cfg_usio;