mirror of
https://github.com/RetroDECK/Duckstation.git
synced 2024-11-22 22:05:38 +00:00
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:
parent
9fa8eb239e
commit
4798f35e40
|
@ -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;
|
||||
|
|
|
@ -39,7 +39,8 @@ private:
|
|||
enum class State : u32
|
||||
{
|
||||
Idle,
|
||||
Transmitting
|
||||
Transmitting,
|
||||
WaitingForACK
|
||||
};
|
||||
|
||||
enum class ActiveDevice : u8
|
||||
|
@ -88,15 +89,17 @@ private:
|
|||
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; }
|
||||
|
||||
TickCount GetTransferTicks() const { return static_cast<TickCount>(ZeroExtend32(m_JOY_BAUD) * 8); }
|
||||
TickCount GetACKTicks() const { return 32; }
|
||||
|
||||
void SoftReset();
|
||||
void UpdateJoyStat();
|
||||
void BeginTransfer();
|
||||
void DoTransfer();
|
||||
void DoACK();
|
||||
void EndTransfer();
|
||||
void ResetDeviceTransferState();
|
||||
|
||||
|
|
Loading…
Reference in a new issue