From 0de34d7bf770f06726524ca1c406acb52795c210 Mon Sep 17 00:00:00 2001 From: Connor McLaughlin Date: Sun, 3 Jan 2021 16:05:43 +1000 Subject: [PATCH] DMA: Increase precision for large transfers Also gets rid of the delay on the GPU side for writing to VRAM (doesn't make sense), and it's not needed since we slice the block transfers now. Fixes palette corruption in Vigilante 8, and missing rider in Championship Motocross 2001 featuring Ricky Carmichael. --- data/database/gamesettings.ini | 42 +++++++++++++++++++++++ src/core/dma.cpp | 63 ++++++++++++++++++++-------------- src/core/gpu.h | 2 +- src/core/gpu_commands.cpp | 1 - 4 files changed, 80 insertions(+), 28 deletions(-) diff --git a/data/database/gamesettings.ini b/data/database/gamesettings.ini index a9501df07..dfc39402e 100644 --- a/data/database/gamesettings.ini +++ b/data/database/gamesettings.ini @@ -597,3 +597,45 @@ DMAMaxSliceTicks = 100 # SLUS-00912 (Destruction Derby Raw (USA)) [SLUS-00912] ForceInterlacing = true + + +# SLUS-00510 (Vigilante 8 (USA) (Rev 1)) +[SLUS-00510] +DMAMaxSliceTicks = 300 +DMAHaltTicks = 100 + + +# SLES-01212 (Vigilante 8 (Europe)) +[SLES-01212] +DMAMaxSliceTicks = 300 +DMAHaltTicks = 100 + + +# SLES-01214 (Vigilante 8 (Germany)) +[SLES-01214] +DMAMaxSliceTicks = 300 +DMAHaltTicks = 100 + + +# SLES-01213 (Vigilante 8 (France)) +[SLES-01213] +DMAMaxSliceTicks = 300 +DMAHaltTicks = 100 + + +# SLES-01215 (Vigilante 8 (Italy)) +[SLES-01215] +DMAMaxSliceTicks = 300 +DMAHaltTicks = 100 + + +# SLPS-01703 (Vigilante 8 (Japan)) +[SLPS-01703] +DMAMaxSliceTicks = 300 +DMAHaltTicks = 100 + + +# SLPS-91182 (Vigilante 8 (Japan)) +[SLPS-91182] +DMAMaxSliceTicks = 300 +DMAHaltTicks = 100 \ No newline at end of file diff --git a/src/core/dma.cpp b/src/core/dma.cpp index a1bc1ee00..1145d5fe0 100644 --- a/src/core/dma.cpp +++ b/src/core/dma.cpp @@ -284,7 +284,6 @@ bool DMA::TransferChannel(Channel channel) case SyncMode::LinkedList: { - TickCount used_ticks = 0; if (!copy_to_device) { Panic("Linked list not implemented for DMA reads"); @@ -295,12 +294,13 @@ bool DMA::TransferChannel(Channel channel) current_address & ADDRESS_MASK); u8* ram_pointer = Bus::g_ram; - bool halt_transfer = false; - while (cs.request) + TickCount remaining_ticks = m_max_slice_ticks; + while (cs.request && remaining_ticks > 0) { u32 header; std::memcpy(&header, &ram_pointer[current_address & ADDRESS_MASK], sizeof(header)); - used_ticks += 10; + CPU::AddPendingTicks(10); + remaining_ticks -= 10; const u32 word_count = header >> 24; const u32 next_address = header & UINT32_C(0x00FFFFFF); @@ -308,35 +308,26 @@ bool DMA::TransferChannel(Channel channel) word_count * UINT32_C(4), word_count, next_address); if (word_count > 0) { - used_ticks += 5; - used_ticks += + CPU::AddPendingTicks(5); + remaining_ticks -= 5; + + const TickCount block_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; + CPU::AddPendingTicks(block_ticks); + remaining_ticks -= block_ticks; } 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; - CPU::AddPendingTicks(used_ticks); if (current_address & UINT32_C(0x800000)) break; - if (halt_transfer) + if (cs.request) { // stall the transfer for a bit if we ran for too long HaltTransfer(m_halt_ticks); @@ -359,34 +350,54 @@ bool DMA::TransferChannel(Channel channel) const u32 block_size = cs.block_control.request.GetBlockSize(); u32 blocks_remaining = cs.block_control.request.GetBlockCount(); - TickCount used_ticks = 0; + TickCount ticks_remaining = m_max_slice_ticks; if (copy_to_device) { do { blocks_remaining--; - used_ticks += TransferMemoryToDevice(channel, current_address & ADDRESS_MASK, increment, block_size); + + const TickCount ticks = + TransferMemoryToDevice(channel, current_address & ADDRESS_MASK, increment, block_size); + CPU::AddPendingTicks(ticks); + ticks_remaining -= ticks; + current_address = (current_address + (increment * block_size)); - } while (cs.request && blocks_remaining > 0); + } while (cs.request && blocks_remaining > 0 && ticks_remaining > 0); } else { do { blocks_remaining--; - used_ticks += TransferDeviceToMemory(channel, current_address & ADDRESS_MASK, increment, block_size); + + const TickCount ticks = + TransferDeviceToMemory(channel, current_address & ADDRESS_MASK, increment, block_size); + CPU::AddPendingTicks(ticks); + ticks_remaining -= ticks; + current_address = (current_address + (increment * block_size)); - } while (cs.request && blocks_remaining > 0); + } while (cs.request && blocks_remaining > 0 && ticks_remaining > 0); } cs.base_address = current_address & BASE_ADDRESS_MASK; cs.block_control.request.block_count = blocks_remaining; - CPU::AddPendingTicks(used_ticks); // finish transfer later if the request was cleared if (blocks_remaining > 0) + { + if (cs.request) + { + // we got halted + if (!m_unhalt_event->IsActive()) + HaltTransfer(m_halt_ticks); + + return false; + } + return true; + } } break; diff --git a/src/core/gpu.h b/src/core/gpu.h index 15f5f7cca..e73540338 100644 --- a/src/core/gpu.h +++ b/src/core/gpu.h @@ -167,7 +167,7 @@ protected: // The GPU internally appears to run at 2x the system clock. ALWAYS_INLINE static constexpr TickCount GPUTicksToSystemTicks(TickCount gpu_ticks) { - return std::max(gpu_ticks >> 1, 1); + return std::max((gpu_ticks + 1) >> 1, 1); } ALWAYS_INLINE static constexpr TickCount SystemTicksToGPUTicks(TickCount sysclk_ticks) { return sysclk_ticks << 1; } diff --git a/src/core/gpu_commands.cpp b/src/core/gpu_commands.cpp index 1cfc402bd..0cf03260a 100644 --- a/src/core/gpu_commands.cpp +++ b/src/core/gpu_commands.cpp @@ -49,7 +49,6 @@ void GPU::ExecuteCommands() for (u32 i = 0; i < words_to_copy; i++) m_blit_buffer.push_back(FifoPop()); m_blit_remaining_words -= words_to_copy; - AddCommandTicks(words_to_copy); Log_DebugPrintf("VRAM write burst of %u words, %u words remaining", words_to_copy, m_blit_remaining_words); if (m_blit_remaining_words == 0)