Implement Broadway GPIOs
SLOT_LED and the AVE ones are not implemented yet, but the other Broadway ones are.
This commit is contained in:
parent
a695b05b21
commit
77189e74cd
|
@ -8,6 +8,7 @@
|
||||||
#include <climits>
|
#include <climits>
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
#include <initializer_list>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
|
||||||
namespace Common
|
namespace Common
|
||||||
|
@ -299,4 +300,44 @@ void SetBit(T& value, size_t bit_number, bool bit_value)
|
||||||
value &= ~(T{1} << bit_number);
|
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
|
} // namespace Common
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
#include "Common/CommonTypes.h"
|
#include "Common/CommonTypes.h"
|
||||||
#include "Common/Logging/Log.h"
|
#include "Common/Logging/Log.h"
|
||||||
#include "Core/CoreTiming.h"
|
#include "Core/CoreTiming.h"
|
||||||
|
#include "Core/HW/DVD/DVDInterface.h"
|
||||||
#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"
|
||||||
|
@ -97,7 +98,11 @@ static u32 ppc_irq_masks;
|
||||||
static u32 arm_irq_flags;
|
static u32 arm_irq_flags;
|
||||||
static u32 arm_irq_masks;
|
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 CoreTiming::EventType* updateInterrupts;
|
||||||
static void UpdateInterrupts(u64 = 0, s64 cyclesLate = 0);
|
static void UpdateInterrupts(u64 = 0, s64 cyclesLate = 0);
|
||||||
|
@ -111,7 +116,7 @@ void DoState(PointerWrap& p)
|
||||||
p.Do(ppc_irq_masks);
|
p.Do(ppc_irq_masks);
|
||||||
p.Do(arm_irq_flags);
|
p.Do(arm_irq_flags);
|
||||||
p.Do(arm_irq_masks);
|
p.Do(arm_irq_masks);
|
||||||
p.Do(sensorbar_power);
|
p.Do(g_gpio_out);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void InitState()
|
static void InitState()
|
||||||
|
@ -125,7 +130,9 @@ static void InitState()
|
||||||
arm_irq_flags = 0;
|
arm_irq_flags = 0;
|
||||||
arm_irq_masks = 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;
|
ppc_irq_masks |= INT_CAUSE_IPC_BROADWAY;
|
||||||
}
|
}
|
||||||
|
@ -181,14 +188,29 @@ void RegisterMMIO(MMIO::Mapping* mmio, u32 base)
|
||||||
CoreTiming::ScheduleEvent(0, updateInterrupts, 0);
|
CoreTiming::ScheduleEvent(0, updateInterrupts, 0);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
mmio->Register(base | GPIOB_OUT, MMIO::Constant<u32>(0),
|
mmio->Register(base | GPIOB_OUT, MMIO::DirectRead<u32>(&g_gpio_out.m_hex),
|
||||||
MMIO::DirectWrite<u32>(&sensorbar_power));
|
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.
|
// Register some stubbed/unknown MMIOs required to make Wii games work.
|
||||||
mmio->Register(base | PPCSPEED, MMIO::InvalidRead<u32>(), MMIO::Nop<u32>());
|
mmio->Register(base | PPCSPEED, MMIO::InvalidRead<u32>(), MMIO::Nop<u32>());
|
||||||
mmio->Register(base | VISOLID, 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_180, MMIO::Constant<u32>(0), MMIO::Nop<u32>());
|
||||||
mmio->Register(base | UNK_1CC, 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>());
|
mmio->Register(base | UNK_1D0, MMIO::Constant<u32>(0), MMIO::Nop<u32>());
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "Common/BitUtils.h"
|
||||||
#include "Common/CommonTypes.h"
|
#include "Common/CommonTypes.h"
|
||||||
|
|
||||||
class PointerWrap;
|
class PointerWrap;
|
||||||
|
@ -35,6 +36,36 @@ enum StarletInterruptCause
|
||||||
INT_CAUSE_IPC_STARLET = 0x80000000
|
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 Init();
|
||||||
void Reset();
|
void Reset();
|
||||||
void Shutdown();
|
void Shutdown();
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
#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
|
||||||
|
@ -103,23 +104,31 @@ void CameraLogic::Update(const Common::Matrix44& transform)
|
||||||
|
|
||||||
std::array<CameraPoint, leds.size()> camera_points;
|
std::array<CameraPoint, leds.size()> camera_points;
|
||||||
|
|
||||||
std::transform(leds.begin(), leds.end(), camera_points.begin(), [&](const Vec3& v) {
|
if (IOS::g_gpio_out[IOS::GPIO::SENSOR_BAR])
|
||||||
const auto point = camera_view * Vec4(v, 1.0);
|
{
|
||||||
|
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)
|
if (point.z > 0)
|
||||||
{
|
{
|
||||||
// FYI: Casting down vs. rounding seems to produce more symmetrical output.
|
// 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 x = s32((1 - point.x / point.w) * CAMERA_WIDTH / 2);
|
||||||
const auto y = s32((1 - point.y / point.w) * CAMERA_HEIGHT / 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)
|
if (x >= 0 && y >= 0 && x < CAMERA_WIDTH && y < CAMERA_HEIGHT)
|
||||||
return CameraPoint{u16(x), u16(y), u8(point_size)};
|
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
|
// IR data is read from offset 0x37 on real hardware
|
||||||
auto& data = reg_data.camera_data;
|
auto& data = reg_data.camera_data;
|
||||||
|
|
Loading…
Reference in New Issue