HW/SerialInterface: Refactor to class.
This commit is contained in:
parent
d371b17f37
commit
bf2f901a99
|
@ -42,7 +42,7 @@ void Init(const Sram* override_sram)
|
||||||
// Init the whole Hardware
|
// Init the whole Hardware
|
||||||
system.GetAudioInterface().Init();
|
system.GetAudioInterface().Init();
|
||||||
system.GetVideoInterface().Init();
|
system.GetVideoInterface().Init();
|
||||||
SerialInterface::Init();
|
system.GetSerialInterface().Init();
|
||||||
system.GetProcessorInterface().Init();
|
system.GetProcessorInterface().Init();
|
||||||
system.GetExpansionInterface().Init(override_sram); // Needs to be initialized before Memory
|
system.GetExpansionInterface().Init(override_sram); // Needs to be initialized before Memory
|
||||||
system.GetHSP().Init();
|
system.GetHSP().Init();
|
||||||
|
@ -79,7 +79,7 @@ void Shutdown()
|
||||||
system.GetMemory().Shutdown();
|
system.GetMemory().Shutdown();
|
||||||
system.GetHSP().Shutdown();
|
system.GetHSP().Shutdown();
|
||||||
system.GetExpansionInterface().Shutdown();
|
system.GetExpansionInterface().Shutdown();
|
||||||
SerialInterface::Shutdown();
|
system.GetSerialInterface().Shutdown();
|
||||||
system.GetAudioInterface().Shutdown();
|
system.GetAudioInterface().Shutdown();
|
||||||
|
|
||||||
State::Shutdown();
|
State::Shutdown();
|
||||||
|
@ -95,7 +95,7 @@ void DoState(PointerWrap& p)
|
||||||
p.DoMarker("MemoryInterface");
|
p.DoMarker("MemoryInterface");
|
||||||
system.GetVideoInterface().DoState(p);
|
system.GetVideoInterface().DoState(p);
|
||||||
p.DoMarker("VideoInterface");
|
p.DoMarker("VideoInterface");
|
||||||
SerialInterface::DoState(p);
|
system.GetSerialInterface().DoState(p);
|
||||||
p.DoMarker("SerialInterface");
|
p.DoMarker("SerialInterface");
|
||||||
system.GetProcessorInterface().DoState(p);
|
system.GetProcessorInterface().DoState(p);
|
||||||
p.DoMarker("ProcessorInterface");
|
p.DoMarker("ProcessorInterface");
|
||||||
|
|
|
@ -56,14 +56,14 @@ void MemoryManager::InitMMIO(bool is_wii)
|
||||||
system.GetMemoryInterface().RegisterMMIO(m_mmio_mapping.get(), 0x0C004000);
|
system.GetMemoryInterface().RegisterMMIO(m_mmio_mapping.get(), 0x0C004000);
|
||||||
system.GetDSP().RegisterMMIO(m_mmio_mapping.get(), 0x0C005000);
|
system.GetDSP().RegisterMMIO(m_mmio_mapping.get(), 0x0C005000);
|
||||||
system.GetDVDInterface().RegisterMMIO(m_mmio_mapping.get(), 0x0C006000, false);
|
system.GetDVDInterface().RegisterMMIO(m_mmio_mapping.get(), 0x0C006000, false);
|
||||||
SerialInterface::RegisterMMIO(m_mmio_mapping.get(), 0x0C006400);
|
system.GetSerialInterface().RegisterMMIO(m_mmio_mapping.get(), 0x0C006400);
|
||||||
system.GetExpansionInterface().RegisterMMIO(m_mmio_mapping.get(), 0x0C006800);
|
system.GetExpansionInterface().RegisterMMIO(m_mmio_mapping.get(), 0x0C006800);
|
||||||
system.GetAudioInterface().RegisterMMIO(m_mmio_mapping.get(), 0x0C006C00);
|
system.GetAudioInterface().RegisterMMIO(m_mmio_mapping.get(), 0x0C006C00);
|
||||||
if (is_wii)
|
if (is_wii)
|
||||||
{
|
{
|
||||||
IOS::RegisterMMIO(m_mmio_mapping.get(), 0x0D000000);
|
IOS::RegisterMMIO(m_mmio_mapping.get(), 0x0D000000);
|
||||||
system.GetDVDInterface().RegisterMMIO(m_mmio_mapping.get(), 0x0D006000, true);
|
system.GetDVDInterface().RegisterMMIO(m_mmio_mapping.get(), 0x0D006000, true);
|
||||||
SerialInterface::RegisterMMIO(m_mmio_mapping.get(), 0x0D006400);
|
system.GetSerialInterface().RegisterMMIO(m_mmio_mapping.get(), 0x0D006400);
|
||||||
system.GetExpansionInterface().RegisterMMIO(m_mmio_mapping.get(), 0x0D006800);
|
system.GetExpansionInterface().RegisterMMIO(m_mmio_mapping.get(), 0x0D006800);
|
||||||
system.GetAudioInterface().RegisterMMIO(m_mmio_mapping.get(), 0x0D006C00);
|
system.GetAudioInterface().RegisterMMIO(m_mmio_mapping.get(), 0x0D006C00);
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,13 +31,6 @@
|
||||||
|
|
||||||
namespace SerialInterface
|
namespace SerialInterface
|
||||||
{
|
{
|
||||||
// SI Interrupt Types
|
|
||||||
enum SIInterruptType
|
|
||||||
{
|
|
||||||
INT_RDSTINT = 0,
|
|
||||||
INT_TCINT = 1,
|
|
||||||
};
|
|
||||||
|
|
||||||
// SI Internal Hardware Addresses
|
// SI Internal Hardware Addresses
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
|
@ -60,228 +53,69 @@ enum
|
||||||
SI_IO_BUFFER = 0x80,
|
SI_IO_BUFFER = 0x80,
|
||||||
};
|
};
|
||||||
|
|
||||||
// SI Channel Output
|
SerialInterfaceManager::SerialInterfaceManager(Core::System& system) : m_system(system)
|
||||||
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;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct SerialInterfaceState::Data
|
|
||||||
{
|
|
||||||
CoreTiming::EventType* event_type_change_device = nullptr;
|
|
||||||
CoreTiming::EventType* event_type_tranfer_pending = nullptr;
|
|
||||||
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{};
|
|
||||||
};
|
|
||||||
|
|
||||||
SerialInterfaceState::SerialInterfaceState() : m_data(std::make_unique<Data>())
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
SerialInterfaceState::~SerialInterfaceState() = default;
|
SerialInterfaceManager::~SerialInterfaceManager() = default;
|
||||||
|
|
||||||
static void SetNoResponse(u32 channel)
|
void SerialInterfaceManager::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:
|
||||||
state.status_reg.NOREP0 = 1;
|
m_status_reg.NOREP0 = 1;
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
state.status_reg.NOREP1 = 1;
|
m_status_reg.NOREP1 = 1;
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
state.status_reg.NOREP2 = 1;
|
m_status_reg.NOREP2 = 1;
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
state.status_reg.NOREP3 = 1;
|
m_status_reg.NOREP3 = 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ChangeDeviceCallback(Core::System& system, u64 user_data, s64 cycles_late)
|
void SerialInterfaceManager::ChangeDeviceCallback(Core::System& system, 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.
|
||||||
auto& state = system.GetSerialInterfaceState().GetData();
|
auto& si = system.GetSerialInterface();
|
||||||
state.channel[user_data].has_recent_device_change = false;
|
si.m_channel[user_data].has_recent_device_change = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void UpdateInterrupts()
|
void SerialInterfaceManager::UpdateInterrupts()
|
||||||
{
|
{
|
||||||
// check if we have to update the RDSTINT flag
|
// check if we have to update the RDSTINT flag
|
||||||
auto& system = Core::System::GetInstance();
|
if (m_status_reg.RDST0 || m_status_reg.RDST1 || m_status_reg.RDST2 || m_status_reg.RDST3)
|
||||||
auto& state = system.GetSerialInterfaceState().GetData();
|
|
||||||
if (state.status_reg.RDST0 || state.status_reg.RDST1 || state.status_reg.RDST2 ||
|
|
||||||
state.status_reg.RDST3)
|
|
||||||
{
|
{
|
||||||
state.com_csr.RDSTINT = 1;
|
m_com_csr.RDSTINT = 1;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
state.com_csr.RDSTINT = 0;
|
m_com_csr.RDSTINT = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// check if we have to generate an interrupt
|
// check if we have to generate an interrupt
|
||||||
const bool generate_interrupt = (state.com_csr.RDSTINT & state.com_csr.RDSTINTMSK) != 0 ||
|
const bool generate_interrupt = (m_com_csr.RDSTINT & m_com_csr.RDSTINTMSK) != 0 ||
|
||||||
(state.com_csr.TCINT & state.com_csr.TCINTMSK) != 0;
|
(m_com_csr.TCINT & m_com_csr.TCINTMSK) != 0;
|
||||||
|
|
||||||
system.GetProcessorInterface().SetInterrupt(ProcessorInterface::INT_CAUSE_SI, generate_interrupt);
|
m_system.GetProcessorInterface().SetInterrupt(ProcessorInterface::INT_CAUSE_SI,
|
||||||
|
generate_interrupt);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void GenerateSIInterrupt(SIInterruptType type)
|
void SerialInterfaceManager::GenerateSIInterrupt(SIInterruptType type)
|
||||||
{
|
{
|
||||||
auto& state = Core::System::GetInstance().GetSerialInterfaceState().GetData();
|
|
||||||
switch (type)
|
switch (type)
|
||||||
{
|
{
|
||||||
case INT_RDSTINT:
|
case INT_RDSTINT:
|
||||||
state.com_csr.RDSTINT = 1;
|
m_com_csr.RDSTINT = 1;
|
||||||
break;
|
break;
|
||||||
case INT_TCINT:
|
case INT_TCINT:
|
||||||
state.com_csr.TCINT = 1;
|
m_com_csr.TCINT = 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -296,23 +130,26 @@ constexpr s32 ConvertSILengthField(u32 field)
|
||||||
return ((field - 1) & SI_XFER_LENGTH_MASK) + 1;
|
return ((field - 1) & SI_XFER_LENGTH_MASK) + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void RunSIBuffer(Core::System& system, u64 user_data, s64 cycles_late)
|
void SerialInterfaceManager::GlobalRunSIBuffer(Core::System& system, u64 user_data, s64 cycles_late)
|
||||||
{
|
{
|
||||||
auto& state = system.GetSerialInterfaceState().GetData();
|
system.GetSerialInterface().RunSIBuffer(user_data, cycles_late);
|
||||||
if (state.com_csr.TSTART)
|
}
|
||||||
{
|
|
||||||
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 = state.channel[state.com_csr.CHANNEL].device;
|
void SerialInterfaceManager::RunSIBuffer(u64 user_data, s64 cycles_late)
|
||||||
const s32 actual_response_length = device->RunBuffer(state.si_buffer.data(), request_length);
|
{
|
||||||
|
if (m_com_csr.TSTART)
|
||||||
|
{
|
||||||
|
const s32 request_length = ConvertSILengthField(m_com_csr.OUTLNGTH);
|
||||||
|
const s32 expected_response_length = ConvertSILengthField(m_com_csr.INLNGTH);
|
||||||
|
const std::vector<u8> request_copy(m_si_buffer.data(), m_si_buffer.data() + request_length);
|
||||||
|
|
||||||
|
const std::unique_ptr<ISIDevice>& device = m_channel[m_com_csr.CHANNEL].device;
|
||||||
|
const s32 actual_response_length = device->RunBuffer(m_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: {}",
|
||||||
state.com_csr.CHANNEL, request_length, expected_response_length,
|
m_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)
|
||||||
{
|
{
|
||||||
|
@ -337,64 +174,60 @@ static void RunSIBuffer(Core::System& system, 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)
|
||||||
{
|
{
|
||||||
state.com_csr.TSTART = 0;
|
m_com_csr.TSTART = 0;
|
||||||
state.com_csr.COMERR = actual_response_length < 0;
|
m_com_csr.COMERR = actual_response_length < 0;
|
||||||
if (actual_response_length < 0)
|
if (actual_response_length < 0)
|
||||||
SetNoResponse(state.com_csr.CHANNEL);
|
SetNoResponse(m_com_csr.CHANNEL);
|
||||||
GenerateSIInterrupt(INT_TCINT);
|
GenerateSIInterrupt(INT_TCINT);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
system.GetCoreTiming().ScheduleEvent(device->TransferInterval() - cycles_late,
|
m_system.GetCoreTiming().ScheduleEvent(device->TransferInterval() - cycles_late,
|
||||||
state.event_type_tranfer_pending);
|
m_event_type_tranfer_pending);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DoState(PointerWrap& p)
|
void SerialInterfaceManager::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(state.channel[i].in_hi.hex);
|
p.Do(m_channel[i].in_hi.hex);
|
||||||
p.Do(state.channel[i].in_lo.hex);
|
p.Do(m_channel[i].in_lo.hex);
|
||||||
p.Do(state.channel[i].out.hex);
|
p.Do(m_channel[i].out.hex);
|
||||||
p.Do(state.channel[i].has_recent_device_change);
|
p.Do(m_channel[i].has_recent_device_change);
|
||||||
|
|
||||||
std::unique_ptr<ISIDevice>& device = state.channel[i].device;
|
std::unique_ptr<ISIDevice>& device = m_channel[i].device;
|
||||||
SIDevices type = device->GetDeviceType();
|
SIDevices type = device->GetDeviceType();
|
||||||
p.Do(type);
|
p.Do(type);
|
||||||
|
|
||||||
if (type != device->GetDeviceType())
|
if (type != device->GetDeviceType())
|
||||||
{
|
{
|
||||||
AddDevice(SIDevice_Create(Core::System::GetInstance(), type, i));
|
AddDevice(SIDevice_Create(m_system, type, i));
|
||||||
}
|
}
|
||||||
|
|
||||||
device->DoState(p);
|
device->DoState(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
p.Do(state.poll);
|
p.Do(m_poll);
|
||||||
p.Do(state.com_csr);
|
p.Do(m_com_csr);
|
||||||
p.Do(state.status_reg);
|
p.Do(m_status_reg);
|
||||||
p.Do(state.exi_clock_count);
|
p.Do(m_exi_clock_count);
|
||||||
p.Do(state.si_buffer);
|
p.Do(m_si_buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <int device_number>
|
template <int device_number>
|
||||||
static void DeviceEventCallback(Core::System& system, u64 userdata, s64 cyclesLate)
|
void SerialInterfaceManager::DeviceEventCallback(Core::System& system, u64 userdata, s64 cyclesLate)
|
||||||
{
|
{
|
||||||
auto& state = system.GetSerialInterfaceState().GetData();
|
auto& si = system.GetSerialInterface();
|
||||||
state.channel[device_number].device->OnEvent(userdata, cyclesLate);
|
si.m_channel[device_number].device->OnEvent(userdata, cyclesLate);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void RegisterEvents()
|
void SerialInterfaceManager::RegisterEvents()
|
||||||
{
|
{
|
||||||
auto& system = Core::System::GetInstance();
|
auto& core_timing = m_system.GetCoreTiming();
|
||||||
auto& core_timing = system.GetCoreTiming();
|
m_event_type_change_device = core_timing.RegisterEvent("ChangeSIDevice", ChangeDeviceCallback);
|
||||||
auto& state = system.GetSerialInterfaceState().GetData();
|
m_event_type_tranfer_pending = core_timing.RegisterEvent("SITransferPending", GlobalRunSIBuffer);
|
||||||
state.event_type_change_device =
|
|
||||||
core_timing.RegisterEvent("ChangeSIDevice", ChangeDeviceCallback);
|
|
||||||
state.event_type_tranfer_pending = core_timing.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>,
|
||||||
|
@ -404,125 +237,118 @@ static void RegisterEvents()
|
||||||
};
|
};
|
||||||
for (int i = 0; i < MAX_SI_CHANNELS; ++i)
|
for (int i = 0; i < MAX_SI_CHANNELS; ++i)
|
||||||
{
|
{
|
||||||
state.event_types_device[i] =
|
m_event_types_device[i] =
|
||||||
core_timing.RegisterEvent(fmt::format("SIEventChannel{}", i), event_callbacks[i]);
|
core_timing.RegisterEvent(fmt::format("SIEventChannel{}", i), event_callbacks[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScheduleEvent(int device_number, s64 cycles_into_future, u64 userdata)
|
void SerialInterfaceManager::ScheduleEvent(int device_number, s64 cycles_into_future, u64 userdata)
|
||||||
{
|
{
|
||||||
auto& system = Core::System::GetInstance();
|
auto& core_timing = m_system.GetCoreTiming();
|
||||||
auto& core_timing = system.GetCoreTiming();
|
core_timing.ScheduleEvent(cycles_into_future, m_event_types_device[device_number], userdata);
|
||||||
auto& state = system.GetSerialInterfaceState().GetData();
|
|
||||||
core_timing.ScheduleEvent(cycles_into_future, state.event_types_device[device_number], userdata);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void RemoveEvent(int device_number)
|
void SerialInterfaceManager::RemoveEvent(int device_number)
|
||||||
{
|
{
|
||||||
auto& system = Core::System::GetInstance();
|
auto& core_timing = m_system.GetCoreTiming();
|
||||||
auto& core_timing = system.GetCoreTiming();
|
core_timing.RemoveEvent(m_event_types_device[device_number]);
|
||||||
auto& state = system.GetSerialInterfaceState().GetData();
|
|
||||||
core_timing.RemoveEvent(state.event_types_device[device_number]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Init()
|
void SerialInterfaceManager::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++)
|
||||||
{
|
{
|
||||||
state.channel[i].out.hex = 0;
|
m_channel[i].out.hex = 0;
|
||||||
state.channel[i].in_hi.hex = 0;
|
m_channel[i].in_hi.hex = 0;
|
||||||
state.channel[i].in_lo.hex = 0;
|
m_channel[i].in_lo.hex = 0;
|
||||||
state.channel[i].has_recent_device_change = false;
|
m_channel[i].has_recent_device_change = false;
|
||||||
|
|
||||||
if (Movie::IsMovieActive())
|
if (Movie::IsMovieActive())
|
||||||
{
|
{
|
||||||
state.desired_device_types[i] = SIDEVICE_NONE;
|
m_desired_device_types[i] = SIDEVICE_NONE;
|
||||||
|
|
||||||
if (Movie::IsUsingGBA(i))
|
if (Movie::IsUsingGBA(i))
|
||||||
{
|
{
|
||||||
state.desired_device_types[i] = SIDEVICE_GC_GBA_EMULATED;
|
m_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))
|
||||||
state.desired_device_types[i] = SIDEVICE_GC_TARUKONGA;
|
m_desired_device_types[i] = SIDEVICE_GC_TARUKONGA;
|
||||||
else if (SIDevice_IsGCController(current))
|
else if (SIDevice_IsGCController(current))
|
||||||
state.desired_device_types[i] = current;
|
m_desired_device_types[i] = current;
|
||||||
else
|
else
|
||||||
state.desired_device_types[i] = SIDEVICE_GC_CONTROLLER;
|
m_desired_device_types[i] = SIDEVICE_GC_CONTROLLER;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (!NetPlay::IsNetPlayRunning())
|
else if (!NetPlay::IsNetPlayRunning())
|
||||||
{
|
{
|
||||||
state.desired_device_types[i] = Config::Get(Config::GetInfoForSIDevice(i));
|
m_desired_device_types[i] = Config::Get(Config::GetInfoForSIDevice(i));
|
||||||
}
|
}
|
||||||
|
|
||||||
AddDevice(state.desired_device_types[i], i);
|
AddDevice(m_desired_device_types[i], i);
|
||||||
}
|
}
|
||||||
|
|
||||||
state.poll.hex = 0;
|
m_poll.hex = 0;
|
||||||
state.poll.X = 492;
|
m_poll.X = 492;
|
||||||
|
|
||||||
state.com_csr.hex = 0;
|
m_com_csr.hex = 0;
|
||||||
|
|
||||||
state.status_reg.hex = 0;
|
m_status_reg.hex = 0;
|
||||||
|
|
||||||
state.exi_clock_count.hex = 0;
|
m_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...
|
||||||
// state.exi_clock_count.LOCK = 1;
|
// m_exi_clock_count.LOCK = 1;
|
||||||
|
|
||||||
state.si_buffer = {};
|
m_si_buffer = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
void Shutdown()
|
void SerialInterfaceManager::Shutdown()
|
||||||
{
|
{
|
||||||
for (int i = 0; i < MAX_SI_CHANNELS; i++)
|
for (int i = 0; i < MAX_SI_CHANNELS; i++)
|
||||||
RemoveDevice(i);
|
RemoveDevice(i);
|
||||||
GBAConnectionWaiter_Shutdown();
|
GBAConnectionWaiter_Shutdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
void RegisterMMIO(MMIO::Mapping* mmio, u32 base)
|
void SerialInterfaceManager::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 < state.si_buffer.size(); i += sizeof(u32))
|
for (size_t i = 0; i < m_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](Core::System& system, u32) {
|
mmio->Register(address, MMIO::ComplexRead<u32>([i](Core::System& system, u32) {
|
||||||
auto& state_ = system.GetSerialInterfaceState().GetData();
|
auto& si = system.GetSerialInterface();
|
||||||
u32 val;
|
u32 val;
|
||||||
std::memcpy(&val, &state_.si_buffer[i], sizeof(val));
|
std::memcpy(&val, &si.m_si_buffer[i], sizeof(val));
|
||||||
return Common::swap32(val);
|
return Common::swap32(val);
|
||||||
}),
|
}),
|
||||||
MMIO::ComplexWrite<u32>([i](Core::System& system, u32, u32 val) {
|
MMIO::ComplexWrite<u32>([i](Core::System& system, u32, u32 val) {
|
||||||
auto& state_ = system.GetSerialInterfaceState().GetData();
|
auto& si = system.GetSerialInterface();
|
||||||
val = Common::swap32(val);
|
val = Common::swap32(val);
|
||||||
std::memcpy(&state_.si_buffer[i], &val, sizeof(val));
|
std::memcpy(&si.m_si_buffer[i], &val, sizeof(val));
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
for (size_t i = 0; i < state.si_buffer.size(); i += sizeof(u16))
|
for (size_t i = 0; i < m_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](Core::System& system, u32) {
|
mmio->Register(address, MMIO::ComplexRead<u16>([i](Core::System& system, u32) {
|
||||||
auto& state_ = system.GetSerialInterfaceState().GetData();
|
auto& si = system.GetSerialInterface();
|
||||||
u16 val;
|
u16 val;
|
||||||
std::memcpy(&val, &state_.si_buffer[i], sizeof(val));
|
std::memcpy(&val, &si.m_si_buffer[i], sizeof(val));
|
||||||
return Common::swap16(val);
|
return Common::swap16(val);
|
||||||
}),
|
}),
|
||||||
MMIO::ComplexWrite<u16>([i](Core::System& system, u32, u16 val) {
|
MMIO::ComplexWrite<u16>([i](Core::System& system, u32, u16 val) {
|
||||||
auto& state_ = system.GetSerialInterfaceState().GetData();
|
auto& si = system.GetSerialInterface();
|
||||||
val = Common::swap16(val);
|
val = Common::swap16(val);
|
||||||
std::memcpy(&state_.si_buffer[i], &val, sizeof(val));
|
std::memcpy(&si.m_si_buffer[i], &val, sizeof(val));
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -537,128 +363,126 @@ 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>(&state.channel[i].out.hex),
|
MMIO::DirectRead<u32>(&m_channel[i].out.hex),
|
||||||
MMIO::DirectWrite<u32>(&state.channel[i].out.hex));
|
MMIO::DirectWrite<u32>(&m_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](Core::System& system, u32) {
|
MMIO::ComplexRead<u32>([i, rdst_bit](Core::System& system, u32) {
|
||||||
auto& state_ = system.GetSerialInterfaceState().GetData();
|
auto& si = system.GetSerialInterface();
|
||||||
state_.status_reg.hex &= ~(1U << rdst_bit);
|
si.m_status_reg.hex &= ~(1U << rdst_bit);
|
||||||
UpdateInterrupts();
|
si.UpdateInterrupts();
|
||||||
return state_.channel[i].in_hi.hex;
|
return si.m_channel[i].in_hi.hex;
|
||||||
}),
|
}),
|
||||||
MMIO::DirectWrite<u32>(&state.channel[i].in_hi.hex));
|
MMIO::DirectWrite<u32>(&m_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](Core::System& system, u32) {
|
MMIO::ComplexRead<u32>([i, rdst_bit](Core::System& system, u32) {
|
||||||
auto& state_ = system.GetSerialInterfaceState().GetData();
|
auto& si = system.GetSerialInterface();
|
||||||
state_.status_reg.hex &= ~(1U << rdst_bit);
|
si.m_status_reg.hex &= ~(1U << rdst_bit);
|
||||||
UpdateInterrupts();
|
si.UpdateInterrupts();
|
||||||
return state_.channel[i].in_lo.hex;
|
return si.m_channel[i].in_lo.hex;
|
||||||
}),
|
}),
|
||||||
MMIO::DirectWrite<u32>(&state.channel[i].in_lo.hex));
|
MMIO::DirectWrite<u32>(&m_channel[i].in_lo.hex));
|
||||||
}
|
}
|
||||||
|
|
||||||
mmio->Register(base | SI_POLL, MMIO::DirectRead<u32>(&state.poll.hex),
|
mmio->Register(base | SI_POLL, MMIO::DirectRead<u32>(&m_poll.hex),
|
||||||
MMIO::DirectWrite<u32>(&state.poll.hex));
|
MMIO::DirectWrite<u32>(&m_poll.hex));
|
||||||
|
|
||||||
mmio->Register(base | SI_COM_CSR, MMIO::DirectRead<u32>(&state.com_csr.hex),
|
mmio->Register(base | SI_COM_CSR, MMIO::DirectRead<u32>(&m_com_csr.hex),
|
||||||
MMIO::ComplexWrite<u32>([](Core::System& system, u32, u32 val) {
|
MMIO::ComplexWrite<u32>([](Core::System& system, u32, u32 val) {
|
||||||
auto& state_ = system.GetSerialInterfaceState().GetData();
|
auto& si = system.GetSerialInterface();
|
||||||
const USIComCSR tmp_com_csr(val);
|
const USIComCSR tmp_com_csr(val);
|
||||||
|
|
||||||
state_.com_csr.CHANNEL = tmp_com_csr.CHANNEL.Value();
|
si.m_com_csr.CHANNEL = tmp_com_csr.CHANNEL.Value();
|
||||||
state_.com_csr.INLNGTH = tmp_com_csr.INLNGTH.Value();
|
si.m_com_csr.INLNGTH = tmp_com_csr.INLNGTH.Value();
|
||||||
state_.com_csr.OUTLNGTH = tmp_com_csr.OUTLNGTH.Value();
|
si.m_com_csr.OUTLNGTH = tmp_com_csr.OUTLNGTH.Value();
|
||||||
state_.com_csr.RDSTINTMSK = tmp_com_csr.RDSTINTMSK.Value();
|
si.m_com_csr.RDSTINTMSK = tmp_com_csr.RDSTINTMSK.Value();
|
||||||
state_.com_csr.TCINTMSK = tmp_com_csr.TCINTMSK.Value();
|
si.m_com_csr.TCINTMSK = tmp_com_csr.TCINTMSK.Value();
|
||||||
|
|
||||||
if (tmp_com_csr.RDSTINT)
|
if (tmp_com_csr.RDSTINT)
|
||||||
state_.com_csr.RDSTINT = 0;
|
si.m_com_csr.RDSTINT = 0;
|
||||||
if (tmp_com_csr.TCINT)
|
if (tmp_com_csr.TCINT)
|
||||||
state_.com_csr.TCINT = 0;
|
si.m_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 (state_.com_csr.TSTART)
|
if (si.m_com_csr.TSTART)
|
||||||
system.GetCoreTiming().RemoveEvent(state_.event_type_tranfer_pending);
|
system.GetCoreTiming().RemoveEvent(si.m_event_type_tranfer_pending);
|
||||||
state_.com_csr.TSTART = 1;
|
si.m_com_csr.TSTART = 1;
|
||||||
RunSIBuffer(system, 0, 0);
|
si.RunSIBuffer(0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!state_.com_csr.TSTART)
|
if (!si.m_com_csr.TSTART)
|
||||||
UpdateInterrupts();
|
si.UpdateInterrupts();
|
||||||
}));
|
}));
|
||||||
|
|
||||||
mmio->Register(
|
mmio->Register(base | SI_STATUS_REG, MMIO::DirectRead<u32>(&m_status_reg.hex),
|
||||||
base | SI_STATUS_REG, MMIO::DirectRead<u32>(&state.status_reg.hex),
|
|
||||||
MMIO::ComplexWrite<u32>([](Core::System& system, u32, u32 val) {
|
MMIO::ComplexWrite<u32>([](Core::System& system, u32, u32 val) {
|
||||||
auto& state_ = system.GetSerialInterfaceState().GetData();
|
auto& si = system.GetSerialInterface();
|
||||||
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)
|
||||||
state_.status_reg.NOREP0 = 0;
|
si.m_status_reg.NOREP0 = 0;
|
||||||
if (tmp_status.COLL0)
|
if (tmp_status.COLL0)
|
||||||
state_.status_reg.COLL0 = 0;
|
si.m_status_reg.COLL0 = 0;
|
||||||
if (tmp_status.OVRUN0)
|
if (tmp_status.OVRUN0)
|
||||||
state_.status_reg.OVRUN0 = 0;
|
si.m_status_reg.OVRUN0 = 0;
|
||||||
if (tmp_status.UNRUN0)
|
if (tmp_status.UNRUN0)
|
||||||
state_.status_reg.UNRUN0 = 0;
|
si.m_status_reg.UNRUN0 = 0;
|
||||||
|
|
||||||
if (tmp_status.NOREP1)
|
if (tmp_status.NOREP1)
|
||||||
state_.status_reg.NOREP1 = 0;
|
si.m_status_reg.NOREP1 = 0;
|
||||||
if (tmp_status.COLL1)
|
if (tmp_status.COLL1)
|
||||||
state_.status_reg.COLL1 = 0;
|
si.m_status_reg.COLL1 = 0;
|
||||||
if (tmp_status.OVRUN1)
|
if (tmp_status.OVRUN1)
|
||||||
state_.status_reg.OVRUN1 = 0;
|
si.m_status_reg.OVRUN1 = 0;
|
||||||
if (tmp_status.UNRUN1)
|
if (tmp_status.UNRUN1)
|
||||||
state_.status_reg.UNRUN1 = 0;
|
si.m_status_reg.UNRUN1 = 0;
|
||||||
|
|
||||||
if (tmp_status.NOREP2)
|
if (tmp_status.NOREP2)
|
||||||
state_.status_reg.NOREP2 = 0;
|
si.m_status_reg.NOREP2 = 0;
|
||||||
if (tmp_status.COLL2)
|
if (tmp_status.COLL2)
|
||||||
state_.status_reg.COLL2 = 0;
|
si.m_status_reg.COLL2 = 0;
|
||||||
if (tmp_status.OVRUN2)
|
if (tmp_status.OVRUN2)
|
||||||
state_.status_reg.OVRUN2 = 0;
|
si.m_status_reg.OVRUN2 = 0;
|
||||||
if (tmp_status.UNRUN2)
|
if (tmp_status.UNRUN2)
|
||||||
state_.status_reg.UNRUN2 = 0;
|
si.m_status_reg.UNRUN2 = 0;
|
||||||
|
|
||||||
if (tmp_status.NOREP3)
|
if (tmp_status.NOREP3)
|
||||||
state_.status_reg.NOREP3 = 0;
|
si.m_status_reg.NOREP3 = 0;
|
||||||
if (tmp_status.COLL3)
|
if (tmp_status.COLL3)
|
||||||
state_.status_reg.COLL3 = 0;
|
si.m_status_reg.COLL3 = 0;
|
||||||
if (tmp_status.OVRUN3)
|
if (tmp_status.OVRUN3)
|
||||||
state_.status_reg.OVRUN3 = 0;
|
si.m_status_reg.OVRUN3 = 0;
|
||||||
if (tmp_status.UNRUN3)
|
if (tmp_status.UNRUN3)
|
||||||
state_.status_reg.UNRUN3 = 0;
|
si.m_status_reg.UNRUN3 = 0;
|
||||||
|
|
||||||
// send command to devices
|
// send command to devices
|
||||||
if (tmp_status.WR)
|
if (tmp_status.WR)
|
||||||
{
|
{
|
||||||
state_.channel[0].device->SendCommand(state_.channel[0].out.hex, state_.poll.EN0);
|
si.m_channel[0].device->SendCommand(si.m_channel[0].out.hex, si.m_poll.EN0);
|
||||||
state_.channel[1].device->SendCommand(state_.channel[1].out.hex, state_.poll.EN1);
|
si.m_channel[1].device->SendCommand(si.m_channel[1].out.hex, si.m_poll.EN1);
|
||||||
state_.channel[2].device->SendCommand(state_.channel[2].out.hex, state_.poll.EN2);
|
si.m_channel[2].device->SendCommand(si.m_channel[2].out.hex, si.m_poll.EN2);
|
||||||
state_.channel[3].device->SendCommand(state_.channel[3].out.hex, state_.poll.EN3);
|
si.m_channel[3].device->SendCommand(si.m_channel[3].out.hex, si.m_poll.EN3);
|
||||||
|
|
||||||
state_.status_reg.WR = 0;
|
si.m_status_reg.WR = 0;
|
||||||
state_.status_reg.WRST0 = 0;
|
si.m_status_reg.WRST0 = 0;
|
||||||
state_.status_reg.WRST1 = 0;
|
si.m_status_reg.WRST1 = 0;
|
||||||
state_.status_reg.WRST2 = 0;
|
si.m_status_reg.WRST2 = 0;
|
||||||
state_.status_reg.WRST3 = 0;
|
si.m_status_reg.WRST3 = 0;
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
mmio->Register(base | SI_EXI_CLOCK_COUNT, MMIO::DirectRead<u32>(&state.exi_clock_count.hex),
|
mmio->Register(base | SI_EXI_CLOCK_COUNT, MMIO::DirectRead<u32>(&m_exi_clock_count.hex),
|
||||||
MMIO::DirectWrite<u32>(&state.exi_clock_count.hex));
|
MMIO::DirectWrite<u32>(&m_exi_clock_count.hex));
|
||||||
}
|
}
|
||||||
|
|
||||||
void RemoveDevice(int device_number)
|
void SerialInterfaceManager::RemoveDevice(int device_number)
|
||||||
{
|
{
|
||||||
auto& state = Core::System::GetInstance().GetSerialInterfaceState().GetData();
|
m_channel.at(device_number).device.reset();
|
||||||
state.channel.at(device_number).device.reset();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AddDevice(std::unique_ptr<ISIDevice> device)
|
void SerialInterfaceManager::AddDevice(std::unique_ptr<ISIDevice> device)
|
||||||
{
|
{
|
||||||
int device_number = device->GetDeviceNumber();
|
int device_number = device->GetDeviceNumber();
|
||||||
|
|
||||||
|
@ -666,27 +490,23 @@ void AddDevice(std::unique_ptr<ISIDevice> device)
|
||||||
RemoveDevice(device_number);
|
RemoveDevice(device_number);
|
||||||
|
|
||||||
// Set the new one
|
// Set the new one
|
||||||
auto& state = Core::System::GetInstance().GetSerialInterfaceState().GetData();
|
m_channel.at(device_number).device = std::move(device);
|
||||||
state.channel.at(device_number).device = std::move(device);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AddDevice(const SIDevices device, int device_number)
|
void SerialInterfaceManager::AddDevice(const SIDevices device, int device_number)
|
||||||
{
|
{
|
||||||
AddDevice(SIDevice_Create(Core::System::GetInstance(), device, device_number));
|
AddDevice(SIDevice_Create(m_system, device, device_number));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ChangeDevice(SIDevices device, int channel)
|
void SerialInterfaceManager::ChangeDevice(SIDevices device, int channel)
|
||||||
{
|
{
|
||||||
// Actual device change will happen in UpdateDevices.
|
// Actual device change will happen in UpdateDevices.
|
||||||
auto& state = Core::System::GetInstance().GetSerialInterfaceState().GetData();
|
m_desired_device_types[channel] = device;
|
||||||
state.desired_device_types[channel] = device;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ChangeDeviceDeterministic(SIDevices device, int channel)
|
void SerialInterfaceManager::ChangeDeviceDeterministic(SIDevices device, int channel)
|
||||||
{
|
{
|
||||||
auto& system = Core::System::GetInstance();
|
if (m_channel[channel].has_recent_device_change)
|
||||||
auto& state = system.GetSerialInterfaceState().GetData();
|
|
||||||
if (state.channel[channel].has_recent_device_change)
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (GetDeviceType(channel) != SIDEVICE_NONE)
|
if (GetDeviceType(channel) != SIDEVICE_NONE)
|
||||||
|
@ -695,29 +515,27 @@ static void ChangeDeviceDeterministic(SIDevices device, int channel)
|
||||||
device = SIDEVICE_NONE;
|
device = SIDEVICE_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
state.channel[channel].out.hex = 0;
|
m_channel[channel].out.hex = 0;
|
||||||
state.channel[channel].in_hi.hex = 0;
|
m_channel[channel].in_hi.hex = 0;
|
||||||
state.channel[channel].in_lo.hex = 0;
|
m_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.
|
||||||
state.channel[channel].has_recent_device_change = true;
|
m_channel[channel].has_recent_device_change = true;
|
||||||
system.GetCoreTiming().ScheduleEvent(SystemTimers::GetTicksPerSecond(),
|
m_system.GetCoreTiming().ScheduleEvent(SystemTimers::GetTicksPerSecond(),
|
||||||
state.event_type_change_device, channel);
|
m_event_type_change_device, channel);
|
||||||
}
|
}
|
||||||
|
|
||||||
void UpdateDevices()
|
void SerialInterfaceManager::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 = state.desired_device_types[i];
|
const SIDevices desired_type = m_desired_device_types[i];
|
||||||
|
|
||||||
if (current_type != desired_type)
|
if (current_type != desired_type)
|
||||||
{
|
{
|
||||||
|
@ -735,14 +553,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
|
||||||
state.status_reg.RDST0 =
|
m_status_reg.RDST0 =
|
||||||
!!state.channel[0].device->GetData(state.channel[0].in_hi.hex, state.channel[0].in_lo.hex);
|
!!m_channel[0].device->GetData(m_channel[0].in_hi.hex, m_channel[0].in_lo.hex);
|
||||||
state.status_reg.RDST1 =
|
m_status_reg.RDST1 =
|
||||||
!!state.channel[1].device->GetData(state.channel[1].in_hi.hex, state.channel[1].in_lo.hex);
|
!!m_channel[1].device->GetData(m_channel[1].in_hi.hex, m_channel[1].in_lo.hex);
|
||||||
state.status_reg.RDST2 =
|
m_status_reg.RDST2 =
|
||||||
!!state.channel[2].device->GetData(state.channel[2].in_hi.hex, state.channel[2].in_lo.hex);
|
!!m_channel[2].device->GetData(m_channel[2].in_hi.hex, m_channel[2].in_lo.hex);
|
||||||
state.status_reg.RDST3 =
|
m_status_reg.RDST3 =
|
||||||
!!state.channel[3].device->GetData(state.channel[3].in_hi.hex, state.channel[3].in_lo.hex);
|
!!m_channel[3].device->GetData(m_channel[3].in_hi.hex, m_channel[3].in_lo.hex);
|
||||||
|
|
||||||
UpdateInterrupts();
|
UpdateInterrupts();
|
||||||
|
|
||||||
|
@ -750,19 +568,17 @@ void UpdateDevices()
|
||||||
NetPlay::SetSIPollBatching(false);
|
NetPlay::SetSIPollBatching(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
SIDevices GetDeviceType(int channel)
|
SIDevices SerialInterfaceManager::GetDeviceType(int channel)
|
||||||
{
|
{
|
||||||
auto& state = Core::System::GetInstance().GetSerialInterfaceState().GetData();
|
if (channel < 0 || channel >= MAX_SI_CHANNELS || !m_channel[channel].device)
|
||||||
if (channel < 0 || channel >= MAX_SI_CHANNELS || !state.channel[channel].device)
|
|
||||||
return SIDEVICE_NONE;
|
return SIDEVICE_NONE;
|
||||||
|
|
||||||
return state.channel[channel].device->GetDeviceType();
|
return m_channel[channel].device->GetDeviceType();
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 GetPollXLines()
|
u32 SerialInterfaceManager::GetPollXLines()
|
||||||
{
|
{
|
||||||
auto& state = Core::System::GetInstance().GetSerialInterfaceState().GetData();
|
return m_poll.X;
|
||||||
return state.poll.X;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace SerialInterface
|
} // namespace SerialInterface
|
||||||
|
|
|
@ -3,11 +3,23 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
#include <atomic>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
|
#include "Common/BitField.h"
|
||||||
#include "Common/CommonTypes.h"
|
#include "Common/CommonTypes.h"
|
||||||
|
|
||||||
class PointerWrap;
|
class PointerWrap;
|
||||||
|
|
||||||
|
namespace Core
|
||||||
|
{
|
||||||
|
class System;
|
||||||
|
}
|
||||||
|
namespace CoreTiming
|
||||||
|
{
|
||||||
|
struct EventType;
|
||||||
|
}
|
||||||
namespace MMIO
|
namespace MMIO
|
||||||
{
|
{
|
||||||
class Mapping;
|
class Mapping;
|
||||||
|
@ -15,23 +27,6 @@ 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;
|
||||||
|
|
||||||
|
@ -41,25 +36,212 @@ enum
|
||||||
MAX_SI_CHANNELS = 0x04
|
MAX_SI_CHANNELS = 0x04
|
||||||
};
|
};
|
||||||
|
|
||||||
void Init();
|
class SerialInterfaceManager
|
||||||
void Shutdown();
|
{
|
||||||
void DoState(PointerWrap& p);
|
public:
|
||||||
|
explicit SerialInterfaceManager(Core::System& system);
|
||||||
|
SerialInterfaceManager(const SerialInterfaceManager&) = delete;
|
||||||
|
SerialInterfaceManager(SerialInterfaceManager&&) = delete;
|
||||||
|
SerialInterfaceManager& operator=(const SerialInterfaceManager&) = delete;
|
||||||
|
SerialInterfaceManager& operator=(SerialInterfaceManager&&) = delete;
|
||||||
|
~SerialInterfaceManager();
|
||||||
|
|
||||||
void RegisterMMIO(MMIO::Mapping* mmio, u32 base);
|
void Init();
|
||||||
|
void Shutdown();
|
||||||
|
void DoState(PointerWrap& p);
|
||||||
|
|
||||||
void ScheduleEvent(int device_number, s64 cycles_into_future, u64 userdata = 0);
|
void RegisterMMIO(MMIO::Mapping* mmio, u32 base);
|
||||||
void RemoveEvent(int device_number);
|
|
||||||
|
|
||||||
void UpdateDevices();
|
void ScheduleEvent(int device_number, s64 cycles_into_future, u64 userdata = 0);
|
||||||
|
void RemoveEvent(int device_number);
|
||||||
|
|
||||||
void RemoveDevice(int device_number);
|
void UpdateDevices();
|
||||||
void AddDevice(SIDevices device, int device_number);
|
|
||||||
void AddDevice(std::unique_ptr<ISIDevice> device);
|
|
||||||
|
|
||||||
void ChangeDevice(SIDevices device, int channel);
|
void RemoveDevice(int device_number);
|
||||||
|
void AddDevice(SIDevices device, int device_number);
|
||||||
|
void AddDevice(std::unique_ptr<ISIDevice> device);
|
||||||
|
|
||||||
SIDevices GetDeviceType(int channel);
|
void ChangeDevice(SIDevices device, int channel);
|
||||||
|
|
||||||
u32 GetPollXLines();
|
SIDevices GetDeviceType(int channel);
|
||||||
|
|
||||||
|
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
|
} // namespace SerialInterface
|
||||||
|
|
|
@ -34,12 +34,12 @@ CSIDevice_GBAEmu::CSIDevice_GBAEmu(Core::System& system, SIDevices device, int d
|
||||||
m_core->Start(system.GetCoreTiming().GetTicks());
|
m_core->Start(system.GetCoreTiming().GetTicks());
|
||||||
m_gbahost = Host_CreateGBAHost(m_core);
|
m_gbahost = Host_CreateGBAHost(m_core);
|
||||||
m_core->SetHost(m_gbahost);
|
m_core->SetHost(m_gbahost);
|
||||||
ScheduleEvent(m_device_number, GetSyncInterval());
|
system.GetSerialInterface().ScheduleEvent(m_device_number, GetSyncInterval());
|
||||||
}
|
}
|
||||||
|
|
||||||
CSIDevice_GBAEmu::~CSIDevice_GBAEmu()
|
CSIDevice_GBAEmu::~CSIDevice_GBAEmu()
|
||||||
{
|
{
|
||||||
RemoveEvent(m_device_number);
|
m_system.GetSerialInterface().RemoveEvent(m_device_number);
|
||||||
m_core->Stop();
|
m_core->Stop();
|
||||||
m_gbahost.reset();
|
m_gbahost.reset();
|
||||||
m_core.reset();
|
m_core.reset();
|
||||||
|
@ -59,14 +59,15 @@ int CSIDevice_GBAEmu::RunBuffer(u8* buffer, int request_length)
|
||||||
m_timestamp_sent = m_system.GetCoreTiming().GetTicks();
|
m_timestamp_sent = m_system.GetCoreTiming().GetTicks();
|
||||||
m_core->SendJoybusCommand(m_timestamp_sent, TransferInterval(), buffer, m_keys);
|
m_core->SendJoybusCommand(m_timestamp_sent, TransferInterval(), buffer, m_keys);
|
||||||
|
|
||||||
RemoveEvent(m_device_number);
|
auto& si = m_system.GetSerialInterface();
|
||||||
ScheduleEvent(m_device_number, TransferInterval() + GetSyncInterval());
|
si.RemoveEvent(m_device_number);
|
||||||
|
si.ScheduleEvent(m_device_number, TransferInterval() + GetSyncInterval());
|
||||||
for (int i = 0; i < MAX_SI_CHANNELS; ++i)
|
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;
|
continue;
|
||||||
RemoveEvent(i);
|
si.RemoveEvent(i);
|
||||||
ScheduleEvent(i, 0, static_cast<u64>(TransferInterval()));
|
si.ScheduleEvent(i, 0, static_cast<u64>(TransferInterval()));
|
||||||
}
|
}
|
||||||
|
|
||||||
m_next_action = NextAction::WaitTransferTime;
|
m_next_action = NextAction::WaitTransferTime;
|
||||||
|
@ -164,6 +165,6 @@ void CSIDevice_GBAEmu::DoState(PointerWrap& p)
|
||||||
void CSIDevice_GBAEmu::OnEvent(u64 userdata, s64 cycles_late)
|
void CSIDevice_GBAEmu::OnEvent(u64 userdata, s64 cycles_late)
|
||||||
{
|
{
|
||||||
m_core->SendJoybusCommand(m_system.GetCoreTiming().GetTicks() + userdata, 0, nullptr, m_keys);
|
m_core->SendJoybusCommand(m_system.GetCoreTiming().GetTicks() + userdata, 0, nullptr, m_keys);
|
||||||
ScheduleEvent(m_device_number, userdata + GetSyncInterval());
|
m_system.GetSerialInterface().ScheduleEvent(m_device_number, userdata + GetSyncInterval());
|
||||||
}
|
}
|
||||||
} // namespace SerialInterface
|
} // namespace SerialInterface
|
||||||
|
|
|
@ -885,8 +885,9 @@ void VideoInterfaceManager::Update(u64 ticks)
|
||||||
{
|
{
|
||||||
Core::UpdateInputGate(!Config::Get(Config::MAIN_INPUT_BACKGROUND_INPUT),
|
Core::UpdateInputGate(!Config::Get(Config::MAIN_INPUT_BACKGROUND_INPUT),
|
||||||
Config::Get(Config::MAIN_LOCK_CURSOR));
|
Config::Get(Config::MAIN_LOCK_CURSOR));
|
||||||
SerialInterface::UpdateDevices();
|
auto& si = m_system.GetSerialInterface();
|
||||||
m_half_line_of_next_si_poll += 2 * SerialInterface::GetPollXLines();
|
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
|
// If this half-line is at the actual boundary of either field, schedule an SI poll to happen
|
||||||
|
|
|
@ -169,9 +169,10 @@ std::string GetInputDisplay()
|
||||||
s_wiimotes = {};
|
s_wiimotes = {};
|
||||||
for (int i = 0; i < 4; ++i)
|
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;
|
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;
|
s_controllers[i] = ControllerType::GC;
|
||||||
else
|
else
|
||||||
s_controllers[i] = ControllerType::None;
|
s_controllers[i] = ControllerType::None;
|
||||||
|
@ -484,6 +485,7 @@ void ChangePads()
|
||||||
if (s_controllers == controllers)
|
if (s_controllers == controllers)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
auto& si = Core::System::GetInstance().GetSerialInterface();
|
||||||
for (int i = 0; i < SerialInterface::MAX_SI_CHANNELS; ++i)
|
for (int i = 0; i < SerialInterface::MAX_SI_CHANNELS; ++i)
|
||||||
{
|
{
|
||||||
SerialInterface::SIDevices device = SerialInterface::SIDEVICE_NONE;
|
SerialInterface::SIDevices device = SerialInterface::SIDEVICE_NONE;
|
||||||
|
@ -505,7 +507,7 @@ void ChangePads()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SerialInterface::ChangeDevice(device, i);
|
si.ChangeDevice(device, i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -67,6 +67,7 @@
|
||||||
#include "Core/NetPlayCommon.h"
|
#include "Core/NetPlayCommon.h"
|
||||||
#include "Core/PowerPC/PowerPC.h"
|
#include "Core/PowerPC/PowerPC.h"
|
||||||
#include "Core/SyncIdentifier.h"
|
#include "Core/SyncIdentifier.h"
|
||||||
|
#include "Core/System.h"
|
||||||
#include "DiscIO/Blob.h"
|
#include "DiscIO/Blob.h"
|
||||||
|
|
||||||
#include "InputCommon/ControllerEmu/ControlGroup/Attachments.h"
|
#include "InputCommon/ControllerEmu/ControlGroup/Attachments.h"
|
||||||
|
@ -1833,11 +1834,12 @@ void NetPlayClient::UpdateDevices()
|
||||||
u8 local_pad = 0;
|
u8 local_pad = 0;
|
||||||
u8 pad = 0;
|
u8 pad = 0;
|
||||||
|
|
||||||
|
auto& si = Core::System::GetInstance().GetSerialInterface();
|
||||||
for (auto player_id : m_pad_map)
|
for (auto player_id : m_pad_map)
|
||||||
{
|
{
|
||||||
if (m_gba_config[pad].enabled && player_id > 0)
|
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)
|
else if (player_id == m_local_player->pid)
|
||||||
{
|
{
|
||||||
|
@ -1846,7 +1848,7 @@ void NetPlayClient::UpdateDevices()
|
||||||
Config::Get(Config::GetInfoForSIDevice(local_pad));
|
Config::Get(Config::GetInfoForSIDevice(local_pad));
|
||||||
if (SerialInterface::SIDevice_IsGCController(si_device))
|
if (SerialInterface::SIDevice_IsGCController(si_device))
|
||||||
{
|
{
|
||||||
SerialInterface::ChangeDevice(si_device, pad);
|
si.ChangeDevice(si_device, pad);
|
||||||
|
|
||||||
if (si_device == SerialInterface::SIDEVICE_WIIU_ADAPTER)
|
if (si_device == SerialInterface::SIDEVICE_WIIU_ADAPTER)
|
||||||
{
|
{
|
||||||
|
@ -1855,17 +1857,17 @@ void NetPlayClient::UpdateDevices()
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
SerialInterface::ChangeDevice(SerialInterface::SIDEVICE_GC_CONTROLLER, pad);
|
si.ChangeDevice(SerialInterface::SIDEVICE_GC_CONTROLLER, pad);
|
||||||
}
|
}
|
||||||
local_pad++;
|
local_pad++;
|
||||||
}
|
}
|
||||||
else if (player_id > 0)
|
else if (player_id > 0)
|
||||||
{
|
{
|
||||||
SerialInterface::ChangeDevice(SerialInterface::SIDEVICE_GC_CONTROLLER, pad);
|
si.ChangeDevice(SerialInterface::SIDEVICE_GC_CONTROLLER, pad);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
SerialInterface::ChangeDevice(SerialInterface::SIDEVICE_NONE, pad);
|
si.ChangeDevice(SerialInterface::SIDEVICE_NONE, pad);
|
||||||
}
|
}
|
||||||
pad++;
|
pad++;
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,7 +38,7 @@ struct System::Impl
|
||||||
explicit Impl(System& system)
|
explicit Impl(System& system)
|
||||||
: m_audio_interface(system), m_core_timing(system), m_dsp(system), m_dvd_interface(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_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)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -65,7 +65,7 @@ struct System::Impl
|
||||||
PixelShaderManager m_pixel_shader_manager;
|
PixelShaderManager m_pixel_shader_manager;
|
||||||
PowerPC::PowerPCState& m_ppc_state;
|
PowerPC::PowerPCState& m_ppc_state;
|
||||||
ProcessorInterface::ProcessorInterfaceManager m_processor_interface;
|
ProcessorInterface::ProcessorInterfaceManager m_processor_interface;
|
||||||
SerialInterface::SerialInterfaceState m_serial_interface_state;
|
SerialInterface::SerialInterfaceManager m_serial_interface;
|
||||||
Sram m_sram;
|
Sram m_sram;
|
||||||
VertexShaderManager m_vertex_shader_manager;
|
VertexShaderManager m_vertex_shader_manager;
|
||||||
VideoInterface::VideoInterfaceManager m_video_interface;
|
VideoInterface::VideoInterfaceManager m_video_interface;
|
||||||
|
@ -209,9 +209,9 @@ ProcessorInterface::ProcessorInterfaceManager& System::GetProcessorInterface() c
|
||||||
return m_impl->m_processor_interface;
|
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
|
Sram& System::GetSRAM() const
|
||||||
|
|
|
@ -78,7 +78,7 @@ class ProcessorInterfaceManager;
|
||||||
}
|
}
|
||||||
namespace SerialInterface
|
namespace SerialInterface
|
||||||
{
|
{
|
||||||
class SerialInterfaceState;
|
class SerialInterfaceManager;
|
||||||
};
|
};
|
||||||
namespace VideoInterface
|
namespace VideoInterface
|
||||||
{
|
{
|
||||||
|
@ -138,7 +138,7 @@ public:
|
||||||
PixelShaderManager& GetPixelShaderManager() const;
|
PixelShaderManager& GetPixelShaderManager() const;
|
||||||
PowerPC::PowerPCState& GetPPCState() const;
|
PowerPC::PowerPCState& GetPPCState() const;
|
||||||
ProcessorInterface::ProcessorInterfaceManager& GetProcessorInterface() const;
|
ProcessorInterface::ProcessorInterfaceManager& GetProcessorInterface() const;
|
||||||
SerialInterface::SerialInterfaceState& GetSerialInterfaceState() const;
|
SerialInterface::SerialInterfaceManager& GetSerialInterface() const;
|
||||||
Sram& GetSRAM() const;
|
Sram& GetSRAM() const;
|
||||||
VertexShaderManager& GetVertexShaderManager() const;
|
VertexShaderManager& GetVertexShaderManager() const;
|
||||||
VideoInterface::VideoInterfaceManager& GetVideoInterface() const;
|
VideoInterface::VideoInterfaceManager& GetVideoInterface() const;
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
#include "Core/HW/SI/SI.h"
|
#include "Core/HW/SI/SI.h"
|
||||||
#include "Core/HW/SI/SI_Device.h"
|
#include "Core/HW/SI/SI_Device.h"
|
||||||
#include "Core/NetPlayProto.h"
|
#include "Core/NetPlayProto.h"
|
||||||
|
#include "Core/System.h"
|
||||||
|
|
||||||
#include "DolphinQt/Config/Mapping/GCPadWiiUConfigDialog.h"
|
#include "DolphinQt/Config/Mapping/GCPadWiiUConfigDialog.h"
|
||||||
#include "DolphinQt/Config/Mapping/MappingWindow.h"
|
#include "DolphinQt/Config/Mapping/MappingWindow.h"
|
||||||
|
@ -192,7 +193,10 @@ void GamecubeControllersWidget::SaveSettings()
|
||||||
Config::SetBaseOrCurrent(Config::GetInfoForSIDevice(static_cast<int>(i)), si_device);
|
Config::SetBaseOrCurrent(Config::GetInfoForSIDevice(static_cast<int>(i)), si_device);
|
||||||
|
|
||||||
if (Core::IsRunning())
|
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())
|
if (GCAdapter::UseAdapter())
|
||||||
|
|
Loading…
Reference in New Issue