From f055d37346de574635e1fd280f104d5b51e9b3a1 Mon Sep 17 00:00:00 2001 From: Jordan Woyak Date: Sun, 28 Apr 2019 19:50:36 -0500 Subject: [PATCH] WiimoteEmu: Add game quirk report for reading of EXT/IR input directly, which will fail with TAS/NetPlay. --- Source/Core/Core/Analytics.cpp | 3 ++- Source/Core/Core/Analytics.h | 4 ++++ Source/Core/Core/HW/WiimoteEmu/Camera.h | 3 ++- Source/Core/Core/HW/WiimoteEmu/EmuSubroutines.cpp | 14 ++++++++++++++ .../Core/Core/HW/WiimoteEmu/Extension/Extension.h | 3 ++- 5 files changed, 24 insertions(+), 3 deletions(-) diff --git a/Source/Core/Core/Analytics.cpp b/Source/Core/Core/Analytics.cpp index 69a5825094..4486a9708a 100644 --- a/Source/Core/Core/Analytics.cpp +++ b/Source/Core/Core/Analytics.cpp @@ -139,7 +139,8 @@ void DolphinAnalytics::ReportGameStart() // Keep in sync with enum class GameQuirk definition. static const char* GAME_QUIRKS_NAMES[] = { - "icache-matters", // ICACHE_MATTERS + "icache-matters", + "directly-reads-wiimote-input", }; static_assert(sizeof(GAME_QUIRKS_NAMES) / sizeof(GAME_QUIRKS_NAMES[0]) == static_cast(GameQuirk::COUNT), diff --git a/Source/Core/Core/Analytics.h b/Source/Core/Core/Analytics.h index 0de0f839f8..194e1d1a18 100644 --- a/Source/Core/Core/Analytics.h +++ b/Source/Core/Core/Analytics.h @@ -24,6 +24,10 @@ enum class GameQuirk // Sometimes code run from ICache is different from its mirror in RAM. ICACHE_MATTERS = 0, + // The Wii remote hardware makes it possible to bypass normal data reporting and directly + // "read" extension or IR data. This would break our current TAS/NetPlay implementation. + DIRECTLY_READS_WIIMOTE_INPUT, + COUNT, }; diff --git a/Source/Core/Core/HW/WiimoteEmu/Camera.h b/Source/Core/Core/HW/WiimoteEmu/Camera.h index 7ad44022f8..29c3d9cd94 100644 --- a/Source/Core/Core/HW/WiimoteEmu/Camera.h +++ b/Source/Core/Core/HW/WiimoteEmu/Camera.h @@ -75,6 +75,7 @@ public: void SetEnabled(bool is_enabled); static constexpr u8 I2C_ADDR = 0x58; + static constexpr int CAMERA_DATA_BYTES = 36; private: // TODO: some of this memory is write-only and should return error 7. @@ -89,7 +90,7 @@ private: u8 mode; u8 unk[3]; // addr: 0x37 - u8 camera_data[36]; + u8 camera_data[CAMERA_DATA_BYTES]; u8 unk2[165]; }; #pragma pack(pop) diff --git a/Source/Core/Core/HW/WiimoteEmu/EmuSubroutines.cpp b/Source/Core/Core/HW/WiimoteEmu/EmuSubroutines.cpp index ec5a595597..3320deb47f 100644 --- a/Source/Core/Core/HW/WiimoteEmu/EmuSubroutines.cpp +++ b/Source/Core/Core/HW/WiimoteEmu/EmuSubroutines.cpp @@ -12,6 +12,7 @@ #include "Common/Logging/Log.h" #include "Common/MsgHandler.h" #include "Common/Swap.h" +#include "Core/Analytics.h" #include "Core/Core.h" #include "Core/HW/WiimoteCommon/WiimoteHid.h" #include "Core/HW/WiimoteEmu/WiimoteEmu.h" @@ -507,6 +508,19 @@ bool Wiimote::ProcessReadDataRequest() break; } + // It is possible to bypass data reporting and directly read extension input. + // While I am not aware of any games that actually do this, + // our NetPlay and TAS methods are completely unprepared for it. + const bool is_reading_ext = EncryptedExtension::I2C_ADDR == m_read_request.slave_address && + m_read_request.address < EncryptedExtension::CONTROLLER_DATA_BYTES; + const bool is_reading_ir = + CameraLogic::I2C_ADDR == m_read_request.slave_address && + m_read_request.address < CameraLogic::REPORT_DATA_OFFSET + CameraLogic::CAMERA_DATA_BYTES && + m_read_request.address + m_read_request.size > CameraLogic::REPORT_DATA_OFFSET; + + if (is_reading_ext || is_reading_ir) + DolphinAnalytics::Instance()->ReportGameQuirk(GameQuirk::DIRECTLY_READS_WIIMOTE_INPUT); + // Top byte of address is ignored on the bus, but it IS maintained in the read-reply. auto const bytes_read = m_i2c_bus.BusRead( m_read_request.slave_address, (u8)m_read_request.address, bytes_to_read, reply.data); diff --git a/Source/Core/Core/HW/WiimoteEmu/Extension/Extension.h b/Source/Core/Core/HW/WiimoteEmu/Extension/Extension.h index d42bdfd3d8..b959f389a8 100644 --- a/Source/Core/Core/HW/WiimoteEmu/Extension/Extension.h +++ b/Source/Core/Core/HW/WiimoteEmu/Extension/Extension.h @@ -62,6 +62,7 @@ class EncryptedExtension : public Extension { public: static constexpr u8 I2C_ADDR = 0x52; + static constexpr int CONTROLLER_DATA_BYTES = 21; using Extension::Extension; @@ -76,7 +77,7 @@ protected: struct Register { // 21 bytes of possible extension data - u8 controller_data[21]; + u8 controller_data[CONTROLLER_DATA_BYTES]; u8 unknown2[11];