From 77189e74cd6d86d6e9dd4098968533ec82a56525 Mon Sep 17 00:00:00 2001 From: Pokechu22 Date: Wed, 21 Aug 2019 13:05:21 -0700 Subject: [PATCH] Implement Broadway GPIOs SLOT_LED and the AVE ones are not implemented yet, but the other Broadway ones are. --- Source/Core/Common/BitUtils.h | 41 +++++++++++++++++++++++ Source/Core/Core/HW/WII_IPC.cpp | 36 ++++++++++++++++---- Source/Core/Core/HW/WII_IPC.h | 31 +++++++++++++++++ Source/Core/Core/HW/WiimoteEmu/Camera.cpp | 35 ++++++++++++------- 4 files changed, 123 insertions(+), 20 deletions(-) diff --git a/Source/Core/Common/BitUtils.h b/Source/Core/Common/BitUtils.h index 79c1a7799e..538718f3aa 100644 --- a/Source/Core/Common/BitUtils.h +++ b/Source/Core/Common/BitUtils.h @@ -8,6 +8,7 @@ #include #include #include +#include #include namespace Common @@ -299,4 +300,44 @@ void SetBit(T& value, size_t bit_number, bool bit_value) value &= ~(T{1} << bit_number); } +template +class FlagBit +{ +public: + FlagBit(std::underlying_type_t& bits, T bit) : m_bits(bits), m_bit(bit) {} + explicit operator bool() const + { + return (m_bits & static_cast>(m_bit)) != 0; + } + FlagBit& operator=(const bool rhs) + { + if (rhs) + m_bits |= static_cast>(m_bit); + else + m_bits &= ~static_cast>(m_bit); + return *this; + } + +private: + std::underlying_type_t& m_bits; + T m_bit; +}; + +template +class Flags +{ +public: + constexpr Flags() = default; + constexpr Flags(std::initializer_list bits) + { + for (auto bit : bits) + { + m_hex |= static_cast>(bit); + } + } + FlagBit operator[](T bit) { return FlagBit(m_hex, bit); } + + std::underlying_type_t m_hex = 0; +}; + } // namespace Common diff --git a/Source/Core/Core/HW/WII_IPC.cpp b/Source/Core/Core/HW/WII_IPC.cpp index d231adcfd2..e6a48cb31b 100644 --- a/Source/Core/Core/HW/WII_IPC.cpp +++ b/Source/Core/Core/HW/WII_IPC.cpp @@ -8,6 +8,7 @@ #include "Common/CommonTypes.h" #include "Common/Logging/Log.h" #include "Core/CoreTiming.h" +#include "Core/HW/DVD/DVDInterface.h" #include "Core/HW/MMIO.h" #include "Core/HW/ProcessorInterface.h" #include "Core/IOS/IOS.h" @@ -97,7 +98,11 @@ static u32 ppc_irq_masks; static u32 arm_irq_flags; static u32 arm_irq_masks; -static u32 sensorbar_power; // do we need to care about this? +// 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 CoreTiming::EventType* updateInterrupts; static void UpdateInterrupts(u64 = 0, s64 cyclesLate = 0); @@ -111,7 +116,7 @@ void DoState(PointerWrap& p) p.Do(ppc_irq_masks); p.Do(arm_irq_flags); p.Do(arm_irq_masks); - p.Do(sensorbar_power); + p.Do(g_gpio_out); } static void InitState() @@ -125,7 +130,9 @@ static void InitState() arm_irq_flags = 0; arm_irq_masks = 0; - sensorbar_power = 0; + // The only input broadway has is SLOT_IN; all the others it has access to are outputs + gpio_dir = {GPIO::SLOT_LED, GPIO::SENSOR_BAR, GPIO::DO_EJECT, GPIO::AVE_SCL, GPIO::AVE_SDA}; + g_gpio_out = {}; ppc_irq_masks |= INT_CAUSE_IPC_BROADWAY; } @@ -181,14 +188,29 @@ void RegisterMMIO(MMIO::Mapping* mmio, u32 base) CoreTiming::ScheduleEvent(0, updateInterrupts, 0); })); - mmio->Register(base | GPIOB_OUT, MMIO::Constant(0), - MMIO::DirectWrite(&sensorbar_power)); + mmio->Register(base | GPIOB_OUT, MMIO::DirectRead(&g_gpio_out.m_hex), + MMIO::ComplexWrite([](u32, u32 val) { + g_gpio_out.m_hex = val & gpio_owner.m_hex; + if (g_gpio_out[GPIO::DO_EJECT]) + { + INFO_LOG(WII_IPC, "Ejecting disc due to GPIO write"); + DVDInterface::EjectDisc(); + } + // SENSOR_BAR is checked by WiimoteEmu::CameraLogic + // TODO: AVE, SLOT_LED + })); + mmio->Register(base | GPIOB_DIR, MMIO::DirectRead(&gpio_dir.m_hex), + MMIO::DirectWrite(&gpio_dir.m_hex)); + mmio->Register(base | GPIOB_IN, MMIO::ComplexRead([](u32) { + Common::Flags gpio_in; + gpio_in[GPIO::SLOT_IN] = DVDInterface::IsDiscInside(); + return gpio_in.m_hex; + }), + MMIO::Nop()); // Register some stubbed/unknown MMIOs required to make Wii games work. mmio->Register(base | PPCSPEED, MMIO::InvalidRead(), MMIO::Nop()); mmio->Register(base | VISOLID, MMIO::InvalidRead(), MMIO::Nop()); - mmio->Register(base | GPIOB_DIR, MMIO::Constant(0), MMIO::Nop()); - mmio->Register(base | GPIOB_IN, MMIO::Constant(0), MMIO::Nop()); mmio->Register(base | UNK_180, MMIO::Constant(0), MMIO::Nop()); mmio->Register(base | UNK_1CC, MMIO::Constant(0), MMIO::Nop()); mmio->Register(base | UNK_1D0, MMIO::Constant(0), MMIO::Nop()); diff --git a/Source/Core/Core/HW/WII_IPC.h b/Source/Core/Core/HW/WII_IPC.h index 34419b8988..f13d824f26 100644 --- a/Source/Core/Core/HW/WII_IPC.h +++ b/Source/Core/Core/HW/WII_IPC.h @@ -4,6 +4,7 @@ #pragma once +#include "Common/BitUtils.h" #include "Common/CommonTypes.h" class PointerWrap; @@ -35,6 +36,36 @@ enum StarletInterruptCause INT_CAUSE_IPC_STARLET = 0x80000000 }; +enum class GPIO : u32 +{ + POWER = 0x1, + SHUTDOWN = 0x2, + FAN = 0x4, + DC_DC = 0x8, + DI_SPIN = 0x10, + SLOT_LED = 0x20, + EJECT_BTN = 0x40, + SLOT_IN = 0x80, + SENSOR_BAR = 0x100, + DO_EJECT = 0x200, + EEP_CS = 0x400, + EEP_CLK = 0x800, + EEP_MOSI = 0x1000, + EEP_MISO = 0x2000, + AVE_SCL = 0x4000, + AVE_SDA = 0x8000, + DEBUG0 = 0x10000, + DEBUG1 = 0x20000, + DEBUG2 = 0x40000, + DEBUG3 = 0x80000, + DEBUG4 = 0x100000, + DEBUG5 = 0x200000, + DEBUG6 = 0x400000, + DEBUG7 = 0x800000, +}; + +extern Common::Flags g_gpio_out; + void Init(); void Reset(); void Shutdown(); diff --git a/Source/Core/Core/HW/WiimoteEmu/Camera.cpp b/Source/Core/Core/HW/WiimoteEmu/Camera.cpp index 10966ce2a2..25b542bc8a 100644 --- a/Source/Core/Core/HW/WiimoteEmu/Camera.cpp +++ b/Source/Core/Core/HW/WiimoteEmu/Camera.cpp @@ -12,6 +12,7 @@ #include "Common/MathUtil.h" #include "Common/Matrix.h" +#include "Core/HW/WII_IPC.h" #include "Core/HW/WiimoteCommon/WiimoteReport.h" namespace WiimoteEmu @@ -103,23 +104,31 @@ void CameraLogic::Update(const Common::Matrix44& transform) std::array camera_points; - std::transform(leds.begin(), leds.end(), camera_points.begin(), [&](const Vec3& v) { - const auto point = camera_view * Vec4(v, 1.0); + if (IOS::g_gpio_out[IOS::GPIO::SENSOR_BAR]) + { + std::transform(leds.begin(), leds.end(), camera_points.begin(), [&](const Vec3& v) { + const auto point = camera_view * Vec4(v, 1.0); - if (point.z > 0) - { - // FYI: Casting down vs. rounding seems to produce more symmetrical output. - const auto x = s32((1 - point.x / point.w) * CAMERA_WIDTH / 2); - const auto y = s32((1 - point.y / point.w) * CAMERA_HEIGHT / 2); + if (point.z > 0) + { + // FYI: Casting down vs. rounding seems to produce more symmetrical output. + const auto x = s32((1 - point.x / point.w) * CAMERA_WIDTH / 2); + const auto y = s32((1 - point.y / point.w) * CAMERA_HEIGHT / 2); - const auto point_size = std::lround(MAX_POINT_SIZE / point.w / 2); + const auto point_size = std::lround(MAX_POINT_SIZE / point.w / 2); - if (x >= 0 && y >= 0 && x < CAMERA_WIDTH && y < CAMERA_HEIGHT) - return CameraPoint{u16(x), u16(y), u8(point_size)}; - } + if (x >= 0 && y >= 0 && x < CAMERA_WIDTH && y < CAMERA_HEIGHT) + return CameraPoint{u16(x), u16(y), u8(point_size)}; + } - return INVISIBLE_POINT; - }); + return INVISIBLE_POINT; + }); + } + else + { + // Sensor bar is off + camera_points.fill(INVISIBLE_POINT); + } // IR data is read from offset 0x37 on real hardware auto& data = reg_data.camera_data;