diff --git a/Common/Arm64Emitter.cpp b/Common/Arm64Emitter.cpp index 9029117e45..7708958f62 100644 --- a/Common/Arm64Emitter.cpp +++ b/Common/Arm64Emitter.cpp @@ -16,6 +16,7 @@ #include "Arm64Emitter.h" #include "MathUtil.h" #include "CommonTypes.h" +#include "CPUDetect.h" namespace Arm64Gen { @@ -312,6 +313,13 @@ void ARM64XEmitter::FlushIcache() void ARM64XEmitter::FlushIcacheSection(u8* start, u8* end) { + if (cpu_info.sBugs.bExynos8890Invalidation) + { + // Over invalidate to force this CPU to listen. + start = m_startcode + 4096 < start ? start - 4096 : m_startcode; + end += 4096; + } + #if defined(IOS) // Header file says this is equivalent to: sys_icache_invalidate(start, end - start); sys_cache_control(kCacheFunctionPrepareForExecution, start, end - start); diff --git a/Common/ArmCPUDetect.cpp b/Common/ArmCPUDetect.cpp index 78cc3a918f..025c8833b4 100644 --- a/Common/ArmCPUDetect.cpp +++ b/Common/ArmCPUDetect.cpp @@ -296,6 +296,8 @@ void CPUInfo::Detect() // Whether the above detection failed or not, on ARM64 we do have ASIMD/NEON. bNEON = true; bASIMD = true; + + sBugs.bExynos8890Invalidation = strcmp(cpu_string, "universal8890") == 0; #endif } diff --git a/Common/CPUDetect.h b/Common/CPUDetect.h index 0adbfac8e6..25b8b42ee8 100644 --- a/Common/CPUDetect.h +++ b/Common/CPUDetect.h @@ -89,6 +89,15 @@ struct CPUInfo { bool bXBurst1; bool bXBurst2; + // Bugs + struct { + // Samsung Galaxy S7 devices (Exynos 8890) have a bug that causes invalidation to work incorrectly. + // This may be caused by interaction between the separate CPU cores. + // Padding jit blocks and over-invalidating seems to "solve" it. + // Only affects ARM64. + bool bExynos8890Invalidation; + } sBugs; + // Call Detect() explicit CPUInfo(); diff --git a/Core/MIPS/ARM64/Arm64Jit.cpp b/Core/MIPS/ARM64/Arm64Jit.cpp index a3f032ea5a..9ced4a8ada 100644 --- a/Core/MIPS/ARM64/Arm64Jit.cpp +++ b/Core/MIPS/ARM64/Arm64Jit.cpp @@ -329,6 +329,14 @@ const u8 *Arm64Jit::DoJit(u32 em_address, JitBlock *b) { if (dontLogBlocks > 0) dontLogBlocks--; + if (cpu_info.sBugs.bExynos8890Invalidation) { + // What a waste. If we don't do both this and over-invalidate, the device crashes. + // This space won't ever get run, but it's wasted jit cache space. + for (int i = 0; i < 32; ++i) { + HINT(HINT_NOP); + } + } + // Don't forget to zap the newly written instructions in the instruction cache! FlushIcache(); diff --git a/GPU/Common/VertexDecoderArm64.cpp b/GPU/Common/VertexDecoderArm64.cpp index 7b85c686c5..20303b7a44 100644 --- a/GPU/Common/VertexDecoderArm64.cpp +++ b/GPU/Common/VertexDecoderArm64.cpp @@ -275,6 +275,14 @@ JittedVertexDecoder VertexDecoderJitCache::Compile(const VertexDecoder &dec, int RET(); + if (cpu_info.sBugs.bExynos8890Invalidation) { + // Apparently the vertex cache hasn't been the problem, but adding this here for the same + // reasons as the standard jit. + for (int i = 0; i < 32; ++i) { + HINT(HINT_NOP); + } + } + FlushIcache(); if (log) {