From 4bb8fb211d35f1a0ba55fa1d7016f70f51ebe6b7 Mon Sep 17 00:00:00 2001 From: Connor McLaughlin Date: Tue, 24 Sep 2019 21:38:58 +1000 Subject: [PATCH] DMA: Delay transfer/interrupt --- src/pse/dma.cpp | 73 +++++++++++++++++++++++++++++++++++++++++++--- src/pse/dma.h | 14 +++++++-- src/pse/system.cpp | 3 +- 3 files changed, 83 insertions(+), 7 deletions(-) diff --git a/src/pse/dma.cpp b/src/pse/dma.cpp index 887f9b070..941d3de12 100644 --- a/src/pse/dma.cpp +++ b/src/pse/dma.cpp @@ -5,14 +5,16 @@ #include "common/state_wrapper.h" #include "gpu.h" #include "interrupt_controller.h" +#include "system.h" Log_SetChannel(DMA); DMA::DMA() = default; DMA::~DMA() = default; -bool DMA::Initialize(Bus* bus, InterruptController* interrupt_controller, GPU* gpu, CDROM* cdrom) +bool DMA::Initialize(System* system, Bus* bus, InterruptController* interrupt_controller, GPU* gpu, CDROM* cdrom) { + m_system = system; m_bus = bus; m_interrupt_controller = interrupt_controller; m_gpu = gpu; @@ -22,6 +24,8 @@ bool DMA::Initialize(Bus* bus, InterruptController* interrupt_controller, GPU* g void DMA::Reset() { + m_transfer_ticks = 0; + m_transfer_pending = false; m_state = {}; m_DPCR.bits = 0x07654321; m_DICR.bits = 0; @@ -99,7 +103,7 @@ void DMA::WriteRegister(u32 offset, u32 value) (value & ChannelState::ChannelControl::WRITE_MASK); Log_DebugPrintf("DMA channel %u channel control <- 0x%08X", channel_index, state.channel_control.bits); if (CanRunChannel(static_cast(channel_index))) - RunDMA(static_cast(channel_index)); + UpdateTransferPending(); return; } @@ -143,8 +147,39 @@ void DMA::SetRequest(Channel channel, bool request) return; cs.request = request; - if (CanRunChannel(channel)) - RunDMA(channel); + UpdateTransferPending(); +} + +void DMA::Execute(TickCount ticks) +{ + if (!m_transfer_pending) + return; + + m_transfer_ticks -= ticks; + if (m_transfer_ticks <= 0) + { + m_transfer_pending = false; + + for (u32 i = 0; i < NUM_CHANNELS; i++) + { + const Channel channel = static_cast(i); + if (CanRunChannel(channel)) + { + RunDMA(channel); + m_transfer_pending |= CanRunChannel(channel); + } + } + + if (m_transfer_pending) + { + m_transfer_ticks += TRANSFER_TICKS; + m_system->SetDowncount(m_transfer_ticks); + } + } + else + { + m_system->SetDowncount(m_transfer_ticks); + } } bool DMA::CanRunChannel(Channel channel) const @@ -159,6 +194,17 @@ bool DMA::CanRunChannel(Channel channel) const return (cs.channel_control.enable_busy && cs.request); } +bool DMA::CanRunAnyChannels() const +{ + for (u32 i = 0; i < NUM_CHANNELS; i++) + { + if (CanRunChannel(static_cast(i))) + return true; + } + + return false; +} + void DMA::RunDMA(Channel channel) { ChannelState& cs = m_state[static_cast(channel)]; @@ -353,3 +399,22 @@ void DMA::DMAWrite(Channel channel, u32 value, PhysicalMemoryAddress src_address break; } } + +void DMA::UpdateTransferPending() +{ + if (CanRunAnyChannels()) + { + if (m_transfer_pending) + return; + + m_system->Synchronize(); + m_transfer_pending = true; + m_transfer_ticks = TRANSFER_TICKS; + m_system->SetDowncount(m_transfer_ticks); + } + else + { + m_transfer_pending = false; + m_transfer_ticks = 0; + } +} diff --git a/src/pse/dma.h b/src/pse/dma.h index 6958c761b..23a35a659 100644 --- a/src/pse/dma.h +++ b/src/pse/dma.h @@ -5,6 +5,7 @@ class StateWrapper; +class System; class Bus; class InterruptController; class GPU; @@ -32,7 +33,7 @@ public: DMA(); ~DMA(); - bool Initialize(Bus* bus, InterruptController* interrupt_controller, GPU* gpu, CDROM* cdrom); + bool Initialize(System* system, Bus* bus, InterruptController* interrupt_controller, GPU* gpu, CDROM* cdrom); void Reset(); bool DoState(StateWrapper& sw); @@ -41,8 +42,11 @@ public: void SetRequest(Channel channel, bool request); + void Execute(TickCount ticks); + private: static constexpr PhysicalMemoryAddress ADDRESS_MASK = UINT32_C(0x00FFFFFF); + static constexpr u32 TRANSFER_TICKS = 10; enum class SyncMode : u32 { @@ -54,6 +58,7 @@ private: // is everything enabled for a channel to operate? bool CanRunChannel(Channel channel) const; + bool CanRunAnyChannels() const; void RunDMA(Channel channel); @@ -63,11 +68,17 @@ private: // from memory -> device void DMAWrite(Channel channel, u32 value, PhysicalMemoryAddress src_address, u32 remaining_words); + void UpdateTransferPending(); + + System* m_system = nullptr; Bus* m_bus = nullptr; InterruptController* m_interrupt_controller = nullptr; GPU* m_gpu = nullptr; CDROM* m_cdrom = nullptr; + TickCount m_transfer_ticks = 0; + bool m_transfer_pending = false; + struct ChannelState { u32 base_address; @@ -107,7 +118,6 @@ private: } channel_control; bool request = false; - bool irq = false; }; std::array m_state = {}; diff --git a/src/pse/system.cpp b/src/pse/system.cpp index 59f7f6648..a9fb11839 100644 --- a/src/pse/system.cpp +++ b/src/pse/system.cpp @@ -39,7 +39,7 @@ bool System::Initialize() return false; } - if (!m_dma->Initialize(m_bus.get(), m_interrupt_controller.get(), m_gpu.get(), m_cdrom.get())) + if (!m_dma->Initialize(this, m_bus.get(), m_interrupt_controller.get(), m_gpu.get(), m_cdrom.get())) return false; if (!m_interrupt_controller->Initialize(m_cpu.get())) @@ -246,6 +246,7 @@ void System::Synchronize() const TickCount pending_ticks = m_cpu->GetPendingTicks(); m_cpu->ResetPendingTicks(); + m_dma->Execute(pending_ticks); m_gpu->Execute(pending_ticks); m_timers->AddSystemTicks(pending_ticks); m_cdrom->Execute(pending_ticks);