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