mirror of
https://github.com/RetroDECK/Duckstation.git
synced 2024-11-26 23:55:40 +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)
|
if (static_cast<Channel>(channel_index) == Channel::OTC)
|
||||||
SetRequest(static_cast<Channel>(channel_index), state.channel_control.start_trigger);
|
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));
|
TransferChannel(static_cast<Channel>(channel_index));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -171,17 +171,16 @@ void DMA::WriteRegister(u32 offset, u32 value)
|
||||||
{
|
{
|
||||||
Log_TracePrintf("DPCR <- 0x%08X", value);
|
Log_TracePrintf("DPCR <- 0x%08X", value);
|
||||||
m_DPCR.bits = value;
|
m_DPCR.bits = value;
|
||||||
if (!IsTransferHalted())
|
|
||||||
|
for (u32 i = 0; i < NUM_CHANNELS; i++)
|
||||||
{
|
{
|
||||||
for (u32 i = 0; i < NUM_CHANNELS; i++)
|
if (CanTransferChannel(static_cast<Channel>(i)))
|
||||||
{
|
{
|
||||||
if (CanTransferChannel(static_cast<Channel>(i)))
|
if (!TransferChannel(static_cast<Channel>(i)))
|
||||||
{
|
break;
|
||||||
if (!TransferChannel(static_cast<Channel>(i)))
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -209,7 +208,7 @@ void DMA::SetRequest(Channel channel, bool request)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
cs.request = request;
|
cs.request = request;
|
||||||
if (!IsTransferHalted() && CanTransferChannel(channel))
|
if (CanTransferChannel(channel))
|
||||||
TransferChannel(channel);
|
TransferChannel(channel);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -222,6 +221,9 @@ bool DMA::CanTransferChannel(Channel channel) const
|
||||||
if (!cs.channel_control.enable_busy)
|
if (!cs.channel_control.enable_busy)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
if (cs.channel_control.sync_mode != SyncMode::Manual && IsTransferHalted())
|
||||||
|
return false;
|
||||||
|
|
||||||
return cs.request;
|
return cs.request;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -275,48 +277,61 @@ bool DMA::TransferChannel(Channel channel)
|
||||||
if (!copy_to_device)
|
if (!copy_to_device)
|
||||||
{
|
{
|
||||||
Panic("Linked list not implemented for DMA reads");
|
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();
|
||||||
|
bool halt_transfer = false;
|
||||||
|
while (cs.request)
|
||||||
{
|
{
|
||||||
Log_DebugPrintf("DMA%u: Copying linked list starting at 0x%08X to device", static_cast<u32>(channel),
|
u32 header;
|
||||||
current_address & ADDRESS_MASK);
|
std::memcpy(&header, &ram_pointer[current_address & ADDRESS_MASK], sizeof(header));
|
||||||
|
used_ticks++;
|
||||||
|
|
||||||
u8* ram_pointer = m_bus->GetRAM();
|
const u32 word_count = header >> 24;
|
||||||
while (cs.request && used_ticks < m_max_slice_ticks)
|
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);
|
||||||
|
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))
|
||||||
{
|
{
|
||||||
u32 header;
|
|
||||||
std::memcpy(&header, &ram_pointer[current_address & ADDRESS_MASK], sizeof(header));
|
|
||||||
used_ticks++;
|
|
||||||
|
|
||||||
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);
|
|
||||||
if (word_count > 0)
|
|
||||||
{
|
|
||||||
used_ticks +=
|
|
||||||
TransferMemoryToDevice(channel, (current_address + sizeof(header)) & ADDRESS_MASK, 4, word_count);
|
|
||||||
}
|
|
||||||
|
|
||||||
current_address = next_address;
|
current_address = next_address;
|
||||||
if (current_address & UINT32_C(0x800000))
|
halt_transfer = true;
|
||||||
break;
|
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;
|
cs.base_address = current_address;
|
||||||
m_system->StallCPU(used_ticks);
|
m_system->StallCPU(used_ticks);
|
||||||
|
|
||||||
if ((current_address & UINT32_C(0x800000)) == 0)
|
if (current_address & UINT32_C(0x800000))
|
||||||
{
|
break;
|
||||||
if (used_ticks >= m_max_slice_ticks && cs.request)
|
|
||||||
{
|
|
||||||
// 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if (halt_transfer)
|
||||||
|
{
|
||||||
|
// stall the transfer for a bit if we ran for too long
|
||||||
|
HaltTransfer(m_halt_ticks);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
// linked list not yet complete
|
// linked list not yet complete
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue