mirror of
https://github.com/RetroDECK/Duckstation.git
synced 2024-11-23 06:15:38 +00:00
DMA: Run manual channels while halted
Fixes games which have looping linked lists but still expect CD/OTC reads to work. Also caps the number of ticks used when looping linked lists are present, which doesn't steal so much time from the CPU per batch. Fixes: - Victory Spike - Magical Drop III - Yokubari Tokudai-gou! - Yuukyuu no Eden - The Eternal Eden - Loading screen in World Cup Golf - Professional Edition
This commit is contained in:
parent
2d067bb101
commit
e293c22cde
|
@ -154,7 +154,7 @@ void DMA::WriteRegister(u32 offset, u32 value)
|
|||
if (static_cast<Channel>(channel_index) == Channel::OTC)
|
||||
SetRequest(static_cast<Channel>(channel_index), state.channel_control.start_trigger);
|
||||
|
||||
if (!IsTransferHalted() && CanTransferChannel(static_cast<Channel>(channel_index)))
|
||||
if (CanTransferChannel(static_cast<Channel>(channel_index)))
|
||||
TransferChannel(static_cast<Channel>(channel_index));
|
||||
return;
|
||||
}
|
||||
|
@ -171,8 +171,7 @@ void DMA::WriteRegister(u32 offset, u32 value)
|
|||
{
|
||||
Log_TracePrintf("DPCR <- 0x%08X", value);
|
||||
m_DPCR.bits = value;
|
||||
if (!IsTransferHalted())
|
||||
{
|
||||
|
||||
for (u32 i = 0; i < NUM_CHANNELS; i++)
|
||||
{
|
||||
if (CanTransferChannel(static_cast<Channel>(i)))
|
||||
|
@ -181,7 +180,7 @@ void DMA::WriteRegister(u32 offset, u32 value)
|
|||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -209,7 +208,7 @@ void DMA::SetRequest(Channel channel, bool request)
|
|||
return;
|
||||
|
||||
cs.request = request;
|
||||
if (!IsTransferHalted() && CanTransferChannel(channel))
|
||||
if (CanTransferChannel(channel))
|
||||
TransferChannel(channel);
|
||||
}
|
||||
|
||||
|
@ -222,6 +221,9 @@ bool DMA::CanTransferChannel(Channel channel) const
|
|||
if (!cs.channel_control.enable_busy)
|
||||
return false;
|
||||
|
||||
if (cs.channel_control.sync_mode != SyncMode::Manual && IsTransferHalted())
|
||||
return false;
|
||||
|
||||
return cs.request;
|
||||
}
|
||||
|
||||
|
@ -275,14 +277,15 @@ bool DMA::TransferChannel(Channel channel)
|
|||
if (!copy_to_device)
|
||||
{
|
||||
Panic("Linked list not implemented for DMA reads");
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
Log_DebugPrintf("DMA%u: Copying linked list starting at 0x%08X to device", static_cast<u32>(channel),
|
||||
current_address & ADDRESS_MASK);
|
||||
|
||||
u8* ram_pointer = m_bus->GetRAM();
|
||||
while (cs.request && used_ticks < m_max_slice_ticks)
|
||||
bool halt_transfer = false;
|
||||
while (cs.request)
|
||||
{
|
||||
u32 header;
|
||||
std::memcpy(&header, &ram_pointer[current_address & ADDRESS_MASK], sizeof(header));
|
||||
|
@ -290,33 +293,45 @@ bool DMA::TransferChannel(Channel channel)
|
|||
|
||||
const u32 word_count = header >> 24;
|
||||
const u32 next_address = header & UINT32_C(0x00FFFFFF);
|
||||
Log_TracePrintf(" .. linked list entry at 0x%08X size=%u(%u words) next=0x%08X",
|
||||
current_address & ADDRESS_MASK, word_count * UINT32_C(4), word_count, next_address);
|
||||
Log_TracePrintf(" .. linked list entry at 0x%08X size=%u(%u words) next=0x%08X", current_address & ADDRESS_MASK,
|
||||
word_count * UINT32_C(4), word_count, next_address);
|
||||
if (word_count > 0)
|
||||
{
|
||||
used_ticks +=
|
||||
TransferMemoryToDevice(channel, (current_address + sizeof(header)) & ADDRESS_MASK, 4, word_count);
|
||||
}
|
||||
else if ((current_address & ADDRESS_MASK) == (next_address & ADDRESS_MASK))
|
||||
{
|
||||
current_address = next_address;
|
||||
halt_transfer = true;
|
||||
break;
|
||||
}
|
||||
|
||||
current_address = next_address;
|
||||
if (current_address & UINT32_C(0x800000))
|
||||
break;
|
||||
|
||||
if (used_ticks >= m_max_slice_ticks)
|
||||
{
|
||||
halt_transfer = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
cs.base_address = current_address;
|
||||
m_system->StallCPU(used_ticks);
|
||||
|
||||
if ((current_address & UINT32_C(0x800000)) == 0)
|
||||
{
|
||||
if (used_ticks >= m_max_slice_ticks && cs.request)
|
||||
if (current_address & UINT32_C(0x800000))
|
||||
break;
|
||||
|
||||
if (halt_transfer)
|
||||
{
|
||||
// stall the transfer for a bit if we ran for too long
|
||||
// Log_WarningPrintf("breaking dma chain at 0x%08X", current_address);
|
||||
HaltTransfer(m_halt_ticks);
|
||||
return false;
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
// linked list not yet complete
|
||||
return true;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue