From 6b21b41b2fbf499a7e921ac8a06af3904e78e286 Mon Sep 17 00:00:00 2001 From: Pokechu22 Date: Sat, 3 Sep 2022 17:41:22 -0700 Subject: [PATCH] Restructure device some --- Source/Core/Common/I2C.cpp | 75 +++++++++++++++++++-------- Source/Core/Common/I2C.h | 91 ++++++++++++++++----------------- Source/Core/Core/HW/WII_IPC.cpp | 2 + 3 files changed, 102 insertions(+), 66 deletions(-) diff --git a/Source/Core/Common/I2C.cpp b/Source/Core/Common/I2C.cpp index 843110e2fb..4f0fa701dd 100644 --- a/Source/Core/Common/I2C.cpp +++ b/Source/Core/Common/I2C.cpp @@ -10,6 +10,7 @@ #include #include "Common/Assert.h" +#include "Common/ChunkFile.h" #include "Common/EnumFormatter.h" #include "Common/Logging/Log.h" #include "Core/Debugger/Debugger_SymbolMap.h" @@ -25,47 +26,70 @@ std::string_view GetAVERegisterName(u8 address); namespace Common { -void I2CBusOld::AddSlave(I2CSlave* slave) +void I2CBusBase::AddSlave(I2CSlave* slave) { m_slaves.emplace_back(slave); } -void I2CBusOld::RemoveSlave(I2CSlave* slave) +void I2CBusBase::RemoveSlave(I2CSlave* slave) { m_slaves.erase(std::remove(m_slaves.begin(), m_slaves.end(), slave), m_slaves.end()); } -void I2CBusOld::Reset() +void I2CBusBase::Reset() { m_slaves.clear(); } -int I2CBusOld::BusRead(u8 slave_addr, u8 addr, int count, u8* data_out) +I2CSlave* I2CBusBase::GetSlave(u8 slave_addr) { - for (auto& slave : m_slaves) + for (I2CSlave* slave : m_slaves) { - auto const bytes_read = slave->BusRead(slave_addr, addr, count, data_out); - - // A slave responded, we are done. - if (bytes_read) - return bytes_read; + if (slave->Matches(slave_addr)) + return slave; } - - return 0; + return nullptr; } -int I2CBusOld::BusWrite(u8 slave_addr, u8 addr, int count, const u8* data_in) +int I2CBusSimple::BusRead(u8 slave_addr, u8 addr, int count, u8* data_out) { - for (auto& slave : m_slaves) + I2CSlave* slave = GetSlave(slave_addr); + if (slave != nullptr) { - auto const bytes_written = slave->BusWrite(slave_addr, addr, count, data_in); - - // A slave responded, we are done. - if (bytes_written) - return bytes_written; + for (int i = 0; i < count; i++) + { + // TODO: Does this make sense? The transmitter can't NACK a read... it's the receiver that + // does that + auto byte = slave->ReadByte(addr + i); + if (byte.has_value()) + data_out[i] = byte.value(); + else + return i; + } + return count; } + else + { + return 0; + } +} - return 0; +int I2CBusSimple::BusWrite(u8 slave_addr, u8 addr, int count, const u8* data_in) +{ + I2CSlave* slave = GetSlave(slave_addr); + if (slave != nullptr) + { + for (int i = 0; i < count; i++) + { + if (!slave->WriteByte(addr + i, data_in[i])) + return i; + } + return count; + } + else + { + return 0; + } } bool I2CBus::GetSCL() const @@ -310,6 +334,17 @@ void I2CBus::SCLFallingEdge(const bool sda) // Dolphin_Debugger::PrintCallstack(Common::Log::LogType::WII_IPC, Common::Log::LogLevel::LINFO); } +void I2CBus::DoState(PointerWrap& p) +{ + p.Do(state); + p.Do(bit_counter); + p.Do(current_byte); + p.Do(i2c_address); + p.Do(device_address); + // TODO: verify m_devices is the same so that the state is compatible. + // (We don't take ownership of saving/loading m_devices, though). +} + }; // namespace Common template <> diff --git a/Source/Core/Common/I2C.h b/Source/Core/Common/I2C.h index fcccb4f322..16fcd8dc06 100644 --- a/Source/Core/Common/I2C.h +++ b/Source/Core/Common/I2C.h @@ -9,70 +9,67 @@ #include "Common/CommonTypes.h" +class PointerWrap; + namespace Common { -class I2CBusOld; - class I2CSlave { - friend I2CBusOld; - -protected: - virtual ~I2CSlave() = default; - - virtual int BusRead(u8 slave_addr, u8 addr, int count, u8* data_out) = 0; - virtual int BusWrite(u8 slave_addr, u8 addr, int count, const u8* data_in) = 0; - - template - static int RawRead(T* reg_data, u8 addr, int count, u8* data_out) - { - static_assert(std::is_standard_layout_v && std::is_trivially_copyable_v); - static_assert(0x100 == sizeof(T)); - - // TODO: addr wraps around after 0xff - - u8* src = reinterpret_cast(reg_data) + addr; - count = std::min(count, int(reinterpret_cast(reg_data + 1) - src)); - - std::copy_n(src, count, data_out); - - return count; - } - - template - static int RawWrite(T* reg_data, u8 addr, int count, const u8* data_in) - { - static_assert(std::is_standard_layout_v && std::is_trivially_copyable_v); - static_assert(0x100 == sizeof(T)); - - // TODO: addr wraps around after 0xff - - u8* dst = reinterpret_cast(reg_data) + addr; - count = std::min(count, int(reinterpret_cast(reg_data + 1) - dst)); - - std::copy_n(data_in, count, dst); - - return count; - } +public: + virtual bool Matches(u8 slave_addr) = 0; + virtual std::optional ReadByte(u8 addr) = 0; + virtual bool WriteByte(u8 addr, u8 value) = 0; }; -class I2CBusOld +template +class I2CSlaveSimple : I2CSlave { public: + bool Matches(u8 slave_addr) override { return slave_addr == slave_addr_val; } + std::optional ReadByte(u8 addr) { return data_bytes[addr]; } + bool WriteByte(u8 addr, u8 value) + { + data_bytes[addr] = value; + return true; + } + + union + { + T data; + std::array data_bytes; + }; + + static_assert(std::is_standard_layout_v && std::is_trivially_copyable_v); + static_assert(sizeof(T) == 0x100); +}; + +class I2CBusBase +{ +public: + virtual ~I2CBusBase() = default; + void AddSlave(I2CSlave* slave); void RemoveSlave(I2CSlave* slave); void Reset(); - // TODO: change int to u16 or something - int BusRead(u8 slave_addr, u8 addr, int count, u8* data_out); - int BusWrite(u8 slave_addr, u8 addr, int count, const u8* data_in); +protected: + // Returns nullptr if there is no match + I2CSlave* GetSlave(u8 slave_addr); private: // Pointers are unowned: std::vector m_slaves; }; +class I2CBusSimple : public I2CBusBase +{ +public: + // TODO: change int to u16 or something + int BusRead(u8 slave_addr, u8 addr, int count, u8* data_out); + int BusWrite(u8 slave_addr, u8 addr, int count, const u8* data_in); +}; + // An I²C bus implementation accessed via bit-banging. // A few assumptions and limitations exist: // - All devices support both writes and reads. @@ -91,7 +88,7 @@ private: // read from a different device would result in reading from the last used device address (without // any warning). // - 10-bit addressing and other reserved addressing modes are not implemented. -class I2CBus +class I2CBus : public I2CBusBase { public: enum class State @@ -114,6 +111,8 @@ public: bool GetSCL() const; bool GetSDA() const; + void DoState(PointerWrap& p); + private: void Start(); void Stop(); diff --git a/Source/Core/Core/HW/WII_IPC.cpp b/Source/Core/Core/HW/WII_IPC.cpp index e8be5abd5c..e8a9711019 100644 --- a/Source/Core/Core/HW/WII_IPC.cpp +++ b/Source/Core/Core/HW/WII_IPC.cpp @@ -144,6 +144,8 @@ void WiiIPC::DoState(PointerWrap& p) p.Do(m_arm_irq_masks); p.Do(m_gpio_dir); p.Do(m_gpio_out); + i2c_state.DoState(p); + p.Do(ave_state); p.Do(m_resets); }