From 0bee242493340ac9d5de3e2574ccf31876322a67 Mon Sep 17 00:00:00 2001 From: hrydgard Date: Sun, 14 Jun 2009 11:30:33 +0000 Subject: [PATCH] Unbreak the build (sorry, forgot a few includes), move FP classification to MathUtil, add some more unittests. git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@3442 8ced0084-cf51-0410-be5f-012b33b47a6e --- Source/Core/Common/Src/MathUtil.cpp | 56 +++++++++++++++++++ Source/Core/Common/Src/MathUtil.h | 28 +++++++++- Source/Core/Common/Src/SDCardUtil.cpp | 4 +- Source/Core/Core/Src/Boot/Boot_ELF.cpp | 1 - Source/Core/Core/Src/PowerPC/PowerPC.cpp | 71 ++---------------------- Source/Core/Core/Src/PowerPC/PowerPC.h | 2 - Source/Core/DiscIO/Src/Blob.cpp | 1 - Source/UnitTests/UnitTests.cpp | 62 +++++++++++++++++---- 8 files changed, 138 insertions(+), 87 deletions(-) diff --git a/Source/Core/Common/Src/MathUtil.cpp b/Source/Core/Common/Src/MathUtil.cpp index e2dbaa0640..88e929ec41 100644 --- a/Source/Core/Common/Src/MathUtil.cpp +++ b/Source/Core/Common/Src/MathUtil.cpp @@ -22,9 +22,64 @@ #include +namespace { + static u32 saved_sse_state = _mm_getcsr(); static const u32 default_sse_state = _mm_getcsr(); +} + +namespace MathUtil +{ + +int ClassifyFP(double dvalue) +{ + // TODO: Optimize the below to be as fast as possible. + IntDouble value; + value.d = dvalue; + // 5 bits (C, <, >, =, ?) + // easy cases first + if (value.i == 0) { + // positive zero + return 0x2; + } else if (value.i == 0x8000000000000000ULL) { + // negative zero + return 0x12; + } else if (value.i == 0x7FF0000000000000ULL) { + // positive inf + return 0x5; + } else if (value.i == 0xFFF0000000000000ULL) { + // negative inf + return 0x9; + } else { + // OK let's dissect this thing. + int sign = value.i >> 63; + int exp = (int)((value.i >> 52) & 0x7FF); + if (exp >= 1 && exp <= 2046) { + // Nice normalized number. + if (sign) { + return 0x8; // negative + } else { + return 0x4; // positive + } + } + u64 mantissa = value.i & 0x000FFFFFFFFFFFFFULL; + if (exp == 0 && mantissa) { + // Denormalized number. + if (sign) { + return 0x18; + } else { + return 0x14; + } + } else if (exp == 0x7FF && mantissa /* && mantissa_top*/) { + return 0x11; // Quiet NAN + } + } + + return 0x4; +} + +} // namespace void LoadDefaultSSEState() { @@ -145,3 +200,4 @@ void Matrix44::Multiply(const Matrix44 &a, const Matrix44 &b, Matrix44 &result) { MatrixMul(4, a.data, b.data, result.data); } + diff --git a/Source/Core/Common/Src/MathUtil.h b/Source/Core/Common/Src/MathUtil.h index 1399ee1f76..1226fc4f48 100644 --- a/Source/Core/Common/Src/MathUtil.h +++ b/Source/Core/Common/Src/MathUtil.h @@ -83,8 +83,29 @@ inline double FlushToZeroAsFloat(double d) return x.d; } -} // namespace MathUtil +enum PPCFpClass +{ + PPC_FPCLASS_QNAN = 0x11, + PPC_FPCLASS_NINF = 0x9, + PPC_FPCLASS_NN = 0x8, + PPC_FPCLASS_ND = 0x18, + PPC_FPCLASS_NZ = 0x12, + PPC_FPCLASS_PZ = 0x2, + PPC_FPCLASS_PD = 0x14, + PPC_FPCLASS_PN = 0x4, + PPC_FPCLASS_PINF = 0x5, +}; +// Uses PowerPC conventions for the return value, so it can be easily +// used directly in CPU emulation. +int ClassifyFP(double dvalue); + +// TODO: More efficient float version. +inline int ClassifyFP(float fvalue) { + ClassifyFP((double)fvalue); +} + +} // namespace MathUtil inline float pow2f(float x) {return x * x;} inline double pow2(double x) {return x * x;} @@ -103,7 +124,10 @@ void LoadDefaultSSEState(); #define ROUND_UP(x, a) (((x) + (a) - 1) & ~((a) - 1)) -// ugly matrix implementation + +// Tiny matrix/vector library. +// Used for things like Free-Look in the gfx plugin. + class Matrix33 { public: diff --git a/Source/Core/Common/Src/SDCardUtil.cpp b/Source/Core/Common/Src/SDCardUtil.cpp index 27d4895d2c..3002b89db7 100644 --- a/Source/Core/Common/Src/SDCardUtil.cpp +++ b/Source/Core/Common/Src/SDCardUtil.cpp @@ -25,8 +25,8 @@ ** ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -// A simple and portable program used to generate a blank FAT32 image file -// Modified for Dolphin-emu +// A simple and portable piece of code used to generate a blank FAT32 image file. +// Modified for Dolphin. #include "SDCardUtil.h" diff --git a/Source/Core/Core/Src/Boot/Boot_ELF.cpp b/Source/Core/Core/Src/Boot/Boot_ELF.cpp index 5b1ce87dd9..8a52da2ef3 100644 --- a/Source/Core/Core/Src/Boot/Boot_ELF.cpp +++ b/Source/Core/Core/Src/Boot/Boot_ELF.cpp @@ -21,7 +21,6 @@ #include "Boot_ELF.h" #include "Boot_WiiWAD.h" #include "ElfReader.h" -#include "MappedFile.h" bool CBoot::IsElfWii(const char *filename) { diff --git a/Source/Core/Core/Src/PowerPC/PowerPC.cpp b/Source/Core/Core/Src/PowerPC/PowerPC.cpp index d780925896..534af97d6a 100644 --- a/Source/Core/Core/Src/PowerPC/PowerPC.cpp +++ b/Source/Core/Core/Src/PowerPC/PowerPC.cpp @@ -18,6 +18,7 @@ #include #include "Common.h" +#include "MathUtil.h" #include "ChunkFile.h" #include "../HW/Memmap.h" @@ -355,72 +356,6 @@ void OnIdleIL() CoreTiming::Idle(); } -int PPCFPClass(double dvalue) -{ - /* // win32-only reference implementation, to compare to: - switch (_fpclass(dvalue)) - { - case _FPCLASS_SNAN: - case _FPCLASS_QNAN: return 0x11; - case _FPCLASS_NINF: return 0x9; - case _FPCLASS_NN: return 0x8; - case _FPCLASS_ND: return 0x18; - case _FPCLASS_NZ: return 0x12; - case _FPCLASS_PZ: return 0x2; - case _FPCLASS_PD: return 0x14; - case _FPCLASS_PN: return 0x4; - case _FPCLASS_PINF: return 0x5; - default: return 0x4; - }*/ - - // TODO: Optimize the below to be as fast as possible. - union { - double d; - u64 i; - } value; - value.d = dvalue; - // 5 bits (C, <, >, =, ?) - // easy cases first - if (value.i == 0) { - // positive zero - return 0x2; - } else if (value.i == 0x8000000000000000ULL) { - // negative zero - return 0x12; - } else if (value.i == 0x7FF0000000000000ULL) { - // positive inf - return 0x5; - } else if (value.i == 0xFFF0000000000000ULL) { - // negative inf - return 0x9; - } else { - // OK let's dissect this thing. - int sign = value.i >> 63; - int exp = (int)((value.i >> 52) & 0x7FF); - if (exp >= 1 && exp <= 2046) { - // Nice normalized number. - if (sign) { - return 0x8; // negative - } else { - return 0x4; // positive - } - } - u64 mantissa = value.i & 0x000FFFFFFFFFFFFFULL; - if (exp == 0 && mantissa) { - // Denormalized number. - if (sign) { - return 0x18; - } else { - return 0x14; - } - } else if (exp == 0x7FF && mantissa /* && mantissa_top*/) { - return 0x11; // Quiet NAN - } - } - - return 0x4; -} - } // namespace @@ -428,7 +363,9 @@ int PPCFPClass(double dvalue) void UpdateFPRF(double dvalue) { - FPSCR.FPRF = PowerPC::PPCFPClass(dvalue); + FPSCR.FPRF = MathUtil::ClassifyFP(dvalue); + //if (FPSCR.FPRF == 0x11) + // PanicAlert("QNAN alert"); } void UpdateFEX() { diff --git a/Source/Core/Core/Src/PowerPC/PowerPC.h b/Source/Core/Core/Src/PowerPC/PowerPC.h index d3e23dc8d6..1540c72aa4 100644 --- a/Source/Core/Core/Src/PowerPC/PowerPC.h +++ b/Source/Core/Core/Src/PowerPC/PowerPC.h @@ -91,8 +91,6 @@ volatile CPUState *GetStatePtr(); // this oddity is here instead of an extern d void CompactCR(); void ExpandCR(); -int PPCFPClass(double dvalue); - void OnIdle(u32 _uThreadAddr); void OnIdleIL(); diff --git a/Source/Core/DiscIO/Src/Blob.cpp b/Source/Core/DiscIO/Src/Blob.cpp index 76f9bb2d79..2d8e53c285 100644 --- a/Source/Core/DiscIO/Src/Blob.cpp +++ b/Source/Core/DiscIO/Src/Blob.cpp @@ -22,7 +22,6 @@ #include "CompressedBlob.h" #include "FileBlob.h" #include "DriveBlob.h" -#include "MappedFile.h" namespace DiscIO { diff --git a/Source/UnitTests/UnitTests.cpp b/Source/UnitTests/UnitTests.cpp index b258a862bb..f06f0987f3 100644 --- a/Source/UnitTests/UnitTests.cpp +++ b/Source/UnitTests/UnitTests.cpp @@ -18,6 +18,8 @@ #include #include +#include "StringUtil.h" +#include "MathUtil.h" #include "PowerPC/PowerPC.h" #include "HW/SI_DeviceGCController.h" @@ -25,32 +27,68 @@ using namespace std; int fail_count = 0; +#define EXPECT_TRUE(a) \ + if (!a) { \ + cout << "FAIL (" __FUNCTION__ "): " << #a << " is false" << endl; \ + cout << "Value: " << a << endl << "Expected: true" << endl; \ + fail_count++; \ + } + +#define EXPECT_FALSE(a) \ + if (a) { \ + cout << "FAIL (" __FUNCTION__ "): " << #a << " is true" << endl; \ + cout << "Value: " << a << endl << "Expected: false" << endl; \ + fail_count++; \ + } + #define EXPECT_EQ(a, b) \ if ((a) != (b)) { \ - cout << "FAIL: " << #a << " %s is not equal to " << #b << endl; \ + cout << "FAIL (" __FUNCTION__ "): " << #a << " is not equal to " << #b << endl; \ cout << "Actual: " << a << endl << "Expected: " << b << endl; \ fail_count++; \ } void CoreTests() +{ +} + +void MathTests() { // Tests that our fp classifier is correct. - EXPECT_EQ(PowerPC::PPCFPClass(1.0), 0x4); - EXPECT_EQ(PowerPC::PPCFPClass(-1.0), 0x8); - EXPECT_EQ(PowerPC::PPCFPClass(1235223.0), 0x4); - EXPECT_EQ(PowerPC::PPCFPClass(-126323521.0), 0x8); - EXPECT_EQ(PowerPC::PPCFPClass(1.0E-308), 0x14); - EXPECT_EQ(PowerPC::PPCFPClass(-1.0E-308), 0x18); - EXPECT_EQ(PowerPC::PPCFPClass(0.0), 0x2); - EXPECT_EQ(PowerPC::PPCFPClass(-0.0), 0x12); - EXPECT_EQ(PowerPC::PPCFPClass(HUGE_VAL), 0x5); // weird #define for infinity - EXPECT_EQ(PowerPC::PPCFPClass(-HUGE_VAL), 0x9); - EXPECT_EQ(PowerPC::PPCFPClass(sqrt(-1.0)), 0x11); // SNAN + EXPECT_EQ(MathUtil::ClassifyFP(1.0), MathUtil::PPC_FPCLASS_PN); + EXPECT_EQ(MathUtil::ClassifyFP(-1.0), 0x8); + EXPECT_EQ(MathUtil::ClassifyFP(1235223.0), 0x4); + EXPECT_EQ(MathUtil::ClassifyFP(-126323521.0), 0x8); + EXPECT_EQ(MathUtil::ClassifyFP(1.0E-308), 0x14); + EXPECT_EQ(MathUtil::ClassifyFP(-1.0E-308), 0x18); + EXPECT_EQ(MathUtil::ClassifyFP(0.0), 0x2); + EXPECT_EQ(MathUtil::ClassifyFP(-0.0), 0x12); + EXPECT_EQ(MathUtil::ClassifyFP(HUGE_VAL), 0x5); // weird #define for infinity + EXPECT_EQ(MathUtil::ClassifyFP(-HUGE_VAL), 0x9); + EXPECT_EQ(MathUtil::ClassifyFP(sqrt(-1.0)), 0x11); // SNAN + + EXPECT_FALSE(MathUtil::IsNAN(1.0)); + EXPECT_TRUE(MathUtil::IsNAN(sqrt(-1.0))); + EXPECT_FALSE(MathUtil::IsSNAN(sqrt(-1.0))); + // EXPECT_TRUE(MathUtil::IsQNAN(sqrt(-1.0))); // Hmm... + EXPECT_EQ(pow2(2.0), 4.0); + EXPECT_EQ(pow2(-2.0), 4.0); +} + +void StringTests() +{ + EXPECT_EQ(StripSpaces(" abc "), "abc"); + EXPECT_EQ(StripNewline(" abc \n"), " abc "); + EXPECT_EQ(StripNewline(" abc \n "), " abc \n "); + EXPECT_EQ(StripQuotes("\"abc\""), "abc"); + EXPECT_EQ(StripQuotes("\"abc\" "), "\"abc\" "); } int main(int argc, _TCHAR* argv[]) { CoreTests(); + MathTests(); + StringTests(); if (fail_count == 0) { printf("All tests passed.\n");