From 46a2f6ed24067dfdc2002ff9a1a365d941ff7779 Mon Sep 17 00:00:00 2001 From: Gregory Hainaut Date: Tue, 12 Jan 2016 19:25:11 +0100 Subject: [PATCH] interpreter: fix a subtle bug in a QFSRV Math is correct but a shift of 64 bits is illegal in x86 because the cl register is masked From the x86 spec: The destination operand can be a register or a memory location. The count operand can be an immediate value or the CL register. The count is masked to 5 bits (or 6 bits if in 64-bit mode and REX.W is used). The count range is limited to 0 to 31 (or 63 if 64-bit mode and REX.W is used). A special opcode encoding is provided for a count of 1. --- pcsx2/MMI.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/pcsx2/MMI.cpp b/pcsx2/MMI.cpp index a20239239f..7235193220 100644 --- a/pcsx2/MMI.cpp +++ b/pcsx2/MMI.cpp @@ -1032,8 +1032,12 @@ void QFSRV() { // JayteeMaster: changed a bit to avoid screw up */ Rd.UD[0] = cpuRegs.GPR.r[_Rt_].UD[1] >> (sa_amt - 64); Rd.UD[1] = cpuRegs.GPR.r[_Rs_].UD[0] >> (sa_amt - 64); - Rd.UD[0]|= cpuRegs.GPR.r[_Rs_].UD[0] << (128 - sa_amt); - Rd.UD[1]|= cpuRegs.GPR.r[_Rs_].UD[1] << (128 - sa_amt); + if (sa_amt != 64) { + // A 64 bit shift is equivalent to a 0 bit shift because value is masked + // on 6 bits + Rd.UD[0]|= cpuRegs.GPR.r[_Rs_].UD[0] << (128u - sa_amt); + Rd.UD[1]|= cpuRegs.GPR.r[_Rs_].UD[1] << (128u - sa_amt); + } cpuRegs.GPR.r[_Rd_] = Rd; } }