From 17753d5168cd24a8225a134c090e53e5ba65503b Mon Sep 17 00:00:00 2001 From: "Admiral H. Curtiss" Date: Thu, 11 Jan 2024 06:48:17 +0100 Subject: [PATCH] Core/IOS/WiiIPC: Refactor to class, move to System. --- Source/Core/Core/HW/HW.cpp | 6 +- Source/Core/Core/HW/Memmap.cpp | 2 +- Source/Core/Core/HW/WII_IPC.cpp | 260 ++++++++---------- Source/Core/Core/HW/WII_IPC.h | 102 ++++++- Source/Core/Core/IOS/Device.h | 1 - Source/Core/Core/IOS/IOS.cpp | 11 +- .../Core/IOS/USB/Bluetooth/WiimoteDevice.cpp | 4 +- Source/Core/Core/System.cpp | 9 +- Source/Core/Core/System.h | 5 + 9 files changed, 234 insertions(+), 166 deletions(-) diff --git a/Source/Core/Core/HW/HW.cpp b/Source/Core/Core/HW/HW.cpp index 674018b6f7..920ba50246 100644 --- a/Source/Core/Core/HW/HW.cpp +++ b/Source/Core/Core/HW/HW.cpp @@ -56,7 +56,7 @@ void Init(Core::System& system, const Sram* override_sram) if (SConfig::GetInstance().bWii) { - IOS::Init(); + system.GetWiiIPC().Init(); IOS::HLE::Init(system); // Depends on Memory } } @@ -65,7 +65,7 @@ void Shutdown(Core::System& system) { // IOS should always be shut down regardless of bWii because it can be running in GC mode (MIOS). IOS::HLE::Shutdown(); // Depends on Memory - IOS::Shutdown(); + system.GetWiiIPC().Shutdown(); system.GetSystemTimers().Shutdown(); system.GetCPU().Shutdown(); @@ -110,7 +110,7 @@ void DoState(Core::System& system, PointerWrap& p) if (SConfig::GetInstance().bWii) { - IOS::DoState(p); + system.GetWiiIPC().DoState(p); p.DoMarker("IOS"); IOS::HLE::GetIOS()->DoState(p); p.DoMarker("IOS::HLE"); diff --git a/Source/Core/Core/HW/Memmap.cpp b/Source/Core/Core/HW/Memmap.cpp index d864ef38d7..ea185ac4cd 100644 --- a/Source/Core/Core/HW/Memmap.cpp +++ b/Source/Core/Core/HW/Memmap.cpp @@ -63,7 +63,7 @@ void MemoryManager::InitMMIO(bool is_wii) m_system.GetAudioInterface().RegisterMMIO(m_mmio_mapping.get(), 0x0C006C00); if (is_wii) { - IOS::RegisterMMIO(m_mmio_mapping.get(), 0x0D000000); + m_system.GetWiiIPC().RegisterMMIO(m_mmio_mapping.get(), 0x0D000000); m_system.GetDVDInterface().RegisterMMIO(m_mmio_mapping.get(), 0x0D006000, true); m_system.GetSerialInterface().RegisterMMIO(m_mmio_mapping.get(), 0x0D006400); m_system.GetExpansionInterface().RegisterMMIO(m_mmio_mapping.get(), 0x0D006800); diff --git a/Source/Core/Core/HW/WII_IPC.cpp b/Source/Core/Core/HW/WII_IPC.cpp index 24e1c0a3be..06be7c000e 100644 --- a/Source/Core/Core/HW/WII_IPC.cpp +++ b/Source/Core/Core/HW/WII_IPC.cpp @@ -11,6 +11,7 @@ #include "Core/HW/MMIO.h" #include "Core/HW/ProcessorInterface.h" #include "Core/IOS/IOS.h" +#include "Core/System.h" // This is the intercommunication between ARM and PPC. Currently only PPC actually uses it, because // of the IOS HLE @@ -19,8 +20,8 @@ // X2 Reload (a new IOS is being loaded, old one doesn't need to reply anymore) // Y1 Command executed and reply available in HW_IPC_ARMMSG // Y2 Command acknowledge -// ppc_msg is a pointer to 0x40byte command structure -// arm_msg is, similarly, starlet's response buffer* +// m_ppc_msg is a pointer to 0x40byte command structure +// m_arm_msg is, similarly, starlet's response buffer* namespace IOS { @@ -54,164 +55,123 @@ enum UNK_1D0 = 0x1d0, }; -struct CtrlRegister -{ - u8 X1 : 1; - u8 X2 : 1; - u8 Y1 : 1; - u8 Y2 : 1; - u8 IX1 : 1; - u8 IX2 : 1; - u8 IY1 : 1; - u8 IY2 : 1; - - CtrlRegister() { X1 = X2 = Y1 = Y2 = IX1 = IX2 = IY1 = IY2 = 0; } - inline u8 ppc() { return (IY2 << 5) | (IY1 << 4) | (X2 << 3) | (Y1 << 2) | (Y2 << 1) | X1; } - inline u8 arm() { return (IX2 << 5) | (IX1 << 4) | (Y2 << 3) | (X1 << 2) | (X2 << 1) | Y1; } - inline void ppc(u32 v) - { - X1 = v & 1; - X2 = (v >> 3) & 1; - if ((v >> 2) & 1) - Y1 = 0; - if ((v >> 1) & 1) - Y2 = 0; - IY1 = (v >> 4) & 1; - IY2 = (v >> 5) & 1; - } - - inline void arm(u32 v) - { - Y1 = v & 1; - Y2 = (v >> 3) & 1; - if ((v >> 2) & 1) - X1 = 0; - if ((v >> 1) & 1) - X2 = 0; - IX1 = (v >> 4) & 1; - IX2 = (v >> 5) & 1; - } -}; - -// STATE_TO_SAVE -static u32 ppc_msg; -static u32 arm_msg; -static CtrlRegister ctrl; - -static u32 ppc_irq_flags; -static u32 ppc_irq_masks; -static u32 arm_irq_flags; -static u32 arm_irq_masks; - // Indicates which pins are accessible by broadway. Writable by starlet only. static constexpr Common::Flags gpio_owner = {GPIO::SLOT_LED, GPIO::SLOT_IN, GPIO::SENSOR_BAR, GPIO::DO_EJECT, GPIO::AVE_SCL, GPIO::AVE_SDA}; -static Common::Flags gpio_dir; -Common::Flags g_gpio_out; -static u32 resets; - -static CoreTiming::EventType* updateInterrupts; -static void UpdateInterrupts(Core::System& system, u64 userdata, s64 cyclesLate); - -void DoState(PointerWrap& p) +WiiIPC::WiiIPC(Core::System& system) : m_system(system) { - p.Do(ppc_msg); - p.Do(arm_msg); - p.Do(ctrl); - p.Do(ppc_irq_flags); - p.Do(ppc_irq_masks); - p.Do(arm_irq_flags); - p.Do(arm_irq_masks); - p.Do(g_gpio_out); } -static void InitState() -{ - ctrl = CtrlRegister(); - ppc_msg = 0; - arm_msg = 0; +WiiIPC::~WiiIPC() = default; - ppc_irq_flags = 0; - ppc_irq_masks = 0; - arm_irq_flags = 0; - arm_irq_masks = 0; +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_out); +} + +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, and EEP_MISO; Broadway only has access to // SLOT_IN - gpio_dir = { + 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, }; - g_gpio_out = {}; + m_gpio_out = {}; // A cleared bit indicates the device is reset/off, so set everything to 1 (this may not exactly // match hardware) - resets = 0xffffffff; + m_resets = 0xffffffff; - ppc_irq_masks |= INT_CAUSE_IPC_BROADWAY; + m_ppc_irq_masks |= INT_CAUSE_IPC_BROADWAY; } -void Init() +void WiiIPC::Init() { InitState(); - updateInterrupts = - Core::System::GetInstance().GetCoreTiming().RegisterEvent("IPCInterrupt", UpdateInterrupts); + m_event_type_update_interrupts = + m_system.GetCoreTiming().RegisterEvent("IPCInterrupt", UpdateInterruptsCallback); } -void Reset() +void WiiIPC::Reset() { INFO_LOG_FMT(WII_IPC, "Resetting ..."); InitState(); } -void Shutdown() +void WiiIPC::Shutdown() { } -void RegisterMMIO(MMIO::Mapping* mmio, u32 base) +void WiiIPC::RegisterMMIO(MMIO::Mapping* mmio, u32 base) { - mmio->Register(base | IPC_PPCMSG, MMIO::InvalidRead(), MMIO::DirectWrite(&ppc_msg)); + mmio->Register(base | IPC_PPCMSG, MMIO::InvalidRead(), MMIO::DirectWrite(&m_ppc_msg)); - mmio->Register(base | IPC_PPCCTRL, - MMIO::ComplexRead([](Core::System&, u32) { return ctrl.ppc(); }), + mmio->Register(base | IPC_PPCCTRL, MMIO::ComplexRead([](Core::System& system, u32) { + auto& wii_ipc = system.GetWiiIPC(); + return wii_ipc.m_ctrl.ppc(); + }), MMIO::ComplexWrite([](Core::System& system, u32, u32 val) { - ctrl.ppc(val); + auto& wii_ipc = system.GetWiiIPC(); + wii_ipc.m_ctrl.ppc(val); // The IPC interrupt is triggered when IY1/IY2 is set and // Y1/Y2 is written to -- even when this results in clearing the bit. - if ((val >> 2 & 1 && ctrl.IY1) || (val >> 1 & 1 && ctrl.IY2)) - ppc_irq_flags |= INT_CAUSE_IPC_BROADWAY; - if (ctrl.X1) - HLE::GetIOS()->EnqueueIPCRequest(ppc_msg); + if ((val >> 2 & 1 && wii_ipc.m_ctrl.IY1) || (val >> 1 & 1 && wii_ipc.m_ctrl.IY2)) + wii_ipc.m_ppc_irq_flags |= INT_CAUSE_IPC_BROADWAY; + if (wii_ipc.m_ctrl.X1) + HLE::GetIOS()->EnqueueIPCRequest(wii_ipc.m_ppc_msg); HLE::GetIOS()->UpdateIPC(); - system.GetCoreTiming().ScheduleEvent(0, updateInterrupts, 0); + system.GetCoreTiming().ScheduleEvent(0, wii_ipc.m_event_type_update_interrupts, + 0); })); - mmio->Register(base | IPC_ARMMSG, MMIO::DirectRead(&arm_msg), MMIO::InvalidWrite()); + mmio->Register(base | IPC_ARMMSG, MMIO::DirectRead(&m_arm_msg), MMIO::InvalidWrite()); mmio->Register(base | PPC_IRQFLAG, MMIO::InvalidRead(), MMIO::ComplexWrite([](Core::System& system, u32, u32 val) { - ppc_irq_flags &= ~val; + auto& wii_ipc = system.GetWiiIPC(); + wii_ipc.m_ppc_irq_flags &= ~val; HLE::GetIOS()->UpdateIPC(); - system.GetCoreTiming().ScheduleEvent(0, updateInterrupts, 0); + system.GetCoreTiming().ScheduleEvent(0, wii_ipc.m_event_type_update_interrupts, + 0); })); mmio->Register(base | PPC_IRQMASK, MMIO::InvalidRead(), MMIO::ComplexWrite([](Core::System& system, u32, u32 val) { - ppc_irq_masks = val; - if (ppc_irq_masks & INT_CAUSE_IPC_BROADWAY) // wtf? - Reset(); + auto& wii_ipc = system.GetWiiIPC(); + wii_ipc.m_ppc_irq_masks = val; + if (wii_ipc.m_ppc_irq_masks & INT_CAUSE_IPC_BROADWAY) // wtf? + wii_ipc.Reset(); HLE::GetIOS()->UpdateIPC(); - system.GetCoreTiming().ScheduleEvent(0, updateInterrupts, 0); + system.GetCoreTiming().ScheduleEvent(0, wii_ipc.m_event_type_update_interrupts, + 0); })); - mmio->Register(base | GPIOB_OUT, MMIO::DirectRead(&g_gpio_out.m_hex), + mmio->Register(base | GPIOB_OUT, MMIO::DirectRead(&m_gpio_out.m_hex), MMIO::ComplexWrite([](Core::System& system, u32, u32 val) { - g_gpio_out.m_hex = - (val & gpio_owner.m_hex) | (g_gpio_out.m_hex & ~gpio_owner.m_hex); - if (g_gpio_out[GPIO::DO_EJECT]) + auto& wii_ipc = system.GetWiiIPC(); + wii_ipc.m_gpio_out.m_hex = + (val & gpio_owner.m_hex) | (wii_ipc.m_gpio_out.m_hex & ~gpio_owner.m_hex); + if (wii_ipc.m_gpio_out[GPIO::DO_EJECT]) { INFO_LOG_FMT(WII_IPC, "Ejecting disc due to GPIO write"); system.GetDVDInterface().EjectDisc(DVD::EjectCause::Software); @@ -219,9 +179,11 @@ void RegisterMMIO(MMIO::Mapping* mmio, u32 base) // SENSOR_BAR is checked by WiimoteEmu::CameraLogic // TODO: AVE, SLOT_LED })); - mmio->Register(base | GPIOB_DIR, MMIO::DirectRead(&gpio_dir.m_hex), - MMIO::ComplexWrite([](Core::System&, u32, u32 val) { - gpio_dir.m_hex = (val & gpio_owner.m_hex) | (gpio_dir.m_hex & ~gpio_owner.m_hex); + mmio->Register(base | GPIOB_DIR, MMIO::DirectRead(&m_gpio_dir.m_hex), + MMIO::ComplexWrite([](Core::System& system, u32, u32 val) { + auto& wii_ipc = system.GetWiiIPC(); + wii_ipc.m_gpio_dir.m_hex = + (val & gpio_owner.m_hex) | (wii_ipc.m_gpio_dir.m_hex & ~gpio_owner.m_hex); })); mmio->Register(base | GPIOB_IN, MMIO::ComplexRead([](Core::System& system, u32) { Common::Flags gpio_in; @@ -240,11 +202,12 @@ void RegisterMMIO(MMIO::Mapping* mmio, u32 base) // Also: The HW_GPIO registers always have read access to all pins, but any writes (changes) must // go through the HW_GPIOB registers if the corresponding bit is set in the HW_GPIO_OWNER // register. - mmio->Register(base | GPIO_OUT, MMIO::DirectRead(&g_gpio_out.m_hex), + mmio->Register(base | GPIO_OUT, MMIO::DirectRead(&m_gpio_out.m_hex), MMIO::ComplexWrite([](Core::System& system, u32, u32 val) { - g_gpio_out.m_hex = - (g_gpio_out.m_hex & gpio_owner.m_hex) | (val & ~gpio_owner.m_hex); - if (g_gpio_out[GPIO::DO_EJECT]) + auto& wii_ipc = system.GetWiiIPC(); + wii_ipc.m_gpio_out.m_hex = + (wii_ipc.m_gpio_out.m_hex & gpio_owner.m_hex) | (val & ~gpio_owner.m_hex); + if (wii_ipc.m_gpio_out[GPIO::DO_EJECT]) { INFO_LOG_FMT(WII_IPC, "Ejecting disc due to GPIO write"); system.GetDVDInterface().EjectDisc(DVD::EjectCause::Software); @@ -252,9 +215,11 @@ void RegisterMMIO(MMIO::Mapping* mmio, u32 base) // SENSOR_BAR is checked by WiimoteEmu::CameraLogic // TODO: AVE, SLOT_LED })); - mmio->Register(base | GPIO_DIR, MMIO::DirectRead(&gpio_dir.m_hex), - MMIO::ComplexWrite([](Core::System&, u32, u32 val) { - gpio_dir.m_hex = (gpio_dir.m_hex & gpio_owner.m_hex) | (val & ~gpio_owner.m_hex); + mmio->Register(base | GPIO_DIR, MMIO::DirectRead(&m_gpio_dir.m_hex), + MMIO::ComplexWrite([](Core::System& system, u32, u32 val) { + auto& wii_ipc = system.GetWiiIPC(); + wii_ipc.m_gpio_dir.m_hex = + (wii_ipc.m_gpio_dir.m_hex & gpio_owner.m_hex) | (val & ~gpio_owner.m_hex); })); mmio->Register(base | GPIO_IN, MMIO::ComplexRead([](Core::System& system, u32) { Common::Flags gpio_in; @@ -263,15 +228,16 @@ void RegisterMMIO(MMIO::Mapping* mmio, u32 base) }), MMIO::Nop()); - mmio->Register(base | HW_RESETS, MMIO::DirectRead(&resets), + mmio->Register(base | HW_RESETS, MMIO::DirectRead(&m_resets), MMIO::ComplexWrite([](Core::System& system, u32, u32 val) { // A reset occurs when the corresponding bit is cleared - const bool di_reset_triggered = (resets & 0x400) && !(val & 0x400); - resets = val; + auto& wii_ipc = system.GetWiiIPC(); + const bool di_reset_triggered = (wii_ipc.m_resets & 0x400) && !(val & 0x400); + wii_ipc.m_resets = val; if (di_reset_triggered) { // The GPIO *disables* spinning up the drive - const bool spinup = !g_gpio_out[GPIO::DI_SPIN]; + const bool spinup = !wii_ipc.m_gpio_out[GPIO::DI_SPIN]; INFO_LOG_FMT(WII_IPC, "Resetting DI {} spinup", spinup ? "with" : "without"); system.GetDVDInterface().ResetDrive(spinup); } @@ -285,53 +251,59 @@ void RegisterMMIO(MMIO::Mapping* mmio, u32 base) mmio->Register(base | UNK_1D0, MMIO::Constant(0), MMIO::Nop()); } -static void UpdateInterrupts(Core::System& system, u64 userdata, s64 cyclesLate) +void WiiIPC::UpdateInterruptsCallback(Core::System& system, u64 userdata, s64 cycles_late) { - if ((ctrl.Y1 & ctrl.IY1) || (ctrl.Y2 & ctrl.IY2)) + system.GetWiiIPC().UpdateInterrupts(); +} + +void WiiIPC::UpdateInterrupts() +{ + if ((m_ctrl.Y1 & m_ctrl.IY1) || (m_ctrl.Y2 & m_ctrl.IY2)) { - ppc_irq_flags |= INT_CAUSE_IPC_BROADWAY; + m_ppc_irq_flags |= INT_CAUSE_IPC_BROADWAY; } - if ((ctrl.X1 & ctrl.IX1) || (ctrl.X2 & ctrl.IX2)) + if ((m_ctrl.X1 & m_ctrl.IX1) || (m_ctrl.X2 & m_ctrl.IX2)) { - ppc_irq_flags |= INT_CAUSE_IPC_STARLET; + m_ppc_irq_flags |= INT_CAUSE_IPC_STARLET; } // Generate interrupt on PI if any of the devices behind starlet have an interrupt and mask is set - system.GetProcessorInterface().SetInterrupt(ProcessorInterface::INT_CAUSE_WII_IPC, - !!(ppc_irq_flags & ppc_irq_masks)); + m_system.GetProcessorInterface().SetInterrupt(ProcessorInterface::INT_CAUSE_WII_IPC, + !!(m_ppc_irq_flags & m_ppc_irq_masks)); } -void ClearX1() +void WiiIPC::ClearX1() { - ctrl.X1 = 0; + m_ctrl.X1 = 0; } -void GenerateAck(u32 address) +void WiiIPC::GenerateAck(u32 address) { - ctrl.Y2 = 1; - DEBUG_LOG_FMT(WII_IPC, "GenerateAck: {:08x} | {:08x} [R:{} A:{} E:{}]", ppc_msg, address, ctrl.Y1, - ctrl.Y2, ctrl.X1); + m_ctrl.Y2 = 1; + DEBUG_LOG_FMT(WII_IPC, "GenerateAck: {:08x} | {:08x} [R:{} A:{} E:{}]", m_ppc_msg, address, + m_ctrl.Y1, m_ctrl.Y2, m_ctrl.X1); // Based on a hardware test, the IPC interrupt takes approximately 100 TB ticks to fire // after Y2 is seen in the control register. - Core::System::GetInstance().GetCoreTiming().ScheduleEvent(100 * SystemTimers::TIMER_RATIO, - updateInterrupts); + m_system.GetCoreTiming().ScheduleEvent(100 * SystemTimers::TIMER_RATIO, + m_event_type_update_interrupts); } -void GenerateReply(u32 address) +void WiiIPC::GenerateReply(u32 address) { - arm_msg = address; - ctrl.Y1 = 1; - DEBUG_LOG_FMT(WII_IPC, "GenerateReply: {:08x} | {:08x} [R:{} A:{} E:{}]", ppc_msg, address, - ctrl.Y1, ctrl.Y2, ctrl.X1); + m_arm_msg = address; + m_ctrl.Y1 = 1; + DEBUG_LOG_FMT(WII_IPC, "GenerateReply: {:08x} | {:08x} [R:{} A:{} E:{}]", m_ppc_msg, address, + m_ctrl.Y1, m_ctrl.Y2, m_ctrl.X1); // Based on a hardware test, the IPC interrupt takes approximately 100 TB ticks to fire // after Y1 is seen in the control register. - Core::System::GetInstance().GetCoreTiming().ScheduleEvent(100 * SystemTimers::TIMER_RATIO, - updateInterrupts); + m_system.GetCoreTiming().ScheduleEvent(100 * SystemTimers::TIMER_RATIO, + m_event_type_update_interrupts); } -bool IsReady() +bool WiiIPC::IsReady() const { - return ((ctrl.Y1 == 0) && (ctrl.Y2 == 0) && ((ppc_irq_flags & INT_CAUSE_IPC_BROADWAY) == 0)); + return ((m_ctrl.Y1 == 0) && (m_ctrl.Y2 == 0) && + ((m_ppc_irq_flags & INT_CAUSE_IPC_BROADWAY) == 0)); } } // namespace IOS diff --git a/Source/Core/Core/HW/WII_IPC.h b/Source/Core/Core/HW/WII_IPC.h index 801b7a9cbc..64144f43c0 100644 --- a/Source/Core/Core/HW/WII_IPC.h +++ b/Source/Core/Core/HW/WII_IPC.h @@ -7,6 +7,14 @@ #include "Common/CommonTypes.h" class PointerWrap; +namespace Core +{ +class System; +} +namespace CoreTiming +{ +struct EventType; +} namespace MMIO { class Mapping; @@ -63,18 +71,92 @@ enum class GPIO : u32 DEBUG7 = 0x800000, }; -extern Common::Flags g_gpio_out; +struct CtrlRegister +{ + u8 X1 : 1; + u8 X2 : 1; + u8 Y1 : 1; + u8 Y2 : 1; + u8 IX1 : 1; + u8 IX2 : 1; + u8 IY1 : 1; + u8 IY2 : 1; -void Init(); -void Reset(); -void Shutdown(); -void DoState(PointerWrap& p); + CtrlRegister() { X1 = X2 = Y1 = Y2 = IX1 = IX2 = IY1 = IY2 = 0; } + inline u8 ppc() { return (IY2 << 5) | (IY1 << 4) | (X2 << 3) | (Y1 << 2) | (Y2 << 1) | X1; } + inline u8 arm() { return (IX2 << 5) | (IX1 << 4) | (Y2 << 3) | (X1 << 2) | (X2 << 1) | Y1; } + inline void ppc(u32 v) + { + X1 = v & 1; + X2 = (v >> 3) & 1; + if ((v >> 2) & 1) + Y1 = 0; + if ((v >> 1) & 1) + Y2 = 0; + IY1 = (v >> 4) & 1; + IY2 = (v >> 5) & 1; + } -void RegisterMMIO(MMIO::Mapping* mmio, u32 base); + inline void arm(u32 v) + { + Y1 = v & 1; + Y2 = (v >> 3) & 1; + if ((v >> 2) & 1) + X1 = 0; + if ((v >> 1) & 1) + X2 = 0; + IX1 = (v >> 4) & 1; + IX2 = (v >> 5) & 1; + } +}; -void ClearX1(); -void GenerateAck(u32 address); -void GenerateReply(u32 address); +class WiiIPC +{ +public: + explicit WiiIPC(Core::System& system); + WiiIPC(const WiiIPC&) = delete; + WiiIPC(WiiIPC&&) = delete; + WiiIPC& operator=(const WiiIPC&) = delete; + WiiIPC& operator=(WiiIPC&&) = delete; + ~WiiIPC(); -bool IsReady(); + void Init(); + void Reset(); + void Shutdown(); + void DoState(PointerWrap& p); + + void RegisterMMIO(MMIO::Mapping* mmio, u32 base); + + void ClearX1(); + void GenerateAck(u32 address); + void GenerateReply(u32 address); + + bool IsReady() const; + + Common::Flags GetGPIOOutFlags() const { return m_gpio_out; } + +private: + void InitState(); + + static void UpdateInterruptsCallback(Core::System& system, u64 userdata, s64 cycles_late); + void UpdateInterrupts(); + + u32 m_ppc_msg = 0; + u32 m_arm_msg = 0; + CtrlRegister m_ctrl{}; + + u32 m_ppc_irq_flags = 0; + u32 m_ppc_irq_masks = 0; + u32 m_arm_irq_flags = 0; + u32 m_arm_irq_masks = 0; + + Common::Flags m_gpio_dir{}; + Common::Flags m_gpio_out{}; + + u32 m_resets = 0; + + CoreTiming::EventType* m_event_type_update_interrupts = nullptr; + + Core::System& m_system; +}; } // namespace IOS diff --git a/Source/Core/Core/IOS/Device.h b/Source/Core/Core/IOS/Device.h index 651d78ae60..64d14adf3f 100644 --- a/Source/Core/Core/IOS/Device.h +++ b/Source/Core/Core/IOS/Device.h @@ -234,7 +234,6 @@ public: { } -protected: EmulationKernel& GetEmulationKernel() const { return static_cast(m_ios); } Core::System& GetSystem() const { return GetEmulationKernel().GetSystem(); } diff --git a/Source/Core/Core/IOS/IOS.cpp b/Source/Core/Core/IOS/IOS.cpp index cbf9c2e991..12e2df0384 100644 --- a/Source/Core/Core/IOS/IOS.cpp +++ b/Source/Core/Core/IOS/IOS.cpp @@ -539,7 +539,7 @@ void EmulationKernel::InitIPC() return; INFO_LOG_FMT(IOS, "IPC initialised."); - GenerateAck(0); + m_system.GetWiiIPC().GenerateAck(0); } void EmulationKernel::AddDevice(std::unique_ptr device) @@ -816,13 +816,14 @@ void EmulationKernel::HandleIPCEvent(u64 userdata) void EmulationKernel::UpdateIPC() { - if (m_ipc_paused || !IsReady()) + auto& wii_ipc = m_system.GetWiiIPC(); + if (m_ipc_paused || !wii_ipc.IsReady()) return; if (!m_request_queue.empty()) { - ClearX1(); - GenerateAck(m_request_queue.front()); + wii_ipc.ClearX1(); + wii_ipc.GenerateAck(m_request_queue.front()); u32 command = m_request_queue.front(); m_request_queue.pop_front(); ExecuteIPCCommand(command); @@ -831,7 +832,7 @@ void EmulationKernel::UpdateIPC() if (!m_reply_queue.empty()) { - GenerateReply(m_reply_queue.front()); + wii_ipc.GenerateReply(m_reply_queue.front()); DEBUG_LOG_FMT(IOS, "<<-- Reply to IPC Request @ {:#010x}", m_reply_queue.front()); m_reply_queue.pop_front(); return; diff --git a/Source/Core/Core/IOS/USB/Bluetooth/WiimoteDevice.cpp b/Source/Core/Core/IOS/USB/Bluetooth/WiimoteDevice.cpp index b92123796b..950e20404f 100644 --- a/Source/Core/Core/IOS/USB/Bluetooth/WiimoteDevice.cpp +++ b/Source/Core/Core/IOS/USB/Bluetooth/WiimoteDevice.cpp @@ -27,6 +27,7 @@ #include "Core/IOS/USB/Bluetooth/BTEmu.h" #include "Core/IOS/USB/Bluetooth/WiimoteHIDAttr.h" #include "Core/IOS/USB/Bluetooth/l2cap.h" +#include "Core/System.h" namespace IOS::HLE { @@ -368,8 +369,9 @@ WiimoteDevice::PrepareInput(WiimoteEmu::DesiredWiimoteState* wiimote_state) const auto* channel = FindChannelWithPSM(L2CAP_PSM_HID_INTR); if (channel && channel->IsComplete()) { + auto gpio_out = m_host->GetSystem().GetWiiIPC().GetGPIOOutFlags(); m_hid_source->PrepareInput(wiimote_state, - IOS::g_gpio_out[IOS::GPIO::SENSOR_BAR] ? + gpio_out[IOS::GPIO::SENSOR_BAR] ? WiimoteCommon::HIDWiimote::SensorBarState::Enabled : WiimoteCommon::HIDWiimote::SensorBarState::Disabled); return NextUpdateInputCall::Update; diff --git a/Source/Core/Core/System.cpp b/Source/Core/Core/System.cpp index 7488976ddf..d4898d9e97 100644 --- a/Source/Core/Core/System.cpp +++ b/Source/Core/Core/System.cpp @@ -24,6 +24,7 @@ #include "Core/HW/Sram.h" #include "Core/HW/SystemTimers.h" #include "Core/HW/VideoInterface.h" +#include "Core/HW/WII_IPC.h" #include "Core/PowerPC/Interpreter/Interpreter.h" #include "Core/PowerPC/JitInterface.h" #include "Core/PowerPC/PowerPC.h" @@ -45,7 +46,7 @@ struct System::Impl explicit Impl(System& system) : m_audio_interface(system), m_core_timing(system), m_command_processor{system}, m_cpu(system), m_dsp(system), m_dvd_interface(system), m_dvd_thread(system), - m_expansion_interface(system), m_fifo{system}, m_gp_fifo(system), + m_expansion_interface(system), m_fifo{system}, m_gp_fifo(system), m_wii_ipc(system), m_memory(system), m_pixel_engine{system}, m_power_pc(system), m_mmu(system, m_memory, m_power_pc), m_processor_interface(system), m_serial_interface(system), m_system_timers(system), m_video_interface(system), @@ -72,6 +73,7 @@ struct System::Impl HSP::HSPManager m_hsp; IOS::HLE::USB::InfinityBase m_infinity_base; IOS::HLE::USB::SkylanderPortal m_skylander_portal; + IOS::WiiIPC m_wii_ipc; Memory::MemoryManager m_memory; MemoryInterface::MemoryInterfaceManager m_memory_interface; PixelEngine::PixelEngineManager m_pixel_engine; @@ -219,6 +221,11 @@ IOS::HLE::USB::InfinityBase& System::GetInfinityBase() const return m_impl->m_infinity_base; } +IOS::WiiIPC& System::GetWiiIPC() const +{ + return m_impl->m_wii_ipc; +} + Memory::MemoryManager& System::GetMemory() const { return m_impl->m_memory; diff --git a/Source/Core/Core/System.h b/Source/Core/Core/System.h index 8e5d56aeb0..ef38d88d08 100644 --- a/Source/Core/Core/System.h +++ b/Source/Core/Core/System.h @@ -56,6 +56,10 @@ namespace HSP { class HSPManager; } +namespace IOS +{ +class WiiIPC; +} namespace IOS::HLE::USB { class SkylanderPortal; @@ -151,6 +155,7 @@ public: JitInterface& GetJitInterface() const; IOS::HLE::USB::SkylanderPortal& GetSkylanderPortal() const; IOS::HLE::USB::InfinityBase& GetInfinityBase() const; + IOS::WiiIPC& GetWiiIPC() const; Memory::MemoryManager& GetMemory() const; MemoryInterface::MemoryInterfaceManager& GetMemoryInterface() const; PowerPC::MMU& GetMMU() const;