From bf2f901a99184accb9594bf815845e98c22cf0ec Mon Sep 17 00:00:00 2001 From: "Admiral H. Curtiss" Date: Sun, 12 Mar 2023 14:20:32 +0100 Subject: [PATCH] HW/SerialInterface: Refactor to class. --- Source/Core/Core/HW/HW.cpp | 6 +- Source/Core/Core/HW/Memmap.cpp | 4 +- Source/Core/Core/HW/SI/SI.cpp | 606 ++++++------------ Source/Core/Core/HW/SI/SI.h | 242 ++++++- Source/Core/Core/HW/SI/SI_DeviceGBAEmu.cpp | 17 +- Source/Core/Core/HW/VideoInterface.cpp | 5 +- Source/Core/Core/Movie.cpp | 8 +- Source/Core/Core/NetPlayClient.cpp | 12 +- Source/Core/Core/System.cpp | 8 +- Source/Core/Core/System.h | 4 +- .../Config/GamecubeControllersWidget.cpp | 6 +- 11 files changed, 463 insertions(+), 455 deletions(-) diff --git a/Source/Core/Core/HW/HW.cpp b/Source/Core/Core/HW/HW.cpp index bd80e8a904..a8e8ae466f 100644 --- a/Source/Core/Core/HW/HW.cpp +++ b/Source/Core/Core/HW/HW.cpp @@ -42,7 +42,7 @@ void Init(const Sram* override_sram) // Init the whole Hardware system.GetAudioInterface().Init(); system.GetVideoInterface().Init(); - SerialInterface::Init(); + system.GetSerialInterface().Init(); system.GetProcessorInterface().Init(); system.GetExpansionInterface().Init(override_sram); // Needs to be initialized before Memory system.GetHSP().Init(); @@ -79,7 +79,7 @@ void Shutdown() system.GetMemory().Shutdown(); system.GetHSP().Shutdown(); system.GetExpansionInterface().Shutdown(); - SerialInterface::Shutdown(); + system.GetSerialInterface().Shutdown(); system.GetAudioInterface().Shutdown(); State::Shutdown(); @@ -95,7 +95,7 @@ void DoState(PointerWrap& p) p.DoMarker("MemoryInterface"); system.GetVideoInterface().DoState(p); p.DoMarker("VideoInterface"); - SerialInterface::DoState(p); + system.GetSerialInterface().DoState(p); p.DoMarker("SerialInterface"); system.GetProcessorInterface().DoState(p); p.DoMarker("ProcessorInterface"); diff --git a/Source/Core/Core/HW/Memmap.cpp b/Source/Core/Core/HW/Memmap.cpp index 871956aeff..25c102d6a4 100644 --- a/Source/Core/Core/HW/Memmap.cpp +++ b/Source/Core/Core/HW/Memmap.cpp @@ -56,14 +56,14 @@ void MemoryManager::InitMMIO(bool is_wii) system.GetMemoryInterface().RegisterMMIO(m_mmio_mapping.get(), 0x0C004000); system.GetDSP().RegisterMMIO(m_mmio_mapping.get(), 0x0C005000); 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.GetAudioInterface().RegisterMMIO(m_mmio_mapping.get(), 0x0C006C00); if (is_wii) { IOS::RegisterMMIO(m_mmio_mapping.get(), 0x0D000000); 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.GetAudioInterface().RegisterMMIO(m_mmio_mapping.get(), 0x0D006C00); } diff --git a/Source/Core/Core/HW/SI/SI.cpp b/Source/Core/Core/HW/SI/SI.cpp index b38d114a07..1312c548bc 100644 --- a/Source/Core/Core/HW/SI/SI.cpp +++ b/Source/Core/Core/HW/SI/SI.cpp @@ -31,13 +31,6 @@ namespace SerialInterface { -// SI Interrupt Types -enum SIInterruptType -{ - INT_RDSTINT = 0, - INT_TCINT = 1, -}; - // SI Internal Hardware Addresses enum { @@ -60,228 +53,69 @@ enum SI_IO_BUFFER = 0x80, }; -// 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 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 event_types_device{}; - - // User-configured device type. possibly overridden by TAS/Netplay - std::array, MAX_SI_CHANNELS> desired_device_types{}; - - std::array channel{}; - USIPoll poll; - USIComCSR com_csr; - USIStatusReg status_reg; - USIEXIClockCount exi_clock_count; - std::array si_buffer{}; -}; - -SerialInterfaceState::SerialInterfaceState() : m_data(std::make_unique()) +SerialInterfaceManager::SerialInterfaceManager(Core::System& system) : m_system(system) { } -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 switch (channel) { case 0: - state.status_reg.NOREP0 = 1; + m_status_reg.NOREP0 = 1; break; case 1: - state.status_reg.NOREP1 = 1; + m_status_reg.NOREP1 = 1; break; case 2: - state.status_reg.NOREP2 = 1; + m_status_reg.NOREP2 = 1; break; case 3: - state.status_reg.NOREP3 = 1; + m_status_reg.NOREP3 = 1; 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. - auto& state = system.GetSerialInterfaceState().GetData(); - state.channel[user_data].has_recent_device_change = false; + auto& si = system.GetSerialInterface(); + 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 - auto& system = Core::System::GetInstance(); - auto& state = system.GetSerialInterfaceState().GetData(); - if (state.status_reg.RDST0 || state.status_reg.RDST1 || state.status_reg.RDST2 || - state.status_reg.RDST3) + if (m_status_reg.RDST0 || m_status_reg.RDST1 || m_status_reg.RDST2 || m_status_reg.RDST3) { - state.com_csr.RDSTINT = 1; + m_com_csr.RDSTINT = 1; } else { - state.com_csr.RDSTINT = 0; + m_com_csr.RDSTINT = 0; } // check if we have to generate an interrupt - const bool generate_interrupt = (state.com_csr.RDSTINT & state.com_csr.RDSTINTMSK) != 0 || - (state.com_csr.TCINT & state.com_csr.TCINTMSK) != 0; + const bool generate_interrupt = (m_com_csr.RDSTINT & m_com_csr.RDSTINTMSK) != 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) { case INT_RDSTINT: - state.com_csr.RDSTINT = 1; + m_com_csr.RDSTINT = 1; break; case INT_TCINT: - state.com_csr.TCINT = 1; + m_com_csr.TCINT = 1; break; } @@ -296,23 +130,26 @@ constexpr s32 ConvertSILengthField(u32 field) 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(); - 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 request_copy(state.si_buffer.data(), - state.si_buffer.data() + request_length); + system.GetSerialInterface().RunSIBuffer(user_data, cycles_late); +} - const std::unique_ptr& device = state.channel[state.com_csr.CHANNEL].device; - const s32 actual_response_length = device->RunBuffer(state.si_buffer.data(), request_length); +void SerialInterfaceManager::RunSIBuffer(u64 user_data, s64 cycles_late) +{ + 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 request_copy(m_si_buffer.data(), m_si_buffer.data() + request_length); + + const std::unique_ptr& 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, "RunSIBuffer chan: {} request_length: {} expected_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); 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 if (actual_response_length != 0) { - state.com_csr.TSTART = 0; - state.com_csr.COMERR = actual_response_length < 0; + m_com_csr.TSTART = 0; + m_com_csr.COMERR = actual_response_length < 0; if (actual_response_length < 0) - SetNoResponse(state.com_csr.CHANNEL); + SetNoResponse(m_com_csr.CHANNEL); GenerateSIInterrupt(INT_TCINT); } else { - system.GetCoreTiming().ScheduleEvent(device->TransferInterval() - cycles_late, - state.event_type_tranfer_pending); + m_system.GetCoreTiming().ScheduleEvent(device->TransferInterval() - cycles_late, + 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++) { - p.Do(state.channel[i].in_hi.hex); - p.Do(state.channel[i].in_lo.hex); - p.Do(state.channel[i].out.hex); - p.Do(state.channel[i].has_recent_device_change); + p.Do(m_channel[i].in_hi.hex); + p.Do(m_channel[i].in_lo.hex); + p.Do(m_channel[i].out.hex); + p.Do(m_channel[i].has_recent_device_change); - std::unique_ptr& device = state.channel[i].device; + std::unique_ptr& device = m_channel[i].device; SIDevices type = device->GetDeviceType(); p.Do(type); if (type != device->GetDeviceType()) { - AddDevice(SIDevice_Create(Core::System::GetInstance(), type, i)); + AddDevice(SIDevice_Create(m_system, type, i)); } device->DoState(p); } - p.Do(state.poll); - p.Do(state.com_csr); - p.Do(state.status_reg); - p.Do(state.exi_clock_count); - p.Do(state.si_buffer); + p.Do(m_poll); + p.Do(m_com_csr); + p.Do(m_status_reg); + p.Do(m_exi_clock_count); + p.Do(m_si_buffer); } template -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(); - state.channel[device_number].device->OnEvent(userdata, cyclesLate); + auto& si = system.GetSerialInterface(); + si.m_channel[device_number].device->OnEvent(userdata, cyclesLate); } -static void RegisterEvents() +void SerialInterfaceManager::RegisterEvents() { - auto& system = Core::System::GetInstance(); - auto& core_timing = system.GetCoreTiming(); - auto& state = system.GetSerialInterfaceState().GetData(); - state.event_type_change_device = - core_timing.RegisterEvent("ChangeSIDevice", ChangeDeviceCallback); - state.event_type_tranfer_pending = core_timing.RegisterEvent("SITransferPending", RunSIBuffer); + auto& core_timing = m_system.GetCoreTiming(); + m_event_type_change_device = core_timing.RegisterEvent("ChangeSIDevice", ChangeDeviceCallback); + m_event_type_tranfer_pending = core_timing.RegisterEvent("SITransferPending", GlobalRunSIBuffer); constexpr std::array event_callbacks = { DeviceEventCallback<0>, @@ -404,125 +237,118 @@ static void RegisterEvents() }; 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]); } } -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 = system.GetCoreTiming(); - auto& state = system.GetSerialInterfaceState().GetData(); - core_timing.ScheduleEvent(cycles_into_future, state.event_types_device[device_number], userdata); + auto& core_timing = m_system.GetCoreTiming(); + core_timing.ScheduleEvent(cycles_into_future, m_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 = system.GetCoreTiming(); - auto& state = system.GetSerialInterfaceState().GetData(); - core_timing.RemoveEvent(state.event_types_device[device_number]); + auto& core_timing = m_system.GetCoreTiming(); + core_timing.RemoveEvent(m_event_types_device[device_number]); } -void Init() +void SerialInterfaceManager::Init() { - auto& state = Core::System::GetInstance().GetSerialInterfaceState().GetData(); RegisterEvents(); for (int i = 0; i < MAX_SI_CHANNELS; i++) { - state.channel[i].out.hex = 0; - state.channel[i].in_hi.hex = 0; - state.channel[i].in_lo.hex = 0; - state.channel[i].has_recent_device_change = false; + m_channel[i].out.hex = 0; + m_channel[i].in_hi.hex = 0; + m_channel[i].in_lo.hex = 0; + m_channel[i].has_recent_device_change = false; if (Movie::IsMovieActive()) { - state.desired_device_types[i] = SIDEVICE_NONE; + m_desired_device_types[i] = SIDEVICE_NONE; 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)) { SIDevices current = Config::Get(Config::GetInfoForSIDevice(i)); // GC pad-compatible devices can be used for both playing and recording 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)) - state.desired_device_types[i] = current; + m_desired_device_types[i] = current; else - state.desired_device_types[i] = SIDEVICE_GC_CONTROLLER; + m_desired_device_types[i] = SIDEVICE_GC_CONTROLLER; } } 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; - state.poll.X = 492; + m_poll.hex = 0; + 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... - // 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++) RemoveDevice(i); 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. 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(io_buffer_base + i); mmio->Register(address, MMIO::ComplexRead([i](Core::System& system, u32) { - auto& state_ = system.GetSerialInterfaceState().GetData(); + auto& si = system.GetSerialInterface(); 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); }), MMIO::ComplexWrite([i](Core::System& system, u32, u32 val) { - auto& state_ = system.GetSerialInterfaceState().GetData(); + auto& si = system.GetSerialInterface(); 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(io_buffer_base + i); mmio->Register(address, MMIO::ComplexRead([i](Core::System& system, u32) { - auto& state_ = system.GetSerialInterfaceState().GetData(); + auto& si = system.GetSerialInterface(); 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); }), MMIO::ComplexWrite([i](Core::System& system, u32, u16 val) { - auto& state_ = system.GetSerialInterfaceState().GetData(); + auto& si = system.GetSerialInterface(); 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; mmio->Register(base | (SI_CHANNEL_0_OUT + 0xC * i), - MMIO::DirectRead(&state.channel[i].out.hex), - MMIO::DirectWrite(&state.channel[i].out.hex)); + MMIO::DirectRead(&m_channel[i].out.hex), + MMIO::DirectWrite(&m_channel[i].out.hex)); mmio->Register(base | (SI_CHANNEL_0_IN_HI + 0xC * i), MMIO::ComplexRead([i, rdst_bit](Core::System& system, u32) { - auto& state_ = system.GetSerialInterfaceState().GetData(); - state_.status_reg.hex &= ~(1U << rdst_bit); - UpdateInterrupts(); - return state_.channel[i].in_hi.hex; + auto& si = system.GetSerialInterface(); + si.m_status_reg.hex &= ~(1U << rdst_bit); + si.UpdateInterrupts(); + return si.m_channel[i].in_hi.hex; }), - MMIO::DirectWrite(&state.channel[i].in_hi.hex)); + MMIO::DirectWrite(&m_channel[i].in_hi.hex)); mmio->Register(base | (SI_CHANNEL_0_IN_LO + 0xC * i), MMIO::ComplexRead([i, rdst_bit](Core::System& system, u32) { - auto& state_ = system.GetSerialInterfaceState().GetData(); - state_.status_reg.hex &= ~(1U << rdst_bit); - UpdateInterrupts(); - return state_.channel[i].in_lo.hex; + auto& si = system.GetSerialInterface(); + si.m_status_reg.hex &= ~(1U << rdst_bit); + si.UpdateInterrupts(); + return si.m_channel[i].in_lo.hex; }), - MMIO::DirectWrite(&state.channel[i].in_lo.hex)); + MMIO::DirectWrite(&m_channel[i].in_lo.hex)); } - mmio->Register(base | SI_POLL, MMIO::DirectRead(&state.poll.hex), - MMIO::DirectWrite(&state.poll.hex)); + mmio->Register(base | SI_POLL, MMIO::DirectRead(&m_poll.hex), + MMIO::DirectWrite(&m_poll.hex)); - mmio->Register(base | SI_COM_CSR, MMIO::DirectRead(&state.com_csr.hex), + mmio->Register(base | SI_COM_CSR, MMIO::DirectRead(&m_com_csr.hex), MMIO::ComplexWrite([](Core::System& system, u32, u32 val) { - auto& state_ = system.GetSerialInterfaceState().GetData(); + auto& si = system.GetSerialInterface(); const USIComCSR tmp_com_csr(val); - state_.com_csr.CHANNEL = tmp_com_csr.CHANNEL.Value(); - state_.com_csr.INLNGTH = tmp_com_csr.INLNGTH.Value(); - state_.com_csr.OUTLNGTH = tmp_com_csr.OUTLNGTH.Value(); - state_.com_csr.RDSTINTMSK = tmp_com_csr.RDSTINTMSK.Value(); - state_.com_csr.TCINTMSK = tmp_com_csr.TCINTMSK.Value(); + si.m_com_csr.CHANNEL = tmp_com_csr.CHANNEL.Value(); + si.m_com_csr.INLNGTH = tmp_com_csr.INLNGTH.Value(); + si.m_com_csr.OUTLNGTH = tmp_com_csr.OUTLNGTH.Value(); + si.m_com_csr.RDSTINTMSK = tmp_com_csr.RDSTINTMSK.Value(); + si.m_com_csr.TCINTMSK = tmp_com_csr.TCINTMSK.Value(); if (tmp_com_csr.RDSTINT) - state_.com_csr.RDSTINT = 0; + si.m_com_csr.RDSTINT = 0; 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 if (tmp_com_csr.TSTART) { - if (state_.com_csr.TSTART) - system.GetCoreTiming().RemoveEvent(state_.event_type_tranfer_pending); - state_.com_csr.TSTART = 1; - RunSIBuffer(system, 0, 0); + if (si.m_com_csr.TSTART) + system.GetCoreTiming().RemoveEvent(si.m_event_type_tranfer_pending); + si.m_com_csr.TSTART = 1; + si.RunSIBuffer(0, 0); } - if (!state_.com_csr.TSTART) - UpdateInterrupts(); + if (!si.m_com_csr.TSTART) + si.UpdateInterrupts(); })); - mmio->Register( - base | SI_STATUS_REG, MMIO::DirectRead(&state.status_reg.hex), - MMIO::ComplexWrite([](Core::System& system, u32, u32 val) { - auto& state_ = system.GetSerialInterfaceState().GetData(); - const USIStatusReg tmp_status(val); + mmio->Register(base | SI_STATUS_REG, MMIO::DirectRead(&m_status_reg.hex), + MMIO::ComplexWrite([](Core::System& system, u32, u32 val) { + auto& si = system.GetSerialInterface(); + const USIStatusReg tmp_status(val); - // clear bits ( if (tmp.bit) SISR.bit=0 ) - if (tmp_status.NOREP0) - state_.status_reg.NOREP0 = 0; - if (tmp_status.COLL0) - state_.status_reg.COLL0 = 0; - if (tmp_status.OVRUN0) - state_.status_reg.OVRUN0 = 0; - if (tmp_status.UNRUN0) - state_.status_reg.UNRUN0 = 0; + // clear bits ( if (tmp.bit) SISR.bit=0 ) + if (tmp_status.NOREP0) + si.m_status_reg.NOREP0 = 0; + if (tmp_status.COLL0) + si.m_status_reg.COLL0 = 0; + if (tmp_status.OVRUN0) + si.m_status_reg.OVRUN0 = 0; + if (tmp_status.UNRUN0) + si.m_status_reg.UNRUN0 = 0; - if (tmp_status.NOREP1) - state_.status_reg.NOREP1 = 0; - if (tmp_status.COLL1) - state_.status_reg.COLL1 = 0; - if (tmp_status.OVRUN1) - state_.status_reg.OVRUN1 = 0; - if (tmp_status.UNRUN1) - state_.status_reg.UNRUN1 = 0; + if (tmp_status.NOREP1) + si.m_status_reg.NOREP1 = 0; + if (tmp_status.COLL1) + si.m_status_reg.COLL1 = 0; + if (tmp_status.OVRUN1) + si.m_status_reg.OVRUN1 = 0; + if (tmp_status.UNRUN1) + si.m_status_reg.UNRUN1 = 0; - if (tmp_status.NOREP2) - state_.status_reg.NOREP2 = 0; - if (tmp_status.COLL2) - state_.status_reg.COLL2 = 0; - if (tmp_status.OVRUN2) - state_.status_reg.OVRUN2 = 0; - if (tmp_status.UNRUN2) - state_.status_reg.UNRUN2 = 0; + if (tmp_status.NOREP2) + si.m_status_reg.NOREP2 = 0; + if (tmp_status.COLL2) + si.m_status_reg.COLL2 = 0; + if (tmp_status.OVRUN2) + si.m_status_reg.OVRUN2 = 0; + if (tmp_status.UNRUN2) + si.m_status_reg.UNRUN2 = 0; - if (tmp_status.NOREP3) - state_.status_reg.NOREP3 = 0; - if (tmp_status.COLL3) - state_.status_reg.COLL3 = 0; - if (tmp_status.OVRUN3) - state_.status_reg.OVRUN3 = 0; - if (tmp_status.UNRUN3) - state_.status_reg.UNRUN3 = 0; + if (tmp_status.NOREP3) + si.m_status_reg.NOREP3 = 0; + if (tmp_status.COLL3) + si.m_status_reg.COLL3 = 0; + if (tmp_status.OVRUN3) + si.m_status_reg.OVRUN3 = 0; + if (tmp_status.UNRUN3) + si.m_status_reg.UNRUN3 = 0; - // send command to devices - if (tmp_status.WR) - { - state_.channel[0].device->SendCommand(state_.channel[0].out.hex, state_.poll.EN0); - state_.channel[1].device->SendCommand(state_.channel[1].out.hex, state_.poll.EN1); - state_.channel[2].device->SendCommand(state_.channel[2].out.hex, state_.poll.EN2); - state_.channel[3].device->SendCommand(state_.channel[3].out.hex, state_.poll.EN3); + // send command to devices + if (tmp_status.WR) + { + si.m_channel[0].device->SendCommand(si.m_channel[0].out.hex, si.m_poll.EN0); + si.m_channel[1].device->SendCommand(si.m_channel[1].out.hex, si.m_poll.EN1); + si.m_channel[2].device->SendCommand(si.m_channel[2].out.hex, si.m_poll.EN2); + si.m_channel[3].device->SendCommand(si.m_channel[3].out.hex, si.m_poll.EN3); - state_.status_reg.WR = 0; - state_.status_reg.WRST0 = 0; - state_.status_reg.WRST1 = 0; - state_.status_reg.WRST2 = 0; - state_.status_reg.WRST3 = 0; - } - })); + si.m_status_reg.WR = 0; + si.m_status_reg.WRST0 = 0; + si.m_status_reg.WRST1 = 0; + si.m_status_reg.WRST2 = 0; + si.m_status_reg.WRST3 = 0; + } + })); - mmio->Register(base | SI_EXI_CLOCK_COUNT, MMIO::DirectRead(&state.exi_clock_count.hex), - MMIO::DirectWrite(&state.exi_clock_count.hex)); + mmio->Register(base | SI_EXI_CLOCK_COUNT, MMIO::DirectRead(&m_exi_clock_count.hex), + MMIO::DirectWrite(&m_exi_clock_count.hex)); } -void RemoveDevice(int device_number) +void SerialInterfaceManager::RemoveDevice(int device_number) { - auto& state = Core::System::GetInstance().GetSerialInterfaceState().GetData(); - state.channel.at(device_number).device.reset(); + m_channel.at(device_number).device.reset(); } -void AddDevice(std::unique_ptr device) +void SerialInterfaceManager::AddDevice(std::unique_ptr device) { int device_number = device->GetDeviceNumber(); @@ -666,27 +490,23 @@ void AddDevice(std::unique_ptr device) RemoveDevice(device_number); // Set the new one - auto& state = Core::System::GetInstance().GetSerialInterfaceState().GetData(); - state.channel.at(device_number).device = std::move(device); + m_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. - auto& state = Core::System::GetInstance().GetSerialInterfaceState().GetData(); - state.desired_device_types[channel] = device; + m_desired_device_types[channel] = device; } -static void ChangeDeviceDeterministic(SIDevices device, int channel) +void SerialInterfaceManager::ChangeDeviceDeterministic(SIDevices device, int channel) { - auto& system = Core::System::GetInstance(); - auto& state = system.GetSerialInterfaceState().GetData(); - if (state.channel[channel].has_recent_device_change) + if (m_channel[channel].has_recent_device_change) return; if (GetDeviceType(channel) != SIDEVICE_NONE) @@ -695,29 +515,27 @@ static void ChangeDeviceDeterministic(SIDevices device, int channel) device = SIDEVICE_NONE; } - state.channel[channel].out.hex = 0; - state.channel[channel].in_hi.hex = 0; - state.channel[channel].in_lo.hex = 0; + m_channel[channel].out.hex = 0; + m_channel[channel].in_hi.hex = 0; + m_channel[channel].in_lo.hex = 0; SetNoResponse(channel); AddDevice(device, channel); // Prevent additional device changes on this channel for one second. - state.channel[channel].has_recent_device_change = true; - system.GetCoreTiming().ScheduleEvent(SystemTimers::GetTicksPerSecond(), - state.event_type_change_device, channel); + m_channel[channel].has_recent_device_change = true; + m_system.GetCoreTiming().ScheduleEvent(SystemTimers::GetTicksPerSecond(), + m_event_type_change_device, channel); } -void UpdateDevices() +void SerialInterfaceManager::UpdateDevices() { - auto& state = Core::System::GetInstance().GetSerialInterfaceState().GetData(); - // Check for device change requests: for (int i = 0; i != MAX_SI_CHANNELS; ++i) { const SIDevices current_type = GetDeviceType(i); - const SIDevices desired_type = state.desired_device_types[i]; + const SIDevices desired_type = m_desired_device_types[i]; if (current_type != desired_type) { @@ -735,14 +553,14 @@ void UpdateDevices() g_controller_interface.UpdateInput(); // Update channels and set the status bit if there's new data - state.status_reg.RDST0 = - !!state.channel[0].device->GetData(state.channel[0].in_hi.hex, state.channel[0].in_lo.hex); - state.status_reg.RDST1 = - !!state.channel[1].device->GetData(state.channel[1].in_hi.hex, state.channel[1].in_lo.hex); - state.status_reg.RDST2 = - !!state.channel[2].device->GetData(state.channel[2].in_hi.hex, state.channel[2].in_lo.hex); - state.status_reg.RDST3 = - !!state.channel[3].device->GetData(state.channel[3].in_hi.hex, state.channel[3].in_lo.hex); + m_status_reg.RDST0 = + !!m_channel[0].device->GetData(m_channel[0].in_hi.hex, m_channel[0].in_lo.hex); + m_status_reg.RDST1 = + !!m_channel[1].device->GetData(m_channel[1].in_hi.hex, m_channel[1].in_lo.hex); + m_status_reg.RDST2 = + !!m_channel[2].device->GetData(m_channel[2].in_hi.hex, m_channel[2].in_lo.hex); + m_status_reg.RDST3 = + !!m_channel[3].device->GetData(m_channel[3].in_hi.hex, m_channel[3].in_lo.hex); UpdateInterrupts(); @@ -750,19 +568,17 @@ void UpdateDevices() 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 || !state.channel[channel].device) + if (channel < 0 || channel >= MAX_SI_CHANNELS || !m_channel[channel].device) 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 state.poll.X; + return m_poll.X; } } // namespace SerialInterface diff --git a/Source/Core/Core/HW/SI/SI.h b/Source/Core/Core/HW/SI/SI.h index 2c877c7ba6..cedd5856cd 100644 --- a/Source/Core/Core/HW/SI/SI.h +++ b/Source/Core/Core/HW/SI/SI.h @@ -3,11 +3,23 @@ #pragma once +#include +#include #include + +#include "Common/BitField.h" #include "Common/CommonTypes.h" class PointerWrap; +namespace Core +{ +class System; +} +namespace CoreTiming +{ +struct EventType; +} namespace MMIO { class Mapping; @@ -15,23 +27,6 @@ class Mapping; namespace SerialInterface { -class SerialInterfaceState -{ -public: - SerialInterfaceState(); - SerialInterfaceState(const SerialInterfaceState&) = delete; - SerialInterfaceState(SerialInterfaceState&&) = delete; - SerialInterfaceState& operator=(const SerialInterfaceState&) = delete; - SerialInterfaceState& operator=(SerialInterfaceState&&) = delete; - ~SerialInterfaceState(); - - struct Data; - Data& GetData() { return *m_data; } - -private: - std::unique_ptr m_data; -}; - class ISIDevice; enum SIDevices : int; @@ -41,25 +36,212 @@ enum MAX_SI_CHANNELS = 0x04 }; -void Init(); -void Shutdown(); -void DoState(PointerWrap& p); +class SerialInterfaceManager +{ +public: + explicit SerialInterfaceManager(Core::System& system); + SerialInterfaceManager(const SerialInterfaceManager&) = delete; + SerialInterfaceManager(SerialInterfaceManager&&) = delete; + SerialInterfaceManager& operator=(const SerialInterfaceManager&) = delete; + SerialInterfaceManager& operator=(SerialInterfaceManager&&) = delete; + ~SerialInterfaceManager(); -void 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 RemoveEvent(int device_number); + void RegisterMMIO(MMIO::Mapping* mmio, u32 base); -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 AddDevice(SIDevices device, int device_number); -void AddDevice(std::unique_ptr device); + void UpdateDevices(); -void ChangeDevice(SIDevices device, int channel); + void RemoveDevice(int device_number); + void AddDevice(SIDevices device, int device_number); + void AddDevice(std::unique_ptr 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 + 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 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 m_event_types_device{}; + + // User-configured device type. possibly overridden by TAS/Netplay + std::array, MAX_SI_CHANNELS> m_desired_device_types{}; + + std::array m_channel; + USIPoll m_poll; + USIComCSR m_com_csr; + USIStatusReg m_status_reg; + USIEXIClockCount m_exi_clock_count; + std::array m_si_buffer{}; + + Core::System& m_system; +}; } // namespace SerialInterface diff --git a/Source/Core/Core/HW/SI/SI_DeviceGBAEmu.cpp b/Source/Core/Core/HW/SI/SI_DeviceGBAEmu.cpp index 2c6b37154b..0eb88a2f4b 100644 --- a/Source/Core/Core/HW/SI/SI_DeviceGBAEmu.cpp +++ b/Source/Core/Core/HW/SI/SI_DeviceGBAEmu.cpp @@ -34,12 +34,12 @@ CSIDevice_GBAEmu::CSIDevice_GBAEmu(Core::System& system, SIDevices device, int d m_core->Start(system.GetCoreTiming().GetTicks()); m_gbahost = Host_CreateGBAHost(m_core); m_core->SetHost(m_gbahost); - ScheduleEvent(m_device_number, GetSyncInterval()); + system.GetSerialInterface().ScheduleEvent(m_device_number, GetSyncInterval()); } CSIDevice_GBAEmu::~CSIDevice_GBAEmu() { - RemoveEvent(m_device_number); + m_system.GetSerialInterface().RemoveEvent(m_device_number); m_core->Stop(); m_gbahost.reset(); m_core.reset(); @@ -59,14 +59,15 @@ int CSIDevice_GBAEmu::RunBuffer(u8* buffer, int request_length) m_timestamp_sent = m_system.GetCoreTiming().GetTicks(); m_core->SendJoybusCommand(m_timestamp_sent, TransferInterval(), buffer, m_keys); - RemoveEvent(m_device_number); - ScheduleEvent(m_device_number, TransferInterval() + GetSyncInterval()); + auto& si = m_system.GetSerialInterface(); + si.RemoveEvent(m_device_number); + si.ScheduleEvent(m_device_number, TransferInterval() + GetSyncInterval()); for (int i = 0; i < MAX_SI_CHANNELS; ++i) { - if (i == m_device_number || SerialInterface::GetDeviceType(i) != GetDeviceType()) + if (i == m_device_number || si.GetDeviceType(i) != GetDeviceType()) continue; - RemoveEvent(i); - ScheduleEvent(i, 0, static_cast(TransferInterval())); + si.RemoveEvent(i); + si.ScheduleEvent(i, 0, static_cast(TransferInterval())); } m_next_action = NextAction::WaitTransferTime; @@ -164,6 +165,6 @@ void CSIDevice_GBAEmu::DoState(PointerWrap& p) void CSIDevice_GBAEmu::OnEvent(u64 userdata, s64 cycles_late) { 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 diff --git a/Source/Core/Core/HW/VideoInterface.cpp b/Source/Core/Core/HW/VideoInterface.cpp index d4a4ff7079..d3ec094a35 100644 --- a/Source/Core/Core/HW/VideoInterface.cpp +++ b/Source/Core/Core/HW/VideoInterface.cpp @@ -885,8 +885,9 @@ void VideoInterfaceManager::Update(u64 ticks) { Core::UpdateInputGate(!Config::Get(Config::MAIN_INPUT_BACKGROUND_INPUT), Config::Get(Config::MAIN_LOCK_CURSOR)); - SerialInterface::UpdateDevices(); - m_half_line_of_next_si_poll += 2 * SerialInterface::GetPollXLines(); + auto& si = m_system.GetSerialInterface(); + si.UpdateDevices(); + m_half_line_of_next_si_poll += 2 * si.GetPollXLines(); } // If this half-line is at the actual boundary of either field, schedule an SI poll to happen diff --git a/Source/Core/Core/Movie.cpp b/Source/Core/Core/Movie.cpp index e4f7a61bca..3218959978 100644 --- a/Source/Core/Core/Movie.cpp +++ b/Source/Core/Core/Movie.cpp @@ -169,9 +169,10 @@ std::string GetInputDisplay() s_wiimotes = {}; for (int i = 0; i < 4; ++i) { - if (SerialInterface::GetDeviceType(i) == SerialInterface::SIDEVICE_GC_GBA_EMULATED) + auto& si = Core::System::GetInstance().GetSerialInterface(); + if (si.GetDeviceType(i) == SerialInterface::SIDEVICE_GC_GBA_EMULATED) s_controllers[i] = ControllerType::GBA; - else if (SerialInterface::GetDeviceType(i) != SerialInterface::SIDEVICE_NONE) + else if (si.GetDeviceType(i) != SerialInterface::SIDEVICE_NONE) s_controllers[i] = ControllerType::GC; else s_controllers[i] = ControllerType::None; @@ -484,6 +485,7 @@ void ChangePads() if (s_controllers == controllers) return; + auto& si = Core::System::GetInstance().GetSerialInterface(); for (int i = 0; i < SerialInterface::MAX_SI_CHANNELS; ++i) { SerialInterface::SIDevices device = SerialInterface::SIDEVICE_NONE; @@ -505,7 +507,7 @@ void ChangePads() } } - SerialInterface::ChangeDevice(device, i); + si.ChangeDevice(device, i); } } diff --git a/Source/Core/Core/NetPlayClient.cpp b/Source/Core/Core/NetPlayClient.cpp index 265dcd2402..9aa49255c3 100644 --- a/Source/Core/Core/NetPlayClient.cpp +++ b/Source/Core/Core/NetPlayClient.cpp @@ -67,6 +67,7 @@ #include "Core/NetPlayCommon.h" #include "Core/PowerPC/PowerPC.h" #include "Core/SyncIdentifier.h" +#include "Core/System.h" #include "DiscIO/Blob.h" #include "InputCommon/ControllerEmu/ControlGroup/Attachments.h" @@ -1833,11 +1834,12 @@ void NetPlayClient::UpdateDevices() u8 local_pad = 0; u8 pad = 0; + auto& si = Core::System::GetInstance().GetSerialInterface(); for (auto player_id : m_pad_map) { if (m_gba_config[pad].enabled && player_id > 0) { - SerialInterface::ChangeDevice(SerialInterface::SIDEVICE_GC_GBA_EMULATED, pad); + si.ChangeDevice(SerialInterface::SIDEVICE_GC_GBA_EMULATED, pad); } else if (player_id == m_local_player->pid) { @@ -1846,7 +1848,7 @@ void NetPlayClient::UpdateDevices() Config::Get(Config::GetInfoForSIDevice(local_pad)); if (SerialInterface::SIDevice_IsGCController(si_device)) { - SerialInterface::ChangeDevice(si_device, pad); + si.ChangeDevice(si_device, pad); if (si_device == SerialInterface::SIDEVICE_WIIU_ADAPTER) { @@ -1855,17 +1857,17 @@ void NetPlayClient::UpdateDevices() } else { - SerialInterface::ChangeDevice(SerialInterface::SIDEVICE_GC_CONTROLLER, pad); + si.ChangeDevice(SerialInterface::SIDEVICE_GC_CONTROLLER, pad); } local_pad++; } else if (player_id > 0) { - SerialInterface::ChangeDevice(SerialInterface::SIDEVICE_GC_CONTROLLER, pad); + si.ChangeDevice(SerialInterface::SIDEVICE_GC_CONTROLLER, pad); } else { - SerialInterface::ChangeDevice(SerialInterface::SIDEVICE_NONE, pad); + si.ChangeDevice(SerialInterface::SIDEVICE_NONE, pad); } pad++; } diff --git a/Source/Core/Core/System.cpp b/Source/Core/Core/System.cpp index 35ce686d3a..047c73793d 100644 --- a/Source/Core/Core/System.cpp +++ b/Source/Core/Core/System.cpp @@ -38,7 +38,7 @@ struct System::Impl explicit Impl(System& system) : m_audio_interface(system), m_core_timing(system), m_dsp(system), m_dvd_interface(system), m_dvd_thread(system), m_expansion_interface(system), m_gp_fifo(system), - m_ppc_state(PowerPC::ppcState), m_video_interface(system) + m_ppc_state(PowerPC::ppcState), m_serial_interface(system), m_video_interface(system) { } @@ -65,7 +65,7 @@ struct System::Impl PixelShaderManager m_pixel_shader_manager; PowerPC::PowerPCState& m_ppc_state; ProcessorInterface::ProcessorInterfaceManager m_processor_interface; - SerialInterface::SerialInterfaceState m_serial_interface_state; + SerialInterface::SerialInterfaceManager m_serial_interface; Sram m_sram; VertexShaderManager m_vertex_shader_manager; VideoInterface::VideoInterfaceManager m_video_interface; @@ -209,9 +209,9 @@ ProcessorInterface::ProcessorInterfaceManager& System::GetProcessorInterface() c return m_impl->m_processor_interface; } -SerialInterface::SerialInterfaceState& System::GetSerialInterfaceState() const +SerialInterface::SerialInterfaceManager& System::GetSerialInterface() const { - return m_impl->m_serial_interface_state; + return m_impl->m_serial_interface; } Sram& System::GetSRAM() const diff --git a/Source/Core/Core/System.h b/Source/Core/Core/System.h index f9162ad378..d49819a1aa 100644 --- a/Source/Core/Core/System.h +++ b/Source/Core/Core/System.h @@ -78,7 +78,7 @@ class ProcessorInterfaceManager; } namespace SerialInterface { -class SerialInterfaceState; +class SerialInterfaceManager; }; namespace VideoInterface { @@ -138,7 +138,7 @@ public: PixelShaderManager& GetPixelShaderManager() const; PowerPC::PowerPCState& GetPPCState() const; ProcessorInterface::ProcessorInterfaceManager& GetProcessorInterface() const; - SerialInterface::SerialInterfaceState& GetSerialInterfaceState() const; + SerialInterface::SerialInterfaceManager& GetSerialInterface() const; Sram& GetSRAM() const; VertexShaderManager& GetVertexShaderManager() const; VideoInterface::VideoInterfaceManager& GetVideoInterface() const; diff --git a/Source/Core/DolphinQt/Config/GamecubeControllersWidget.cpp b/Source/Core/DolphinQt/Config/GamecubeControllersWidget.cpp index 5425ed8af0..c27ab2e99f 100644 --- a/Source/Core/DolphinQt/Config/GamecubeControllersWidget.cpp +++ b/Source/Core/DolphinQt/Config/GamecubeControllersWidget.cpp @@ -19,6 +19,7 @@ #include "Core/HW/SI/SI.h" #include "Core/HW/SI/SI_Device.h" #include "Core/NetPlayProto.h" +#include "Core/System.h" #include "DolphinQt/Config/Mapping/GCPadWiiUConfigDialog.h" #include "DolphinQt/Config/Mapping/MappingWindow.h" @@ -192,7 +193,10 @@ void GamecubeControllersWidget::SaveSettings() Config::SetBaseOrCurrent(Config::GetInfoForSIDevice(static_cast(i)), si_device); if (Core::IsRunning()) - SerialInterface::ChangeDevice(si_device, static_cast(i)); + { + Core::System::GetInstance().GetSerialInterface().ChangeDevice(si_device, + static_cast(i)); + } } if (GCAdapter::UseAdapter())