Implement Broadway GPIOs

SLOT_LED and the AVE ones are not implemented yet, but the other Broadway ones are.
This commit is contained in:
Pokechu22 2019-08-21 13:05:21 -07:00
parent a695b05b21
commit 77189e74cd
4 changed files with 123 additions and 20 deletions

View File

@ -8,6 +8,7 @@
#include <climits>
#include <cstddef>
#include <cstring>
#include <initializer_list>
#include <type_traits>
namespace Common
@ -299,4 +300,44 @@ void SetBit(T& value, size_t bit_number, bool bit_value)
value &= ~(T{1} << bit_number);
}
template <typename T>
class FlagBit
{
public:
FlagBit(std::underlying_type_t<T>& bits, T bit) : m_bits(bits), m_bit(bit) {}
explicit operator bool() const
{
return (m_bits & static_cast<std::underlying_type_t<T>>(m_bit)) != 0;
}
FlagBit& operator=(const bool rhs)
{
if (rhs)
m_bits |= static_cast<std::underlying_type_t<T>>(m_bit);
else
m_bits &= ~static_cast<std::underlying_type_t<T>>(m_bit);
return *this;
}
private:
std::underlying_type_t<T>& m_bits;
T m_bit;
};
template <typename T>
class Flags
{
public:
constexpr Flags() = default;
constexpr Flags(std::initializer_list<T> bits)
{
for (auto bit : bits)
{
m_hex |= static_cast<std::underlying_type_t<T>>(bit);
}
}
FlagBit<T> operator[](T bit) { return FlagBit(m_hex, bit); }
std::underlying_type_t<T> m_hex = 0;
};
} // namespace Common

View File

@ -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> 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 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<u32>(0),
MMIO::DirectWrite<u32>(&sensorbar_power));
mmio->Register(base | GPIOB_OUT, MMIO::DirectRead<u32>(&g_gpio_out.m_hex),
MMIO::ComplexWrite<u32>([](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<u32>(&gpio_dir.m_hex),
MMIO::DirectWrite<u32>(&gpio_dir.m_hex));
mmio->Register(base | GPIOB_IN, MMIO::ComplexRead<u32>([](u32) {
Common::Flags<GPIO> gpio_in;
gpio_in[GPIO::SLOT_IN] = DVDInterface::IsDiscInside();
return gpio_in.m_hex;
}),
MMIO::Nop<u32>());
// Register some stubbed/unknown MMIOs required to make Wii games work.
mmio->Register(base | PPCSPEED, MMIO::InvalidRead<u32>(), MMIO::Nop<u32>());
mmio->Register(base | VISOLID, MMIO::InvalidRead<u32>(), MMIO::Nop<u32>());
mmio->Register(base | GPIOB_DIR, MMIO::Constant<u32>(0), MMIO::Nop<u32>());
mmio->Register(base | GPIOB_IN, MMIO::Constant<u32>(0), MMIO::Nop<u32>());
mmio->Register(base | UNK_180, MMIO::Constant<u32>(0), MMIO::Nop<u32>());
mmio->Register(base | UNK_1CC, MMIO::Constant<u32>(0), MMIO::Nop<u32>());
mmio->Register(base | UNK_1D0, MMIO::Constant<u32>(0), MMIO::Nop<u32>());

View File

@ -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<GPIO> g_gpio_out;
void Init();
void Reset();
void Shutdown();

View File

@ -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,6 +104,8 @@ void CameraLogic::Update(const Common::Matrix44& transform)
std::array<CameraPoint, leds.size()> camera_points;
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);
@ -120,6 +123,12 @@ void CameraLogic::Update(const Common::Matrix44& transform)
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;