Partial implementation of DMA controller and GPU stubs
This commit is contained in:
157
src/pse/dma.cpp
157
src/pse/dma.cpp
@ -17,7 +17,7 @@ bool DMA::Initialize(Bus* bus, GPU* gpu)
|
||||
void DMA::Reset()
|
||||
{
|
||||
m_state = {};
|
||||
m_DPCR.bits = 0;
|
||||
m_DPCR.bits = 0x07654321;
|
||||
m_DCIR = 0;
|
||||
}
|
||||
|
||||
@ -52,5 +52,160 @@ u32 DMA::ReadRegister(u32 offset)
|
||||
|
||||
void DMA::WriteRegister(u32 offset, u32 value)
|
||||
{
|
||||
const u32 channel_index = offset >> 4;
|
||||
if (channel_index < 7)
|
||||
{
|
||||
ChannelState& state = m_state[channel_index];
|
||||
switch (offset & UINT32_C(0x0F))
|
||||
{
|
||||
case 0x00:
|
||||
{
|
||||
state.base_address = value & BASE_ADDRESS_MASK;
|
||||
Log_DebugPrintf("DMA channel %u base address <- 0x%08X", channel_index, state.base_address);
|
||||
return;
|
||||
}
|
||||
case 0x04:
|
||||
{
|
||||
Log_DebugPrintf("DMA channel %u block control <- 0x%08X", channel_index, value);
|
||||
state.block_control.bits = value;
|
||||
return;
|
||||
}
|
||||
|
||||
case 0x08:
|
||||
{
|
||||
state.channel_control.bits = (state.channel_control.bits & ~ChannelState::ChannelControl::WRITE_MASK) |
|
||||
(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>(channel_index)))
|
||||
RunDMA(static_cast<Channel>(channel_index));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (offset)
|
||||
{
|
||||
case 0x70:
|
||||
{
|
||||
Log_DebugPrintf("DPCR <- 0x%08X", value);
|
||||
m_DPCR.bits = value;
|
||||
return;
|
||||
}
|
||||
|
||||
case 0x74:
|
||||
{
|
||||
m_DCIR = (m_DCIR & ~DCIR_WRITE_MASK) | (value & DCIR_WRITE_MASK);
|
||||
Log_DebugPrintf("DCIR <- 0x%08X", m_DCIR);
|
||||
return;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Log_ErrorPrintf("Unhandled register write: %02X <- %08X", offset, value);
|
||||
}
|
||||
|
||||
void DMA::SetRequest(Channel channel, bool request)
|
||||
{
|
||||
ChannelState& cs = m_state[static_cast<u32>(channel)];
|
||||
cs.request = request;
|
||||
|
||||
if (CanRunChannel(channel))
|
||||
RunDMA(channel);
|
||||
}
|
||||
|
||||
bool DMA::CanRunChannel(Channel channel) const
|
||||
{
|
||||
if (!m_DPCR.GetMasterEnable(channel))
|
||||
return false;
|
||||
|
||||
const ChannelState& cs = m_state[static_cast<u32>(channel)];
|
||||
if (cs.channel_control.start_trigger)
|
||||
return true;
|
||||
|
||||
return (cs.channel_control.enable_busy && cs.request);
|
||||
}
|
||||
|
||||
void DMA::RunDMA(Channel channel)
|
||||
{
|
||||
ChannelState& cs = m_state[static_cast<u32>(channel)];
|
||||
const PhysicalMemoryAddress memory_address = cs.base_address;
|
||||
const bool copy_to_device = cs.channel_control.copy_to_device;
|
||||
Log_DebugPrintf("Running DMA for channel %u", static_cast<u32>(channel));
|
||||
Assert(Common::IsAlignedPow2(memory_address, 4));
|
||||
|
||||
// start/trigger bit is cleared on beginning of transfer
|
||||
cs.channel_control.start_trigger = false;
|
||||
|
||||
switch (cs.channel_control.sync_mode)
|
||||
{
|
||||
case SyncMode::Manual:
|
||||
{
|
||||
const u32 word_count = cs.block_control.manual.GetWordCount();
|
||||
Log_DebugPrintf(" ... copying %u words %s 0x%08X", word_count, copy_to_device ? "from" : "to", memory_address);
|
||||
if (copy_to_device)
|
||||
{
|
||||
for (u32 i = 0; i < word_count; i++)
|
||||
{
|
||||
u32 memory_value = 0;
|
||||
m_bus->DispatchAccess<MemoryAccessType::Read, MemoryAccessSize::Word>(memory_address, memory_address,
|
||||
memory_value);
|
||||
DMAWrite(channel, memory_value);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (u32 i = 0; i < word_count; i++)
|
||||
{
|
||||
u32 memory_value = DMARead(channel);
|
||||
m_bus->DispatchAccess<MemoryAccessType::Write, MemoryAccessSize::Word>(memory_address, memory_address,
|
||||
memory_value);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case SyncMode::Request:
|
||||
case SyncMode::LinkedList:
|
||||
default:
|
||||
Panic("Unimplemented sync mode");
|
||||
break;
|
||||
}
|
||||
|
||||
// start/busy bit is cleared on end of transfer
|
||||
cs.channel_control.enable_busy = false;
|
||||
}
|
||||
|
||||
u32 DMA::DMARead(Channel channel)
|
||||
{
|
||||
switch (channel)
|
||||
{
|
||||
case Channel::OTC:
|
||||
{
|
||||
// we just return zeros here.. guessing it's pulled low?
|
||||
return 0;
|
||||
}
|
||||
|
||||
case Channel::MDECin:
|
||||
case Channel::MDECout:
|
||||
case Channel::GPU:
|
||||
case Channel::CDROM:
|
||||
case Channel::SPU:
|
||||
case Channel::PIO:
|
||||
default:
|
||||
Panic("Unhandled DMA channel write");
|
||||
return UINT32_C(0xFFFFFFFF);
|
||||
}
|
||||
}
|
||||
|
||||
void DMA::DMAWrite(Channel channel, u32 value)
|
||||
{
|
||||
Panic("Unhandled DMA channel write");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user