diff --git a/src/core/dma.cpp b/src/core/dma.cpp index 1145d5fe0..2c65599b8 100644 --- a/src/core/dma.cpp +++ b/src/core/dma.cpp @@ -9,6 +9,7 @@ #include "gpu.h" #include "interrupt_controller.h" #include "mdec.h" +#include "pad.h" #include "spu.h" #include "system.h" #ifdef WITH_IMGUI @@ -253,6 +254,34 @@ void DMA::UpdateIRQ() } } +// Plenty of games seem to suffer from this issue where they have a linked list DMA going while polling the +// controller. Using a too-large slice size will result in the serial timing being off, and the game thinking +// the controller is disconnected. So we don't hurt performance too much for the general case, we reduce this +// to equal CPU and DMA time when the controller is transferring, but otherwise leave it at the higher size. +enum : u32 +{ + SLICE_SIZE_WHEN_TRANSMITTING_PAD = 100, + HALT_TICKS_WHEN_TRANSMITTING_PAD = 100 +}; + +TickCount DMA::GetTransferSliceTicks() const +{ +#ifdef _DEBUG + if (g_pad.IsTransmitting()) + { + Log_DebugPrintf("DMA transfer while transmitting pad - using lower slice size of %u vs %u", + SLICE_SIZE_WHEN_TRANSMITTING_PAD, m_max_slice_ticks); + } +#endif + + return g_pad.IsTransmitting() ? SLICE_SIZE_WHEN_TRANSMITTING_PAD : m_max_slice_ticks; +} + +TickCount DMA::GetTransferHaltTicks() const +{ + return g_pad.IsTransmitting() ? HALT_TICKS_WHEN_TRANSMITTING_PAD : m_halt_ticks; +} + bool DMA::TransferChannel(Channel channel) { ChannelState& cs = m_state[static_cast(channel)]; @@ -294,7 +323,7 @@ bool DMA::TransferChannel(Channel channel) current_address & ADDRESS_MASK); u8* ram_pointer = Bus::g_ram; - TickCount remaining_ticks = m_max_slice_ticks; + TickCount remaining_ticks = GetTransferSliceTicks(); while (cs.request && remaining_ticks > 0) { u32 header; @@ -330,7 +359,7 @@ bool DMA::TransferChannel(Channel channel) if (cs.request) { // stall the transfer for a bit if we ran for too long - HaltTransfer(m_halt_ticks); + HaltTransfer(GetTransferHaltTicks()); return false; } else @@ -350,7 +379,7 @@ bool DMA::TransferChannel(Channel channel) const u32 block_size = cs.block_control.request.GetBlockSize(); u32 blocks_remaining = cs.block_control.request.GetBlockCount(); - TickCount ticks_remaining = m_max_slice_ticks; + TickCount ticks_remaining = GetTransferSliceTicks(); if (copy_to_device) { @@ -391,7 +420,7 @@ bool DMA::TransferChannel(Channel channel) { // we got halted if (!m_unhalt_event->IsActive()) - HaltTransfer(m_halt_ticks); + HaltTransfer(GetTransferHaltTicks()); return false; } diff --git a/src/core/dma.h b/src/core/dma.h index b4f76a774..04f56f3f6 100644 --- a/src/core/dma.h +++ b/src/core/dma.h @@ -50,7 +50,6 @@ public: private: static constexpr PhysicalMemoryAddress BASE_ADDRESS_MASK = UINT32_C(0x00FFFFFF); static constexpr PhysicalMemoryAddress ADDRESS_MASK = UINT32_C(0x001FFFFC); - static constexpr u32 TRANSFER_TICKS = 10; enum class SyncMode : u32 { @@ -68,6 +67,8 @@ private: void UpdateIRQ(); // returns false if the DMA should now be halted + TickCount GetTransferSliceTicks() const; + TickCount GetTransferHaltTicks() const; bool TransferChannel(Channel channel); void HaltTransfer(TickCount duration); void UnhaltTransfer(TickCount ticks); diff --git a/src/core/pad.h b/src/core/pad.h index 1d16ce884..f8debd2c1 100644 --- a/src/core/pad.h +++ b/src/core/pad.h @@ -31,6 +31,8 @@ public: u32 ReadRegister(u32 offset); void WriteRegister(u32 offset, u32 value); + ALWAYS_INLINE bool IsTransmitting() const { return m_state != State::Idle; } + private: static constexpr u32 NUM_SLOTS = 2; @@ -87,10 +89,9 @@ private: BitField clk_polarity; }; - bool IsTransmitting() const { return m_state != State::Idle; } - bool CanTransfer() const { return m_transmit_buffer_full && m_JOY_CTRL.SELECT && m_JOY_CTRL.TXEN; } + ALWAYS_INLINE 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); } + 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).