mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-01-24 23:11:14 +01:00
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
This commit is contained in:
parent
f67660cbfe
commit
0bee242493
@ -22,9 +22,64 @@
|
|||||||
|
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
static u32 saved_sse_state = _mm_getcsr();
|
static u32 saved_sse_state = _mm_getcsr();
|
||||||
static const u32 default_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()
|
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);
|
MatrixMul(4, a.data, b.data, result.data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -83,8 +83,29 @@ inline double FlushToZeroAsFloat(double d)
|
|||||||
return x.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 float pow2f(float x) {return x * x;}
|
||||||
inline double pow2(double 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))
|
#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
|
class Matrix33
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -25,8 +25,8 @@
|
|||||||
** ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
** ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// A simple and portable program used to generate a blank FAT32 image file
|
// A simple and portable piece of code used to generate a blank FAT32 image file.
|
||||||
// Modified for Dolphin-emu
|
// Modified for Dolphin.
|
||||||
|
|
||||||
#include "SDCardUtil.h"
|
#include "SDCardUtil.h"
|
||||||
|
|
||||||
|
@ -21,7 +21,6 @@
|
|||||||
#include "Boot_ELF.h"
|
#include "Boot_ELF.h"
|
||||||
#include "Boot_WiiWAD.h"
|
#include "Boot_WiiWAD.h"
|
||||||
#include "ElfReader.h"
|
#include "ElfReader.h"
|
||||||
#include "MappedFile.h"
|
|
||||||
|
|
||||||
bool CBoot::IsElfWii(const char *filename)
|
bool CBoot::IsElfWii(const char *filename)
|
||||||
{
|
{
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
#include <float.h>
|
#include <float.h>
|
||||||
|
|
||||||
#include "Common.h"
|
#include "Common.h"
|
||||||
|
#include "MathUtil.h"
|
||||||
#include "ChunkFile.h"
|
#include "ChunkFile.h"
|
||||||
|
|
||||||
#include "../HW/Memmap.h"
|
#include "../HW/Memmap.h"
|
||||||
@ -355,72 +356,6 @@ void OnIdleIL()
|
|||||||
CoreTiming::Idle();
|
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
|
} // namespace
|
||||||
|
|
||||||
|
|
||||||
@ -428,7 +363,9 @@ int PPCFPClass(double dvalue)
|
|||||||
|
|
||||||
void UpdateFPRF(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() {
|
void UpdateFEX() {
|
||||||
|
@ -91,8 +91,6 @@ volatile CPUState *GetStatePtr(); // this oddity is here instead of an extern d
|
|||||||
void CompactCR();
|
void CompactCR();
|
||||||
void ExpandCR();
|
void ExpandCR();
|
||||||
|
|
||||||
int PPCFPClass(double dvalue);
|
|
||||||
|
|
||||||
void OnIdle(u32 _uThreadAddr);
|
void OnIdle(u32 _uThreadAddr);
|
||||||
void OnIdleIL();
|
void OnIdleIL();
|
||||||
|
|
||||||
|
@ -22,7 +22,6 @@
|
|||||||
#include "CompressedBlob.h"
|
#include "CompressedBlob.h"
|
||||||
#include "FileBlob.h"
|
#include "FileBlob.h"
|
||||||
#include "DriveBlob.h"
|
#include "DriveBlob.h"
|
||||||
#include "MappedFile.h"
|
|
||||||
|
|
||||||
namespace DiscIO
|
namespace DiscIO
|
||||||
{
|
{
|
||||||
|
@ -18,6 +18,8 @@
|
|||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
|
#include "StringUtil.h"
|
||||||
|
#include "MathUtil.h"
|
||||||
#include "PowerPC/PowerPC.h"
|
#include "PowerPC/PowerPC.h"
|
||||||
#include "HW/SI_DeviceGCController.h"
|
#include "HW/SI_DeviceGCController.h"
|
||||||
|
|
||||||
@ -25,32 +27,68 @@ using namespace std;
|
|||||||
|
|
||||||
int fail_count = 0;
|
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) \
|
#define EXPECT_EQ(a, b) \
|
||||||
if ((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; \
|
cout << "Actual: " << a << endl << "Expected: " << b << endl; \
|
||||||
fail_count++; \
|
fail_count++; \
|
||||||
}
|
}
|
||||||
|
|
||||||
void CoreTests()
|
void CoreTests()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void MathTests()
|
||||||
{
|
{
|
||||||
// Tests that our fp classifier is correct.
|
// Tests that our fp classifier is correct.
|
||||||
EXPECT_EQ(PowerPC::PPCFPClass(1.0), 0x4);
|
EXPECT_EQ(MathUtil::ClassifyFP(1.0), MathUtil::PPC_FPCLASS_PN);
|
||||||
EXPECT_EQ(PowerPC::PPCFPClass(-1.0), 0x8);
|
EXPECT_EQ(MathUtil::ClassifyFP(-1.0), 0x8);
|
||||||
EXPECT_EQ(PowerPC::PPCFPClass(1235223.0), 0x4);
|
EXPECT_EQ(MathUtil::ClassifyFP(1235223.0), 0x4);
|
||||||
EXPECT_EQ(PowerPC::PPCFPClass(-126323521.0), 0x8);
|
EXPECT_EQ(MathUtil::ClassifyFP(-126323521.0), 0x8);
|
||||||
EXPECT_EQ(PowerPC::PPCFPClass(1.0E-308), 0x14);
|
EXPECT_EQ(MathUtil::ClassifyFP(1.0E-308), 0x14);
|
||||||
EXPECT_EQ(PowerPC::PPCFPClass(-1.0E-308), 0x18);
|
EXPECT_EQ(MathUtil::ClassifyFP(-1.0E-308), 0x18);
|
||||||
EXPECT_EQ(PowerPC::PPCFPClass(0.0), 0x2);
|
EXPECT_EQ(MathUtil::ClassifyFP(0.0), 0x2);
|
||||||
EXPECT_EQ(PowerPC::PPCFPClass(-0.0), 0x12);
|
EXPECT_EQ(MathUtil::ClassifyFP(-0.0), 0x12);
|
||||||
EXPECT_EQ(PowerPC::PPCFPClass(HUGE_VAL), 0x5); // weird #define for infinity
|
EXPECT_EQ(MathUtil::ClassifyFP(HUGE_VAL), 0x5); // weird #define for infinity
|
||||||
EXPECT_EQ(PowerPC::PPCFPClass(-HUGE_VAL), 0x9);
|
EXPECT_EQ(MathUtil::ClassifyFP(-HUGE_VAL), 0x9);
|
||||||
EXPECT_EQ(PowerPC::PPCFPClass(sqrt(-1.0)), 0x11); // SNAN
|
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[])
|
int main(int argc, _TCHAR* argv[])
|
||||||
{
|
{
|
||||||
CoreTests();
|
CoreTests();
|
||||||
|
MathTests();
|
||||||
|
StringTests();
|
||||||
if (fail_count == 0)
|
if (fail_count == 0)
|
||||||
{
|
{
|
||||||
printf("All tests passed.\n");
|
printf("All tests passed.\n");
|
||||||
|
Loading…
x
Reference in New Issue
Block a user