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)
{
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");

View File

@ -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);

View File

@ -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,125 @@ 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> gpio_owner = {GPIO::SLOT_LED, GPIO::SLOT_IN, GPIO::SENSOR_BAR,
GPIO::DO_EJECT, GPIO::AVE_SCL, GPIO::AVE_SDA};
static Common::Flags<GPIO> gpio_dir;
Common::Flags<GPIO> 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_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
// 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<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::ComplexRead<u32>([](Core::System&, u32) { return ctrl.ppc(); }),
mmio->Register(base | IPC_PPCCTRL, MMIO::ComplexRead<u32>([](Core::System& system, u32) {
auto& wii_ipc = system.GetWiiIPC();
return wii_ipc.m_ctrl.ppc();
}),
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
// 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<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::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();
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::ComplexWrite<u32>([](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<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) {
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 +181,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<u32>(&gpio_dir.m_hex),
MMIO::ComplexWrite<u32>([](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<u32>(&m_gpio_dir.m_hex),
MMIO::ComplexWrite<u32>([](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<u32>([](Core::System& system, u32) {
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
// 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<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) {
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 +217,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<u32>(&gpio_dir.m_hex),
MMIO::ComplexWrite<u32>([](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<u32>(&m_gpio_dir.m_hex),
MMIO::ComplexWrite<u32>([](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<u32>([](Core::System& system, u32) {
Common::Flags<GPIO> gpio_in;
@ -263,15 +230,16 @@ void RegisterMMIO(MMIO::Mapping* mmio, u32 base)
}),
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) {
// 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 +253,59 @@ void RegisterMMIO(MMIO::Mapping* mmio, u32 base)
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
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

View File

@ -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<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();
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<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

View File

@ -38,8 +38,15 @@ public:
virtual u8 GetWiimoteDeviceIndex() const = 0;
virtual void SetWiimoteDeviceIndex(u8 index) = 0;
enum class SensorBarState : bool
{
Disabled,
Enabled
};
// 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;
void SetInterruptCallback(InterruptCallbackType callback) { m_callback = std::move(callback); }

View File

@ -11,7 +11,6 @@
#include "Common/MathUtil.h"
#include "Common/Matrix.h"
#include "Core/HW/WII_IPC.h"
#include "Core/HW/WiimoteCommon/WiimoteReport.h"
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)
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)
{
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;
}
void Wiimote::BuildDesiredWiimoteState(DesiredWiimoteState* target_state)
void Wiimote::BuildDesiredWiimoteState(DesiredWiimoteState* target_state,
SensorBarState sensor_bar_state)
{
// Hotkey / settings modifier
// 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);
// Calculate IR camera state.
target_state->camera_points = CameraLogic::GetCameraPoints(
GetTotalTransformation(),
Common::Vec2(m_fov_x_setting.GetValue(), m_fov_y_setting.GetValue()) / 360 *
float(MathUtil::TAU));
if (sensor_bar_state == SensorBarState::Enabled)
{
target_state->camera_points = CameraLogic::GetCameraPoints(
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.
if (m_motion_plus_setting.GetValue())
@ -498,10 +507,11 @@ void Wiimote::SetWiimoteDeviceIndex(u8 index)
}
// 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();
BuildDesiredWiimoteState(target_state);
BuildDesiredWiimoteState(target_state, sensor_bar_state);
}
void Wiimote::Update(const WiimoteEmu::DesiredWiimoteState& target_state)

View File

@ -156,7 +156,8 @@ public:
u8 GetWiimoteDeviceIndex() const 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 EventLinked() override;
void EventUnlinked() override;
@ -187,7 +188,7 @@ private:
void StepDynamics();
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.
Common::Vec3 GetAcceleration(Common::Vec3 extra_acceleration) const;

View File

@ -465,7 +465,8 @@ void Wiimote::SetWiimoteDeviceIndex(u8 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.
}

View File

@ -67,7 +67,8 @@ public:
u8 GetWiimoteDeviceIndex() const 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 EventLinked() override;
void EventUnlinked() override;

View File

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

View File

@ -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> 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;

View File

@ -18,6 +18,7 @@
#include "Common/StringUtil.h"
#include "Common/Swap.h"
#include "Core/Core.h"
#include "Core/HW/WII_IPC.h"
#include "Core/HW/Wiimote.h"
#include "Core/HW/WiimoteCommon/WiimoteConstants.h"
#include "Core/HW/WiimoteCommon/WiimoteHid.h"
@ -26,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
{
@ -367,7 +369,11 @@ WiimoteDevice::PrepareInput(WiimoteEmu::DesiredWiimoteState* wiimote_state)
const auto* channel = FindChannelWithPSM(L2CAP_PSM_HID_INTR);
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::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;
// 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
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/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;

View File

@ -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;