diff --git a/common/include/Utilities/Math.h b/common/include/Utilities/Math.h new file mode 100644 index 0000000000..e444f687fb --- /dev/null +++ b/common/include/Utilities/Math.h @@ -0,0 +1,41 @@ +/* PCSX2 - PS2 Emulator for PCs + * Copyright (C) 2014- PCSX2 Dev Team + * + * PCSX2 is free software: you can redistribute it and/or modify it under the terms + * of the GNU Lesser General Public License as published by the Free Software Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with PCSX2. + * If not, see . + */ + +#pragma once +// Hopefully this file will be used for cross-source math utilities. +// Currently these are strewn across the code base. Please collect them all! + +#include "Pcsx2Defs.h" + +// On GCC >= 4.7, this is equivalent to __builtin_clrsb(n); +inline u32 count_leading_sign_bits(s32 n) { + // If BSR is used directly, it would have an undefined value for 0. + if (n == 0) + return 32; + + // If the sign bit is 1, we invert the bits to 0 for count-leading-zero. + if (n < 0) + n = ~n; + + // Perform our count leading zero. +#ifdef _MSC_VER + unsigned long ret; + _BitScanReverse(&ret, n); + return 31 - (u32)ret; +#else + return __builtin_clz(n); +#endif +} + diff --git a/pcsx2/MMI.cpp b/pcsx2/MMI.cpp index 6375405461..9aa68670e6 100644 --- a/pcsx2/MMI.cpp +++ b/pcsx2/MMI.cpp @@ -16,6 +16,7 @@ #include "PrecompiledHeader.h" #include "Common.h" +#include "Utilities/Math.h" namespace R5900 { namespace Interpreter { @@ -145,30 +146,13 @@ namespace MMI { //*****************MMI OPCODES********************************* -static __fi void _PLZCW(int n) -{ - // This function counts the number of "like" bits in the source register, starting - // with the MSB and working its way down, and returns the result MINUS ONE. - // So 0xff00 would return 7, not 8. - - int c = 0; - s32 i = cpuRegs.GPR.r[_Rs_].SL[n]; - - // Negate the source based on the sign bit. This allows us to use a simple - // unified bit test of the MSB for either condition. - if( i >= 0 ) i = ~i; - - // shift first, compare, then increment. This excludes the sign bit from our final count. - while( i <<= 1, i < 0 ) c++; - - cpuRegs.GPR.r[_Rd_].UL[n] = c; -} - void PLZCW() { - if (!_Rd_) return; + if (!_Rd_) + return; - _PLZCW (0); - _PLZCW (1); + // Return the leading sign bits, excluding the original bit + cpuRegs.GPR.r[_Rd_].UL[0] = count_leading_sign_bits(cpuRegs.GPR.r[_Rs_].SL[0]) - 1; + cpuRegs.GPR.r[_Rd_].UL[1] = count_leading_sign_bits(cpuRegs.GPR.r[_Rs_].SL[1]) - 1; } __fi void PMFHL_CLAMP(u16& dst, s32 src) diff --git a/pcsx2/x86/iMMI.cpp b/pcsx2/x86/iMMI.cpp index 74ee3d7d49..0183c4e5b1 100644 --- a/pcsx2/x86/iMMI.cpp +++ b/pcsx2/x86/iMMI.cpp @@ -25,6 +25,7 @@ #include "R5900OpcodeTables.h" #include "iR5900.h" #include "iMMI.h" +#include "Utilities/Math.h" using namespace x86Emitter; @@ -66,23 +67,10 @@ void recPLZCW() _deleteEEreg(_Rd_, 0); GPR_SET_CONST(_Rd_); - for(regs = 0; regs < 2; ++regs) { - u32 val = g_cpuConstRegs[_Rs_].UL[regs]; + // Return the leading sign bits, excluding the original bit + g_cpuConstRegs[_Rd_].UL[0] = count_leading_sign_bits(g_cpuConstRegs[_Rs_].SL[0]) - 1; + g_cpuConstRegs[_Rd_].UL[1] = count_leading_sign_bits(g_cpuConstRegs[_Rs_].SL[1]) - 1; - if( val != 0 ) { - u32 setbit = val&0x80000000; - g_cpuConstRegs[_Rd_].UL[regs] = 0; - val <<= 1; - - while((val & 0x80000000) == setbit) { - g_cpuConstRegs[_Rd_].UL[regs]++; - val <<= 1; - } - } - else { - g_cpuConstRegs[_Rd_].UL[regs] = 31; - } - } return; }