diff --git a/src/core/bus.cpp b/src/core/bus.cpp index 0a41c2405..52a9a1079 100644 --- a/src/core/bus.cpp +++ b/src/core/bus.cpp @@ -17,6 +17,7 @@ #include "interrupt_controller.h" #include "mdec.h" #include "pad.h" +#include "settings.h" #include "sio.h" #include "spu.h" #include "timers.h" @@ -1109,13 +1110,13 @@ ALWAYS_INLINE static TickCount DoPadAccess(u32 offset, u32& value) { if constexpr (type == MemoryAccessType::Read) { - value = g_pad.ReadRegister(FIXUP_HALFWORD_OFFSET(size, offset)); + value = Pad::ReadRegister(FIXUP_HALFWORD_OFFSET(size, offset)); value = FIXUP_HALFWORD_READ_VALUE(size, offset, value); return 2; } else { - g_pad.WriteRegister(FIXUP_HALFWORD_OFFSET(size, offset), FIXUP_HALFWORD_WRITE_VALUE(size, offset, value)); + Pad::WriteRegister(FIXUP_HALFWORD_OFFSET(size, offset), FIXUP_HALFWORD_WRITE_VALUE(size, offset, value)); return 0; } } @@ -1317,7 +1318,7 @@ ALWAYS_INLINE static TickCount DoAccessSPU(u32 offset, u32& value) case MemoryAccessSize::Byte: { SPU::WriteRegister(FIXUP_HALFWORD_OFFSET(size, offset), - Truncate16(FIXUP_HALFWORD_READ_VALUE(size, offset, value))); + Truncate16(FIXUP_HALFWORD_READ_VALUE(size, offset, value))); break; } } diff --git a/src/core/dma.cpp b/src/core/dma.cpp index 72715d10f..75975b827 100644 --- a/src/core/dma.cpp +++ b/src/core/dma.cpp @@ -447,19 +447,19 @@ enum : u32 TickCount DMA::GetTransferSliceTicks() { #ifdef _DEBUG - if (g_pad.IsTransmitting()) + if (Pad::IsTransmitting()) { Log_DebugPrintf("DMA transfer while transmitting pad - using lower slice size of %u vs %u", SLICE_SIZE_WHEN_TRANSMITTING_PAD, s_max_slice_ticks); } #endif - return g_pad.IsTransmitting() ? SLICE_SIZE_WHEN_TRANSMITTING_PAD : s_max_slice_ticks; + return Pad::IsTransmitting() ? SLICE_SIZE_WHEN_TRANSMITTING_PAD : s_max_slice_ticks; } TickCount DMA::GetTransferHaltTicks() { - return g_pad.IsTransmitting() ? HALT_TICKS_WHEN_TRANSMITTING_PAD : s_halt_ticks; + return Pad::IsTransmitting() ? HALT_TICKS_WHEN_TRANSMITTING_PAD : s_halt_ticks; } bool DMA::TransferChannel(Channel channel) diff --git a/src/core/multitap.cpp b/src/core/multitap.cpp index f83355aa0..590933979 100644 --- a/src/core/multitap.cpp +++ b/src/core/multitap.cpp @@ -62,7 +62,7 @@ void Multitap::ResetTransferState() bool Multitap::TransferController(u32 slot, const u8 data_in, u8* data_out) const { - Controller* const selected_controller = g_pad.GetController(m_base_index + slot); + Controller* const selected_controller = Pad::GetController(m_base_index + slot); if (!selected_controller) { *data_out = 0xFF; @@ -74,7 +74,7 @@ bool Multitap::TransferController(u32 slot, const u8 data_in, u8* data_out) cons bool Multitap::TransferMemoryCard(u32 slot, const u8 data_in, u8* data_out) const { - MemoryCard* const selected_memcard = g_pad.GetMemoryCard(m_base_index + slot); + MemoryCard* const selected_memcard = Pad::GetMemoryCard(m_base_index + slot); if (!selected_memcard) { *data_out = 0xFF; diff --git a/src/core/pad.cpp b/src/core/pad.cpp index f50e3f393..57557f6e4 100644 --- a/src/core/pad.cpp +++ b/src/core/pad.cpp @@ -2,6 +2,8 @@ // SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0) #include "pad.h" +#include "common/bitfield.h" +#include "common/fifo_queue.h" #include "common/log.h" #include "controller.h" #include "host.h" @@ -9,32 +11,129 @@ #include "memory_card.h" #include "multitap.h" #include "system.h" +#include "types.h" #include "util/state_wrapper.h" +#include +#include Log_SetChannel(Pad); -Pad g_pad; +namespace Pad { -Pad::Pad() = default; +enum class State : u32 +{ + Idle, + Transmitting, + WaitingForACK +}; -Pad::~Pad() = default; +enum class ActiveDevice : u8 +{ + None, + Controller, + MemoryCard, + Multitap +}; + +union JOY_CTRL +{ + u16 bits; + + BitField TXEN; + BitField SELECT; + BitField RXEN; + BitField ACK; + BitField RESET; + BitField RXIMODE; + BitField TXINTEN; + BitField RXINTEN; + BitField ACKINTEN; + BitField SLOT; +}; + +union JOY_STAT +{ + u32 bits; + + BitField TXRDY; + BitField RXFIFONEMPTY; + BitField TXDONE; + BitField ACKINPUT; + BitField INTR; + BitField TMR; +}; + +union JOY_MODE +{ + u16 bits; + + BitField reload_factor; + BitField character_length; + BitField parity_enable; + BitField parity_type; + BitField clk_polarity; +}; + +static bool CanTransfer(); + +static TickCount GetTransferTicks(); + +// From @JaCzekanski +// ACK lasts ~96 ticks or approximately 2.84us at master clock (not implemented). +// ACK delay is between 6.8us-13.7us, or ~338 ticks at master clock for approximately 9.98us. +// Memory card responds faster, approximately 5us or ~170 ticks. +static constexpr TickCount GetACKTicks(bool memory_card) +{ + return memory_card ? 170 : 450; +} + +static void SoftReset(); +static void UpdateJoyStat(); +static void TransferEvent(void*, TickCount ticks, TickCount ticks_late); +static void BeginTransfer(); +static void DoTransfer(TickCount ticks_late); +static void DoACK(); +static void EndTransfer(); +static void ResetDeviceTransferState(); + +static bool DoStateController(StateWrapper& sw, u32 i); +static bool DoStateMemcard(StateWrapper& sw, u32 i); + +static std::array, NUM_CONTROLLER_AND_CARD_PORTS> s_controllers; +static std::array, NUM_CONTROLLER_AND_CARD_PORTS> s_memory_cards; + +static std::array s_multitaps; + +static std::unique_ptr s_transfer_event; +static State s_state = State::Idle; + +static JOY_CTRL s_JOY_CTRL = {}; +static JOY_STAT s_JOY_STAT = {}; +static JOY_MODE s_JOY_MODE = {}; +static u16 s_JOY_BAUD = 0; + +static ActiveDevice s_active_device = ActiveDevice::None; +static u8 s_receive_buffer = 0; +static u8 s_transmit_buffer = 0; +static u8 s_transmit_value = 0; +static bool s_receive_buffer_full = false; +static bool s_transmit_buffer_full = false; + +} // namespace Pad void Pad::Initialize() { - m_transfer_event = TimingEvents::CreateTimingEvent( - "Pad Serial Transfer", 1, 1, - [](void* param, TickCount ticks, TickCount ticks_late) { static_cast(param)->TransferEvent(ticks_late); }, - this, false); + s_transfer_event = TimingEvents::CreateTimingEvent("Pad Serial Transfer", 1, 1, &Pad::TransferEvent, nullptr, false); Reset(); } void Pad::Shutdown() { - m_transfer_event.reset(); + s_transfer_event.reset(); for (u32 i = 0; i < NUM_CONTROLLER_AND_CARD_PORTS; i++) { - m_controllers[i].reset(); - m_memory_cards[i].reset(); + s_controllers[i].reset(); + s_memory_cards[i].reset(); } } @@ -44,20 +143,20 @@ void Pad::Reset() for (u32 i = 0; i < NUM_CONTROLLER_AND_CARD_PORTS; i++) { - if (m_controllers[i]) - m_controllers[i]->Reset(); + if (s_controllers[i]) + s_controllers[i]->Reset(); - if (m_memory_cards[i]) - m_memory_cards[i]->Reset(); + if (s_memory_cards[i]) + s_memory_cards[i]->Reset(); } for (u32 i = 0; i < NUM_MULTITAPS; i++) - m_multitaps[i].Reset(); + s_multitaps[i].Reset(); } bool Pad::DoStateController(StateWrapper& sw, u32 i) { - ControllerType controller_type = m_controllers[i] ? m_controllers[i]->GetType() : ControllerType::None; + ControllerType controller_type = s_controllers[i] ? s_controllers[i]->GetType() : ControllerType::None; ControllerType state_controller_type = controller_type; sw.Do(&state_controller_type); @@ -91,9 +190,9 @@ bool Pad::DoStateController(StateWrapper& sw, u32 i) if (g_settings.load_devices_from_save_states) { - m_controllers[i].reset(); + s_controllers[i].reset(); if (state_controller_type != ControllerType::None) - m_controllers[i] = Controller::Create(state_controller_type, i); + s_controllers[i] = Controller::Create(state_controller_type, i); } else { @@ -103,8 +202,8 @@ bool Pad::DoStateController(StateWrapper& sw, u32 i) // timeout and the controller will just correct itself on the next frame's read attempt -- after all on // physical HW removing a controller is allowed and could happen in the middle of SIO comms) - if (m_controllers[i]) - m_controllers[i]->Reset(); + if (s_controllers[i]) + s_controllers[i]->Reset(); } } @@ -116,7 +215,7 @@ bool Pad::DoStateController(StateWrapper& sw, u32 i) if (!sw.DoMarker("Controller")) return false; - if (auto& controller = m_controllers[i]; controller && controller->GetType() == state_controller_type) + if (auto& controller = s_controllers[i]; controller && controller->GetType() == state_controller_type) return controller->DoState(sw, g_settings.load_devices_from_save_states); else if (auto dummy = Controller::Create(state_controller_type, i); dummy) return dummy->DoState(sw, g_settings.load_devices_from_save_states); @@ -126,21 +225,21 @@ bool Pad::DoStateController(StateWrapper& sw, u32 i) bool Pad::DoStateMemcard(StateWrapper& sw, u32 i) { - bool card_present_in_state = static_cast(m_memory_cards[i]); + bool card_present_in_state = static_cast(s_memory_cards[i]); sw.Do(&card_present_in_state); - if (card_present_in_state && !m_memory_cards[i] && g_settings.load_devices_from_save_states) + if (card_present_in_state && !s_memory_cards[i] && g_settings.load_devices_from_save_states) { Host::AddFormattedOSDMessage( 20.0f, Host::TranslateString("OSDMessage", "Memory card %u present in save state but not in system. Creating temporary card."), i + 1u); - m_memory_cards[i] = MemoryCard::Create(); + s_memory_cards[i] = MemoryCard::Create(); } - MemoryCard* card_ptr = m_memory_cards[i].get(); + MemoryCard* card_ptr = s_memory_cards[i].get(); std::unique_ptr card_from_state; if (card_present_in_state) @@ -164,12 +263,12 @@ bool Pad::DoStateMemcard(StateWrapper& sw, u32 i) if (card_from_state) { - if (m_memory_cards[i]) + if (s_memory_cards[i]) { - if (m_memory_cards[i]->GetData() == card_from_state->GetData()) + if (s_memory_cards[i]->GetData() == card_from_state->GetData()) { - card_from_state->SetFilename(m_memory_cards[i]->GetFilename()); - m_memory_cards[i] = std::move(card_from_state); + card_from_state->SetFilename(s_memory_cards[i]->GetFilename()); + s_memory_cards[i] = std::move(card_from_state); } else { @@ -186,7 +285,7 @@ bool Pad::DoStateMemcard(StateWrapper& sw, u32 i) // described as deferred re-plugging in the log. Log_WarningPrintf("Memory card %u data mismatch. Using current data via instant-replugging.", i + 1u); - m_memory_cards[i]->Reset(); + s_memory_cards[i]->Reset(); } } else @@ -200,7 +299,7 @@ bool Pad::DoStateMemcard(StateWrapper& sw, u32 i) return true; } - if (!card_present_in_state && m_memory_cards[i]) + if (!card_present_in_state && s_memory_cards[i]) { if (g_settings.load_devices_from_save_states) { @@ -208,7 +307,7 @@ bool Pad::DoStateMemcard(StateWrapper& sw, u32 i) 20.0f, Host::TranslateString("OSDMessage", "Memory card %u present in system but not in save state. Removing card."), i + 1u); - m_memory_cards[i].reset(); + s_memory_cards[i].reset(); } else { @@ -216,7 +315,7 @@ bool Pad::DoStateMemcard(StateWrapper& sw, u32 i) 20.0f, Host::TranslateString("OSDMessage", "Memory card %u present in system but not in save state. Replugging card."), i + 1u); - m_memory_cards[i]->Reset(); + s_memory_cards[i]->Reset(); } } @@ -231,20 +330,20 @@ bool Pad::DoState(StateWrapper& sw) { // loading from old savestate which only had max 2 controllers. // honoring load_devices_from_save_states in this case seems debatable, but might as well... - if (m_controllers[i]) + if (s_controllers[i]) { if (g_settings.load_devices_from_save_states) - m_controllers[i].reset(); + s_controllers[i].reset(); else - m_controllers[i]->Reset(); + s_controllers[i]->Reset(); } - if (m_memory_cards[i]) + if (s_memory_cards[i]) { if (g_settings.load_devices_from_save_states) - m_memory_cards[i].reset(); + s_memory_cards[i].reset(); else - m_memory_cards[i]->Reset(); + s_memory_cards[i]->Reset(); } // ... and make sure to skip trying to read controller_type / card_present flags which don't exist in old states. @@ -262,45 +361,60 @@ bool Pad::DoState(StateWrapper& sw) { for (u32 i = 0; i < NUM_MULTITAPS; i++) { - if (!m_multitaps[i].DoState(sw)) + if (!s_multitaps[i].DoState(sw)) return false; } } - sw.Do(&m_state); - sw.Do(&m_JOY_CTRL.bits); - sw.Do(&m_JOY_STAT.bits); - sw.Do(&m_JOY_MODE.bits); - sw.Do(&m_JOY_BAUD); - sw.Do(&m_receive_buffer); - sw.Do(&m_transmit_buffer); - sw.Do(&m_receive_buffer_full); - sw.Do(&m_transmit_buffer_full); + sw.Do(&s_state); + sw.Do(&s_JOY_CTRL.bits); + sw.Do(&s_JOY_STAT.bits); + sw.Do(&s_JOY_MODE.bits); + sw.Do(&s_JOY_BAUD); + sw.Do(&s_receive_buffer); + sw.Do(&s_transmit_buffer); + sw.Do(&s_receive_buffer_full); + sw.Do(&s_transmit_buffer_full); if (sw.IsReading() && IsTransmitting()) - m_transfer_event->Activate(); + s_transfer_event->Activate(); return !sw.HasError(); } +Controller* Pad::GetController(u32 slot) +{ + return s_controllers[slot].get(); +} + void Pad::SetController(u32 slot, std::unique_ptr dev) { - m_controllers[slot] = std::move(dev); + s_controllers[slot] = std::move(dev); +} + +MemoryCard* Pad::GetMemoryCard(u32 slot) +{ + return s_memory_cards[slot].get(); } void Pad::SetMemoryCard(u32 slot, std::unique_ptr dev) { - m_memory_cards[slot] = std::move(dev); + s_memory_cards[slot] = std::move(dev); } std::unique_ptr Pad::RemoveMemoryCard(u32 slot) { - std::unique_ptr ret = std::move(m_memory_cards[slot]); + std::unique_ptr ret = std::move(s_memory_cards[slot]); if (ret) ret->Reset(); return ret; } +Multitap* Pad::GetMultitap(u32 slot) +{ + return &s_multitaps[slot]; +} + u32 Pad::ReadRegister(u32 offset) { switch (offset) @@ -308,11 +422,11 @@ u32 Pad::ReadRegister(u32 offset) case 0x00: // JOY_DATA { if (IsTransmitting()) - m_transfer_event->InvokeEarly(); + s_transfer_event->InvokeEarly(); - const u8 value = m_receive_buffer_full ? m_receive_buffer : 0xFF; - Log_DebugPrintf("JOY_DATA (R) -> 0x%02X%s", ZeroExtend32(value), m_receive_buffer_full ? "" : "(EMPTY)"); - m_receive_buffer_full = false; + const u8 value = s_receive_buffer_full ? s_receive_buffer : 0xFF; + Log_DebugPrintf("JOY_DATA (R) -> 0x%02X%s", ZeroExtend32(value), s_receive_buffer_full ? "" : "(EMPTY)"); + s_receive_buffer_full = false; UpdateJoyStat(); return (ZeroExtend32(value) | (ZeroExtend32(value) << 8) | (ZeroExtend32(value) << 16) | @@ -322,21 +436,21 @@ u32 Pad::ReadRegister(u32 offset) case 0x04: // JOY_STAT { if (IsTransmitting()) - m_transfer_event->InvokeEarly(); + s_transfer_event->InvokeEarly(); - const u32 bits = m_JOY_STAT.bits; - m_JOY_STAT.ACKINPUT = false; + const u32 bits = s_JOY_STAT.bits; + s_JOY_STAT.ACKINPUT = false; return bits; } case 0x08: // JOY_MODE - return ZeroExtend32(m_JOY_MODE.bits); + return ZeroExtend32(s_JOY_MODE.bits); case 0x0A: // JOY_CTRL - return ZeroExtend32(m_JOY_CTRL.bits); + return ZeroExtend32(s_JOY_CTRL.bits); case 0x0E: // JOY_BAUD - return ZeroExtend32(m_JOY_BAUD); + return ZeroExtend32(s_JOY_BAUD); default: Log_ErrorPrintf("Unknown register read: 0x%X", offset); @@ -352,11 +466,11 @@ void Pad::WriteRegister(u32 offset, u32 value) { Log_DebugPrintf("JOY_DATA (W) <- 0x%02X", value); - if (m_transmit_buffer_full) + if (s_transmit_buffer_full) Log_WarningPrint("TX FIFO overrun"); - m_transmit_buffer = Truncate8(value); - m_transmit_buffer_full = true; + s_transmit_buffer = Truncate8(value); + s_transmit_buffer_full = true; if (!IsTransmitting() && CanTransfer()) BeginTransfer(); @@ -368,20 +482,20 @@ void Pad::WriteRegister(u32 offset, u32 value) { Log_DebugPrintf("JOY_CTRL <- 0x%04X", value); - m_JOY_CTRL.bits = Truncate16(value); - if (m_JOY_CTRL.RESET) + s_JOY_CTRL.bits = Truncate16(value); + if (s_JOY_CTRL.RESET) SoftReset(); - if (m_JOY_CTRL.ACK) + if (s_JOY_CTRL.ACK) { // reset stat bits - m_JOY_STAT.INTR = false; + s_JOY_STAT.INTR = false; } - if (!m_JOY_CTRL.SELECT) + if (!s_JOY_CTRL.SELECT) ResetDeviceTransferState(); - if (!m_JOY_CTRL.SELECT || !m_JOY_CTRL.TXEN) + if (!s_JOY_CTRL.SELECT || !s_JOY_CTRL.TXEN) { if (IsTransmitting()) EndTransfer(); @@ -399,14 +513,14 @@ void Pad::WriteRegister(u32 offset, u32 value) case 0x08: // JOY_MODE { Log_DebugPrintf("JOY_MODE <- 0x%08X", value); - m_JOY_MODE.bits = Truncate16(value); + s_JOY_MODE.bits = Truncate16(value); return; } case 0x0E: { Log_DebugPrintf("JOY_BAUD <- 0x%08X", value); - m_JOY_BAUD = Truncate16(value); + s_JOY_BAUD = Truncate16(value); return; } @@ -416,32 +530,47 @@ void Pad::WriteRegister(u32 offset, u32 value) } } +bool Pad::IsTransmitting() +{ + return s_state != State::Idle; +} + +bool Pad::CanTransfer() +{ + return s_transmit_buffer_full && s_JOY_CTRL.SELECT && s_JOY_CTRL.TXEN; +} + +TickCount Pad::GetTransferTicks() +{ + return static_cast(ZeroExtend32(s_JOY_BAUD) * 8); +} + void Pad::SoftReset() { if (IsTransmitting()) EndTransfer(); - m_JOY_CTRL.bits = 0; - m_JOY_STAT.bits = 0; - m_JOY_MODE.bits = 0; - m_receive_buffer = 0; - m_receive_buffer_full = false; - m_transmit_buffer = 0; - m_transmit_buffer_full = false; + s_JOY_CTRL.bits = 0; + s_JOY_STAT.bits = 0; + s_JOY_MODE.bits = 0; + s_receive_buffer = 0; + s_receive_buffer_full = false; + s_transmit_buffer = 0; + s_transmit_buffer_full = false; ResetDeviceTransferState(); UpdateJoyStat(); } void Pad::UpdateJoyStat() { - m_JOY_STAT.RXFIFONEMPTY = m_receive_buffer_full; - m_JOY_STAT.TXDONE = !m_transmit_buffer_full && m_state != State::Transmitting; - m_JOY_STAT.TXRDY = !m_transmit_buffer_full; + s_JOY_STAT.RXFIFONEMPTY = s_receive_buffer_full; + s_JOY_STAT.TXDONE = !s_transmit_buffer_full && s_state != State::Transmitting; + s_JOY_STAT.TXRDY = !s_transmit_buffer_full; } -void Pad::TransferEvent(TickCount ticks_late) +void Pad::TransferEvent(void*, TickCount ticks, TickCount ticks_late) { - if (m_state == State::Transmitting) + if (s_state == State::Transmitting) DoTransfer(ticks_late); else DoACK(); @@ -449,12 +578,12 @@ void Pad::TransferEvent(TickCount ticks_late) void Pad::BeginTransfer() { - DebugAssert(m_state == State::Idle && CanTransfer()); + DebugAssert(s_state == State::Idle && CanTransfer()); Log_DebugPrintf("Starting transfer"); - m_JOY_CTRL.RXEN = true; - m_transmit_value = m_transmit_buffer; - m_transmit_buffer_full = false; + s_JOY_CTRL.RXEN = true; + s_transmit_value = s_transmit_buffer; + s_transmit_buffer_full = false; // The transfer or the interrupt must be delayed, otherwise the BIOS thinks there's no device detected. // It seems to do something resembling the following: @@ -471,37 +600,37 @@ void Pad::BeginTransfer() // test in (7) will fail, and it won't send any more data. So, the transfer/interrupt must be delayed // until after (4) and (5) have been completed. - m_state = State::Transmitting; - m_transfer_event->SetPeriodAndSchedule(GetTransferTicks()); + s_state = State::Transmitting; + s_transfer_event->SetPeriodAndSchedule(GetTransferTicks()); } void Pad::DoTransfer(TickCount ticks_late) { - Log_DebugPrintf("Transferring slot %d", m_JOY_CTRL.SLOT.GetValue()); + Log_DebugPrintf("Transferring slot %d", s_JOY_CTRL.SLOT.GetValue()); - const u8 device_index = m_multitaps[0].IsEnabled() ? 4u : m_JOY_CTRL.SLOT; - Controller* const controller = m_controllers[device_index].get(); - MemoryCard* const memory_card = m_memory_cards[device_index].get(); + const u8 device_index = s_multitaps[0].IsEnabled() ? 4u : s_JOY_CTRL.SLOT; + Controller* const controller = s_controllers[device_index].get(); + MemoryCard* const memory_card = s_memory_cards[device_index].get(); // set rx? - m_JOY_CTRL.RXEN = true; + s_JOY_CTRL.RXEN = true; - const u8 data_out = m_transmit_value; + const u8 data_out = s_transmit_value; u8 data_in = 0xFF; bool ack = false; - switch (m_active_device) + switch (s_active_device) { case ActiveDevice::None: { - if (m_multitaps[m_JOY_CTRL.SLOT].IsEnabled()) + if (s_multitaps[s_JOY_CTRL.SLOT].IsEnabled()) { - if ((ack = m_multitaps[m_JOY_CTRL.SLOT].Transfer(data_out, &data_in)) == true) + if ((ack = s_multitaps[s_JOY_CTRL.SLOT].Transfer(data_out, &data_in)) == true) { Log_TracePrintf("Active device set to tap %d, sent 0x%02X, received 0x%02X", - static_cast(m_JOY_CTRL.SLOT), data_out, data_in); - m_active_device = ActiveDevice::Multitap; + static_cast(s_JOY_CTRL.SLOT), data_out, data_in); + s_active_device = ActiveDevice::Multitap; } } else @@ -517,14 +646,14 @@ void Pad::DoTransfer(TickCount ticks_late) { // memory card responded, make it the active device until non-ack Log_TracePrintf("Transfer to memory card, data_out=0x%02X, data_in=0x%02X", data_out, data_in); - m_active_device = ActiveDevice::MemoryCard; + s_active_device = ActiveDevice::MemoryCard; } } else { // controller responded, make it the active device until non-ack Log_TracePrintf("Transfer to controller, data_out=0x%02X, data_in=0x%02X", data_out, data_in); - m_active_device = ActiveDevice::Controller; + s_active_device = ActiveDevice::Controller; } } } @@ -552,35 +681,35 @@ void Pad::DoTransfer(TickCount ticks_late) case ActiveDevice::Multitap: { - if (m_multitaps[m_JOY_CTRL.SLOT].IsEnabled()) + if (s_multitaps[s_JOY_CTRL.SLOT].IsEnabled()) { - ack = m_multitaps[m_JOY_CTRL.SLOT].Transfer(data_out, &data_in); - Log_TracePrintf("Transfer tap %d, sent 0x%02X, received 0x%02X, acked: %s", static_cast(m_JOY_CTRL.SLOT), + ack = s_multitaps[s_JOY_CTRL.SLOT].Transfer(data_out, &data_in); + Log_TracePrintf("Transfer tap %d, sent 0x%02X, received 0x%02X, acked: %s", static_cast(s_JOY_CTRL.SLOT), data_out, data_in, ack ? "true" : "false"); } } break; } - m_receive_buffer = data_in; - m_receive_buffer_full = true; + s_receive_buffer = data_in; + s_receive_buffer_full = true; // device no longer active? if (!ack) { - m_active_device = ActiveDevice::None; + s_active_device = ActiveDevice::None; EndTransfer(); } else { const bool memcard_transfer = - m_active_device == ActiveDevice::MemoryCard || - (m_active_device == ActiveDevice::Multitap && m_multitaps[m_JOY_CTRL.SLOT].IsReadingMemoryCard()); + s_active_device == ActiveDevice::MemoryCard || + (s_active_device == ActiveDevice::Multitap && s_multitaps[s_JOY_CTRL.SLOT].IsReadingMemoryCard()); const TickCount ack_timer = GetACKTicks(memcard_transfer); Log_DebugPrintf("Delaying ACK for %d ticks", ack_timer); - m_state = State::WaitingForACK; - m_transfer_event->SetPeriodAndSchedule(ack_timer); + s_state = State::WaitingForACK; + s_transfer_event->SetPeriodAndSchedule(ack_timer); } UpdateJoyStat(); @@ -588,12 +717,12 @@ void Pad::DoTransfer(TickCount ticks_late) void Pad::DoACK() { - m_JOY_STAT.ACKINPUT = true; + s_JOY_STAT.ACKINPUT = true; - if (m_JOY_CTRL.ACKINTEN) + if (s_JOY_CTRL.ACKINTEN) { Log_DebugPrintf("Triggering ACK interrupt"); - m_JOY_STAT.INTR = true; + s_JOY_STAT.INTR = true; InterruptController::InterruptRequest(InterruptController::IRQ::IRQ7); } @@ -606,25 +735,25 @@ void Pad::DoACK() void Pad::EndTransfer() { - DebugAssert(m_state == State::Transmitting || m_state == State::WaitingForACK); + DebugAssert(s_state == State::Transmitting || s_state == State::WaitingForACK); Log_DebugPrintf("Ending transfer"); - m_state = State::Idle; - m_transfer_event->Deactivate(); + s_state = State::Idle; + s_transfer_event->Deactivate(); } void Pad::ResetDeviceTransferState() { for (u32 i = 0; i < NUM_CONTROLLER_AND_CARD_PORTS; i++) { - if (m_controllers[i]) - m_controllers[i]->ResetTransferState(); - if (m_memory_cards[i]) - m_memory_cards[i]->ResetTransferState(); + if (s_controllers[i]) + s_controllers[i]->ResetTransferState(); + if (s_memory_cards[i]) + s_memory_cards[i]->ResetTransferState(); } for (u32 i = 0; i < NUM_MULTITAPS; i++) - m_multitaps[i].ResetTransferState(); + s_multitaps[i].ResetTransferState(); - m_active_device = ActiveDevice::None; + s_active_device = ActiveDevice::None; } diff --git a/src/core/pad.h b/src/core/pad.h index 1c212ff71..f68934863 100644 --- a/src/core/pad.h +++ b/src/core/pad.h @@ -2,142 +2,36 @@ // SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0) #pragma once -#include "common/bitfield.h" -#include "common/fifo_queue.h" -#include "multitap.h" #include "types.h" -#include #include class StateWrapper; -class TimingEvent; class Controller; class MemoryCard; +class Multitap; -class Pad final -{ -public: - Pad(); - ~Pad(); +namespace Pad { - void Initialize(); - void Shutdown(); - void Reset(); - bool DoState(StateWrapper& sw); +static constexpr u32 NUM_SLOTS = 2; - Controller* GetController(u32 slot) const { return m_controllers[slot].get(); } - void SetController(u32 slot, std::unique_ptr dev); +void Initialize(); +void Shutdown(); +void Reset(); +bool DoState(StateWrapper& sw); - MemoryCard* GetMemoryCard(u32 slot) { return m_memory_cards[slot].get(); } - void SetMemoryCard(u32 slot, std::unique_ptr dev); - std::unique_ptr RemoveMemoryCard(u32 slot); +Controller* GetController(u32 slot); +void SetController(u32 slot, std::unique_ptr dev); - Multitap* GetMultitap(u32 slot) { return &m_multitaps[slot]; }; +MemoryCard* GetMemoryCard(u32 slot); +void SetMemoryCard(u32 slot, std::unique_ptr dev); +std::unique_ptr RemoveMemoryCard(u32 slot); - u32 ReadRegister(u32 offset); - void WriteRegister(u32 offset, u32 value); +Multitap* GetMultitap(u32 slot); - ALWAYS_INLINE bool IsTransmitting() const { return m_state != State::Idle; } +u32 ReadRegister(u32 offset); +void WriteRegister(u32 offset, u32 value); -private: - static constexpr u32 NUM_SLOTS = 2; +bool IsTransmitting(); - enum class State : u32 - { - Idle, - Transmitting, - WaitingForACK - }; - - enum class ActiveDevice : u8 - { - None, - Controller, - MemoryCard, - Multitap - }; - - union JOY_CTRL - { - u16 bits; - - BitField TXEN; - BitField SELECT; - BitField RXEN; - BitField ACK; - BitField RESET; - BitField RXIMODE; - BitField TXINTEN; - BitField RXINTEN; - BitField ACKINTEN; - BitField SLOT; - }; - - union JOY_STAT - { - u32 bits; - - BitField TXRDY; - BitField RXFIFONEMPTY; - BitField TXDONE; - BitField ACKINPUT; - BitField INTR; - BitField TMR; - }; - - union JOY_MODE - { - u16 bits; - - BitField reload_factor; - BitField character_length; - BitField parity_enable; - BitField parity_type; - BitField clk_polarity; - }; - - ALWAYS_INLINE bool CanTransfer() const { return m_transmit_buffer_full && m_JOY_CTRL.SELECT && m_JOY_CTRL.TXEN; } - - ALWAYS_INLINE TickCount GetTransferTicks() const { return static_cast(ZeroExtend32(m_JOY_BAUD) * 8); } - - // From @JaCzekanski - // ACK lasts ~96 ticks or approximately 2.84us at master clock (not implemented). - // ACK delay is between 6.8us-13.7us, or ~338 ticks at master clock for approximately 9.98us. - // Memory card responds faster, approximately 5us or ~170 ticks. - static constexpr TickCount GetACKTicks(bool memory_card) { return memory_card ? 170 : 450; } - - void SoftReset(); - void UpdateJoyStat(); - void TransferEvent(TickCount ticks_late); - void BeginTransfer(); - void DoTransfer(TickCount ticks_late); - void DoACK(); - void EndTransfer(); - void ResetDeviceTransferState(); - - bool DoStateController(StateWrapper& sw, u32 i); - bool DoStateMemcard(StateWrapper& sw, u32 i); - - std::array, NUM_CONTROLLER_AND_CARD_PORTS> m_controllers; - std::array, NUM_CONTROLLER_AND_CARD_PORTS> m_memory_cards; - - std::array m_multitaps; - - std::unique_ptr m_transfer_event; - State m_state = State::Idle; - - JOY_CTRL m_JOY_CTRL = {}; - JOY_STAT m_JOY_STAT = {}; - JOY_MODE m_JOY_MODE = {}; - u16 m_JOY_BAUD = 0; - - ActiveDevice m_active_device = ActiveDevice::None; - u8 m_receive_buffer = 0; - u8 m_transmit_buffer = 0; - u8 m_transmit_value = 0; - bool m_receive_buffer_full = false; - bool m_transmit_buffer_full = false; -}; - -extern Pad g_pad; +} // namespace Pad diff --git a/src/core/system.cpp b/src/core/system.cpp index ed70b9c19..632dcc650 100644 --- a/src/core/system.cpp +++ b/src/core/system.cpp @@ -1390,7 +1390,7 @@ bool System::Initialize(bool force_software_renderer) InterruptController::Initialize(); CDROM::Initialize(); - g_pad.Initialize(); + Pad::Initialize(); Timers::Initialize(); SPU::Initialize(); MDEC::Initialize(); @@ -1454,7 +1454,7 @@ void System::DestroySystem() MDEC::Shutdown(); SPU::Shutdown(); Timers::Shutdown(); - g_pad.Shutdown(); + Pad::Shutdown(); CDROM::Shutdown(); g_gpu.reset(); InterruptController::Shutdown(); @@ -1655,7 +1655,7 @@ bool System::DoState(StateWrapper& sw, GPUTexture** host_texture, bool update_di if (!sw.DoMarker("CDROM") || !CDROM::DoState(sw)) return false; - if (!sw.DoMarker("Pad") || !g_pad.DoState(sw)) + if (!sw.DoMarker("Pad") || !Pad::DoState(sw)) return false; if (!sw.DoMarker("Timers") || !Timers::DoState(sw)) @@ -1743,7 +1743,7 @@ void System::InternalReset() InterruptController::Reset(); g_gpu->Reset(true); CDROM::Reset(); - g_pad.Reset(); + Pad::Reset(); Timers::Reset(); SPU::Reset(); MDEC::Reset(); @@ -2630,7 +2630,7 @@ void System::StallCPU(TickCount ticks) Controller* System::GetController(u32 slot) { - return g_pad.GetController(slot); + return Pad::GetController(slot); } void System::UpdateControllers() @@ -2639,7 +2639,7 @@ void System::UpdateControllers() for (u32 i = 0; i < NUM_CONTROLLER_AND_CARD_PORTS; i++) { - g_pad.SetController(i, nullptr); + Pad::SetController(i, nullptr); const ControllerType type = g_settings.controller_types[i]; if (type != ControllerType::None) @@ -2648,7 +2648,7 @@ void System::UpdateControllers() if (controller) { controller->LoadSettings(*Host::GetSettingsInterfaceForBindings(), Controller::GetSettingsSection(i).c_str()); - g_pad.SetController(i, std::move(controller)); + Pad::SetController(i, std::move(controller)); } } } @@ -2660,7 +2660,7 @@ void System::UpdateControllerSettings() for (u32 i = 0; i < NUM_CONTROLLER_AND_CARD_PORTS; i++) { - Controller* controller = g_pad.GetController(i); + Controller* controller = Pad::GetController(i); if (controller) controller->LoadSettings(*Host::GetSettingsInterfaceForBindings(), Controller::GetSettingsSection(i).c_str()); } @@ -2670,7 +2670,7 @@ void System::ResetControllers() { for (u32 i = 0; i < NUM_CONTROLLER_AND_CARD_PORTS; i++) { - Controller* controller = g_pad.GetController(i); + Controller* controller = Pad::GetController(i); if (controller) controller->Reset(); } @@ -2758,12 +2758,12 @@ void System::UpdateMemoryCardTypes() { for (u32 i = 0; i < NUM_CONTROLLER_AND_CARD_PORTS; i++) { - g_pad.SetMemoryCard(i, nullptr); + Pad::SetMemoryCard(i, nullptr); const MemoryCardType type = g_settings.memory_card_types[i]; std::unique_ptr card = GetMemoryCardForSlot(i, type); if (card) - g_pad.SetMemoryCard(i, std::move(card)); + Pad::SetMemoryCard(i, std::move(card)); } } @@ -2775,17 +2775,17 @@ void System::UpdatePerGameMemoryCards() if (!Settings::IsPerGameMemoryCardType(type)) continue; - g_pad.SetMemoryCard(i, nullptr); + Pad::SetMemoryCard(i, nullptr); std::unique_ptr card = GetMemoryCardForSlot(i, type); if (card) - g_pad.SetMemoryCard(i, std::move(card)); + Pad::SetMemoryCard(i, std::move(card)); } } bool System::HasMemoryCard(u32 slot) { - return (g_pad.GetMemoryCard(slot) != nullptr); + return (Pad::GetMemoryCard(slot) != nullptr); } void System::SwapMemoryCards() @@ -2793,10 +2793,10 @@ void System::SwapMemoryCards() if (!IsValid()) return; - std::unique_ptr first = g_pad.RemoveMemoryCard(0); - std::unique_ptr second = g_pad.RemoveMemoryCard(1); - g_pad.SetMemoryCard(0, std::move(second)); - g_pad.SetMemoryCard(1, std::move(first)); + std::unique_ptr first = Pad::RemoveMemoryCard(0); + std::unique_ptr second = Pad::RemoveMemoryCard(1); + Pad::SetMemoryCard(0, std::move(second)); + Pad::SetMemoryCard(1, std::move(first)); if (HasMemoryCard(0) && HasMemoryCard(1)) { @@ -2828,29 +2828,29 @@ void System::UpdateMultitaps() { case MultitapMode::Disabled: { - g_pad.GetMultitap(0)->SetEnable(false, 0); - g_pad.GetMultitap(1)->SetEnable(false, 0); + Pad::GetMultitap(0)->SetEnable(false, 0); + Pad::GetMultitap(1)->SetEnable(false, 0); } break; case MultitapMode::Port1Only: { - g_pad.GetMultitap(0)->SetEnable(true, 0); - g_pad.GetMultitap(1)->SetEnable(false, 0); + Pad::GetMultitap(0)->SetEnable(true, 0); + Pad::GetMultitap(1)->SetEnable(false, 0); } break; case MultitapMode::Port2Only: { - g_pad.GetMultitap(0)->SetEnable(false, 0); - g_pad.GetMultitap(1)->SetEnable(true, 1); + Pad::GetMultitap(0)->SetEnable(false, 0); + Pad::GetMultitap(1)->SetEnable(true, 1); } break; case MultitapMode::BothPorts: { - g_pad.GetMultitap(0)->SetEnable(true, 0); - g_pad.GetMultitap(1)->SetEnable(true, 4); + Pad::GetMultitap(0)->SetEnable(true, 0); + Pad::GetMultitap(1)->SetEnable(true, 4); } break; }