From 9b0bf34d00b8ebd7bd99f964a73a67ef0104697e Mon Sep 17 00:00:00 2001 From: magumagu Date: Fri, 9 Jan 2015 22:20:06 -0800 Subject: [PATCH] Allow locked L1 DMA to write to the EFB. I wouldn't have guessed that anyone would do this, but apparently people who write video codecs love doing weird stuff with the locked L1 cache. --- Source/Core/Core/HW/Memmap.cpp | 38 --------- Source/Core/Core/HW/MemmapFunctions.cpp | 106 ++++++++++++++++++++---- 2 files changed, 92 insertions(+), 52 deletions(-) diff --git a/Source/Core/Core/HW/Memmap.cpp b/Source/Core/Core/HW/Memmap.cpp index d97aff3a2f..fc8dc39f34 100644 --- a/Source/Core/Core/HW/Memmap.cpp +++ b/Source/Core/Core/HW/Memmap.cpp @@ -243,44 +243,6 @@ void ClearCacheLine(const u32 address) Write_U64(0, address + i); } -void DMA_LCToMemory(const u32 memAddr, const u32 cacheAddr, const u32 numBlocks) -{ - const u8* src = m_pL1Cache + (cacheAddr & 0x3FFFF); - u8* dst = GetPointer(memAddr); - - if ((dst != nullptr) && (src != nullptr) && (memAddr & 3) == 0 && (cacheAddr & 3) == 0) - { - memcpy(dst, src, 32 * numBlocks); - } - else - { - for (u32 i = 0; i < 32 * numBlocks; i++) - { - u8 Temp = Read_U8(cacheAddr + i); - Write_U8(Temp, memAddr + i); - } - } -} - -void DMA_MemoryToLC(const u32 cacheAddr, const u32 memAddr, const u32 numBlocks) -{ - const u8* src = GetPointer(memAddr); - u8* dst = m_pL1Cache + (cacheAddr & 0x3FFFF); - - if ((dst != nullptr) && (src != nullptr) && (memAddr & 3) == 0 && (cacheAddr & 3) == 0) - { - memcpy(dst, src, 32 * numBlocks); - } - else - { - for (u32 i = 0; i < 32 * numBlocks; i++) - { - u8 Temp = Read_U8(memAddr + i); - Write_U8(Temp, cacheAddr + i); - } - } -} - std::string GetString(u32 em_address, size_t size) { const char* ptr = reinterpret_cast(GetPointer(em_address)); diff --git a/Source/Core/Core/HW/MemmapFunctions.cpp b/Source/Core/Core/HW/MemmapFunctions.cpp index d52bb6f5ad..623bb82b5e 100644 --- a/Source/Core/Core/HW/MemmapFunctions.cpp +++ b/Source/Core/Core/HW/MemmapFunctions.cpp @@ -90,6 +90,24 @@ static u32 EFB_Read(const u32 addr) return var; } +static void EFB_Write(u32 data, u32 addr) +{ + int x = (addr & 0xfff) >> 2; + int y = (addr >> 12) & 0x3ff; + + if (addr & 0x00400000) + { + g_video_backend->Video_AccessEFB(POKE_Z, x, y, data); + DEBUG_LOG(MEMMAP, "EFB Z Write %08x @ %i, %i", data, x, y); + } + else + { + g_video_backend->Video_AccessEFB(POKE_COLOR, x, y, data); + DEBUG_LOG(MEMMAP, "EFB Color Write %08x @ %i, %i", data, x, y); + } +} + + static void GenerateDSIException(u32 _EffectiveAddress, bool _bWrite); template @@ -193,20 +211,8 @@ __forceinline void WriteToHardware(u32 em_address, const T data) { if (em_address < 0xcc000000) { - int x = (em_address & 0xfff) >> 2; - int y = (em_address >> 12) & 0x3ff; - - // TODO figure out a way to send data without falling into the template trap - if (em_address & 0x00400000) - { - g_video_backend->Video_AccessEFB(POKE_Z, x, y, (u32)data); - DEBUG_LOG(MEMMAP, "EFB Z Write %08x @ %i, %i", (u32)data, x, y); - } - else - { - g_video_backend->Video_AccessEFB(POKE_COLOR, x, y, (u32)data); - DEBUG_LOG(MEMMAP, "EFB Color Write %08x @ %i, %i", (u32)data, x, y); - } + // TODO: This only works correctly for 32-bit writes. + EFB_Write((u32)data, em_address); return; } else @@ -460,6 +466,78 @@ void WriteUnchecked_U32(const u32 var, const u32 address) WriteToHardware(address, var); } +void DMA_LCToMemory(const u32 memAddr, const u32 cacheAddr, const u32 numBlocks) +{ + // TODO: It's not completely clear this is the right spot for this code; + // what would happen if, for example, the DVD drive tried to write to the EFB? + // TODO: This is terribly slow. + // TODO: Refactor. + // Avatar: The Last Airbender (GC) uses this for videos. + if ((memAddr & 0x0F000000) == 0x08000000) + { + for (u32 i = 0; i < 32 * numBlocks; i+=4) + { + u32 data = bswap(*(u32*)(Memory::m_pL1Cache + ((cacheAddr + i) & 0x3FFFF))); + EFB_Write(data, memAddr + i); + } + return; + } + + // No known game uses this; here for completeness. + // TODO: Refactor. + if ((memAddr & 0x0F000000) == 0x0C000000) + { + for (u32 i = 0; i < 32 * numBlocks; i += 4) + { + u32 data = bswap(*(u32*)(Memory::m_pL1Cache + ((cacheAddr + i) & 0x3FFFF))); + mmio_mapping->Write(memAddr + i, data); + } + return; + } + + const u8* src = Memory::m_pL1Cache + (cacheAddr & 0x3FFFF); + u8* dst = Memory::GetPointer(memAddr); + if (dst == nullptr) + return; + + memcpy(dst, src, 32 * numBlocks); +} + +void DMA_MemoryToLC(const u32 cacheAddr, const u32 memAddr, const u32 numBlocks) +{ + const u8* src = Memory::GetPointer(memAddr); + u8* dst = Memory::m_pL1Cache + (cacheAddr & 0x3FFFF); + + // No known game uses this; here for completeness. + // TODO: Refactor. + if ((memAddr & 0x0F000000) == 0x08000000) + { + for (u32 i = 0; i < 32 * numBlocks; i += 4) + { + u32 data = EFB_Read(memAddr + i); + *(u32*)(Memory::m_pL1Cache + ((cacheAddr + i) & 0x3FFFF)) = bswap(data); + } + return; + } + + // No known game uses this. + // TODO: Refactor. + if ((memAddr & 0x0F000000) == 0x0C000000) + { + for (u32 i = 0; i < 32 * numBlocks; i += 4) + { + u32 data = mmio_mapping->Read(memAddr + i); + *(u32*)(Memory::m_pL1Cache + ((cacheAddr + i) & 0x3FFFF)) = bswap(data); + } + return; + } + + if (src == nullptr) + return; + + memcpy(dst, src, 32 * numBlocks); +} + // ********************************************************************************* // Warning: Test Area //