diff --git a/Source/Core/Common/I2C.cpp b/Source/Core/Common/I2C.cpp index 43883d171a..82c2a57e9f 100644 --- a/Source/Core/Common/I2C.cpp +++ b/Source/Core/Common/I2C.cpp @@ -295,8 +295,6 @@ void I2CBus::SCLRisingEdge(const bool sda) { current_byte = byte.value(); } - // INFO_LOG_FMT(WII_IPC, "AVE: Read from {:02x} ({}) -> {:02x}", device_address.value(), - // IOS::GetAVERegisterName(device_address.value()), current_byte); } // Dolphin_Debugger::PrintCallstack(Common::Log::LogType::WII_IPC, Common::Log::LogLevel::LINFO); } @@ -508,6 +506,8 @@ void I2CSlaveAutoIncrementing::DoState(PointerWrap& p) } p.Do(m_active); p.Do(m_device_address); + + DoDeviceState(p); } }; // namespace Common diff --git a/Source/Core/Common/I2C.h b/Source/Core/Common/I2C.h index df13e03585..61b3c518bd 100644 --- a/Source/Core/Common/I2C.h +++ b/Source/Core/Common/I2C.h @@ -26,9 +26,28 @@ public: // transmitting device to NACK a read; only the receiver can NACK. virtual std::optional ReadByte() = 0; virtual bool WriteByte(u8 value) = 0; + +protected: + template + static u8 RawRead(T* reg_data, u8 addr) + { + static_assert(std::is_standard_layout_v && std::is_trivially_copyable_v); + static_assert(0x100 == sizeof(T)); + + return reinterpret_cast(reg_data)[addr]; + } + + template + static void RawWrite(T* reg_data, u8 addr, u8 value) + { + static_assert(std::is_standard_layout_v && std::is_trivially_copyable_v); + static_assert(0x100 == sizeof(T)); + + reinterpret_cast(reg_data)[addr] = value; + } }; -class I2CSlaveAutoIncrementing : I2CSlave +class I2CSlaveAutoIncrementing : public I2CSlave { public: I2CSlaveAutoIncrementing(u8 slave_addr) : m_slave_addr(slave_addr) {} @@ -40,12 +59,14 @@ public: std::optional ReadByte() override; bool WriteByte(u8 value) override; - virtual void DoState(PointerWrap& p); + void DoState(PointerWrap& p); protected: virtual u8 ReadByte(u8 addr) = 0; virtual void WriteByte(u8 addr, u8 value) = 0; + virtual void DoDeviceState(PointerWrap& p) = 0; + private: const u8 m_slave_addr; bool m_active = false; diff --git a/Source/Core/Core/HW/WII_IPC.cpp b/Source/Core/Core/HW/WII_IPC.cpp index 76bb5f9476..cd2647e07a 100644 --- a/Source/Core/Core/HW/WII_IPC.cpp +++ b/Source/Core/Core/HW/WII_IPC.cpp @@ -120,84 +120,6 @@ struct AVEState }; #pragma pack() static_assert(sizeof(AVEState) == 0x100); -Common::I2CSlaveSimple<0x70, AVEState> ave_state; -std::bitset ave_ever_logged; - -Common::I2CBus i2c_state; - -static CoreTiming::EventType* updateInterrupts; - -WiiIPC::WiiIPC(Core::System& system) : m_system(system) -{ -} - -WiiIPC::~WiiIPC() = default; - -void WiiIPC::DoState(PointerWrap& p) -{ - p.Do(m_ppc_msg); - p.Do(m_arm_msg); - p.Do(m_ctrl); - p.Do(m_ppc_irq_flags); - p.Do(m_ppc_irq_masks); - p.Do(m_arm_irq_flags); - p.Do(m_arm_irq_masks); - p.Do(m_gpio_dir); - p.Do(m_gpio_out); - i2c_state.DoState(p); - p.Do(ave_state.data); - p.Do(m_resets); -} - -void WiiIPC::InitState() -{ - m_ctrl = CtrlRegister(); - m_ppc_msg = 0; - m_arm_msg = 0; - - m_ppc_irq_flags = 0; - m_ppc_irq_masks = 0; - m_arm_irq_flags = 0; - m_arm_irq_masks = 0; - - // The only inputs are POWER, EJECT_BTN, SLOT_IN, EEP_MISO, and sometimes AVE_SCL and AVE_SDA; - // Broadway only has access to SLOT_IN, AVE_SCL, and AVE_SDA. - m_gpio_dir = { - GPIO::POWER, GPIO::SHUTDOWN, GPIO::FAN, GPIO::DC_DC, GPIO::DI_SPIN, GPIO::SLOT_LED, - GPIO::SENSOR_BAR, GPIO::DO_EJECT, GPIO::EEP_CS, GPIO::EEP_CLK, GPIO::EEP_MOSI, GPIO::AVE_SCL, - GPIO::AVE_SDA, GPIO::DEBUG0, GPIO::DEBUG1, GPIO::DEBUG2, GPIO::DEBUG3, GPIO::DEBUG4, - GPIO::DEBUG5, GPIO::DEBUG6, GPIO::DEBUG7, - }; - m_gpio_out = {}; - - // A cleared bit indicates the device is reset/off, so set everything to 1 (this may not exactly - // match hardware) - m_resets = 0xffffffff; - - m_ppc_irq_masks |= INT_CAUSE_IPC_BROADWAY; - - i2c_state = {}; - ave_state = {}; - ave_state.data.video_output_config = 0x23; - ave_ever_logged.reset(); -} - -void WiiIPC::Init() -{ - InitState(); - m_event_type_update_interrupts = - m_system.GetCoreTiming().RegisterEvent("IPCInterrupt", UpdateInterruptsCallback); -} - -void WiiIPC::Reset() -{ - INFO_LOG_FMT(WII_IPC, "Resetting ..."); - InitState(); -} - -void WiiIPC::Shutdown() -{ -} std::string_view GetAVERegisterName(u8 address) { @@ -243,6 +165,123 @@ std::string_view GetAVERegisterName(u8 address) return fmt::format("Unknown ({:02x})", address); } +class AVEDevice : public Common::I2CSlaveAutoIncrementing +{ +public: + AVEDevice() : I2CSlaveAutoIncrementing(0x70) {} + + void Reset() + { + m_registers = {}; + ave_ever_logged = {}; + } + + AVEState m_registers{}; + +protected: + u8 ReadByte(u8 addr) override + { + const u8 result = RawRead(&m_registers, addr); + INFO_LOG_FMT(WII_IPC, "AVE: Read from {:02x} ({}) -> {:02x}", addr, GetAVERegisterName(addr), + result); + return result; + } + void WriteByte(u8 addr, u8 value) override + { + const u8 old_value = RawRead(&m_registers, addr); + RawWrite(&m_registers, addr, value); + + if (old_value != value || !ave_ever_logged[addr]) + { + INFO_LOG_FMT(WII_IPC, "AVE: Write to {:02x} ({}): {:02x} -> {:02x}", addr, + GetAVERegisterName(addr), old_value, value); + ave_ever_logged[addr] = true; + } + else + { + DEBUG_LOG_FMT(WII_IPC, "AVE: Write to {:02x} ({}): {:02x}", addr, GetAVERegisterName(addr), + value); + } + } + void DoDeviceState(PointerWrap& p) override { p.Do(m_registers); } + +private: + std::bitset ave_ever_logged{}; // logging only, not saved +}; +AVEDevice ave_state; + +Common::I2CBus i2c_state; + +WiiIPC::WiiIPC(Core::System& system) : m_system(system) +{ +} + +WiiIPC::~WiiIPC() = default; + +void WiiIPC::DoState(PointerWrap& p) +{ + p.Do(m_ppc_msg); + p.Do(m_arm_msg); + p.Do(m_ctrl); + p.Do(m_ppc_irq_flags); + p.Do(m_ppc_irq_masks); + p.Do(m_arm_irq_flags); + p.Do(m_arm_irq_masks); + p.Do(m_gpio_dir); + p.Do(m_gpio_out); + i2c_state.DoState(p); + ave_state.DoState(p); + p.Do(m_resets); +} + +void WiiIPC::InitState() +{ + m_ctrl = CtrlRegister(); + m_ppc_msg = 0; + m_arm_msg = 0; + + m_ppc_irq_flags = 0; + m_ppc_irq_masks = 0; + m_arm_irq_flags = 0; + m_arm_irq_masks = 0; + + // The only inputs are POWER, EJECT_BTN, SLOT_IN, EEP_MISO, and sometimes AVE_SCL and AVE_SDA; + // Broadway only has access to SLOT_IN, AVE_SCL, and AVE_SDA. + m_gpio_dir = { + GPIO::POWER, GPIO::SHUTDOWN, GPIO::FAN, GPIO::DC_DC, GPIO::DI_SPIN, GPIO::SLOT_LED, + GPIO::SENSOR_BAR, GPIO::DO_EJECT, GPIO::EEP_CS, GPIO::EEP_CLK, GPIO::EEP_MOSI, GPIO::AVE_SCL, + GPIO::AVE_SDA, GPIO::DEBUG0, GPIO::DEBUG1, GPIO::DEBUG2, GPIO::DEBUG3, GPIO::DEBUG4, + GPIO::DEBUG5, GPIO::DEBUG6, GPIO::DEBUG7, + }; + m_gpio_out = {}; + + // A cleared bit indicates the device is reset/off, so set everything to 1 (this may not exactly + // match hardware) + m_resets = 0xffffffff; + + m_ppc_irq_masks |= INT_CAUSE_IPC_BROADWAY; + + i2c_state = {}; + ave_state.Reset(); +} + +void WiiIPC::Init() +{ + InitState(); + m_event_type_update_interrupts = + m_system.GetCoreTiming().RegisterEvent("IPCInterrupt", UpdateInterruptsCallback); +} + +void WiiIPC::Reset() +{ + INFO_LOG_FMT(WII_IPC, "Resetting ..."); + InitState(); +} + +void WiiIPC::Shutdown() +{ +} + static u32 ReadGPIOIn(Core::System& system) { Common::Flags gpio_in;