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.
This commit is contained in:
Connor McLaughlin 2019-12-05 23:03:54 +10:00
parent 9fa8eb239e
commit 4798f35e40
2 changed files with 47 additions and 23 deletions

View file

@ -100,7 +100,7 @@ u32 Pad::ReadRegister(u32 offset)
{ {
case 0x00: // JOY_DATA case 0x00: // JOY_DATA
{ {
if (!m_transmit_buffer_full) if (!m_receive_buffer_full)
Log_DevPrintf("Read from RX fifo when empty"); Log_DevPrintf("Read from RX fifo when empty");
const u8 value = m_receive_buffer; const u8 value = m_receive_buffer;
@ -209,21 +209,20 @@ void Pad::WriteRegister(u32 offset, u32 value)
void Pad::Execute(TickCount ticks) void Pad::Execute(TickCount ticks)
{ {
switch (m_state) if (m_state == State::Idle)
{ return;
case State::Idle:
break;
case State::Transmitting: m_ticks_remaining -= ticks;
{ if (m_ticks_remaining > 0)
m_ticks_remaining -= ticks; {
if (m_ticks_remaining <= 0) m_system->SetDowncount(m_ticks_remaining);
DoTransfer(); return;
else
m_system->SetDowncount(m_ticks_remaining);
}
break;
} }
if (m_state == State::Transmitting)
DoTransfer();
else
DoACK();
} }
void Pad::SoftReset() void Pad::SoftReset()
@ -344,26 +343,48 @@ void Pad::DoTransfer()
m_receive_buffer = data_in; m_receive_buffer = data_in;
m_receive_buffer_full = true; m_receive_buffer_full = true;
m_JOY_STAT.ACKINPUT |= ack;
// device no longer active? // device no longer active?
if (!ack) 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_JOY_STAT.INTR = true;
m_interrupt_controller->InterruptRequest(InterruptController::IRQ::IRQ7); m_interrupt_controller->InterruptRequest(InterruptController::IRQ::IRQ7);
} }
EndTransfer(); EndTransfer();
UpdateJoyStat();
if (CanTransfer())
BeginTransfer();
} }
void Pad::EndTransfer() void Pad::EndTransfer()
{ {
DebugAssert(m_state == State::Transmitting); DebugAssert(m_state == State::Transmitting || m_state == State::WaitingForACK);
Log_DebugPrintf("Ending transfer"); Log_DebugPrintf("Ending transfer");
m_state = State::Idle; m_state = State::Idle;

View file

@ -39,7 +39,8 @@ private:
enum class State : u32 enum class State : u32
{ {
Idle, Idle,
Transmitting Transmitting,
WaitingForACK
}; };
enum class ActiveDevice : u8 enum class ActiveDevice : u8
@ -88,15 +89,17 @@ private:
BitField<u16, u8, 8, 1> clk_polarity; BitField<u16, u8, 8, 1> 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; } bool CanTransfer() const { return m_transmit_buffer_full && m_JOY_CTRL.SELECT && m_JOY_CTRL.TXEN; }
TickCount GetTransferTicks() const { return static_cast<TickCount>(ZeroExtend32(m_JOY_BAUD) * 8); } TickCount GetTransferTicks() const { return static_cast<TickCount>(ZeroExtend32(m_JOY_BAUD) * 8); }
TickCount GetACKTicks() const { return 32; }
void SoftReset(); void SoftReset();
void UpdateJoyStat(); void UpdateJoyStat();
void BeginTransfer(); void BeginTransfer();
void DoTransfer(); void DoTransfer();
void DoACK();
void EndTransfer(); void EndTransfer();
void ResetDeviceTransferState(); void ResetDeviceTransferState();