618 changes: 217 additions & 401 deletions Source/Core/Core/HW/SI/SI.cpp

Large diffs are not rendered by default.

242 changes: 212 additions & 30 deletions Source/Core/Core/HW/SI/SI.h
Expand Up @@ -3,35 +3,30 @@

#pragma once

#include <array>
#include <atomic>
#include <memory>

#include "Common/BitField.h"
#include "Common/CommonTypes.h"

class PointerWrap;

namespace Core
{
class System;
}
namespace CoreTiming
{
struct EventType;
}
namespace MMIO
{
class Mapping;
}

namespace SerialInterface
{
class SerialInterfaceState
{
public:
SerialInterfaceState();
SerialInterfaceState(const SerialInterfaceState&) = delete;
SerialInterfaceState(SerialInterfaceState&&) = delete;
SerialInterfaceState& operator=(const SerialInterfaceState&) = delete;
SerialInterfaceState& operator=(SerialInterfaceState&&) = delete;
~SerialInterfaceState();

struct Data;
Data& GetData() { return *m_data; }

private:
std::unique_ptr<Data> m_data;
};

class ISIDevice;
enum SIDevices : int;

Expand All @@ -41,25 +36,212 @@ enum
MAX_SI_CHANNELS = 0x04
};

void Init();
void Shutdown();
void DoState(PointerWrap& p);
class SerialInterfaceManager
{
public:
explicit SerialInterfaceManager(Core::System& system);
SerialInterfaceManager(const SerialInterfaceManager&) = delete;
SerialInterfaceManager(SerialInterfaceManager&&) = delete;
SerialInterfaceManager& operator=(const SerialInterfaceManager&) = delete;
SerialInterfaceManager& operator=(SerialInterfaceManager&&) = delete;
~SerialInterfaceManager();

void Init();
void Shutdown();
void DoState(PointerWrap& p);

void RegisterMMIO(MMIO::Mapping* mmio, u32 base);
void RegisterMMIO(MMIO::Mapping* mmio, u32 base);

void ScheduleEvent(int device_number, s64 cycles_into_future, u64 userdata = 0);
void RemoveEvent(int device_number);
void ScheduleEvent(int device_number, s64 cycles_into_future, u64 userdata = 0);
void RemoveEvent(int device_number);

void UpdateDevices();
void UpdateDevices();

void RemoveDevice(int device_number);
void AddDevice(SIDevices device, int device_number);
void AddDevice(std::unique_ptr<ISIDevice> device);
void RemoveDevice(int device_number);
void AddDevice(SIDevices device, int device_number);
void AddDevice(std::unique_ptr<ISIDevice> device);

void ChangeDevice(SIDevices device, int channel);
void ChangeDevice(SIDevices device, int channel);

SIDevices GetDeviceType(int channel);
SIDevices GetDeviceType(int channel);

u32 GetPollXLines();
u32 GetPollXLines();

private:
// SI Interrupt Types
enum SIInterruptType
{
INT_RDSTINT = 0,
INT_TCINT = 1,
};

void SetNoResponse(u32 channel);
void UpdateInterrupts();
void GenerateSIInterrupt(SIInterruptType type);

void ChangeDeviceDeterministic(SIDevices device, int channel);

void RegisterEvents();
void RunSIBuffer(u64 user_data, s64 cycles_late);
static void GlobalRunSIBuffer(Core::System& system, u64 user_data, s64 cycles_late);
static void ChangeDeviceCallback(Core::System& system, u64 user_data, s64 cycles_late);
template <int device_number>
static void DeviceEventCallback(Core::System& system, u64 userdata, s64 cyclesLate);

// SI Channel Output
union USIChannelOut
{
u32 hex = 0;

BitField<0, 8, u32> OUTPUT1;
BitField<8, 8, u32> OUTPUT0;
BitField<16, 8, u32> CMD;
BitField<24, 8, u32> reserved;
};

// SI Channel Input High u32
union USIChannelIn_Hi
{
u32 hex = 0;

BitField<0, 8, u32> INPUT3;
BitField<8, 8, u32> INPUT2;
BitField<16, 8, u32> INPUT1;
BitField<24, 6, u32> INPUT0;
BitField<30, 1, u32> ERRLATCH; // 0: no error 1: Error latched. Check SISR.
BitField<31, 1, u32> ERRSTAT; // 0: no error 1: error on last transfer
};

// SI Channel Input Low u32
union USIChannelIn_Lo
{
u32 hex = 0;

BitField<0, 8, u32> INPUT7;
BitField<8, 8, u32> INPUT6;
BitField<16, 8, u32> INPUT5;
BitField<24, 8, u32> INPUT4;
};

// SI Channel
struct SSIChannel
{
USIChannelOut out{};
USIChannelIn_Hi in_hi{};
USIChannelIn_Lo in_lo{};
std::unique_ptr<ISIDevice> device;

bool has_recent_device_change = false;
};

// SI Poll: Controls how often a device is polled
union USIPoll
{
u32 hex = 0;

BitField<0, 1, u32> VBCPY3; // 1: write to output buffer only on vblank
BitField<1, 1, u32> VBCPY2;
BitField<2, 1, u32> VBCPY1;
BitField<3, 1, u32> VBCPY0;
BitField<4, 1, u32> EN3; // Enable polling of channel
BitField<5, 1, u32> EN2; // does not affect communication RAM transfers
BitField<6, 1, u32> EN1;
BitField<7, 1, u32> EN0;
BitField<8, 8, u32> Y; // Polls per frame
BitField<16, 10, u32>
X; // Polls per X lines. begins at vsync, min 7, max depends on video mode
BitField<26, 6, u32> reserved;
};

// SI Communication Control Status Register
union USIComCSR
{
u32 hex = 0;

BitField<0, 1, u32> TSTART; // write: start transfer read: transfer status
BitField<1, 2, u32> CHANNEL; // determines which SI channel will be
// used on the communication interface.
BitField<3, 3, u32> reserved_1;
BitField<6, 1, u32> CALLBEN; // Callback enable
BitField<7, 1, u32> CMDEN; // Command enable?
BitField<8, 7, u32> INLNGTH;
BitField<15, 1, u32> reserved_2;
BitField<16, 7, u32> OUTLNGTH; // Communication Channel Output Length in bytes
BitField<23, 1, u32> reserved_3;
BitField<24, 1, u32> CHANEN; // Channel enable?
BitField<25, 2, u32> CHANNUM; // Channel number?
BitField<27, 1, u32> RDSTINTMSK; // Read Status Interrupt Status Mask
BitField<28, 1, u32> RDSTINT; // Read Status Interrupt Status
BitField<29, 1, u32> COMERR; // Communication Error (set 0)
BitField<30, 1, u32> TCINTMSK; // Transfer Complete Interrupt Mask
BitField<31, 1, u32> TCINT; // Transfer Complete Interrupt

USIComCSR() = default;
explicit USIComCSR(u32 value) : hex{value} {}
};

// SI Status Register
union USIStatusReg
{
u32 hex = 0;

BitField<0, 1, u32> UNRUN3; // (RWC) write 1: bit cleared read 1: main proc underrun error
BitField<1, 1, u32> OVRUN3; // (RWC) write 1: bit cleared read 1: overrun error
BitField<2, 1, u32> COLL3; // (RWC) write 1: bit cleared read 1: collision error
BitField<3, 1, u32> NOREP3; // (RWC) write 1: bit cleared read 1: response error
BitField<4, 1, u32> WRST3; // (R) 1: buffer channel0 not copied
BitField<5, 1, u32> RDST3; // (R) 1: new Data available
BitField<6, 2, u32> reserved_1; // 7:6
BitField<8, 1, u32> UNRUN2; // (RWC) write 1: bit cleared read 1: main proc underrun error
BitField<9, 1, u32> OVRUN2; // (RWC) write 1: bit cleared read 1: overrun error
BitField<10, 1, u32> COLL2; // (RWC) write 1: bit cleared read 1: collision error
BitField<11, 1, u32> NOREP2; // (RWC) write 1: bit cleared read 1: response error
BitField<12, 1, u32> WRST2; // (R) 1: buffer channel0 not copied
BitField<13, 1, u32> RDST2; // (R) 1: new Data available
BitField<14, 2, u32> reserved_2; // 15:14
BitField<16, 1, u32> UNRUN1; // (RWC) write 1: bit cleared read 1: main proc underrun error
BitField<17, 1, u32> OVRUN1; // (RWC) write 1: bit cleared read 1: overrun error
BitField<18, 1, u32> COLL1; // (RWC) write 1: bit cleared read 1: collision error
BitField<19, 1, u32> NOREP1; // (RWC) write 1: bit cleared read 1: response error
BitField<20, 1, u32> WRST1; // (R) 1: buffer channel0 not copied
BitField<21, 1, u32> RDST1; // (R) 1: new Data available
BitField<22, 2, u32> reserved_3; // 23:22
BitField<24, 1, u32> UNRUN0; // (RWC) write 1: bit cleared read 1: main proc underrun error
BitField<25, 1, u32> OVRUN0; // (RWC) write 1: bit cleared read 1: overrun error
BitField<26, 1, u32> COLL0; // (RWC) write 1: bit cleared read 1: collision error
BitField<27, 1, u32> NOREP0; // (RWC) write 1: bit cleared read 1: response error
BitField<28, 1, u32> WRST0; // (R) 1: buffer channel0 not copied
BitField<29, 1, u32> RDST0; // (R) 1: new Data available
BitField<30, 1, u32> reserved_4;
BitField<31, 1, u32> WR; // (RW) write 1 start copy, read 0 copy done

USIStatusReg() = default;
explicit USIStatusReg(u32 value) : hex{value} {}
};

// SI EXI Clock Count
union USIEXIClockCount
{
u32 hex = 0;

BitField<0, 1, u32> LOCK; // 1: prevents CPU from setting EXI clock to 32MHz
BitField<1, 30, u32> reserved;
};

CoreTiming::EventType* m_event_type_change_device = nullptr;
CoreTiming::EventType* m_event_type_tranfer_pending = nullptr;
std::array<CoreTiming::EventType*, MAX_SI_CHANNELS> m_event_types_device{};

// User-configured device type. possibly overridden by TAS/Netplay
std::array<std::atomic<SIDevices>, MAX_SI_CHANNELS> m_desired_device_types{};

std::array<SSIChannel, MAX_SI_CHANNELS> m_channel;
USIPoll m_poll;
USIComCSR m_com_csr;
USIStatusReg m_status_reg;
USIEXIClockCount m_exi_clock_count;
std::array<u8, 128> m_si_buffer{};

Core::System& m_system;
};
} // namespace SerialInterface
27 changes: 14 additions & 13 deletions Source/Core/Core/HW/SI/SI_Device.cpp
Expand Up @@ -55,8 +55,8 @@ std::istream& operator>>(std::istream& stream, SIDevices& device)
return stream;
}

ISIDevice::ISIDevice(SIDevices device_type, int device_number)
: m_device_number(device_number), m_device_type(device_type)
ISIDevice::ISIDevice(Core::System& system, SIDevices device_type, int device_number)
: m_system(system), m_device_number(device_number), m_device_type(device_type)
{
}

Expand Down Expand Up @@ -169,43 +169,44 @@ bool SIDevice_IsGCController(SIDevices type)
}

// F A C T O R Y
std::unique_ptr<ISIDevice> SIDevice_Create(const SIDevices device, const int port_number)
std::unique_ptr<ISIDevice> SIDevice_Create(Core::System& system, const SIDevices device,
const int port_number)
{
switch (device)
{
case SIDEVICE_GC_CONTROLLER:
return std::make_unique<CSIDevice_GCController>(device, port_number);
return std::make_unique<CSIDevice_GCController>(system, device, port_number);

case SIDEVICE_WIIU_ADAPTER:
return std::make_unique<CSIDevice_GCAdapter>(device, port_number);
return std::make_unique<CSIDevice_GCAdapter>(system, device, port_number);

case SIDEVICE_DANCEMAT:
return std::make_unique<CSIDevice_DanceMat>(device, port_number);
return std::make_unique<CSIDevice_DanceMat>(system, device, port_number);

case SIDEVICE_GC_STEERING:
return std::make_unique<CSIDevice_GCSteeringWheel>(device, port_number);
return std::make_unique<CSIDevice_GCSteeringWheel>(system, device, port_number);

case SIDEVICE_GC_TARUKONGA:
return std::make_unique<CSIDevice_TaruKonga>(device, port_number);
return std::make_unique<CSIDevice_TaruKonga>(system, device, port_number);

case SIDEVICE_GC_GBA:
return std::make_unique<CSIDevice_GBA>(device, port_number);
return std::make_unique<CSIDevice_GBA>(system, device, port_number);

case SIDEVICE_GC_GBA_EMULATED:
#ifdef HAS_LIBMGBA
return std::make_unique<CSIDevice_GBAEmu>(device, port_number);
return std::make_unique<CSIDevice_GBAEmu>(system, device, port_number);
#else
PanicAlertFmtT("Error: This build does not support emulated GBA controllers");
return std::make_unique<CSIDevice_Null>(device, port_number);
return std::make_unique<CSIDevice_Null>(system, device, port_number);
#endif

case SIDEVICE_GC_KEYBOARD:
return std::make_unique<CSIDevice_Keyboard>(device, port_number);
return std::make_unique<CSIDevice_Keyboard>(system, device, port_number);

case SIDEVICE_AM_BASEBOARD:
case SIDEVICE_NONE:
default:
return std::make_unique<CSIDevice_Null>(device, port_number);
return std::make_unique<CSIDevice_Null>(system, device, port_number);
}
}
} // namespace SerialInterface
10 changes: 8 additions & 2 deletions Source/Core/Core/HW/SI/SI_Device.h
Expand Up @@ -8,6 +8,10 @@
#include "Common/CommonTypes.h"

class PointerWrap;
namespace Core
{
class System;
}

namespace SerialInterface
{
Expand Down Expand Up @@ -105,7 +109,7 @@ std::istream& operator>>(std::istream& stream, SIDevices& device);
class ISIDevice
{
public:
ISIDevice(SIDevices device_type, int device_number);
ISIDevice(Core::System& system, SIDevices device_type, int device_number);
virtual ~ISIDevice();

int GetDeviceNumber() const;
Expand All @@ -128,12 +132,14 @@ class ISIDevice
virtual void OnEvent(u64 userdata, s64 cycles_late);

protected:
Core::System& m_system;

int m_device_number;
SIDevices m_device_type;
};

int SIDevice_GetGBATransferTime(EBufferCommands cmd);
bool SIDevice_IsGCController(SIDevices type);

std::unique_ptr<ISIDevice> SIDevice_Create(SIDevices device, int port_number);
std::unique_ptr<ISIDevice> SIDevice_Create(Core::System& system, SIDevices device, int port_number);
} // namespace SerialInterface
4 changes: 2 additions & 2 deletions Source/Core/Core/HW/SI/SI_DeviceDanceMat.cpp
Expand Up @@ -11,8 +11,8 @@

namespace SerialInterface
{
CSIDevice_DanceMat::CSIDevice_DanceMat(SIDevices device, int device_number)
: CSIDevice_GCController(device, device_number)
CSIDevice_DanceMat::CSIDevice_DanceMat(Core::System& system, SIDevices device, int device_number)
: CSIDevice_GCController(system, device, device_number)
{
}

Expand Down
4 changes: 2 additions & 2 deletions Source/Core/Core/HW/SI/SI_DeviceDanceMat.h
Expand Up @@ -10,10 +10,10 @@ struct GCPadStatus;

namespace SerialInterface
{
class CSIDevice_DanceMat : public CSIDevice_GCController
class CSIDevice_DanceMat final : public CSIDevice_GCController
{
public:
CSIDevice_DanceMat(SIDevices device, int device_number);
CSIDevice_DanceMat(Core::System& system, SIDevices device, int device_number);

int RunBuffer(u8* buffer, int request_length) override;
u32 MapPadStatus(const GCPadStatus& pad_status) override;
Expand Down
13 changes: 6 additions & 7 deletions Source/Core/Core/HW/SI/SI_DeviceGBA.cpp
Expand Up @@ -140,13 +140,12 @@ void GBASockServer::Disconnect()
m_booted = false;
}

void GBASockServer::ClockSync()
void GBASockServer::ClockSync(Core::System& system)
{
if (!m_clock_sync)
if (!(m_clock_sync = GetNextClock()))
return;

auto& system = Core::System::GetInstance();
auto& core_timing = system.GetCoreTiming();

u32 time_slice = 0;
Expand Down Expand Up @@ -263,7 +262,8 @@ void GBASockServer::Flush()
}
}

CSIDevice_GBA::CSIDevice_GBA(SIDevices device, int device_number) : ISIDevice(device, device_number)
CSIDevice_GBA::CSIDevice_GBA(Core::System& system, SIDevices device, int device_number)
: ISIDevice(system, device, device_number)
{
}

Expand All @@ -273,7 +273,7 @@ int CSIDevice_GBA::RunBuffer(u8* buffer, int request_length)
{
case NextAction::SendCommand:
{
m_sock_server.ClockSync();
m_sock_server.ClockSync(m_system);
if (m_sock_server.Connect())
{
#ifdef _DEBUG
Expand All @@ -289,15 +289,14 @@ int CSIDevice_GBA::RunBuffer(u8* buffer, int request_length)
}

m_last_cmd = static_cast<EBufferCommands>(buffer[0]);
m_timestamp_sent = Core::System::GetInstance().GetCoreTiming().GetTicks();
m_timestamp_sent = m_system.GetCoreTiming().GetTicks();
m_next_action = NextAction::WaitTransferTime;
return 0;
}

case NextAction::WaitTransferTime:
{
int elapsed_time =
static_cast<int>(Core::System::GetInstance().GetCoreTiming().GetTicks() - m_timestamp_sent);
int elapsed_time = static_cast<int>(m_system.GetCoreTiming().GetTicks() - m_timestamp_sent);
// Tell SI to ask again after TransferInterval() cycles
if (SIDevice_GetGBATransferTime(m_last_cmd) > elapsed_time)
return 0;
Expand Down
6 changes: 3 additions & 3 deletions Source/Core/Core/HW/SI/SI_DeviceGBA.h
Expand Up @@ -25,7 +25,7 @@ class GBASockServer

bool Connect();
bool IsConnected();
void ClockSync();
void ClockSync(Core::System& system);
void Send(const u8* si_buffer);
int Receive(u8* si_buffer, u8 bytes);
void Flush();
Expand All @@ -40,10 +40,10 @@ class GBASockServer
bool m_booted = false;
};

class CSIDevice_GBA : public ISIDevice
class CSIDevice_GBA final : public ISIDevice
{
public:
CSIDevice_GBA(SIDevices device, int device_number);
CSIDevice_GBA(Core::System& system, SIDevices device, int device_number);

int RunBuffer(u8* buffer, int request_length) override;
int TransferInterval() override;
Expand Down
31 changes: 15 additions & 16 deletions Source/Core/Core/HW/SI/SI_DeviceGBAEmu.cpp
Expand Up @@ -27,19 +27,19 @@ static s64 GetSyncInterval()
return SystemTimers::GetTicksPerSecond() / 1000;
}

CSIDevice_GBAEmu::CSIDevice_GBAEmu(SIDevices device, int device_number)
: ISIDevice(device, device_number)
CSIDevice_GBAEmu::CSIDevice_GBAEmu(Core::System& system, SIDevices device, int device_number)
: ISIDevice(system, device, device_number)
{
m_core = std::make_shared<HW::GBA::Core>(m_device_number);
m_core->Start(Core::System::GetInstance().GetCoreTiming().GetTicks());
m_core->Start(system.GetCoreTiming().GetTicks());
m_gbahost = Host_CreateGBAHost(m_core);
m_core->SetHost(m_gbahost);
ScheduleEvent(m_device_number, GetSyncInterval());
system.GetSerialInterface().ScheduleEvent(m_device_number, GetSyncInterval());
}

CSIDevice_GBAEmu::~CSIDevice_GBAEmu()
{
RemoveEvent(m_device_number);
m_system.GetSerialInterface().RemoveEvent(m_device_number);
m_core->Stop();
m_gbahost.reset();
m_core.reset();
Expand All @@ -56,17 +56,18 @@ int CSIDevice_GBAEmu::RunBuffer(u8* buffer, int request_length)
buffer[0], buffer[1], buffer[2], buffer[3], buffer[4]);
#endif
m_last_cmd = static_cast<EBufferCommands>(buffer[0]);
m_timestamp_sent = Core::System::GetInstance().GetCoreTiming().GetTicks();
m_timestamp_sent = m_system.GetCoreTiming().GetTicks();
m_core->SendJoybusCommand(m_timestamp_sent, TransferInterval(), buffer, m_keys);

RemoveEvent(m_device_number);
ScheduleEvent(m_device_number, TransferInterval() + GetSyncInterval());
auto& si = m_system.GetSerialInterface();
si.RemoveEvent(m_device_number);
si.ScheduleEvent(m_device_number, TransferInterval() + GetSyncInterval());
for (int i = 0; i < MAX_SI_CHANNELS; ++i)
{
if (i == m_device_number || SerialInterface::GetDeviceType(i) != GetDeviceType())
if (i == m_device_number || si.GetDeviceType(i) != GetDeviceType())
continue;
RemoveEvent(i);
ScheduleEvent(i, 0, static_cast<u64>(TransferInterval()));
si.RemoveEvent(i);
si.ScheduleEvent(i, 0, static_cast<u64>(TransferInterval()));
}

m_next_action = NextAction::WaitTransferTime;
Expand All @@ -75,8 +76,7 @@ int CSIDevice_GBAEmu::RunBuffer(u8* buffer, int request_length)

case NextAction::WaitTransferTime:
{
int elapsed_time =
static_cast<int>(Core::System::GetInstance().GetCoreTiming().GetTicks() - m_timestamp_sent);
int elapsed_time = static_cast<int>(m_system.GetCoreTiming().GetTicks() - m_timestamp_sent);
// Tell SI to ask again after TransferInterval() cycles
if (TransferInterval() > elapsed_time)
return 0;
Expand Down Expand Up @@ -164,8 +164,7 @@ void CSIDevice_GBAEmu::DoState(PointerWrap& p)

void CSIDevice_GBAEmu::OnEvent(u64 userdata, s64 cycles_late)
{
m_core->SendJoybusCommand(Core::System::GetInstance().GetCoreTiming().GetTicks() + userdata, 0,
nullptr, m_keys);
ScheduleEvent(m_device_number, userdata + GetSyncInterval());
m_core->SendJoybusCommand(m_system.GetCoreTiming().GetTicks() + userdata, 0, nullptr, m_keys);
m_system.GetSerialInterface().ScheduleEvent(m_device_number, userdata + GetSyncInterval());
}
} // namespace SerialInterface
4 changes: 2 additions & 2 deletions Source/Core/Core/HW/SI/SI_DeviceGBAEmu.h
Expand Up @@ -17,10 +17,10 @@ class GBAHostInterface;

namespace SerialInterface
{
class CSIDevice_GBAEmu : public ISIDevice
class CSIDevice_GBAEmu final : public ISIDevice
{
public:
CSIDevice_GBAEmu(SIDevices device, int device_number);
CSIDevice_GBAEmu(Core::System& system, SIDevices device, int device_number);
~CSIDevice_GBAEmu();

int RunBuffer(u8* buffer, int request_length) override;
Expand Down
4 changes: 2 additions & 2 deletions Source/Core/Core/HW/SI/SI_DeviceGCAdapter.cpp
Expand Up @@ -15,8 +15,8 @@

namespace SerialInterface
{
CSIDevice_GCAdapter::CSIDevice_GCAdapter(SIDevices device, int device_number)
: CSIDevice_GCController(device, device_number)
CSIDevice_GCAdapter::CSIDevice_GCAdapter(Core::System& system, SIDevices device, int device_number)
: CSIDevice_GCController(system, device, device_number)
{
// Make sure PAD_GET_ORIGIN gets set due to a newly connected device.
GCAdapter::ResetDeviceType(m_device_number);
Expand Down
4 changes: 2 additions & 2 deletions Source/Core/Core/HW/SI/SI_DeviceGCAdapter.h
Expand Up @@ -9,10 +9,10 @@

namespace SerialInterface
{
class CSIDevice_GCAdapter : public CSIDevice_GCController
class CSIDevice_GCAdapter final : public CSIDevice_GCController
{
public:
CSIDevice_GCAdapter(SIDevices device, int device_number);
CSIDevice_GCAdapter(Core::System& system, SIDevices device, int device_number);

GCPadStatus GetPadStatus() override;
int RunBuffer(u8* buffer, int request_length) override;
Expand Down
16 changes: 8 additions & 8 deletions Source/Core/Core/HW/SI/SI_DeviceGCController.cpp
Expand Up @@ -24,8 +24,9 @@
namespace SerialInterface
{
// --- standard GameCube controller ---
CSIDevice_GCController::CSIDevice_GCController(SIDevices device, int device_number)
: ISIDevice(device, device_number)
CSIDevice_GCController::CSIDevice_GCController(Core::System& system, SIDevices device,
int device_number)
: ISIDevice(system, device, device_number)
{
// Here we set origin to perfectly centered values.
// This purposely differs from real hardware which sets origin to current input state.
Expand Down Expand Up @@ -264,19 +265,18 @@ CSIDevice_GCController::HandleButtonCombos(const GCPadStatus& pad_status)
{
m_last_button_combo = temp_combo;
if (m_last_button_combo != COMBO_NONE)
m_timer_button_combo_start = Core::System::GetInstance().GetCoreTiming().GetTicks();
m_timer_button_combo_start = m_system.GetCoreTiming().GetTicks();
}

if (m_last_button_combo != COMBO_NONE)
{
auto& system = Core::System::GetInstance();
const u64 current_time = system.GetCoreTiming().GetTicks();
const u64 current_time = m_system.GetCoreTiming().GetTicks();
if (u32(current_time - m_timer_button_combo_start) > SystemTimers::GetTicksPerSecond() * 3)
{
if (m_last_button_combo == COMBO_RESET)
{
INFO_LOG_FMT(SERIALINTERFACE, "PAD - COMBO_RESET");
system.GetProcessorInterface().ResetButton_Tap();
m_system.GetProcessorInterface().ResetButton_Tap();
}
else if (m_last_button_combo == COMBO_ORIGIN)
{
Expand Down Expand Up @@ -355,8 +355,8 @@ void CSIDevice_GCController::RefreshConfig()
}
}

CSIDevice_TaruKonga::CSIDevice_TaruKonga(SIDevices device, int device_number)
: CSIDevice_GCController(device, device_number)
CSIDevice_TaruKonga::CSIDevice_TaruKonga(Core::System& system, SIDevices device, int device_number)
: CSIDevice_GCController(system, device, device_number)
{
}

Expand Down
6 changes: 3 additions & 3 deletions Source/Core/Core/HW/SI/SI_DeviceGCController.h
Expand Up @@ -53,7 +53,7 @@ class CSIDevice_GCController : public ISIDevice

public:
// Constructor
CSIDevice_GCController(SIDevices device, int device_number);
CSIDevice_GCController(Core::System& system, SIDevices device, int device_number);
~CSIDevice_GCController() override;

// Run the SI Buffer
Expand Down Expand Up @@ -92,10 +92,10 @@ class CSIDevice_GCController : public ISIDevice
};

// "TaruKonga", the DK Bongo controller
class CSIDevice_TaruKonga : public CSIDevice_GCController
class CSIDevice_TaruKonga final : public CSIDevice_GCController
{
public:
CSIDevice_TaruKonga(SIDevices device, int device_number);
CSIDevice_TaruKonga(Core::System& system, SIDevices device, int device_number);

bool GetData(u32& hi, u32& low) override;

Expand Down
5 changes: 3 additions & 2 deletions Source/Core/Core/HW/SI/SI_DeviceGCSteeringWheel.cpp
Expand Up @@ -14,8 +14,9 @@

namespace SerialInterface
{
CSIDevice_GCSteeringWheel::CSIDevice_GCSteeringWheel(SIDevices device, int device_number)
: CSIDevice_GCController(device, device_number)
CSIDevice_GCSteeringWheel::CSIDevice_GCSteeringWheel(Core::System& system, SIDevices device,
int device_number)
: CSIDevice_GCController(system, device, device_number)
{
}

Expand Down
4 changes: 2 additions & 2 deletions Source/Core/Core/HW/SI/SI_DeviceGCSteeringWheel.h
Expand Up @@ -7,10 +7,10 @@

namespace SerialInterface
{
class CSIDevice_GCSteeringWheel : public CSIDevice_GCController
class CSIDevice_GCSteeringWheel final : public CSIDevice_GCController
{
public:
CSIDevice_GCSteeringWheel(SIDevices device, int device_number);
CSIDevice_GCSteeringWheel(Core::System& system, SIDevices device, int device_number);

int RunBuffer(u8* buffer, int request_length) override;
bool GetData(u32& hi, u32& low) override;
Expand Down
4 changes: 2 additions & 2 deletions Source/Core/Core/HW/SI/SI_DeviceKeyboard.cpp
Expand Up @@ -16,8 +16,8 @@
namespace SerialInterface
{
// --- GameCube keyboard ---
CSIDevice_Keyboard::CSIDevice_Keyboard(SIDevices device, int device_number)
: ISIDevice(device, device_number)
CSIDevice_Keyboard::CSIDevice_Keyboard(Core::System& system, SIDevices device, int device_number)
: ISIDevice(system, device, device_number)
{
}

Expand Down
4 changes: 2 additions & 2 deletions Source/Core/Core/HW/SI/SI_DeviceKeyboard.h
Expand Up @@ -12,11 +12,11 @@ struct KeyboardStatus;

namespace SerialInterface
{
class CSIDevice_Keyboard : public ISIDevice
class CSIDevice_Keyboard final : public ISIDevice
{
public:
// Constructor
CSIDevice_Keyboard(SIDevices device, int device_number);
CSIDevice_Keyboard(Core::System& system, SIDevices device, int device_number);

// Run the SI Buffer
int RunBuffer(u8* buffer, int request_length) override;
Expand Down
4 changes: 2 additions & 2 deletions Source/Core/Core/HW/SI/SI_DeviceNull.cpp
Expand Up @@ -5,8 +5,8 @@

namespace SerialInterface
{
CSIDevice_Null::CSIDevice_Null(SIDevices device, int device_number)
: ISIDevice{device, device_number}
CSIDevice_Null::CSIDevice_Null(Core::System& system, SIDevices device, int device_number)
: ISIDevice{system, device, device_number}
{
}

Expand Down
2 changes: 1 addition & 1 deletion Source/Core/Core/HW/SI/SI_DeviceNull.h
Expand Up @@ -12,7 +12,7 @@ namespace SerialInterface
class CSIDevice_Null final : public ISIDevice
{
public:
CSIDevice_Null(SIDevices device, int device_number);
CSIDevice_Null(Core::System& system, SIDevices device, int device_number);

int RunBuffer(u8* buffer, int request_length) override;
bool GetData(u32& hi, u32& low) override;
Expand Down
5 changes: 3 additions & 2 deletions Source/Core/Core/HW/VideoInterface.cpp
Expand Up @@ -885,8 +885,9 @@ void VideoInterfaceManager::Update(u64 ticks)
{
Core::UpdateInputGate(!Config::Get(Config::MAIN_INPUT_BACKGROUND_INPUT),
Config::Get(Config::MAIN_LOCK_CURSOR));
SerialInterface::UpdateDevices();
m_half_line_of_next_si_poll += 2 * SerialInterface::GetPollXLines();
auto& si = m_system.GetSerialInterface();
si.UpdateDevices();
m_half_line_of_next_si_poll += 2 * si.GetPollXLines();
}

// If this half-line is at the actual boundary of either field, schedule an SI poll to happen
Expand Down
8 changes: 5 additions & 3 deletions Source/Core/Core/Movie.cpp
Expand Up @@ -169,9 +169,10 @@ std::string GetInputDisplay()
s_wiimotes = {};
for (int i = 0; i < 4; ++i)
{
if (SerialInterface::GetDeviceType(i) == SerialInterface::SIDEVICE_GC_GBA_EMULATED)
auto& si = Core::System::GetInstance().GetSerialInterface();
if (si.GetDeviceType(i) == SerialInterface::SIDEVICE_GC_GBA_EMULATED)
s_controllers[i] = ControllerType::GBA;
else if (SerialInterface::GetDeviceType(i) != SerialInterface::SIDEVICE_NONE)
else if (si.GetDeviceType(i) != SerialInterface::SIDEVICE_NONE)
s_controllers[i] = ControllerType::GC;
else
s_controllers[i] = ControllerType::None;
Expand Down Expand Up @@ -484,6 +485,7 @@ void ChangePads()
if (s_controllers == controllers)
return;

auto& si = Core::System::GetInstance().GetSerialInterface();
for (int i = 0; i < SerialInterface::MAX_SI_CHANNELS; ++i)
{
SerialInterface::SIDevices device = SerialInterface::SIDEVICE_NONE;
Expand All @@ -505,7 +507,7 @@ void ChangePads()
}
}

SerialInterface::ChangeDevice(device, i);
si.ChangeDevice(device, i);
}
}

Expand Down
12 changes: 7 additions & 5 deletions Source/Core/Core/NetPlayClient.cpp
Expand Up @@ -67,6 +67,7 @@
#include "Core/NetPlayCommon.h"
#include "Core/PowerPC/PowerPC.h"
#include "Core/SyncIdentifier.h"
#include "Core/System.h"
#include "DiscIO/Blob.h"

#include "InputCommon/ControllerEmu/ControlGroup/Attachments.h"
Expand Down Expand Up @@ -1833,11 +1834,12 @@ void NetPlayClient::UpdateDevices()
u8 local_pad = 0;
u8 pad = 0;

auto& si = Core::System::GetInstance().GetSerialInterface();
for (auto player_id : m_pad_map)
{
if (m_gba_config[pad].enabled && player_id > 0)
{
SerialInterface::ChangeDevice(SerialInterface::SIDEVICE_GC_GBA_EMULATED, pad);
si.ChangeDevice(SerialInterface::SIDEVICE_GC_GBA_EMULATED, pad);
}
else if (player_id == m_local_player->pid)
{
Expand All @@ -1846,7 +1848,7 @@ void NetPlayClient::UpdateDevices()
Config::Get(Config::GetInfoForSIDevice(local_pad));
if (SerialInterface::SIDevice_IsGCController(si_device))
{
SerialInterface::ChangeDevice(si_device, pad);
si.ChangeDevice(si_device, pad);

if (si_device == SerialInterface::SIDEVICE_WIIU_ADAPTER)
{
Expand All @@ -1855,17 +1857,17 @@ void NetPlayClient::UpdateDevices()
}
else
{
SerialInterface::ChangeDevice(SerialInterface::SIDEVICE_GC_CONTROLLER, pad);
si.ChangeDevice(SerialInterface::SIDEVICE_GC_CONTROLLER, pad);
}
local_pad++;
}
else if (player_id > 0)
{
SerialInterface::ChangeDevice(SerialInterface::SIDEVICE_GC_CONTROLLER, pad);
si.ChangeDevice(SerialInterface::SIDEVICE_GC_CONTROLLER, pad);
}
else
{
SerialInterface::ChangeDevice(SerialInterface::SIDEVICE_NONE, pad);
si.ChangeDevice(SerialInterface::SIDEVICE_NONE, pad);
}
pad++;
}
Expand Down
8 changes: 4 additions & 4 deletions Source/Core/Core/System.cpp
Expand Up @@ -38,7 +38,7 @@ struct System::Impl
explicit Impl(System& system)
: m_audio_interface(system), m_core_timing(system), m_dsp(system), m_dvd_interface(system),
m_dvd_thread(system), m_expansion_interface(system), m_gp_fifo(system),
m_ppc_state(PowerPC::ppcState), m_video_interface(system)
m_ppc_state(PowerPC::ppcState), m_serial_interface(system), m_video_interface(system)
{
}

Expand All @@ -65,7 +65,7 @@ struct System::Impl
PixelShaderManager m_pixel_shader_manager;
PowerPC::PowerPCState& m_ppc_state;
ProcessorInterface::ProcessorInterfaceManager m_processor_interface;
SerialInterface::SerialInterfaceState m_serial_interface_state;
SerialInterface::SerialInterfaceManager m_serial_interface;
Sram m_sram;
VertexShaderManager m_vertex_shader_manager;
VideoInterface::VideoInterfaceManager m_video_interface;
Expand Down Expand Up @@ -209,9 +209,9 @@ ProcessorInterface::ProcessorInterfaceManager& System::GetProcessorInterface() c
return m_impl->m_processor_interface;
}

SerialInterface::SerialInterfaceState& System::GetSerialInterfaceState() const
SerialInterface::SerialInterfaceManager& System::GetSerialInterface() const
{
return m_impl->m_serial_interface_state;
return m_impl->m_serial_interface;
}

Sram& System::GetSRAM() const
Expand Down
4 changes: 2 additions & 2 deletions Source/Core/Core/System.h
Expand Up @@ -78,7 +78,7 @@ class ProcessorInterfaceManager;
}
namespace SerialInterface
{
class SerialInterfaceState;
class SerialInterfaceManager;
};
namespace VideoInterface
{
Expand Down Expand Up @@ -138,7 +138,7 @@ class System
PixelShaderManager& GetPixelShaderManager() const;
PowerPC::PowerPCState& GetPPCState() const;
ProcessorInterface::ProcessorInterfaceManager& GetProcessorInterface() const;
SerialInterface::SerialInterfaceState& GetSerialInterfaceState() const;
SerialInterface::SerialInterfaceManager& GetSerialInterface() const;
Sram& GetSRAM() const;
VertexShaderManager& GetVertexShaderManager() const;
VideoInterface::VideoInterfaceManager& GetVideoInterface() const;
Expand Down
6 changes: 5 additions & 1 deletion Source/Core/DolphinQt/Config/GamecubeControllersWidget.cpp
Expand Up @@ -19,6 +19,7 @@
#include "Core/HW/SI/SI.h"
#include "Core/HW/SI/SI_Device.h"
#include "Core/NetPlayProto.h"
#include "Core/System.h"

#include "DolphinQt/Config/Mapping/GCPadWiiUConfigDialog.h"
#include "DolphinQt/Config/Mapping/MappingWindow.h"
Expand Down Expand Up @@ -192,7 +193,10 @@ void GamecubeControllersWidget::SaveSettings()
Config::SetBaseOrCurrent(Config::GetInfoForSIDevice(static_cast<int>(i)), si_device);

if (Core::IsRunning())
SerialInterface::ChangeDevice(si_device, static_cast<s32>(i));
{
Core::System::GetInstance().GetSerialInterface().ChangeDevice(si_device,
static_cast<s32>(i));
}
}

if (GCAdapter::UseAdapter())
Expand Down