Expand Up
@@ -25,6 +25,7 @@
#include " Core/HW/SystemTimers.h"
#include " Core/Movie.h"
#include " Core/NetPlayProto.h"
#include " Core/System.h"
#include " InputCommon/ControllerInterface/ControllerInterface.h"
Expand Down
Expand Up
@@ -198,71 +199,88 @@ union USIEXIClockCount
BitField<1 , 30 , u32> reserved;
};
static CoreTiming::EventType* s_change_device_event;
static CoreTiming::EventType* s_tranfer_pending_event;
static std::array<CoreTiming::EventType*, MAX_SI_CHANNELS> s_device_events;
struct SerialInterfaceState ::Data
{
CoreTiming::EventType* event_type_change_device;
CoreTiming::EventType* event_type_tranfer_pending;
std::array<CoreTiming::EventType*, MAX_SI_CHANNELS> event_types_device;
// User-configured device type. possibly overridden by TAS/Netplay
std::array<std::atomic<SIDevices>, MAX_SI_CHANNELS> desired_device_types;
std::array<SSIChannel, MAX_SI_CHANNELS> channel;
USIPoll poll;
USIComCSR com_csr;
USIStatusReg status_reg;
USIEXIClockCount exi_clock_count;
std::array<u8, 128 > si_buffer;
};
// User-configured device type. possibly overridden by TAS/Netplay
static std::array<std::atomic<SIDevices>, MAX_SI_CHANNELS> s_desired_device_types;
SerialInterfaceState::SerialInterfaceState () : m_data(std::make_unique<Data>())
{
}
// STATE_TO_SAVE
static std::array<SSIChannel, MAX_SI_CHANNELS> s_channel;
static USIPoll s_poll;
static USIComCSR s_com_csr;
static USIStatusReg s_status_reg;
static USIEXIClockCount s_exi_clock_count;
static std::array<u8, 128 > s_si_buffer;
SerialInterfaceState::~SerialInterfaceState () = default ;
static void SetNoResponse (u32 channel)
{
auto & state = Core::System::GetInstance ().GetSerialInterfaceState ().GetData ();
// raise the NO RESPONSE error
switch (channel)
{
case 0 :
s_status_reg .NOREP0 = 1 ;
state. status_reg .NOREP0 = 1 ;
break ;
case 1 :
s_status_reg .NOREP1 = 1 ;
state. status_reg .NOREP1 = 1 ;
break ;
case 2 :
s_status_reg .NOREP2 = 1 ;
state. status_reg .NOREP2 = 1 ;
break ;
case 3 :
s_status_reg .NOREP3 = 1 ;
state. status_reg .NOREP3 = 1 ;
break ;
}
}
static void ChangeDeviceCallback (u64 user_data, s64 cycles_late)
{
// The purpose of this callback is to simply re-enable device changes.
s_channel[user_data].has_recent_device_change = false ;
auto & state = Core::System::GetInstance ().GetSerialInterfaceState ().GetData ();
state.channel [user_data].has_recent_device_change = false ;
}
static void UpdateInterrupts ()
{
// check if we have to update the RDSTINT flag
if (s_status_reg.RDST0 || s_status_reg.RDST1 || s_status_reg.RDST2 || s_status_reg.RDST3 )
s_com_csr.RDSTINT = 1 ;
auto & state = Core::System::GetInstance ().GetSerialInterfaceState ().GetData ();
if (state.status_reg .RDST0 || state.status_reg .RDST1 || state.status_reg .RDST2 ||
state.status_reg .RDST3 )
{
state.com_csr .RDSTINT = 1 ;
}
else
s_com_csr.RDSTINT = 0 ;
{
state.com_csr .RDSTINT = 0 ;
}
// check if we have to generate an interrupt
const bool generate_interrupt = (s_com_csr. RDSTINT & s_com_csr .RDSTINTMSK ) != 0 ||
(s_com_csr. TCINT & s_com_csr .TCINTMSK ) != 0 ;
const bool generate_interrupt = (state. com_csr . RDSTINT & state. com_csr .RDSTINTMSK ) != 0 ||
(state. com_csr . TCINT & state. com_csr .TCINTMSK ) != 0 ;
ProcessorInterface::SetInterrupt (ProcessorInterface::INT_CAUSE_SI, generate_interrupt);
}
static void GenerateSIInterrupt (SIInterruptType type)
{
auto & state = Core::System::GetInstance ().GetSerialInterfaceState ().GetData ();
switch (type)
{
case INT_RDSTINT:
s_com_csr .RDSTINT = 1 ;
state. com_csr .RDSTINT = 1 ;
break ;
case INT_TCINT:
s_com_csr .TCINT = 1 ;
state. com_csr .TCINT = 1 ;
break ;
}
Expand All
@@ -279,19 +297,21 @@ constexpr s32 ConvertSILengthField(u32 field)
static void RunSIBuffer (u64 user_data, s64 cycles_late)
{
if (s_com_csr.TSTART )
auto & state = Core::System::GetInstance ().GetSerialInterfaceState ().GetData ();
if (state.com_csr .TSTART )
{
const s32 request_length = ConvertSILengthField (s_com_csr.OUTLNGTH );
const s32 expected_response_length = ConvertSILengthField (s_com_csr.INLNGTH );
const std::vector<u8> request_copy (s_si_buffer.data (), s_si_buffer.data () + request_length);
const s32 request_length = ConvertSILengthField (state.com_csr .OUTLNGTH );
const s32 expected_response_length = ConvertSILengthField (state.com_csr .INLNGTH );
const std::vector<u8> request_copy (state.si_buffer .data (),
state.si_buffer .data () + request_length);
const std::unique_ptr<ISIDevice>& device = s_channel[s_com_csr .CHANNEL ].device ;
const s32 actual_response_length = device->RunBuffer (s_si_buffer .data (), request_length);
const std::unique_ptr<ISIDevice>& device = state. channel [state. com_csr .CHANNEL ].device ;
const s32 actual_response_length = device->RunBuffer (state. si_buffer .data (), request_length);
DEBUG_LOG_FMT (SERIALINTERFACE,
" RunSIBuffer chan: {} request_length: {} expected_response_length: {} "
" actual_response_length: {}" ,
s_com_csr .CHANNEL , request_length, expected_response_length,
state. com_csr .CHANNEL , request_length, expected_response_length,
actual_response_length);
if (actual_response_length > 0 && expected_response_length != actual_response_length)
{
Expand All
@@ -316,29 +336,31 @@ static void RunSIBuffer(u64 user_data, s64 cycles_late)
// 2) Investigate the timeout period for NOREP0
if (actual_response_length != 0 )
{
s_com_csr .TSTART = 0 ;
s_com_csr .COMERR = actual_response_length < 0 ;
state. com_csr .TSTART = 0 ;
state. com_csr .COMERR = actual_response_length < 0 ;
if (actual_response_length < 0 )
SetNoResponse (s_com_csr .CHANNEL );
SetNoResponse (state. com_csr .CHANNEL );
GenerateSIInterrupt (INT_TCINT);
}
else
{
CoreTiming::ScheduleEvent (device->TransferInterval () - cycles_late, s_tranfer_pending_event);
CoreTiming::ScheduleEvent (device->TransferInterval () - cycles_late,
state.event_type_tranfer_pending );
}
}
}
void DoState (PointerWrap& p)
{
auto & state = Core::System::GetInstance ().GetSerialInterfaceState ().GetData ();
for (int i = 0 ; i < MAX_SI_CHANNELS; i++)
{
p.Do (s_channel [i].in_hi .hex );
p.Do (s_channel [i].in_lo .hex );
p.Do (s_channel [i].out .hex );
p.Do (s_channel [i].has_recent_device_change );
p.Do (state. channel [i].in_hi .hex );
p.Do (state. channel [i].in_lo .hex );
p.Do (state. channel [i].out .hex );
p.Do (state. channel [i].has_recent_device_change );
std::unique_ptr<ISIDevice>& device = s_channel [i].device ;
std::unique_ptr<ISIDevice>& device = state. channel [i].device ;
SIDevices type = device->GetDeviceType ();
p.Do (type);
Expand All
@@ -350,23 +372,26 @@ void DoState(PointerWrap& p)
device->DoState (p);
}
p.Do (s_poll );
p.Do (s_com_csr );
p.Do (s_status_reg );
p.Do (s_exi_clock_count );
p.Do (s_si_buffer );
p.Do (state. poll );
p.Do (state. com_csr );
p.Do (state. status_reg );
p.Do (state. exi_clock_count );
p.Do (state. si_buffer );
}
template <int device_number>
static void DeviceEventCallback (u64 userdata, s64 cyclesLate)
{
s_channel[device_number].device ->OnEvent (userdata, cyclesLate);
auto & state = Core::System::GetInstance ().GetSerialInterfaceState ().GetData ();
state.channel [device_number].device ->OnEvent (userdata, cyclesLate);
}
static void RegisterEvents ()
{
s_change_device_event = CoreTiming::RegisterEvent (" ChangeSIDevice" , ChangeDeviceCallback);
s_tranfer_pending_event = CoreTiming::RegisterEvent (" SITransferPending" , RunSIBuffer);
auto & state = Core::System::GetInstance ().GetSerialInterfaceState ().GetData ();
state.event_type_change_device =
CoreTiming::RegisterEvent (" ChangeSIDevice" , ChangeDeviceCallback);
state.event_type_tranfer_pending = CoreTiming::RegisterEvent (" SITransferPending" , RunSIBuffer);
constexpr std::array<CoreTiming::TimedCallback, MAX_SI_CHANNELS> event_callbacks = {
DeviceEventCallback<0 >,
Expand All
@@ -376,73 +401,76 @@ static void RegisterEvents()
};
for (int i = 0 ; i < MAX_SI_CHANNELS; ++i)
{
s_device_events [i] =
state. event_types_device [i] =
CoreTiming::RegisterEvent (fmt::format (" SIEventChannel{}" , i), event_callbacks[i]);
}
}
void ScheduleEvent (int device_number, s64 cycles_into_future, u64 userdata)
{
CoreTiming::ScheduleEvent (cycles_into_future, s_device_events[device_number], userdata);
auto & state = Core::System::GetInstance ().GetSerialInterfaceState ().GetData ();
CoreTiming::ScheduleEvent (cycles_into_future, state.event_types_device [device_number], userdata);
}
void RemoveEvent (int device_number)
{
CoreTiming::RemoveEvent (s_device_events[device_number]);
auto & state = Core::System::GetInstance ().GetSerialInterfaceState ().GetData ();
CoreTiming::RemoveEvent (state.event_types_device [device_number]);
}
void Init ()
{
auto & state = Core::System::GetInstance ().GetSerialInterfaceState ().GetData ();
RegisterEvents ();
for (int i = 0 ; i < MAX_SI_CHANNELS; i++)
{
s_channel [i].out .hex = 0 ;
s_channel [i].in_hi .hex = 0 ;
s_channel [i].in_lo .hex = 0 ;
s_channel [i].has_recent_device_change = false ;
state. channel [i].out .hex = 0 ;
state. channel [i].in_hi .hex = 0 ;
state. channel [i].in_lo .hex = 0 ;
state. channel [i].has_recent_device_change = false ;
if (Movie::IsMovieActive ())
{
s_desired_device_types [i] = SIDEVICE_NONE;
state. desired_device_types [i] = SIDEVICE_NONE;
if (Movie::IsUsingGBA (i))
{
s_desired_device_types [i] = SIDEVICE_GC_GBA_EMULATED;
state. desired_device_types [i] = SIDEVICE_GC_GBA_EMULATED;
}
else if (Movie::IsUsingPad (i))
{
SIDevices current = Config::Get (Config::GetInfoForSIDevice (i));
// GC pad-compatible devices can be used for both playing and recording
if (Movie::IsUsingBongo (i))
s_desired_device_types [i] = SIDEVICE_GC_TARUKONGA;
state. desired_device_types [i] = SIDEVICE_GC_TARUKONGA;
else if (SIDevice_IsGCController (current))
s_desired_device_types [i] = current;
state. desired_device_types [i] = current;
else
s_desired_device_types [i] = SIDEVICE_GC_CONTROLLER;
state. desired_device_types [i] = SIDEVICE_GC_CONTROLLER;
}
}
else if (!NetPlay::IsNetPlayRunning ())
{
s_desired_device_types [i] = Config::Get (Config::GetInfoForSIDevice (i));
state. desired_device_types [i] = Config::Get (Config::GetInfoForSIDevice (i));
}
AddDevice (s_desired_device_types [i], i);
AddDevice (state. desired_device_types [i], i);
}
s_poll .hex = 0 ;
s_poll .X = 492 ;
state. poll .hex = 0 ;
state. poll .X = 492 ;
s_com_csr .hex = 0 ;
state. com_csr .hex = 0 ;
s_status_reg .hex = 0 ;
state. status_reg .hex = 0 ;
s_exi_clock_count .hex = 0 ;
state. exi_clock_count .hex = 0 ;
// Supposedly set on reset, but logs from real Wii don't look like it is...
// s_exi_clock_count .LOCK = 1;
// state.exi_clock_count .LOCK = 1;
s_si_buffer = {};
state. si_buffer = {};
}
void Shutdown ()
Expand All
@@ -454,34 +482,40 @@ void Shutdown()
void RegisterMMIO (MMIO::Mapping* mmio, u32 base)
{
auto & state = Core::System::GetInstance ().GetSerialInterfaceState ().GetData ();
// Register SI buffer direct accesses.
const u32 io_buffer_base = base | SI_IO_BUFFER;
for (size_t i = 0 ; i < s_si_buffer .size (); i += sizeof (u32))
for (size_t i = 0 ; i < state. si_buffer .size (); i += sizeof (u32))
{
const u32 address = base | static_cast <u32>(io_buffer_base + i);
mmio->Register (address, MMIO::ComplexRead<u32>([i](u32) {
auto & state = Core::System::GetInstance ().GetSerialInterfaceState ().GetData ();
u32 val;
std::memcpy (&val, &s_si_buffer [i], sizeof (val));
std::memcpy (&val, &state. si_buffer [i], sizeof (val));
return Common::swap32 (val);
}),
MMIO::ComplexWrite<u32>([i](u32, u32 val) {
auto & state = Core::System::GetInstance ().GetSerialInterfaceState ().GetData ();
val = Common::swap32 (val);
std::memcpy (&s_si_buffer [i], &val, sizeof (val));
std::memcpy (&state. si_buffer [i], &val, sizeof (val));
}));
}
for (size_t i = 0 ; i < s_si_buffer .size (); i += sizeof (u16))
for (size_t i = 0 ; i < state. si_buffer .size (); i += sizeof (u16))
{
const u32 address = base | static_cast <u32>(io_buffer_base + i);
mmio->Register (address, MMIO::ComplexRead<u16>([i](u32) {
auto & state = Core::System::GetInstance ().GetSerialInterfaceState ().GetData ();
u16 val;
std::memcpy (&val, &s_si_buffer [i], sizeof (val));
std::memcpy (&val, &state. si_buffer [i], sizeof (val));
return Common::swap16 (val);
}),
MMIO::ComplexWrite<u16>([i](u32, u16 val) {
auto & state = Core::System::GetInstance ().GetSerialInterfaceState ().GetData ();
val = Common::swap16 (val);
std::memcpy (&s_si_buffer [i], &val, sizeof (val));
std::memcpy (&state. si_buffer [i], &val, sizeof (val));
}));
}
Expand All
@@ -496,119 +530,124 @@ void RegisterMMIO(MMIO::Mapping* mmio, u32 base)
const u32 rdst_bit = 8 * (3 - i) + 5 ;
mmio->Register (base | (SI_CHANNEL_0_OUT + 0xC * i),
MMIO::DirectRead<u32>(&s_channel [i].out .hex ),
MMIO::DirectWrite<u32>(&s_channel [i].out .hex ));
MMIO::DirectRead<u32>(&state. channel [i].out .hex ),
MMIO::DirectWrite<u32>(&state. channel [i].out .hex ));
mmio->Register (base | (SI_CHANNEL_0_IN_HI + 0xC * i),
MMIO::ComplexRead<u32>([i, rdst_bit](u32) {
s_status_reg.hex &= ~(1U << rdst_bit);
auto & state = Core::System::GetInstance ().GetSerialInterfaceState ().GetData ();
state.status_reg .hex &= ~(1U << rdst_bit);
UpdateInterrupts ();
return s_channel [i].in_hi .hex ;
return state. channel [i].in_hi .hex ;
}),
MMIO::DirectWrite<u32>(&s_channel [i].in_hi .hex ));
MMIO::DirectWrite<u32>(&state. channel [i].in_hi .hex ));
mmio->Register (base | (SI_CHANNEL_0_IN_LO + 0xC * i),
MMIO::ComplexRead<u32>([i, rdst_bit](u32) {
s_status_reg.hex &= ~(1U << rdst_bit);
auto & state = Core::System::GetInstance ().GetSerialInterfaceState ().GetData ();
state.status_reg .hex &= ~(1U << rdst_bit);
UpdateInterrupts ();
return s_channel [i].in_lo .hex ;
return state. channel [i].in_lo .hex ;
}),
MMIO::DirectWrite<u32>(&s_channel [i].in_lo .hex ));
MMIO::DirectWrite<u32>(&state. channel [i].in_lo .hex ));
}
mmio->Register (base | SI_POLL, MMIO::DirectRead<u32>(&s_poll .hex ),
MMIO::DirectWrite<u32>(&s_poll .hex ));
mmio->Register (base | SI_POLL, MMIO::DirectRead<u32>(&state. poll .hex ),
MMIO::DirectWrite<u32>(&state. poll .hex ));
mmio->Register (base | SI_COM_CSR, MMIO::DirectRead<u32>(&s_com_csr .hex ),
mmio->Register (base | SI_COM_CSR, MMIO::DirectRead<u32>(&state. com_csr .hex ),
MMIO::ComplexWrite<u32>([](u32, u32 val) {
auto & state = Core::System::GetInstance ().GetSerialInterfaceState ().GetData ();
const USIComCSR tmp_com_csr (val);
s_com_csr .CHANNEL = tmp_com_csr.CHANNEL .Value ();
s_com_csr .INLNGTH = tmp_com_csr.INLNGTH .Value ();
s_com_csr .OUTLNGTH = tmp_com_csr.OUTLNGTH .Value ();
s_com_csr .RDSTINTMSK = tmp_com_csr.RDSTINTMSK .Value ();
s_com_csr .TCINTMSK = tmp_com_csr.TCINTMSK .Value ();
state. com_csr .CHANNEL = tmp_com_csr.CHANNEL .Value ();
state. com_csr .INLNGTH = tmp_com_csr.INLNGTH .Value ();
state. com_csr .OUTLNGTH = tmp_com_csr.OUTLNGTH .Value ();
state. com_csr .RDSTINTMSK = tmp_com_csr.RDSTINTMSK .Value ();
state. com_csr .TCINTMSK = tmp_com_csr.TCINTMSK .Value ();
if (tmp_com_csr.RDSTINT )
s_com_csr .RDSTINT = 0 ;
state. com_csr .RDSTINT = 0 ;
if (tmp_com_csr.TCINT )
s_com_csr .TCINT = 0 ;
state. com_csr .TCINT = 0 ;
// be careful: run si-buffer after updating the INT flags
if (tmp_com_csr.TSTART )
{
if (s_com_csr .TSTART )
CoreTiming::RemoveEvent (s_tranfer_pending_event );
s_com_csr .TSTART = 1 ;
if (state. com_csr .TSTART )
CoreTiming::RemoveEvent (state. event_type_tranfer_pending );
state. com_csr .TSTART = 1 ;
RunSIBuffer (0 , 0 );
}
if (!s_com_csr .TSTART )
if (!state. com_csr .TSTART )
UpdateInterrupts ();
}));
mmio->Register (base | SI_STATUS_REG, MMIO::DirectRead<u32>(&s_status_reg .hex ),
mmio->Register (base | SI_STATUS_REG, MMIO::DirectRead<u32>(&state. status_reg .hex ),
MMIO::ComplexWrite<u32>([](u32, u32 val) {
auto & state = Core::System::GetInstance ().GetSerialInterfaceState ().GetData ();
const USIStatusReg tmp_status (val);
// clear bits ( if (tmp.bit) SISR.bit=0 )
if (tmp_status.NOREP0 )
s_status_reg .NOREP0 = 0 ;
state. status_reg .NOREP0 = 0 ;
if (tmp_status.COLL0 )
s_status_reg .COLL0 = 0 ;
state. status_reg .COLL0 = 0 ;
if (tmp_status.OVRUN0 )
s_status_reg .OVRUN0 = 0 ;
state. status_reg .OVRUN0 = 0 ;
if (tmp_status.UNRUN0 )
s_status_reg .UNRUN0 = 0 ;
state. status_reg .UNRUN0 = 0 ;
if (tmp_status.NOREP1 )
s_status_reg .NOREP1 = 0 ;
state. status_reg .NOREP1 = 0 ;
if (tmp_status.COLL1 )
s_status_reg .COLL1 = 0 ;
state. status_reg .COLL1 = 0 ;
if (tmp_status.OVRUN1 )
s_status_reg .OVRUN1 = 0 ;
state. status_reg .OVRUN1 = 0 ;
if (tmp_status.UNRUN1 )
s_status_reg .UNRUN1 = 0 ;
state. status_reg .UNRUN1 = 0 ;
if (tmp_status.NOREP2 )
s_status_reg .NOREP2 = 0 ;
state. status_reg .NOREP2 = 0 ;
if (tmp_status.COLL2 )
s_status_reg .COLL2 = 0 ;
state. status_reg .COLL2 = 0 ;
if (tmp_status.OVRUN2 )
s_status_reg .OVRUN2 = 0 ;
state. status_reg .OVRUN2 = 0 ;
if (tmp_status.UNRUN2 )
s_status_reg .UNRUN2 = 0 ;
state. status_reg .UNRUN2 = 0 ;
if (tmp_status.NOREP3 )
s_status_reg .NOREP3 = 0 ;
state. status_reg .NOREP3 = 0 ;
if (tmp_status.COLL3 )
s_status_reg .COLL3 = 0 ;
state. status_reg .COLL3 = 0 ;
if (tmp_status.OVRUN3 )
s_status_reg .OVRUN3 = 0 ;
state. status_reg .OVRUN3 = 0 ;
if (tmp_status.UNRUN3 )
s_status_reg .UNRUN3 = 0 ;
state. status_reg .UNRUN3 = 0 ;
// send command to devices
if (tmp_status.WR )
{
s_channel [0 ].device ->SendCommand (s_channel [0 ].out .hex , s_poll .EN0 );
s_channel [1 ].device ->SendCommand (s_channel [1 ].out .hex , s_poll .EN1 );
s_channel [2 ].device ->SendCommand (s_channel [2 ].out .hex , s_poll .EN2 );
s_channel [3 ].device ->SendCommand (s_channel [3 ].out .hex , s_poll .EN3 );
s_status_reg .WR = 0 ;
s_status_reg .WRST0 = 0 ;
s_status_reg .WRST1 = 0 ;
s_status_reg .WRST2 = 0 ;
s_status_reg .WRST3 = 0 ;
state. channel [0 ].device ->SendCommand (state. channel [0 ].out .hex , state. poll .EN0 );
state. channel [1 ].device ->SendCommand (state. channel [1 ].out .hex , state. poll .EN1 );
state. channel [2 ].device ->SendCommand (state. channel [2 ].out .hex , state. poll .EN2 );
state. channel [3 ].device ->SendCommand (state. channel [3 ].out .hex , state. poll .EN3 );
state. status_reg .WR = 0 ;
state. status_reg .WRST0 = 0 ;
state. status_reg .WRST1 = 0 ;
state. status_reg .WRST2 = 0 ;
state. status_reg .WRST3 = 0 ;
}
}));
mmio->Register (base | SI_EXI_CLOCK_COUNT, MMIO::DirectRead<u32>(&s_exi_clock_count .hex ),
MMIO::DirectWrite<u32>(&s_exi_clock_count .hex ));
mmio->Register (base | SI_EXI_CLOCK_COUNT, MMIO::DirectRead<u32>(&state. exi_clock_count .hex ),
MMIO::DirectWrite<u32>(&state. exi_clock_count .hex ));
}
void RemoveDevice (int device_number)
{
s_channel.at (device_number).device .reset ();
auto & state = Core::System::GetInstance ().GetSerialInterfaceState ().GetData ();
state.channel .at (device_number).device .reset ();
}
void AddDevice (std::unique_ptr<ISIDevice> device)
Expand All
@@ -619,7 +658,8 @@ void AddDevice(std::unique_ptr<ISIDevice> device)
RemoveDevice (device_number);
// Set the new one
s_channel.at (device_number).device = std::move (device);
auto & state = Core::System::GetInstance ().GetSerialInterfaceState ().GetData ();
state.channel .at (device_number).device = std::move (device);
}
void AddDevice (const SIDevices device, int device_number)
Expand All
@@ -630,12 +670,14 @@ void AddDevice(const SIDevices device, int device_number)
void ChangeDevice (SIDevices device, int channel)
{
// Actual device change will happen in UpdateDevices.
s_desired_device_types[channel] = device;
auto & state = Core::System::GetInstance ().GetSerialInterfaceState ().GetData ();
state.desired_device_types [channel] = device;
}
static void ChangeDeviceDeterministic (SIDevices device, int channel)
{
if (s_channel[channel].has_recent_device_change )
auto & state = Core::System::GetInstance ().GetSerialInterfaceState ().GetData ();
if (state.channel [channel].has_recent_device_change )
return ;
if (GetDeviceType (channel) != SIDEVICE_NONE)
Expand All
@@ -644,26 +686,29 @@ static void ChangeDeviceDeterministic(SIDevices device, int channel)
device = SIDEVICE_NONE;
}
s_channel [channel].out .hex = 0 ;
s_channel [channel].in_hi .hex = 0 ;
s_channel [channel].in_lo .hex = 0 ;
state. channel [channel].out .hex = 0 ;
state. channel [channel].in_hi .hex = 0 ;
state. channel [channel].in_lo .hex = 0 ;
SetNoResponse (channel);
AddDevice (device, channel);
// Prevent additional device changes on this channel for one second.
s_channel[channel].has_recent_device_change = true ;
CoreTiming::ScheduleEvent (SystemTimers::GetTicksPerSecond (), s_change_device_event, channel);
state.channel [channel].has_recent_device_change = true ;
CoreTiming::ScheduleEvent (SystemTimers::GetTicksPerSecond (), state.event_type_change_device ,
channel);
}
void UpdateDevices ()
{
auto & state = Core::System::GetInstance ().GetSerialInterfaceState ().GetData ();
// Check for device change requests:
for (int i = 0 ; i != MAX_SI_CHANNELS; ++i)
{
const SIDevices current_type = GetDeviceType (i);
const SIDevices desired_type = s_desired_device_types [i];
const SIDevices desired_type = state. desired_device_types [i];
if (current_type != desired_type)
{
Expand All
@@ -681,14 +726,14 @@ void UpdateDevices()
g_controller_interface.UpdateInput ();
// Update channels and set the status bit if there's new data
s_status_reg .RDST0 =
!!s_channel [0 ].device ->GetData (s_channel [0 ].in_hi .hex , s_channel [0 ].in_lo .hex );
s_status_reg .RDST1 =
!!s_channel [1 ].device ->GetData (s_channel [1 ].in_hi .hex , s_channel [1 ].in_lo .hex );
s_status_reg .RDST2 =
!!s_channel [2 ].device ->GetData (s_channel [2 ].in_hi .hex , s_channel [2 ].in_lo .hex );
s_status_reg .RDST3 =
!!s_channel [3 ].device ->GetData (s_channel [3 ].in_hi .hex , s_channel [3 ].in_lo .hex );
state. status_reg .RDST0 =
!!state. channel [0 ].device ->GetData (state. channel [0 ].in_hi .hex , state. channel [0 ].in_lo .hex );
state. status_reg .RDST1 =
!!state. channel [1 ].device ->GetData (state. channel [1 ].in_hi .hex , state. channel [1 ].in_lo .hex );
state. status_reg .RDST2 =
!!state. channel [2 ].device ->GetData (state. channel [2 ].in_hi .hex , state. channel [2 ].in_lo .hex );
state. status_reg .RDST3 =
!!state. channel [3 ].device ->GetData (state. channel [3 ].in_hi .hex , state. channel [3 ].in_lo .hex );
UpdateInterrupts ();
Expand All
@@ -698,15 +743,17 @@ void UpdateDevices()
SIDevices GetDeviceType (int channel)
{
if (channel < 0 || channel >= MAX_SI_CHANNELS || !s_channel[channel].device )
auto & state = Core::System::GetInstance ().GetSerialInterfaceState ().GetData ();
if (channel < 0 || channel >= MAX_SI_CHANNELS || !state.channel [channel].device )
return SIDEVICE_NONE;
return s_channel [channel].device ->GetDeviceType ();
return state. channel [channel].device ->GetDeviceType ();
}
u32 GetPollXLines ()
{
return s_poll.X ;
auto & state = Core::System::GetInstance ().GetSerialInterfaceState ().GetData ();
return state.poll .X ;
}
} // namespace SerialInterface