diff --git a/Core/HLE/sceDmac.cpp b/Core/HLE/sceDmac.cpp index 9222ff356f..1706bdf609 100644 --- a/Core/HLE/sceDmac.cpp +++ b/Core/HLE/sceDmac.cpp @@ -16,20 +16,30 @@ // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. #include "Globals.h" +#include "Core/CoreTiming.h" #include "Core/MemMap.h" #include "Core/Reporting.h" #include "Core/HLE/HLE.h" #include "GPU/GPUInterface.h" #include "GPU/GPUState.h" -u32 sceDmacMemcpy(u32 dst, u32 src, u32 size) { - if (!Memory::IsValidAddress(dst) || !Memory::IsValidAddress(src)) { - ERROR_LOG(HLE, "sceDmacMemcpy(dest=%08x, src=%08x, size=%i): invalid address", dst, src, size); - return 0; +u64 dmacMemcpyDeadline; + +void __DmacInit() { + dmacMemcpyDeadline = 0; +} + +void __DmacDoState(PointerWrap &p) { + auto s = p.Section("sceDmac", 0, 1); + if (s == 0) { + dmacMemcpyDeadline = 0; + return; } - DEBUG_LOG(HLE, "sceDmacMemcpy(dest=%08x, src=%08x, size=%i)", dst, src, size); + p.Do(dmacMemcpyDeadline); +} +int __DmacMemcpy(u32 dst, u32 src, u32 size) { Memory::Memcpy(dst, Memory::GetPointer(src), size); src &= ~0x40000000; @@ -37,13 +47,56 @@ u32 sceDmacMemcpy(u32 dst, u32 src, u32 size) { if (Memory::IsVRAMAddress(src) || Memory::IsVRAMAddress(dst)) { gpu->UpdateMemory(dst, src, size); } + + // This number seems strangely reproducible. + if (size >= 272) { + // Approx. 225 MiB/s or 235929600 B/s, so let's go with 236 B/us. + int delayUs = size / 236; + dmacMemcpyDeadline = CoreTiming::GetTicks() + usToCycles(delayUs); + return hleDelayResult(0, "dmac copy", delayUs); + } return 0; } -u32 sceDmacTryMemcpy(u32 x, u32 y , u32 z) -{ - ERROR_LOG_REPORT(HLE,"UNIMPL sceDmacTryMemcpy(%08x, %08x, %i)", x ,y ,z); - return 0; +u32 sceDmacMemcpy(u32 dst, u32 src, u32 size) { + if (size == 0) { + ERROR_LOG(HLE, "sceDmacMemcpy(dest=%08x, src=%08x, size=%i): invalid size", dst, src, size); + return SCE_KERNEL_ERROR_INVALID_SIZE; + } + if (!Memory::IsValidAddress(dst) || !Memory::IsValidAddress(src)) { + ERROR_LOG(HLE, "sceDmacMemcpy(dest=%08x, src=%08x, size=%i): invalid address", dst, src, size); + return SCE_KERNEL_ERROR_INVALID_POINTER; + } + + if (dmacMemcpyDeadline > CoreTiming::GetTicks()) { + WARN_LOG_REPORT(HLE, "sceDmacMemcpy(dest=%08x, src=%08x, size=%i): overlapping read", dst, src, size); + // TODO: Should block, seems like copy doesn't start until previous finishes. + // Might matter for overlapping copies. + } else { + DEBUG_LOG(HLE, "sceDmacMemcpy(dest=%08x, src=%08x, size=%i)", dst, src, size); + } + + return __DmacMemcpy(dst, src, size); +} + +u32 sceDmacTryMemcpy(u32 dst, u32 src, u32 size) { + if (size == 0) { + ERROR_LOG(HLE, "sceDmacTryMemcpy(dest=%08x, src=%08x, size=%i): invalid size", dst, src, size); + return SCE_KERNEL_ERROR_INVALID_SIZE; + } + if (!Memory::IsValidAddress(dst) || !Memory::IsValidAddress(src)) { + ERROR_LOG(HLE, "sceDmacTryMemcpy(dest=%08x, src=%08x, size=%i): invalid address", dst, src, size); + return SCE_KERNEL_ERROR_INVALID_POINTER; + } + + if (dmacMemcpyDeadline > CoreTiming::GetTicks()) { + DEBUG_LOG(HLE, "sceDmacTryMemcpy(dest=%08x, src=%08x, size=%i): busy", dst, src, size); + return SCE_KERNEL_ERROR_BUSY; + } else { + DEBUG_LOG(HLE, "sceDmacTryMemcpy(dest=%08x, src=%08x, size=%i)", dst, src, size); + } + + return __DmacMemcpy(dst, src, size); } const HLEFunction sceDmac[] = { diff --git a/Core/HLE/sceDmac.h b/Core/HLE/sceDmac.h index 0f40d75120..c2f9f498fd 100644 --- a/Core/HLE/sceDmac.h +++ b/Core/HLE/sceDmac.h @@ -17,4 +17,9 @@ #pragma once +class PointerWrap; + +void __DmacInit(); +void __DmacDoState(PointerWrap &p); + void Register_sceDmac(); diff --git a/GPU/GPUCommon.cpp b/GPU/GPUCommon.cpp index dc5d06fa86..9816bf4f66 100644 --- a/GPU/GPUCommon.cpp +++ b/GPU/GPUCommon.cpp @@ -203,7 +203,7 @@ u32 GPUCommon::EnqueueList(u32 listpc, u32 stall, int subIntrBase, PSPPointer