diff --git a/src/core/pad.cpp b/src/core/pad.cpp index 165e6d141..bdabf36fd 100644 --- a/src/core/pad.cpp +++ b/src/core/pad.cpp @@ -100,7 +100,7 @@ u32 Pad::ReadRegister(u32 offset) { case 0x00: // JOY_DATA { - if (!m_transmit_buffer_full) + if (!m_receive_buffer_full) Log_DevPrintf("Read from RX fifo when empty"); const u8 value = m_receive_buffer; @@ -209,21 +209,20 @@ void Pad::WriteRegister(u32 offset, u32 value) void Pad::Execute(TickCount ticks) { - switch (m_state) - { - case State::Idle: - break; + if (m_state == State::Idle) + return; - case State::Transmitting: - { - m_ticks_remaining -= ticks; - if (m_ticks_remaining <= 0) - DoTransfer(); - else - m_system->SetDowncount(m_ticks_remaining); - } - break; + m_ticks_remaining -= ticks; + if (m_ticks_remaining > 0) + { + m_system->SetDowncount(m_ticks_remaining); + return; } + + if (m_state == State::Transmitting) + DoTransfer(); + else + DoACK(); } void Pad::SoftReset() @@ -344,26 +343,48 @@ void Pad::DoTransfer() m_receive_buffer = data_in; m_receive_buffer_full = true; - m_JOY_STAT.ACKINPUT |= ack; // device no longer active? if (!ack) + { m_active_device = ActiveDevice::None; + EndTransfer(); + } + else + { + const TickCount ack_timer = GetACKTicks(); + Log_DebugPrintf("Delaying ACK for %d ticks", ack_timer); + m_state = State::WaitingForACK; + m_ticks_remaining += ack_timer; + if (m_ticks_remaining <= 0) + DoACK(); + else + m_system->SetDowncount(m_ticks_remaining); + } + + UpdateJoyStat(); +} + +void Pad::DoACK() +{ + m_JOY_STAT.ACKINPUT = true; - if (m_JOY_STAT.ACKINPUT && m_JOY_CTRL.ACKINTEN) + if (m_JOY_CTRL.ACKINTEN) { - Log_DebugPrintf("Triggering interrupt"); + Log_DebugPrintf("Triggering ACK interrupt"); m_JOY_STAT.INTR = true; m_interrupt_controller->InterruptRequest(InterruptController::IRQ::IRQ7); } EndTransfer(); - UpdateJoyStat(); + + if (CanTransfer()) + BeginTransfer(); } void Pad::EndTransfer() { - DebugAssert(m_state == State::Transmitting); + DebugAssert(m_state == State::Transmitting || m_state == State::WaitingForACK); Log_DebugPrintf("Ending transfer"); m_state = State::Idle; diff --git a/src/core/pad.h b/src/core/pad.h index fad1cae46..3b5dbda36 100644 --- a/src/core/pad.h +++ b/src/core/pad.h @@ -39,7 +39,8 @@ private: enum class State : u32 { Idle, - Transmitting + Transmitting, + WaitingForACK }; enum class ActiveDevice : u8 @@ -88,15 +89,17 @@ private: BitField clk_polarity; }; - bool IsTransmitting() const { return m_state == State::Transmitting; } + bool IsTransmitting() const { return m_state != State::Idle; } bool CanTransfer() const { return m_transmit_buffer_full && m_JOY_CTRL.SELECT && m_JOY_CTRL.TXEN; } TickCount GetTransferTicks() const { return static_cast(ZeroExtend32(m_JOY_BAUD) * 8); } + TickCount GetACKTicks() const { return 32; } void SoftReset(); void UpdateJoyStat(); void BeginTransfer(); void DoTransfer(); + void DoACK(); void EndTransfer(); void ResetDeviceTransferState();