Merge pull request #12494 from AdmiralCurtiss/globals-wiiipc

Core/IOS/WiiIPC: Refactor to class, move to System.
This commit is contained in:
Mai 2024-01-12 02:08:00 -05:00 committed by GitHub
commit 6725c25600
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 273 additions and 184 deletions

View File

@ -56,7 +56,7 @@ void Init(Core::System& system, const Sram* override_sram)
if (SConfig::GetInstance().bWii) if (SConfig::GetInstance().bWii)
{ {
IOS::Init(); system.GetWiiIPC().Init();
IOS::HLE::Init(system); // Depends on Memory 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 should always be shut down regardless of bWii because it can be running in GC mode (MIOS).
IOS::HLE::Shutdown(); // Depends on Memory IOS::HLE::Shutdown(); // Depends on Memory
IOS::Shutdown(); system.GetWiiIPC().Shutdown();
system.GetSystemTimers().Shutdown(); system.GetSystemTimers().Shutdown();
system.GetCPU().Shutdown(); system.GetCPU().Shutdown();
@ -110,7 +110,7 @@ void DoState(Core::System& system, PointerWrap& p)
if (SConfig::GetInstance().bWii) if (SConfig::GetInstance().bWii)
{ {
IOS::DoState(p); system.GetWiiIPC().DoState(p);
p.DoMarker("IOS"); p.DoMarker("IOS");
IOS::HLE::GetIOS()->DoState(p); IOS::HLE::GetIOS()->DoState(p);
p.DoMarker("IOS::HLE"); p.DoMarker("IOS::HLE");

View File

@ -63,7 +63,7 @@ void MemoryManager::InitMMIO(bool is_wii)
m_system.GetAudioInterface().RegisterMMIO(m_mmio_mapping.get(), 0x0C006C00); m_system.GetAudioInterface().RegisterMMIO(m_mmio_mapping.get(), 0x0C006C00);
if (is_wii) 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.GetDVDInterface().RegisterMMIO(m_mmio_mapping.get(), 0x0D006000, true);
m_system.GetSerialInterface().RegisterMMIO(m_mmio_mapping.get(), 0x0D006400); m_system.GetSerialInterface().RegisterMMIO(m_mmio_mapping.get(), 0x0D006400);
m_system.GetExpansionInterface().RegisterMMIO(m_mmio_mapping.get(), 0x0D006800); m_system.GetExpansionInterface().RegisterMMIO(m_mmio_mapping.get(), 0x0D006800);

View File

@ -11,6 +11,7 @@
#include "Core/HW/MMIO.h" #include "Core/HW/MMIO.h"
#include "Core/HW/ProcessorInterface.h" #include "Core/HW/ProcessorInterface.h"
#include "Core/IOS/IOS.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 // This is the intercommunication between ARM and PPC. Currently only PPC actually uses it, because
// of the IOS HLE // of the IOS HLE
@ -19,8 +20,8 @@
// X2 Reload (a new IOS is being loaded, old one doesn't need to reply anymore) // 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 // Y1 Command executed and reply available in HW_IPC_ARMMSG
// Y2 Command acknowledge // Y2 Command acknowledge
// ppc_msg is a pointer to 0x40byte command structure // m_ppc_msg is a pointer to 0x40byte command structure
// arm_msg is, similarly, starlet's response buffer* // m_arm_msg is, similarly, starlet's response buffer*
namespace IOS namespace IOS
{ {
@ -54,164 +55,125 @@ enum
UNK_1D0 = 0x1d0, 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. // Indicates which pins are accessible by broadway. Writable by starlet only.
static constexpr Common::Flags<GPIO> gpio_owner = {GPIO::SLOT_LED, GPIO::SLOT_IN, GPIO::SENSOR_BAR, static constexpr Common::Flags<GPIO> gpio_owner = {GPIO::SLOT_LED, GPIO::SLOT_IN, GPIO::SENSOR_BAR,
GPIO::DO_EJECT, GPIO::AVE_SCL, GPIO::AVE_SDA}; GPIO::DO_EJECT, GPIO::AVE_SCL, GPIO::AVE_SDA};
static Common::Flags<GPIO> gpio_dir;
Common::Flags<GPIO> g_gpio_out;
static u32 resets; WiiIPC::WiiIPC(Core::System& system) : m_system(system)
static CoreTiming::EventType* updateInterrupts;
static void UpdateInterrupts(Core::System& system, u64 userdata, s64 cyclesLate);
void DoState(PointerWrap& p)
{ {
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() WiiIPC::~WiiIPC() = default;
{
ctrl = CtrlRegister();
ppc_msg = 0;
arm_msg = 0;
ppc_irq_flags = 0; void WiiIPC::DoState(PointerWrap& p)
ppc_irq_masks = 0; {
arm_irq_flags = 0; p.Do(m_ppc_msg);
arm_irq_masks = 0; 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);
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, and EEP_MISO; Broadway only has access to // The only inputs are POWER, EJECT_BTN, SLOT_IN, and EEP_MISO; Broadway only has access to
// SLOT_IN // SLOT_IN
gpio_dir = { m_gpio_dir = {
GPIO::POWER, GPIO::SHUTDOWN, GPIO::FAN, GPIO::DC_DC, GPIO::DI_SPIN, GPIO::SLOT_LED, 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::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::AVE_SDA, GPIO::DEBUG0, GPIO::DEBUG1, GPIO::DEBUG2, GPIO::DEBUG3, GPIO::DEBUG4,
GPIO::DEBUG5, GPIO::DEBUG6, GPIO::DEBUG7, 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 // A cleared bit indicates the device is reset/off, so set everything to 1 (this may not exactly
// match hardware) // 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(); InitState();
updateInterrupts = m_event_type_update_interrupts =
Core::System::GetInstance().GetCoreTiming().RegisterEvent("IPCInterrupt", UpdateInterrupts); m_system.GetCoreTiming().RegisterEvent("IPCInterrupt", UpdateInterruptsCallback);
} }
void Reset() void WiiIPC::Reset()
{ {
INFO_LOG_FMT(WII_IPC, "Resetting ..."); INFO_LOG_FMT(WII_IPC, "Resetting ...");
InitState(); 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<u32>(), MMIO::DirectWrite<u32>(&ppc_msg)); mmio->Register(base | IPC_PPCMSG, MMIO::InvalidRead<u32>(), MMIO::DirectWrite<u32>(&m_ppc_msg));
mmio->Register(base | IPC_PPCCTRL, mmio->Register(base | IPC_PPCCTRL, MMIO::ComplexRead<u32>([](Core::System& system, u32) {
MMIO::ComplexRead<u32>([](Core::System&, u32) { return ctrl.ppc(); }), auto& wii_ipc = system.GetWiiIPC();
return wii_ipc.m_ctrl.ppc();
}),
MMIO::ComplexWrite<u32>([](Core::System& system, u32, u32 val) { MMIO::ComplexWrite<u32>([](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 // The IPC interrupt is triggered when IY1/IY2 is set and
// Y1/Y2 is written to -- even when this results in clearing the bit. // Y1/Y2 is written to -- even when this results in clearing the bit.
if ((val >> 2 & 1 && ctrl.IY1) || (val >> 1 & 1 && ctrl.IY2)) if ((val >> 2 & 1 && wii_ipc.m_ctrl.IY1) || (val >> 1 & 1 && wii_ipc.m_ctrl.IY2))
ppc_irq_flags |= INT_CAUSE_IPC_BROADWAY; wii_ipc.m_ppc_irq_flags |= INT_CAUSE_IPC_BROADWAY;
if (ctrl.X1) if (wii_ipc.m_ctrl.X1)
HLE::GetIOS()->EnqueueIPCRequest(ppc_msg); HLE::GetIOS()->EnqueueIPCRequest(wii_ipc.m_ppc_msg);
HLE::GetIOS()->UpdateIPC(); 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<u32>(&arm_msg), MMIO::InvalidWrite<u32>()); mmio->Register(base | IPC_ARMMSG, MMIO::DirectRead<u32>(&m_arm_msg), MMIO::InvalidWrite<u32>());
mmio->Register(base | PPC_IRQFLAG, MMIO::InvalidRead<u32>(), mmio->Register(base | PPC_IRQFLAG, MMIO::InvalidRead<u32>(),
MMIO::ComplexWrite<u32>([](Core::System& system, u32, u32 val) { MMIO::ComplexWrite<u32>([](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(); 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<u32>(), mmio->Register(base | PPC_IRQMASK, MMIO::InvalidRead<u32>(),
MMIO::ComplexWrite<u32>([](Core::System& system, u32, u32 val) { MMIO::ComplexWrite<u32>([](Core::System& system, u32, u32 val) {
ppc_irq_masks = val; auto& wii_ipc = system.GetWiiIPC();
if (ppc_irq_masks & INT_CAUSE_IPC_BROADWAY) // wtf? wii_ipc.m_ppc_irq_masks = val;
Reset(); if (wii_ipc.m_ppc_irq_masks & INT_CAUSE_IPC_BROADWAY) // wtf?
wii_ipc.Reset();
HLE::GetIOS()->UpdateIPC(); 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<u32>(&g_gpio_out.m_hex), mmio->Register(base | GPIOB_OUT, MMIO::DirectRead<u32>(&m_gpio_out.m_hex),
MMIO::ComplexWrite<u32>([](Core::System& system, u32, u32 val) { MMIO::ComplexWrite<u32>([](Core::System& system, u32, u32 val) {
g_gpio_out.m_hex = auto& wii_ipc = system.GetWiiIPC();
(val & gpio_owner.m_hex) | (g_gpio_out.m_hex & ~gpio_owner.m_hex); wii_ipc.m_gpio_out.m_hex =
if (g_gpio_out[GPIO::DO_EJECT]) (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"); INFO_LOG_FMT(WII_IPC, "Ejecting disc due to GPIO write");
system.GetDVDInterface().EjectDisc(DVD::EjectCause::Software); system.GetDVDInterface().EjectDisc(DVD::EjectCause::Software);
@ -219,9 +181,11 @@ void RegisterMMIO(MMIO::Mapping* mmio, u32 base)
// SENSOR_BAR is checked by WiimoteEmu::CameraLogic // SENSOR_BAR is checked by WiimoteEmu::CameraLogic
// TODO: AVE, SLOT_LED // TODO: AVE, SLOT_LED
})); }));
mmio->Register(base | GPIOB_DIR, MMIO::DirectRead<u32>(&gpio_dir.m_hex), mmio->Register(base | GPIOB_DIR, MMIO::DirectRead<u32>(&m_gpio_dir.m_hex),
MMIO::ComplexWrite<u32>([](Core::System&, u32, u32 val) { MMIO::ComplexWrite<u32>([](Core::System& system, u32, u32 val) {
gpio_dir.m_hex = (val & gpio_owner.m_hex) | (gpio_dir.m_hex & ~gpio_owner.m_hex); 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<u32>([](Core::System& system, u32) { mmio->Register(base | GPIOB_IN, MMIO::ComplexRead<u32>([](Core::System& system, u32) {
Common::Flags<GPIO> gpio_in; Common::Flags<GPIO> gpio_in;
@ -240,11 +204,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 // 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 // go through the HW_GPIOB registers if the corresponding bit is set in the HW_GPIO_OWNER
// register. // register.
mmio->Register(base | GPIO_OUT, MMIO::DirectRead<u32>(&g_gpio_out.m_hex), mmio->Register(base | GPIO_OUT, MMIO::DirectRead<u32>(&m_gpio_out.m_hex),
MMIO::ComplexWrite<u32>([](Core::System& system, u32, u32 val) { MMIO::ComplexWrite<u32>([](Core::System& system, u32, u32 val) {
g_gpio_out.m_hex = auto& wii_ipc = system.GetWiiIPC();
(g_gpio_out.m_hex & gpio_owner.m_hex) | (val & ~gpio_owner.m_hex); wii_ipc.m_gpio_out.m_hex =
if (g_gpio_out[GPIO::DO_EJECT]) (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"); INFO_LOG_FMT(WII_IPC, "Ejecting disc due to GPIO write");
system.GetDVDInterface().EjectDisc(DVD::EjectCause::Software); system.GetDVDInterface().EjectDisc(DVD::EjectCause::Software);
@ -252,9 +217,11 @@ void RegisterMMIO(MMIO::Mapping* mmio, u32 base)
// SENSOR_BAR is checked by WiimoteEmu::CameraLogic // SENSOR_BAR is checked by WiimoteEmu::CameraLogic
// TODO: AVE, SLOT_LED // TODO: AVE, SLOT_LED
})); }));
mmio->Register(base | GPIO_DIR, MMIO::DirectRead<u32>(&gpio_dir.m_hex), mmio->Register(base | GPIO_DIR, MMIO::DirectRead<u32>(&m_gpio_dir.m_hex),
MMIO::ComplexWrite<u32>([](Core::System&, u32, u32 val) { MMIO::ComplexWrite<u32>([](Core::System& system, u32, u32 val) {
gpio_dir.m_hex = (gpio_dir.m_hex & gpio_owner.m_hex) | (val & ~gpio_owner.m_hex); 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<u32>([](Core::System& system, u32) { mmio->Register(base | GPIO_IN, MMIO::ComplexRead<u32>([](Core::System& system, u32) {
Common::Flags<GPIO> gpio_in; Common::Flags<GPIO> gpio_in;
@ -263,15 +230,16 @@ void RegisterMMIO(MMIO::Mapping* mmio, u32 base)
}), }),
MMIO::Nop<u32>()); MMIO::Nop<u32>());
mmio->Register(base | HW_RESETS, MMIO::DirectRead<u32>(&resets), mmio->Register(base | HW_RESETS, MMIO::DirectRead<u32>(&m_resets),
MMIO::ComplexWrite<u32>([](Core::System& system, u32, u32 val) { MMIO::ComplexWrite<u32>([](Core::System& system, u32, u32 val) {
// A reset occurs when the corresponding bit is cleared // A reset occurs when the corresponding bit is cleared
const bool di_reset_triggered = (resets & 0x400) && !(val & 0x400); auto& wii_ipc = system.GetWiiIPC();
resets = val; const bool di_reset_triggered = (wii_ipc.m_resets & 0x400) && !(val & 0x400);
wii_ipc.m_resets = val;
if (di_reset_triggered) if (di_reset_triggered)
{ {
// The GPIO *disables* spinning up the drive // 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"); INFO_LOG_FMT(WII_IPC, "Resetting DI {} spinup", spinup ? "with" : "without");
system.GetDVDInterface().ResetDrive(spinup); system.GetDVDInterface().ResetDrive(spinup);
} }
@ -285,53 +253,59 @@ void RegisterMMIO(MMIO::Mapping* mmio, u32 base)
mmio->Register(base | UNK_1D0, MMIO::Constant<u32>(0), MMIO::Nop<u32>()); mmio->Register(base | UNK_1D0, MMIO::Constant<u32>(0), MMIO::Nop<u32>());
} }
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 // 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, m_system.GetProcessorInterface().SetInterrupt(ProcessorInterface::INT_CAUSE_WII_IPC,
!!(ppc_irq_flags & ppc_irq_masks)); !!(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; m_ctrl.Y2 = 1;
DEBUG_LOG_FMT(WII_IPC, "GenerateAck: {:08x} | {:08x} [R:{} A:{} E:{}]", ppc_msg, address, ctrl.Y1, DEBUG_LOG_FMT(WII_IPC, "GenerateAck: {:08x} | {:08x} [R:{} A:{} E:{}]", m_ppc_msg, address,
ctrl.Y2, ctrl.X1); m_ctrl.Y1, m_ctrl.Y2, m_ctrl.X1);
// Based on a hardware test, the IPC interrupt takes approximately 100 TB ticks to fire // Based on a hardware test, the IPC interrupt takes approximately 100 TB ticks to fire
// after Y2 is seen in the control register. // after Y2 is seen in the control register.
Core::System::GetInstance().GetCoreTiming().ScheduleEvent(100 * SystemTimers::TIMER_RATIO, m_system.GetCoreTiming().ScheduleEvent(100 * SystemTimers::TIMER_RATIO,
updateInterrupts); m_event_type_update_interrupts);
} }
void GenerateReply(u32 address) void WiiIPC::GenerateReply(u32 address)
{ {
arm_msg = address; m_arm_msg = address;
ctrl.Y1 = 1; m_ctrl.Y1 = 1;
DEBUG_LOG_FMT(WII_IPC, "GenerateReply: {:08x} | {:08x} [R:{} A:{} E:{}]", ppc_msg, address, DEBUG_LOG_FMT(WII_IPC, "GenerateReply: {:08x} | {:08x} [R:{} A:{} E:{}]", m_ppc_msg, address,
ctrl.Y1, ctrl.Y2, ctrl.X1); m_ctrl.Y1, m_ctrl.Y2, m_ctrl.X1);
// Based on a hardware test, the IPC interrupt takes approximately 100 TB ticks to fire // Based on a hardware test, the IPC interrupt takes approximately 100 TB ticks to fire
// after Y1 is seen in the control register. // after Y1 is seen in the control register.
Core::System::GetInstance().GetCoreTiming().ScheduleEvent(100 * SystemTimers::TIMER_RATIO, m_system.GetCoreTiming().ScheduleEvent(100 * SystemTimers::TIMER_RATIO,
updateInterrupts); 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 } // namespace IOS

View File

@ -7,6 +7,14 @@
#include "Common/CommonTypes.h" #include "Common/CommonTypes.h"
class PointerWrap; class PointerWrap;
namespace Core
{
class System;
}
namespace CoreTiming
{
struct EventType;
}
namespace MMIO namespace MMIO
{ {
class Mapping; class Mapping;
@ -63,18 +71,92 @@ enum class GPIO : u32
DEBUG7 = 0x800000, DEBUG7 = 0x800000,
}; };
extern Common::Flags<GPIO> 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(); CtrlRegister() { X1 = X2 = Y1 = Y2 = IX1 = IX2 = IY1 = IY2 = 0; }
void Reset(); inline u8 ppc() { return (IY2 << 5) | (IY1 << 4) | (X2 << 3) | (Y1 << 2) | (Y2 << 1) | X1; }
void Shutdown(); inline u8 arm() { return (IX2 << 5) | (IX1 << 4) | (Y2 << 3) | (X1 << 2) | (X2 << 1) | Y1; }
void DoState(PointerWrap& p); 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(); class WiiIPC
void GenerateAck(u32 address); {
void GenerateReply(u32 address); 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<GPIO> 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<GPIO> m_gpio_dir{};
Common::Flags<GPIO> m_gpio_out{};
u32 m_resets = 0;
CoreTiming::EventType* m_event_type_update_interrupts = nullptr;
Core::System& m_system;
};
} // namespace IOS } // namespace IOS

View File

@ -38,8 +38,15 @@ public:
virtual u8 GetWiimoteDeviceIndex() const = 0; virtual u8 GetWiimoteDeviceIndex() const = 0;
virtual void SetWiimoteDeviceIndex(u8 index) = 0; virtual void SetWiimoteDeviceIndex(u8 index) = 0;
enum class SensorBarState : bool
{
Disabled,
Enabled
};
// Called every ~200hz after HID channels are established. // Called every ~200hz after HID channels are established.
virtual void PrepareInput(WiimoteEmu::DesiredWiimoteState* target_state) = 0; virtual void PrepareInput(WiimoteEmu::DesiredWiimoteState* target_state,
SensorBarState sensor_bar_state) = 0;
virtual void Update(const WiimoteEmu::DesiredWiimoteState& target_state) = 0; virtual void Update(const WiimoteEmu::DesiredWiimoteState& target_state) = 0;
void SetInterruptCallback(InterruptCallbackType callback) { m_callback = std::move(callback); } void SetInterruptCallback(InterruptCallbackType callback) { m_callback = std::move(callback); }

View File

@ -11,7 +11,6 @@
#include "Common/MathUtil.h" #include "Common/MathUtil.h"
#include "Common/Matrix.h" #include "Common/Matrix.h"
#include "Core/HW/WII_IPC.h"
#include "Core/HW/WiimoteCommon/WiimoteReport.h" #include "Core/HW/WiimoteCommon/WiimoteReport.h"
namespace WiimoteEmu namespace WiimoteEmu
@ -111,10 +110,6 @@ void CameraLogic::Update(const std::array<CameraPoint, NUM_POINTS>& camera_point
if (m_reg_data.enable_object_tracking != OBJECT_TRACKING_ENABLE) if (m_reg_data.enable_object_tracking != OBJECT_TRACKING_ENABLE)
return; return;
// If the sensor bar is off the camera will see no LEDs and return 0xFFs.
if (!IOS::g_gpio_out[IOS::GPIO::SENSOR_BAR])
return;
switch (m_reg_data.mode) switch (m_reg_data.mode)
{ {
case IR_MODE_BASIC: case IR_MODE_BASIC:

View File

@ -446,7 +446,8 @@ void Wiimote::UpdateButtonsStatus(const DesiredWiimoteState& target_state)
m_status.buttons.hex = target_state.buttons.hex & ButtonData::BUTTON_MASK; m_status.buttons.hex = target_state.buttons.hex & ButtonData::BUTTON_MASK;
} }
void Wiimote::BuildDesiredWiimoteState(DesiredWiimoteState* target_state) void Wiimote::BuildDesiredWiimoteState(DesiredWiimoteState* target_state,
SensorBarState sensor_bar_state)
{ {
// Hotkey / settings modifier // Hotkey / settings modifier
// Data is later accessed in IsSideways and IsUpright // Data is later accessed in IsSideways and IsUpright
@ -468,10 +469,18 @@ void Wiimote::BuildDesiredWiimoteState(DesiredWiimoteState* target_state)
ConvertAccelData(GetTotalAcceleration(), ACCEL_ZERO_G << 2, ACCEL_ONE_G << 2); ConvertAccelData(GetTotalAcceleration(), ACCEL_ZERO_G << 2, ACCEL_ONE_G << 2);
// Calculate IR camera state. // Calculate IR camera state.
target_state->camera_points = CameraLogic::GetCameraPoints( if (sensor_bar_state == SensorBarState::Enabled)
GetTotalTransformation(), {
Common::Vec2(m_fov_x_setting.GetValue(), m_fov_y_setting.GetValue()) / 360 * target_state->camera_points = CameraLogic::GetCameraPoints(
float(MathUtil::TAU)); GetTotalTransformation(),
Common::Vec2(m_fov_x_setting.GetValue(), m_fov_y_setting.GetValue()) / 360 *
float(MathUtil::TAU));
}
else
{
// If the sensor bar is off the camera will see no LEDs and return 0xFFs.
target_state->camera_points = DesiredWiimoteState::DEFAULT_CAMERA;
}
// Calculate MotionPlus state. // Calculate MotionPlus state.
if (m_motion_plus_setting.GetValue()) if (m_motion_plus_setting.GetValue())
@ -498,10 +507,11 @@ void Wiimote::SetWiimoteDeviceIndex(u8 index)
} }
// This is called every ::Wiimote::UPDATE_FREQ (200hz) // This is called every ::Wiimote::UPDATE_FREQ (200hz)
void Wiimote::PrepareInput(WiimoteEmu::DesiredWiimoteState* target_state) void Wiimote::PrepareInput(WiimoteEmu::DesiredWiimoteState* target_state,
SensorBarState sensor_bar_state)
{ {
const auto lock = GetStateLock(); const auto lock = GetStateLock();
BuildDesiredWiimoteState(target_state); BuildDesiredWiimoteState(target_state, sensor_bar_state);
} }
void Wiimote::Update(const WiimoteEmu::DesiredWiimoteState& target_state) void Wiimote::Update(const WiimoteEmu::DesiredWiimoteState& target_state)

View File

@ -156,7 +156,8 @@ public:
u8 GetWiimoteDeviceIndex() const override; u8 GetWiimoteDeviceIndex() const override;
void SetWiimoteDeviceIndex(u8 index) override; void SetWiimoteDeviceIndex(u8 index) override;
void PrepareInput(WiimoteEmu::DesiredWiimoteState* target_state) override; void PrepareInput(WiimoteEmu::DesiredWiimoteState* target_state,
SensorBarState sensor_bar_state) override;
void Update(const WiimoteEmu::DesiredWiimoteState& target_state) override; void Update(const WiimoteEmu::DesiredWiimoteState& target_state) override;
void EventLinked() override; void EventLinked() override;
void EventUnlinked() override; void EventUnlinked() override;
@ -187,7 +188,7 @@ private:
void StepDynamics(); void StepDynamics();
void UpdateButtonsStatus(const DesiredWiimoteState& target_state); void UpdateButtonsStatus(const DesiredWiimoteState& target_state);
void BuildDesiredWiimoteState(DesiredWiimoteState* target_state); void BuildDesiredWiimoteState(DesiredWiimoteState* target_state, SensorBarState sensor_bar_state);
// Returns simulated accelerometer data in m/s^2. // Returns simulated accelerometer data in m/s^2.
Common::Vec3 GetAcceleration(Common::Vec3 extra_acceleration) const; Common::Vec3 GetAcceleration(Common::Vec3 extra_acceleration) const;

View File

@ -465,7 +465,8 @@ void Wiimote::SetWiimoteDeviceIndex(u8 index)
m_bt_device_index = index; m_bt_device_index = index;
} }
void Wiimote::PrepareInput(WiimoteEmu::DesiredWiimoteState* target_state) void Wiimote::PrepareInput(WiimoteEmu::DesiredWiimoteState* target_state,
SensorBarState sensor_bar_state)
{ {
// Nothing to do here on real Wiimotes. // Nothing to do here on real Wiimotes.
} }

View File

@ -67,7 +67,8 @@ public:
u8 GetWiimoteDeviceIndex() const override; u8 GetWiimoteDeviceIndex() const override;
void SetWiimoteDeviceIndex(u8 index) override; void SetWiimoteDeviceIndex(u8 index) override;
void PrepareInput(WiimoteEmu::DesiredWiimoteState* target_state) override; void PrepareInput(WiimoteEmu::DesiredWiimoteState* target_state,
SensorBarState sensor_bar_state) override;
void Update(const WiimoteEmu::DesiredWiimoteState& target_state) override; void Update(const WiimoteEmu::DesiredWiimoteState& target_state) override;
void EventLinked() override; void EventLinked() override;
void EventUnlinked() override; void EventUnlinked() override;

View File

@ -234,7 +234,6 @@ public:
{ {
} }
protected:
EmulationKernel& GetEmulationKernel() const { return static_cast<EmulationKernel&>(m_ios); } EmulationKernel& GetEmulationKernel() const { return static_cast<EmulationKernel&>(m_ios); }
Core::System& GetSystem() const { return GetEmulationKernel().GetSystem(); } Core::System& GetSystem() const { return GetEmulationKernel().GetSystem(); }

View File

@ -539,7 +539,7 @@ void EmulationKernel::InitIPC()
return; return;
INFO_LOG_FMT(IOS, "IPC initialised."); INFO_LOG_FMT(IOS, "IPC initialised.");
GenerateAck(0); m_system.GetWiiIPC().GenerateAck(0);
} }
void EmulationKernel::AddDevice(std::unique_ptr<Device> device) void EmulationKernel::AddDevice(std::unique_ptr<Device> device)
@ -816,13 +816,14 @@ void EmulationKernel::HandleIPCEvent(u64 userdata)
void EmulationKernel::UpdateIPC() void EmulationKernel::UpdateIPC()
{ {
if (m_ipc_paused || !IsReady()) auto& wii_ipc = m_system.GetWiiIPC();
if (m_ipc_paused || !wii_ipc.IsReady())
return; return;
if (!m_request_queue.empty()) if (!m_request_queue.empty())
{ {
ClearX1(); wii_ipc.ClearX1();
GenerateAck(m_request_queue.front()); wii_ipc.GenerateAck(m_request_queue.front());
u32 command = m_request_queue.front(); u32 command = m_request_queue.front();
m_request_queue.pop_front(); m_request_queue.pop_front();
ExecuteIPCCommand(command); ExecuteIPCCommand(command);
@ -831,7 +832,7 @@ void EmulationKernel::UpdateIPC()
if (!m_reply_queue.empty()) 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()); DEBUG_LOG_FMT(IOS, "<<-- Reply to IPC Request @ {:#010x}", m_reply_queue.front());
m_reply_queue.pop_front(); m_reply_queue.pop_front();
return; return;

View File

@ -18,6 +18,7 @@
#include "Common/StringUtil.h" #include "Common/StringUtil.h"
#include "Common/Swap.h" #include "Common/Swap.h"
#include "Core/Core.h" #include "Core/Core.h"
#include "Core/HW/WII_IPC.h"
#include "Core/HW/Wiimote.h" #include "Core/HW/Wiimote.h"
#include "Core/HW/WiimoteCommon/WiimoteConstants.h" #include "Core/HW/WiimoteCommon/WiimoteConstants.h"
#include "Core/HW/WiimoteCommon/WiimoteHid.h" #include "Core/HW/WiimoteCommon/WiimoteHid.h"
@ -26,6 +27,7 @@
#include "Core/IOS/USB/Bluetooth/BTEmu.h" #include "Core/IOS/USB/Bluetooth/BTEmu.h"
#include "Core/IOS/USB/Bluetooth/WiimoteHIDAttr.h" #include "Core/IOS/USB/Bluetooth/WiimoteHIDAttr.h"
#include "Core/IOS/USB/Bluetooth/l2cap.h" #include "Core/IOS/USB/Bluetooth/l2cap.h"
#include "Core/System.h"
namespace IOS::HLE namespace IOS::HLE
{ {
@ -367,7 +369,11 @@ WiimoteDevice::PrepareInput(WiimoteEmu::DesiredWiimoteState* wiimote_state)
const auto* channel = FindChannelWithPSM(L2CAP_PSM_HID_INTR); const auto* channel = FindChannelWithPSM(L2CAP_PSM_HID_INTR);
if (channel && channel->IsComplete()) if (channel && channel->IsComplete())
{ {
m_hid_source->PrepareInput(wiimote_state); auto gpio_out = m_host->GetSystem().GetWiiIPC().GetGPIOOutFlags();
m_hid_source->PrepareInput(wiimote_state,
gpio_out[IOS::GPIO::SENSOR_BAR] ?
WiimoteCommon::HIDWiimote::SensorBarState::Enabled :
WiimoteCommon::HIDWiimote::SensorBarState::Disabled);
return NextUpdateInputCall::Update; return NextUpdateInputCall::Update;
} }
return NextUpdateInputCall::None; return NextUpdateInputCall::None;

View File

@ -95,7 +95,7 @@ static size_t s_state_writes_in_queue;
static std::condition_variable s_state_write_queue_is_empty; static std::condition_variable s_state_write_queue_is_empty;
// Don't forget to increase this after doing changes on the savestate system // Don't forget to increase this after doing changes on the savestate system
constexpr u32 STATE_VERSION = 166; // Last changed in PR 12487 constexpr u32 STATE_VERSION = 167; // Last changed in PR 12494
// Increase this if the StateExtendedHeader definition changes // Increase this if the StateExtendedHeader definition changes
constexpr u32 EXTENDED_HEADER_VERSION = 1; // Last changed in PR 12217 constexpr u32 EXTENDED_HEADER_VERSION = 1; // Last changed in PR 12217

View File

@ -24,6 +24,7 @@
#include "Core/HW/Sram.h" #include "Core/HW/Sram.h"
#include "Core/HW/SystemTimers.h" #include "Core/HW/SystemTimers.h"
#include "Core/HW/VideoInterface.h" #include "Core/HW/VideoInterface.h"
#include "Core/HW/WII_IPC.h"
#include "Core/PowerPC/Interpreter/Interpreter.h" #include "Core/PowerPC/Interpreter/Interpreter.h"
#include "Core/PowerPC/JitInterface.h" #include "Core/PowerPC/JitInterface.h"
#include "Core/PowerPC/PowerPC.h" #include "Core/PowerPC/PowerPC.h"
@ -45,7 +46,7 @@ struct System::Impl
explicit Impl(System& system) explicit Impl(System& system)
: m_audio_interface(system), m_core_timing(system), m_command_processor{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_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_memory(system), m_pixel_engine{system}, m_power_pc(system),
m_mmu(system, m_memory, m_power_pc), m_processor_interface(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), m_serial_interface(system), m_system_timers(system), m_video_interface(system),
@ -72,6 +73,7 @@ struct System::Impl
HSP::HSPManager m_hsp; HSP::HSPManager m_hsp;
IOS::HLE::USB::InfinityBase m_infinity_base; IOS::HLE::USB::InfinityBase m_infinity_base;
IOS::HLE::USB::SkylanderPortal m_skylander_portal; IOS::HLE::USB::SkylanderPortal m_skylander_portal;
IOS::WiiIPC m_wii_ipc;
Memory::MemoryManager m_memory; Memory::MemoryManager m_memory;
MemoryInterface::MemoryInterfaceManager m_memory_interface; MemoryInterface::MemoryInterfaceManager m_memory_interface;
PixelEngine::PixelEngineManager m_pixel_engine; PixelEngine::PixelEngineManager m_pixel_engine;
@ -219,6 +221,11 @@ IOS::HLE::USB::InfinityBase& System::GetInfinityBase() const
return m_impl->m_infinity_base; return m_impl->m_infinity_base;
} }
IOS::WiiIPC& System::GetWiiIPC() const
{
return m_impl->m_wii_ipc;
}
Memory::MemoryManager& System::GetMemory() const Memory::MemoryManager& System::GetMemory() const
{ {
return m_impl->m_memory; return m_impl->m_memory;

View File

@ -56,6 +56,10 @@ namespace HSP
{ {
class HSPManager; class HSPManager;
} }
namespace IOS
{
class WiiIPC;
}
namespace IOS::HLE::USB namespace IOS::HLE::USB
{ {
class SkylanderPortal; class SkylanderPortal;
@ -151,6 +155,7 @@ public:
JitInterface& GetJitInterface() const; JitInterface& GetJitInterface() const;
IOS::HLE::USB::SkylanderPortal& GetSkylanderPortal() const; IOS::HLE::USB::SkylanderPortal& GetSkylanderPortal() const;
IOS::HLE::USB::InfinityBase& GetInfinityBase() const; IOS::HLE::USB::InfinityBase& GetInfinityBase() const;
IOS::WiiIPC& GetWiiIPC() const;
Memory::MemoryManager& GetMemory() const; Memory::MemoryManager& GetMemory() const;
MemoryInterface::MemoryInterfaceManager& GetMemoryInterface() const; MemoryInterface::MemoryInterfaceManager& GetMemoryInterface() const;
PowerPC::MMU& GetMMU() const; PowerPC::MMU& GetMMU() const;