mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-03-29 22:20:48 +00:00
USIO: Emulation Performance Optimization
This commit is contained in:
parent
43288a6760
commit
cf1e68fb0e
@ -3,9 +3,7 @@
|
|||||||
|
|
||||||
#include "stdafx.h"
|
#include "stdafx.h"
|
||||||
#include "usio.h"
|
#include "usio.h"
|
||||||
#include "Emu/Cell/lv2/sys_usbd.h"
|
|
||||||
#include "Input/pad_thread.h"
|
#include "Input/pad_thread.h"
|
||||||
#include "Emu/System.h"
|
|
||||||
#include "Emu/IdManager.h"
|
#include "Emu/IdManager.h"
|
||||||
#include "Emu/system_utils.hpp"
|
#include "Emu/system_utils.hpp"
|
||||||
|
|
||||||
@ -120,7 +118,7 @@ void usb_device_usio::load_backup()
|
|||||||
|
|
||||||
if (usio_backup_file.size() != file_size)
|
if (usio_backup_file.size() != file_size)
|
||||||
{
|
{
|
||||||
usio_log.trace("Invalid USIO Backup file detected. Treating it as an empty file: %s", usio_backup_path);
|
usio_log.trace("Invalid USIO Backup file detected: %s", usio_backup_path);
|
||||||
usio_backup_file.trunc(file_size);
|
usio_backup_file.trunc(file_size);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -130,8 +128,9 @@ void usb_device_usio::load_backup()
|
|||||||
|
|
||||||
void usb_device_usio::save_backup()
|
void usb_device_usio::save_backup()
|
||||||
{
|
{
|
||||||
if (!usio_backup_file)
|
if (!usio_backup_file && !usio_backup_path.empty() && !usio_backup_file.open(usio_backup_path, fs::create + fs::write + fs::lock))
|
||||||
{
|
{
|
||||||
|
usio_log.error("Failed to create a new USIO Backup file: %s", usio_backup_path);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -144,7 +143,7 @@ void usb_device_usio::translate_input()
|
|||||||
std::lock_guard lock(pad::g_pad_mutex);
|
std::lock_guard lock(pad::g_pad_mutex);
|
||||||
const auto handler = pad::get_current_handler();
|
const auto handler = pad::get_current_handler();
|
||||||
|
|
||||||
std::vector<u8> input_buf = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
std::vector<u8> input_buf = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0xFF, 0xFF, 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};
|
||||||
constexpr le_t<u16> c_small_hit = 0x4D0;
|
constexpr le_t<u16> c_small_hit = 0x4D0;
|
||||||
constexpr le_t<u16> c_big_hit = 0x1800;
|
constexpr le_t<u16> c_big_hit = 0x1800;
|
||||||
le_t<u16> test_keys = 0x0000;
|
le_t<u16> test_keys = 0x0000;
|
||||||
@ -263,23 +262,23 @@ void usb_device_usio::translate_input()
|
|||||||
std::memcpy(input_buf.data(), &test_keys, sizeof(u16));
|
std::memcpy(input_buf.data(), &test_keys, sizeof(u16));
|
||||||
std::memcpy(input_buf.data() + 16, &coin_counter, sizeof(u16));
|
std::memcpy(input_buf.data() + 16, &coin_counter, sizeof(u16));
|
||||||
|
|
||||||
q_replies.push(input_buf);
|
response = std::move(input_buf);
|
||||||
q_replies.push({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});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void usb_device_usio::usio_write(u8 channel, u16 reg, const std::vector<u8>& data)
|
void usb_device_usio::usio_write(u8 channel, u16 reg, std::vector<u8>& data)
|
||||||
{
|
{
|
||||||
auto write_memory = [&](std::vector<u8>& memory, bool exact_size = true)
|
auto write_memory = [&](std::vector<u8>& memory)
|
||||||
{
|
{
|
||||||
ensure(data.size() == memory.size() || (data.size() <= memory.size() && !exact_size));
|
auto size = memory.size();
|
||||||
memcpy(memory.data(), data.data(), data.size());
|
memory = std::move(data);
|
||||||
|
memory.resize(size);
|
||||||
};
|
};
|
||||||
|
|
||||||
const auto get_u16 = [&](std::string_view usio_func) -> u16
|
const auto get_u16 = [&](std::string_view usio_func) -> u16
|
||||||
{
|
{
|
||||||
if (data.size() != 2)
|
if (data.size() != 2)
|
||||||
{
|
{
|
||||||
usio_log.fatal("data.size() is %d, expected 2 for get_u16 in %s", data.size(), usio_func);
|
usio_log.error("data.size() is %d, expected 2 for get_u16 in %s", data.size(), usio_func);
|
||||||
}
|
}
|
||||||
return *reinterpret_cast<const le_t<u16>*>(data.data());
|
return *reinterpret_cast<const le_t<u16>*>(data.data());
|
||||||
};
|
};
|
||||||
@ -290,19 +289,18 @@ void usb_device_usio::usio_write(u8 channel, u16 reg, const std::vector<u8>& dat
|
|||||||
{
|
{
|
||||||
case 0x0002:
|
case 0x0002:
|
||||||
{
|
{
|
||||||
usio_log.notice("SetSystemError: 0x%04X", get_u16("SetSystemError"));
|
usio_log.trace("SetSystemError: 0x%04X", get_u16("SetSystemError"));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 0x000A:
|
case 0x000A:
|
||||||
{
|
{
|
||||||
u16 command = get_u16("ClearSram");
|
if (get_u16("ClearSram") == 0x6666)
|
||||||
ensure(command == 0x6666, "USIO: Unexpected Command instead of ClearSram");
|
usio_log.trace("ClearSram");
|
||||||
usio_log.notice("ClearSram");
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 0x0028:
|
case 0x0028:
|
||||||
{
|
{
|
||||||
usio_log.notice("SetExpansionMode: 0x%04X", get_u16("SetExpansionMode"));
|
usio_log.trace("SetExpansionMode: 0x%04X", get_u16("SetExpansionMode"));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 0x0048:
|
case 0x0048:
|
||||||
@ -310,7 +308,7 @@ void usb_device_usio::usio_write(u8 channel, u16 reg, const std::vector<u8>& dat
|
|||||||
case 0x0068:
|
case 0x0068:
|
||||||
case 0x0078:
|
case 0x0078:
|
||||||
{
|
{
|
||||||
usio_log.notice("SetHopperRequest(Hopper: %d, Request: 0x%04X)", (reg - 0x48) / 0x10, get_u16("SetHopperRequest"));
|
usio_log.trace("SetHopperRequest(Hopper: %d, Request: 0x%04X)", (reg - 0x48) / 0x10, get_u16("SetHopperRequest"));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 0x004A:
|
case 0x004A:
|
||||||
@ -318,7 +316,7 @@ void usb_device_usio::usio_write(u8 channel, u16 reg, const std::vector<u8>& dat
|
|||||||
case 0x006A:
|
case 0x006A:
|
||||||
case 0x007A:
|
case 0x007A:
|
||||||
{
|
{
|
||||||
usio_log.notice("SetHopperRequest(Hopper: %d, Limit: 0x%04X)", (reg - 0x4A) / 0x10, get_u16("SetHopperLimit"));
|
usio_log.trace("SetHopperRequest(Hopper: %d, Limit: 0x%04X)", (reg - 0x4A) / 0x10, get_u16("SetHopperLimit"));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
@ -337,7 +335,7 @@ void usb_device_usio::usio_write(u8 channel, u16 reg, const std::vector<u8>& dat
|
|||||||
{
|
{
|
||||||
case 0x0000:
|
case 0x0000:
|
||||||
{
|
{
|
||||||
write_memory(g_fxo->get<usio_memory>().backup_memory, false);
|
write_memory(g_fxo->get<usio_memory>().backup_memory);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 0x0180:
|
case 0x0180:
|
||||||
@ -358,34 +356,6 @@ void usb_device_usio::usio_write(u8 channel, u16 reg, const std::vector<u8>& dat
|
|||||||
|
|
||||||
void usb_device_usio::usio_read(u8 channel, u16 reg, u16 size)
|
void usb_device_usio::usio_read(u8 channel, u16 reg, u16 size)
|
||||||
{
|
{
|
||||||
auto push_zeroes = [&]()
|
|
||||||
{
|
|
||||||
// Give it 00s
|
|
||||||
std::vector<u8> zeroes;
|
|
||||||
u16 left = size;
|
|
||||||
while (left > 0)
|
|
||||||
{
|
|
||||||
u16 to_push = std::min(left, static_cast<u16>(64));
|
|
||||||
zeroes.resize(to_push);
|
|
||||||
q_replies.push(zeroes);
|
|
||||||
left -= to_push;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
auto push_vector = [&](std::vector<u8>& memory)
|
|
||||||
{
|
|
||||||
std::vector<u8> buffer;
|
|
||||||
u16 left = size;
|
|
||||||
while (left > 0)
|
|
||||||
{
|
|
||||||
u16 to_push = std::min(left, static_cast<u16>(64));
|
|
||||||
buffer.resize(to_push);
|
|
||||||
memcpy(buffer.data(), memory.data() + (size - left), buffer.size());
|
|
||||||
q_replies.push(buffer);
|
|
||||||
left -= to_push;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if (channel == 0)
|
if (channel == 0)
|
||||||
{
|
{
|
||||||
switch (reg)
|
switch (reg)
|
||||||
@ -395,21 +365,19 @@ void usb_device_usio::usio_read(u8 channel, u16 reg, u16 size)
|
|||||||
// Get Buffer, rarely gives a reply on real HW
|
// Get Buffer, rarely gives a reply on real HW
|
||||||
// First U16 seems to be a timestamp of sort
|
// First U16 seems to be a timestamp of sort
|
||||||
// Purpose seems related to connectivity check
|
// Purpose seems related to connectivity check
|
||||||
q_replies.push({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, 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};
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 0x0080:
|
case 0x0080:
|
||||||
{
|
{
|
||||||
// Card reader check - 1
|
// Card reader check - 1
|
||||||
ensure(size == 0x10);
|
response = {0x02, 0x03, 0x06, 0x00, 0xFF, 0x0F, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x10, 0x00};
|
||||||
q_replies.push({0x02, 0x03, 0x06, 0x00, 0xFF, 0x0F, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x10, 0x00});
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 0x7000:
|
case 0x7000:
|
||||||
{
|
{
|
||||||
// Card reader check - 2
|
// Card reader check - 2
|
||||||
ensure(size == 0x06);
|
response.resize(size);
|
||||||
// No data returned
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 0x1080:
|
case 0x1080:
|
||||||
@ -420,28 +388,22 @@ void usb_device_usio::usio_read(u8 channel, u16 reg, u16 size)
|
|||||||
}
|
}
|
||||||
case 0x1800:
|
case 0x1800:
|
||||||
{
|
{
|
||||||
usio_log.trace("Firmware Query on 0x1800");
|
|
||||||
ensure(size == 0x70);
|
|
||||||
// Firmware
|
// Firmware
|
||||||
// "NBGI.;USIO01;Ver1.00;JPN,Multipurpose with PPG."
|
// "NBGI.;USIO01;Ver1.00;JPN,Multipurpose with PPG."
|
||||||
q_replies.push({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});
|
response = {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};
|
||||||
q_replies.push({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});
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 0x1880:
|
case 0x1880:
|
||||||
{
|
{
|
||||||
// Seems to contain a few extra bytes of info in addition to the firmware string
|
// Seems to contain a few extra bytes of info in addition to the firmware string
|
||||||
usio_log.trace("Firmware query on 0x1880");
|
|
||||||
ensure(size == 0x70);
|
|
||||||
// Firmware
|
// Firmware
|
||||||
// "NBGI2;USIO01;Ver1.00;JPN,Multipurpose with PPG."
|
// "NBGI2;USIO01;Ver1.00;JPN,Multipurpose with PPG."
|
||||||
q_replies.push({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});
|
response = {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, 0x01, 0x03, 0x02, 0x00, 0x08, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x03, 0x00, 0x08, 0xE2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||||
q_replies.push({0x01, 0x00, 0x13, 0x00, 0x30, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x02, 0x00, 0x08, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x03, 0x00, 0x08, 0xE2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00});
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
usio_log.fatal("Unhandled channel 0 register read: 0x%04X", reg);
|
usio_log.error("Unhandled channel 0 register read: 0x%04X", reg);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -458,32 +420,30 @@ void usb_device_usio::usio_read(u8 channel, u16 reg, u16 size)
|
|||||||
{
|
{
|
||||||
case 0x0000:
|
case 0x0000:
|
||||||
{
|
{
|
||||||
ensure(size <= 0xB8);
|
response = g_fxo->get<usio_memory>().backup_memory;
|
||||||
push_vector(g_fxo->get<usio_memory>().backup_memory);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 0x0180:
|
case 0x0180:
|
||||||
{
|
{
|
||||||
ensure(size == 0x28);
|
response = g_fxo->get<usio_memory>().last_game_status;
|
||||||
push_vector(g_fxo->get<usio_memory>().last_game_status);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 0x0200:
|
case 0x0200:
|
||||||
{
|
{
|
||||||
ensure(size == 0x100);
|
//ensure(size == 0x100);
|
||||||
// No data returned
|
// No data returned
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 0x1000:
|
case 0x1000:
|
||||||
{
|
{
|
||||||
ensure(size == 0x1000);
|
//ensure(size == 0x1000);
|
||||||
push_zeroes();
|
response.resize(size);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
usio_log.fatal("Unhandled read of sram(chip: %d, addr: 0x%04X)", channel - 2, reg);
|
usio_log.error("Unhandled read of sram(chip: %d, addr: 0x%04X)", channel - 2, reg);
|
||||||
push_zeroes();
|
response.resize(size);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -491,8 +451,8 @@ void usb_device_usio::usio_read(u8 channel, u16 reg, u16 size)
|
|||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
usio_log.fatal("Unhandled read of sram(chip: %d, addr: 0x%04X)", channel - 2, reg);
|
usio_log.error("Unhandled read of sram(chip: %d, addr: 0x%04X)", channel - 2, reg);
|
||||||
push_zeroes();
|
response.resize(size);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -509,9 +469,11 @@ void usb_device_usio::interrupt_transfer(u32 buf_size, u8* buf, u32 endpoint, Us
|
|||||||
{
|
{
|
||||||
constexpr u8 USIO_COMMAND_WRITE = 0x90;
|
constexpr u8 USIO_COMMAND_WRITE = 0x90;
|
||||||
constexpr u8 USIO_COMMAND_READ = 0x10;
|
constexpr u8 USIO_COMMAND_READ = 0x10;
|
||||||
|
constexpr u8 USIO_COMMAND_INIT = 0xA0;
|
||||||
|
|
||||||
static bool expecting_data = false;
|
static bool expecting_data = false;
|
||||||
static std::vector<u8> usio_data;
|
static std::vector<u8> usio_data;
|
||||||
|
static u32 response_seek = 0;
|
||||||
static u8 usio_channel = 0;
|
static u8 usio_channel = 0;
|
||||||
static u16 usio_register = 0;
|
static u16 usio_register = 0;
|
||||||
static u16 usio_length = 0;
|
static u16 usio_length = 0;
|
||||||
@ -521,11 +483,6 @@ void usb_device_usio::interrupt_transfer(u32 buf_size, u8* buf, u32 endpoint, Us
|
|||||||
// The latency varies per operation but it doesn't seem to matter for this device so let's go fast!
|
// The latency varies per operation but it doesn't seem to matter for this device so let's go fast!
|
||||||
transfer->expected_time = get_timestamp();
|
transfer->expected_time = get_timestamp();
|
||||||
|
|
||||||
if (!usio_backup_path.empty() && !usio_backup_file && !usio_backup_file.open(usio_backup_path, fs::create + fs::read + fs::write + fs::lock))
|
|
||||||
{
|
|
||||||
usio_log.error("Failed to create a new USIO Backup file: %s", usio_backup_path);
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (endpoint)
|
switch (endpoint)
|
||||||
{
|
{
|
||||||
case 0x01:
|
case 0x01:
|
||||||
@ -556,56 +513,38 @@ void usb_device_usio::interrupt_transfer(u32 buf_size, u8* buf, u32 endpoint, Us
|
|||||||
{
|
{
|
||||||
usio_log.trace("UsioWrite(Channel: 0x%02X, Register: 0x%04X, Length: 0x%04X)", usio_channel, usio_register, usio_length);
|
usio_log.trace("UsioWrite(Channel: 0x%02X, Register: 0x%04X, Length: 0x%04X)", usio_channel, usio_register, usio_length);
|
||||||
ensure(((~(usio_register >> 8)) & 0xF0) == buf[1]);
|
ensure(((~(usio_register >> 8)) & 0xF0) == buf[1]);
|
||||||
|
|
||||||
expecting_data = true;
|
expecting_data = true;
|
||||||
usio_data.clear();
|
usio_data.clear();
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
else if ((buf[0] & USIO_COMMAND_READ) == USIO_COMMAND_READ)
|
||||||
if ((buf[0] & USIO_COMMAND_READ) == USIO_COMMAND_READ)
|
|
||||||
{
|
{
|
||||||
usio_log.trace("UsioRead(Channel: 0x%02X, Register: 0x%04X, Length: 0x%04X)", usio_channel, usio_register, usio_length);
|
usio_log.trace("UsioRead(Channel: 0x%02X, Register: 0x%04X, Length: 0x%04X)", usio_channel, usio_register, usio_length);
|
||||||
|
response_seek = 0;
|
||||||
|
response.clear();
|
||||||
usio_read(usio_channel, usio_register, usio_length);
|
usio_read(usio_channel, usio_register, usio_length);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
else if ((buf[0] & USIO_COMMAND_INIT) == USIO_COMMAND_INIT) // Init and reset commands
|
||||||
// Init and reset commands
|
|
||||||
if ((buf[0] & 0xA0) == 0xA0)
|
|
||||||
{
|
{
|
||||||
const std::array<u8, 2> init_command = {0xA0, 0xF0}; // This kind of command starts with 0xA0, 0xF0 commonly. For example, {0xA0, 0xF0, 0x28, 0x00, 0x00, 0x80}
|
//const std::array<u8, 2> init_command = {0xA0, 0xF0}; // This kind of command starts with 0xA0, 0xF0 commonly. For example, {0xA0, 0xF0, 0x28, 0x00, 0x00, 0x80}
|
||||||
ensure(memcmp(buf, init_command.data(), 2) == 0);
|
//ensure(memcmp(buf, init_command.data(), 2) == 0);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
fmt::throw_exception("Received an unexpected command: 0x%02X", buf[0]);
|
{
|
||||||
|
usio_log.error("Received an unexpected command: 0x%02X", buf[0]);
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
case 0x82:
|
case 0x82:
|
||||||
{
|
{
|
||||||
// Read endpoint
|
// Read endpoint
|
||||||
if (!q_replies.empty())
|
const u32 size = std::min(buf_size, static_cast<u32>(response.size() - response_seek));
|
||||||
{
|
memcpy(buf, response.data() + response_seek, size);
|
||||||
// Sometimes software will outright ignore what usio sends and read with a buffer of 0
|
response_seek += size;
|
||||||
if (buf_size == 0)
|
transfer->expected_count = size;
|
||||||
{
|
|
||||||
transfer->expected_count = q_replies.front().size();
|
|
||||||
q_replies.pop();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Otherwise we expect the buffer to be appropriately sized
|
|
||||||
ensure(buf_size >= q_replies.front().size());
|
|
||||||
memcpy(buf, q_replies.front().data(), q_replies.front().size());
|
|
||||||
transfer->expected_count = q_replies.front().size();
|
|
||||||
q_replies.pop();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
transfer->expected_count = 0;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
usio_log.fatal("Unhandled endpoint: 0x%x", endpoint);
|
usio_log.error("Unhandled endpoint: 0x%x", endpoint);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "Emu/Io/usb_device.h"
|
#include "Emu/Io/usb_device.h"
|
||||||
#include <queue>
|
|
||||||
|
|
||||||
class usb_device_usio : public usb_device_emulated
|
class usb_device_usio : public usb_device_emulated
|
||||||
{
|
{
|
||||||
@ -17,7 +16,7 @@ private:
|
|||||||
void load_backup();
|
void load_backup();
|
||||||
void save_backup();
|
void save_backup();
|
||||||
void translate_input();
|
void translate_input();
|
||||||
void usio_write(u8 channel, u16 reg, const std::vector<u8>& data);
|
void usio_write(u8 channel, u16 reg, std::vector<u8>& data);
|
||||||
void usio_read(u8 channel, u16 reg, u16 size);
|
void usio_read(u8 channel, u16 reg, u16 size);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -27,5 +26,5 @@ private:
|
|||||||
le_t<u16> coin_counter = 0;
|
le_t<u16> coin_counter = 0;
|
||||||
std::string usio_backup_path;
|
std::string usio_backup_path;
|
||||||
fs::file usio_backup_file;
|
fs::file usio_backup_file;
|
||||||
std::queue<std::vector<u8>> q_replies;
|
std::vector<u8> response;
|
||||||
};
|
};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user