DMA: Delay transfer/interrupt
This commit is contained in:
parent
4cc83e2228
commit
4bb8fb211d
|
@ -5,14 +5,16 @@
|
||||||
#include "common/state_wrapper.h"
|
#include "common/state_wrapper.h"
|
||||||
#include "gpu.h"
|
#include "gpu.h"
|
||||||
#include "interrupt_controller.h"
|
#include "interrupt_controller.h"
|
||||||
|
#include "system.h"
|
||||||
Log_SetChannel(DMA);
|
Log_SetChannel(DMA);
|
||||||
|
|
||||||
DMA::DMA() = default;
|
DMA::DMA() = default;
|
||||||
|
|
||||||
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_bus = bus;
|
||||||
m_interrupt_controller = interrupt_controller;
|
m_interrupt_controller = interrupt_controller;
|
||||||
m_gpu = gpu;
|
m_gpu = gpu;
|
||||||
|
@ -22,6 +24,8 @@ bool DMA::Initialize(Bus* bus, InterruptController* interrupt_controller, GPU* g
|
||||||
|
|
||||||
void DMA::Reset()
|
void DMA::Reset()
|
||||||
{
|
{
|
||||||
|
m_transfer_ticks = 0;
|
||||||
|
m_transfer_pending = false;
|
||||||
m_state = {};
|
m_state = {};
|
||||||
m_DPCR.bits = 0x07654321;
|
m_DPCR.bits = 0x07654321;
|
||||||
m_DICR.bits = 0;
|
m_DICR.bits = 0;
|
||||||
|
@ -99,7 +103,7 @@ void DMA::WriteRegister(u32 offset, u32 value)
|
||||||
(value & ChannelState::ChannelControl::WRITE_MASK);
|
(value & ChannelState::ChannelControl::WRITE_MASK);
|
||||||
Log_DebugPrintf("DMA channel %u channel control <- 0x%08X", channel_index, state.channel_control.bits);
|
Log_DebugPrintf("DMA channel %u channel control <- 0x%08X", channel_index, state.channel_control.bits);
|
||||||
if (CanRunChannel(static_cast<Channel>(channel_index)))
|
if (CanRunChannel(static_cast<Channel>(channel_index)))
|
||||||
RunDMA(static_cast<Channel>(channel_index));
|
UpdateTransferPending();
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -143,8 +147,39 @@ void DMA::SetRequest(Channel channel, bool request)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
cs.request = request;
|
cs.request = request;
|
||||||
if (CanRunChannel(channel))
|
UpdateTransferPending();
|
||||||
RunDMA(channel);
|
}
|
||||||
|
|
||||||
|
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<Channel>(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
|
bool DMA::CanRunChannel(Channel channel) const
|
||||||
|
@ -159,6 +194,17 @@ bool DMA::CanRunChannel(Channel channel) const
|
||||||
return (cs.channel_control.enable_busy && cs.request);
|
return (cs.channel_control.enable_busy && cs.request);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool DMA::CanRunAnyChannels() const
|
||||||
|
{
|
||||||
|
for (u32 i = 0; i < NUM_CHANNELS; i++)
|
||||||
|
{
|
||||||
|
if (CanRunChannel(static_cast<Channel>(i)))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
void DMA::RunDMA(Channel channel)
|
void DMA::RunDMA(Channel channel)
|
||||||
{
|
{
|
||||||
ChannelState& cs = m_state[static_cast<u32>(channel)];
|
ChannelState& cs = m_state[static_cast<u32>(channel)];
|
||||||
|
@ -353,3 +399,22 @@ void DMA::DMAWrite(Channel channel, u32 value, PhysicalMemoryAddress src_address
|
||||||
break;
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
|
|
||||||
class StateWrapper;
|
class StateWrapper;
|
||||||
|
|
||||||
|
class System;
|
||||||
class Bus;
|
class Bus;
|
||||||
class InterruptController;
|
class InterruptController;
|
||||||
class GPU;
|
class GPU;
|
||||||
|
@ -32,7 +33,7 @@ public:
|
||||||
DMA();
|
DMA();
|
||||||
~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();
|
void Reset();
|
||||||
bool DoState(StateWrapper& sw);
|
bool DoState(StateWrapper& sw);
|
||||||
|
|
||||||
|
@ -41,8 +42,11 @@ public:
|
||||||
|
|
||||||
void SetRequest(Channel channel, bool request);
|
void SetRequest(Channel channel, bool request);
|
||||||
|
|
||||||
|
void Execute(TickCount ticks);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static constexpr PhysicalMemoryAddress ADDRESS_MASK = UINT32_C(0x00FFFFFF);
|
static constexpr PhysicalMemoryAddress ADDRESS_MASK = UINT32_C(0x00FFFFFF);
|
||||||
|
static constexpr u32 TRANSFER_TICKS = 10;
|
||||||
|
|
||||||
enum class SyncMode : u32
|
enum class SyncMode : u32
|
||||||
{
|
{
|
||||||
|
@ -54,6 +58,7 @@ private:
|
||||||
|
|
||||||
// is everything enabled for a channel to operate?
|
// is everything enabled for a channel to operate?
|
||||||
bool CanRunChannel(Channel channel) const;
|
bool CanRunChannel(Channel channel) const;
|
||||||
|
bool CanRunAnyChannels() const;
|
||||||
|
|
||||||
void RunDMA(Channel channel);
|
void RunDMA(Channel channel);
|
||||||
|
|
||||||
|
@ -63,11 +68,17 @@ private:
|
||||||
// from memory -> device
|
// from memory -> device
|
||||||
void DMAWrite(Channel channel, u32 value, PhysicalMemoryAddress src_address, u32 remaining_words);
|
void DMAWrite(Channel channel, u32 value, PhysicalMemoryAddress src_address, u32 remaining_words);
|
||||||
|
|
||||||
|
void UpdateTransferPending();
|
||||||
|
|
||||||
|
System* m_system = nullptr;
|
||||||
Bus* m_bus = nullptr;
|
Bus* m_bus = nullptr;
|
||||||
InterruptController* m_interrupt_controller = nullptr;
|
InterruptController* m_interrupt_controller = nullptr;
|
||||||
GPU* m_gpu = nullptr;
|
GPU* m_gpu = nullptr;
|
||||||
CDROM* m_cdrom = nullptr;
|
CDROM* m_cdrom = nullptr;
|
||||||
|
|
||||||
|
TickCount m_transfer_ticks = 0;
|
||||||
|
bool m_transfer_pending = false;
|
||||||
|
|
||||||
struct ChannelState
|
struct ChannelState
|
||||||
{
|
{
|
||||||
u32 base_address;
|
u32 base_address;
|
||||||
|
@ -107,7 +118,6 @@ private:
|
||||||
} channel_control;
|
} channel_control;
|
||||||
|
|
||||||
bool request = false;
|
bool request = false;
|
||||||
bool irq = false;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
std::array<ChannelState, NUM_CHANNELS> m_state = {};
|
std::array<ChannelState, NUM_CHANNELS> m_state = {};
|
||||||
|
|
|
@ -39,7 +39,7 @@ bool System::Initialize()
|
||||||
return false;
|
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;
|
return false;
|
||||||
|
|
||||||
if (!m_interrupt_controller->Initialize(m_cpu.get()))
|
if (!m_interrupt_controller->Initialize(m_cpu.get()))
|
||||||
|
@ -246,6 +246,7 @@ void System::Synchronize()
|
||||||
const TickCount pending_ticks = m_cpu->GetPendingTicks();
|
const TickCount pending_ticks = m_cpu->GetPendingTicks();
|
||||||
m_cpu->ResetPendingTicks();
|
m_cpu->ResetPendingTicks();
|
||||||
|
|
||||||
|
m_dma->Execute(pending_ticks);
|
||||||
m_gpu->Execute(pending_ticks);
|
m_gpu->Execute(pending_ticks);
|
||||||
m_timers->AddSystemTicks(pending_ticks);
|
m_timers->AddSystemTicks(pending_ticks);
|
||||||
m_cdrom->Execute(pending_ticks);
|
m_cdrom->Execute(pending_ticks);
|
||||||
|
|
Loading…
Reference in New Issue