diff --git a/Source/Core/Core/HW/Memmap.cpp b/Source/Core/Core/HW/Memmap.cpp index c3d3099851..f6a4dbe2c2 100644 --- a/Source/Core/Core/HW/Memmap.cpp +++ b/Source/Core/Core/HW/Memmap.cpp @@ -235,6 +235,20 @@ void Memset(const u32 _Address, const u8 _iValue, const u32 _iLength) } } +void ClearCacheLine(const u32 _Address) +{ + u8 *ptr = GetPointer(_Address); + if (ptr != nullptr) + { + memset(ptr, 0, 32); + } + else + { + for (u32 i = 0; i < 32; i += 8) + Write_U64(0, _Address + i); + } +} + void DMA_LCToMemory(const u32 _MemAddr, const u32 _CacheAddr, const u32 _iNumBlocks) { const u8 *src = m_pL1Cache + (_CacheAddr & 0x3FFFF); diff --git a/Source/Core/Core/HW/Memmap.h b/Source/Core/Core/HW/Memmap.h index d1ae34711d..f130cf643f 100644 --- a/Source/Core/Core/HW/Memmap.h +++ b/Source/Core/Core/HW/Memmap.h @@ -126,6 +126,7 @@ u8* GetPointer(const u32 _Address); void DMA_LCToMemory(const u32 _iMemAddr, const u32 _iCacheAddr, const u32 _iNumBlocks); void DMA_MemoryToLC(const u32 _iCacheAddr, const u32 _iMemAddr, const u32 _iNumBlocks); void Memset(const u32 _Address, const u8 _Data, const u32 _iLength); +void ClearCacheLine(const u32 _Address); // Zeroes 32 bytes; address should be 32-byte-aligned // TLB functions void SDRUpdated(); diff --git a/Source/Core/Core/PowerPC/Interpreter/Interpreter_LoadStore.cpp b/Source/Core/Core/PowerPC/Interpreter/Interpreter_LoadStore.cpp index 199b3661f3..fc04cbfb9b 100644 --- a/Source/Core/Core/PowerPC/Interpreter/Interpreter_LoadStore.cpp +++ b/Source/Core/Core/PowerPC/Interpreter/Interpreter_LoadStore.cpp @@ -376,7 +376,7 @@ void Interpreter::dcbz(UGeckoInstruction _inst) { // HACK but works... we think if (!Core::g_CoreStartupParameter.bDCBZOFF) - Memory::Memset(Helper_Get_EA_X(_inst) & (~31), 0, 32); + Memory::ClearCacheLine(Helper_Get_EA_X(_inst) & (~31)); if (!JitInterface::GetCore()) PowerPC::CheckExceptions(); } diff --git a/Source/Core/Core/PowerPC/Jit64/Jit_LoadStore.cpp b/Source/Core/Core/PowerPC/Jit64/Jit_LoadStore.cpp index e7f0508c67..142a5e2443 100644 --- a/Source/Core/Core/PowerPC/Jit64/Jit_LoadStore.cpp +++ b/Source/Core/Core/PowerPC/Jit64/Jit_LoadStore.cpp @@ -260,17 +260,37 @@ void Jit64::dcbz(UGeckoInstruction inst) { INSTRUCTION_START JITDISABLE(bJITLoadStoreOff); + if (Core::g_CoreStartupParameter.bDCBZOFF) + return; - // FIXME - FALLBACK_IF(true); + int a = inst.RA; + int b = inst.RB; - MOV(32, R(EAX), gpr.R(inst.RB)); - if (inst.RA) - ADD(32, R(EAX), gpr.R(inst.RA)); + u32 mem_mask = Memory::ADDR_MASK_HW_ACCESS; + if (Core::g_CoreStartupParameter.bMMU || Core::g_CoreStartupParameter.bTLBHack) + mem_mask |= Memory::ADDR_MASK_MEM1; + + MOV(32, R(EAX), gpr.R(b)); + if (a) + ADD(32, R(EAX), gpr.R(a)); AND(32, R(EAX), Imm32(~31)); + TEST(32, R(EAX), Imm32(mem_mask)); + FixupBranch fast = J_CC(CC_Z, true); + + // Should this code ever run? I can't find any games that use DCBZ on non-physical addresses, but + // supposedly there are, at least for some MMU titles. Let's be careful and support it to be sure. + MOV(32, M(&PC), Imm32(jit->js.compilerPC)); + u32 registersInUse = CallerSavedRegistersInUse(); + ABI_PushRegistersAndAdjustStack(registersInUse, false); + ABI_CallFunctionR((void *)&Memory::ClearCacheLine, EAX); + ABI_PopRegistersAndAdjustStack(registersInUse, false); + + FixupBranch exit = J(); + SetJumpTarget(fast); PXOR(XMM0, R(XMM0)); - MOVAPS(MComplex(EBX, EAX, SCALE_1, 0), XMM0); - MOVAPS(MComplex(EBX, EAX, SCALE_1, 16), XMM0); + MOVAPS(MComplex(RBX, RAX, SCALE_1, 0), XMM0); + MOVAPS(MComplex(RBX, RAX, SCALE_1, 16), XMM0); + SetJumpTarget(exit); } void Jit64::stX(UGeckoInstruction inst)