From 4798f35e40784ec64611f68fa3517f64e6988b95 Mon Sep 17 00:00:00 2001 From: Connor McLaughlin Date: Thu, 5 Dec 2019 23:03:54 +1000 Subject: [PATCH] Pad: Delay ACK after receiving byte The controller routines in the BIOS seem to depend on this, if they happen at the same time depending on what part of the code it was in, it'll assume no controller is connected. --- src/core/pad.cpp | 63 ++++++++++++++++++++++++++++++++---------------- src/core/pad.h | 7 ++++-- 2 files changed, 47 insertions(+), 23 deletions(-) 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; - - if (m_JOY_STAT.ACKINPUT && m_JOY_CTRL.ACKINTEN) { - Log_DebugPrintf("Triggering interrupt"); + 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_CTRL.ACKINTEN) + { + 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();