diff --git a/Core/MIPS/ARM/ArmCompVFPU.cpp b/Core/MIPS/ARM/ArmCompVFPU.cpp index 850b5ebf8ffe..84e84027651d 100644 --- a/Core/MIPS/ARM/ArmCompVFPU.cpp +++ b/Core/MIPS/ARM/ArmCompVFPU.cpp @@ -1832,24 +1832,18 @@ namespace MIPSComp fpr.ReleaseSpillLocksAndDiscardTemps(); } -#ifndef M_PI_2 -#define M_PI_2 1.57079632679489661923 -#endif // sincosf is unavailable in the Android NDK: // https://code.google.com/p/android/issues/detail?id=38423 double SinCos(float angle) { union { struct { float sin; float cos; }; double out; } sincos; - angle *= (float)M_PI_2; - sincos.sin = sinf(angle); - sincos.cos = cosf(angle); + vfpu_sincos(angle, sincos.sin, sincos.cos); return sincos.out; } double SinCosNegSin(float angle) { union { struct { float sin; float cos; }; double out; } sincos; - angle *= (float)M_PI_2; - sincos.sin = -sinf(angle); - sincos.cos = cosf(angle); + vfpu_sincos(angle, sincos.sin, sincos.cos); + sincos.sin = -sincos.sin; return sincos.out; } diff --git a/Core/MIPS/MIPS.cpp b/Core/MIPS/MIPS.cpp index 5a60c8879ec2..e8ffb19b717d 100644 --- a/Core/MIPS/MIPS.cpp +++ b/Core/MIPS/MIPS.cpp @@ -59,7 +59,10 @@ u8 fromvoffset[128]; #define M_LN10 2.30258509299404568402f #undef M_PI #define M_PI 3.14159265358979323846f + +#ifndef M_PI_2 #define M_PI_2 1.57079632679489661923f +#endif #define M_PI_4 0.785398163397448309616f #define M_1_PI 0.318309886183790671538f #define M_2_PI 0.636619772367581343076f diff --git a/Core/MIPS/MIPSIntVFPU.cpp b/Core/MIPS/MIPSIntVFPU.cpp index a8828144d9a7..5c503fe649b8 100644 --- a/Core/MIPS/MIPSIntVFPU.cpp +++ b/Core/MIPS/MIPSIntVFPU.cpp @@ -59,7 +59,9 @@ #define M_LN10 2.30258509299404568402f #undef M_PI #define M_PI 3.14159265358979323846f +#ifndef M_PI_2 #define M_PI_2 1.57079632679489661923f +#endif #define M_PI_4 0.785398163397448309616f #define M_1_PI 0.318309886183790671538f #define M_2_PI 0.636619772367581343076f @@ -517,14 +519,15 @@ namespace MIPSInt case 5: if (s[i] < -1.0f) d[i] = -1.0f; else {if(s[i] > 1.0f) d[i] = 1.0f; else d[i] = s[i];} break; // vsat1 case 16: d[i] = 1.0f / s[i]; break; //vrcp case 17: d[i] = 1.0f / sqrtf(s[i]); break; //vrsq - case 18: d[i] = sinf((float)M_PI_2 * s[i]); break; //vsin - case 19: d[i] = cosf((float)M_PI_2 * s[i]); break; //vcos + + case 18: { d[i] = vfpu_sin(s[i]); } break; //vsin + case 19: { d[i] = vfpu_cos(s[i]); } break; //vcos case 20: d[i] = powf(2.0f, s[i]); break; //vexp2 case 21: d[i] = logf(s[i])/log(2.0f); break; //vlog2 case 22: d[i] = fabsf(sqrtf(s[i])); break; //vsqrt case 23: d[i] = asinf(s[i]) / M_PI_2; break; //vasin case 24: d[i] = -1.0f / s[i]; break; // vnrcp - case 26: d[i] = -sinf((float)M_PI_2 * s[i]); break; // vnsin + case 26: { d[i] = -vfpu_sin(s[i]); } break; // vnsin case 28: d[i] = 1.0f / powf(2.0, s[i]); break; // vrexp2 default: _dbg_assert_msg_(CPU,0,"Trying to interpret VV2Op instruction that can't be interpreted"); @@ -1285,21 +1288,18 @@ namespace MIPSInt } // Generates one line of a rotation matrix around one of the three axes - void Int_Vrot(MIPSOpcode op) - { + void Int_Vrot(MIPSOpcode op) { int vd = _VD; int vs = _VS; int imm = (op >> 16) & 0x1f; VectorSize sz = GetVecSize(op); - float angle = V(vs) * M_PI_2; bool negSin = (imm & 0x10) ? true : false; - float sine = sinf(angle); - float cosine = cosf(angle); + float sine, cosine; + vfpu_sincos(V(vs), sine, cosine); if (negSin) sine = -sine; float d[4] = {0}; - if (((imm >> 2) & 3) == (imm & 3)) - { + if (((imm >> 2) & 3) == (imm & 3)) { for (int i = 0; i < 4; i++) d[i] = sine; } @@ -1845,7 +1845,7 @@ namespace MIPSInt ERROR_LOG_REPORT(CPU, "vsbn not implemented for size %d", GetNumVectorElements(sz)); } for (int i = 0; i < GetNumVectorElements(sz); ++i) { - // Simply replace the expontent bits. + // Simply replace the exponent bits. u32 prev = s.u[i] & 0x7F800000; if (prev != 0 && prev != 0x7F800000) { d.u[i] = (s.u[i] & ~0x7F800000) | (exp << 23); diff --git a/Core/MIPS/MIPSVFPUUtils.h b/Core/MIPS/MIPSVFPUUtils.h index 54b3acb5f39a..b33cf7025068 100644 --- a/Core/MIPS/MIPSVFPUUtils.h +++ b/Core/MIPS/MIPSVFPUUtils.h @@ -17,17 +17,41 @@ #pragma once +#include +#include "Core/MIPS/MIPS.h" #define _VD (op & 0x7F) #define _VS ((op>>8) & 0x7F) #define _VT ((op>>16) & 0x7F) -inline int Xpose(int v) -{ +inline int Xpose(int v) { return v^0x20; } +#ifndef M_PI_2 +#define M_PI_2 1.57079632679489661923 +#endif + +inline float vfpu_sin(float angle) { + angle -= floorf(angle * 0.25f) * 4.f; + angle *= (float)M_PI_2; + return sinf(angle); +} + +inline float vfpu_cos(float angle) { + angle -= floorf(angle * 0.25f) * 4.f; + angle *= (float)M_PI_2; + return cosf(angle); +} + +inline void vfpu_sincos(float angle, float &sine, float &cosine) { + angle -= floorf(angle * 0.25f) * 4.f; + angle *= (float)M_PI_2; + sine = sinf(angle); + cosine = cosf(angle); +} + #define VFPU_FLOAT16_EXP_MAX 0x1f #define VFPU_SH_FLOAT16_SIGN 15 #define VFPU_MASK_FLOAT16_SIGN 0x1 diff --git a/Core/MIPS/x86/CompVFPU.cpp b/Core/MIPS/x86/CompVFPU.cpp index 0a14e561b526..823c22f6ce70 100644 --- a/Core/MIPS/x86/CompVFPU.cpp +++ b/Core/MIPS/x86/CompVFPU.cpp @@ -2125,15 +2125,12 @@ typedef u32float SinCosArg; #endif void SinCos(SinCosArg angle) { - angle *= (float)1.57079632679489661923; // pi / 2 - sincostemp[0] = sinf(angle); - sincostemp[1] = cosf(angle); + vfpu_sincos(angle, sincostemp[0], sincostemp[1]); } void SinCosNegSin(SinCosArg angle) { - angle *= (float)1.57079632679489661923; // pi / 2 - sincostemp[0] = -sinf(angle); - sincostemp[1] = cosf(angle); + vfpu_sincos(angle, sincostemp[0], sincostemp[1]); + sincostemp[0] = -sincostemp[0]; } // Very heavily used by FF:CC diff --git a/unittest/UnitTest.cpp b/unittest/UnitTest.cpp index ba946487bc74..a9e9a4341a21 100644 --- a/unittest/UnitTest.cpp +++ b/unittest/UnitTest.cpp @@ -37,10 +37,12 @@ #include "math/math_util.h" #include "util/text/parsers.h" #include "Core/Config.h" +#include "Core/MIPS/MIPSVFPUUtils.h" #define EXPECT_TRUE(a) if (!(a)) { printf("%s:%i: Test Fail\n", __FUNCTION__, __LINE__); return false; } #define EXPECT_FALSE(a) if ((a)) { printf("%s:%i: Test Fail\n", __FUNCTION__, __LINE__); return false; } -#define EXPECT_EQ_FLOAT(a, b) if ((a) != (b)) { printf("%s:" __LINE__ ": Test Fail\n%f\nvs\n%f\n", __FUNCTION__, a, b); return false; } +#define EXPECT_EQ_FLOAT(a, b) if ((a) != (b)) { printf("%s:%i: Test Fail\n%f\nvs\n%f\n", __FUNCTION__, __LINE__, a, b); return false; } +#define EXPECT_APPROX_EQ_FLOAT(a, b) if (fabsf((a)-(b))>0.00001f) { printf("%s:%i: Test Fail\n%f\nvs\n%f\n", __FUNCTION__, __LINE__, a, b); /*return false;*/ } #define EXPECT_EQ_STR(a, b) if (a != b) { printf("%s: Test Fail\n%s\nvs\n%s\n", __FUNCTION__, a.c_str(), b.c_str()); return false; } #define RET(a) if (!(a)) { return false; } @@ -385,6 +387,35 @@ bool TestParsers() { return true; } +bool TestVFPUSinCos() { + float sine, cosine; + vfpu_sincos(0.0f, sine, cosine); + EXPECT_EQ_FLOAT(sine, 0.0f); + EXPECT_EQ_FLOAT(cosine, 1.0f); + vfpu_sincos(1.0f, sine, cosine); + EXPECT_APPROX_EQ_FLOAT(sine, 1.0f); + EXPECT_APPROX_EQ_FLOAT(cosine, 0.0f); + vfpu_sincos(2.0f, sine, cosine); + EXPECT_APPROX_EQ_FLOAT(sine, 0.0f); + EXPECT_APPROX_EQ_FLOAT(cosine, -1.0f); + vfpu_sincos(3.0f, sine, cosine); + EXPECT_APPROX_EQ_FLOAT(sine, -1.0f); + EXPECT_APPROX_EQ_FLOAT(cosine, 0.0f); + vfpu_sincos(4.0f, sine, cosine); + EXPECT_EQ_FLOAT(sine, 0.0f); + EXPECT_EQ_FLOAT(cosine, 1.0f); + vfpu_sincos(5.0f, sine, cosine); + EXPECT_APPROX_EQ_FLOAT(sine, 1.0f); + EXPECT_APPROX_EQ_FLOAT(cosine, 0.0f); + + for (float angle = -10.0f; angle < 10.0f; angle++) { + vfpu_sincos(angle, sine, cosine); + EXPECT_APPROX_EQ_FLOAT(sine, sinf(angle * M_PI_2)); + EXPECT_APPROX_EQ_FLOAT(cosine, cosf(angle * M_PI_2)); + } + return true; +} + int main(int argc, const char *argv[]) { cpu_info.bNEON = true; cpu_info.bVFP = true; @@ -393,7 +424,8 @@ int main(int argc, const char *argv[]) { g_Config.bEnableLogging = true; //TestAsin(); //TestSinCos(); - TestArmEmitter(); + //TestArmEmitter(); + TestVFPUSinCos(); //TestMathUtil(); //TestParsers(); return 0;