kerneltest/e32test/math/t_vfp.cpp
changeset 0 a41df078684a
child 31 56f325a607ea
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kerneltest/e32test/math/t_vfp.cpp	Mon Oct 19 15:55:17 2009 +0100
@@ -0,0 +1,1236 @@
+// Copyright (c) 2003-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of the License "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+// e32test\math\t_vfp.cpp
+// Overview:
+// Test the ARM Vector Floating Point operations.
+// API Information:
+// VFP
+// Details:
+// - Check that the HAL agrees with the hardware about whether
+// VFP is supported.
+// - Test setting VFP to IEEE with no exceptions mode, if IEEE mode is
+// supported, otherwise leave the mode alone.
+// - Test single and double precision vector floating point operations:
+// ABS, NEG, ADD, SUB, MUL, DIV, NMUL, SQRT, MAC, MSC, NMAC and NMSC.
+// Verify results are as expected - if IEEE mode was set, verify
+// bit-for-bit, in accordance with the IEEE specification, otherwise
+// use normal floating point equality.
+// - Test VFP context save.
+// - Test various VFP operations that cause bounces to support code if
+// IEEE mode is supported.
+// - Test setting VFP to RunFast mode if RunFast mode is supported.
+// - Test setting VFP rounding mode.
+// - Test inheriting VFP mode to created threads.
+// Platforms/Drives/Compatibility:
+// All 
+// Assumptions/Requirement/Pre-requisites:
+// Failures and causes:
+// Base Port information:
+// 
+//
+
+//! @file
+//! @SYMTestCaseID KBASE-0017-T_VFP
+//! @SYMTestCaseDesc VFPv2 general functionality and bounce handling
+//! @SYMREQ 5159
+//! @SYMTestPriority Critical
+//! @SYMTestActions Check VFP functions correctly in all modes and that mode switching works correctly.
+//! @SYMTestExpectedResults Test runs until this message is emitted: RTEST: SUCCESS : T_VFP test completed O.K.
+//! @SYMTestType UT
+
+#include "t_vfp.h"
+#define __E32TEST_EXTENSION__
+#include <e32test.h>
+#include <e32math.h>
+#include <hal.h>
+#include <e32svr.h>
+#include <u32hal.h>
+
+RTest test(_L("T_VFP"));
+TUint32 FPSID;
+TUint32 ArchVersion; 
+TBool Double;
+TBool IEEEMode;
+TInt CPUs;
+TInt CurrentCpu1;
+TInt CurrentCpu2;
+
+typedef void TSglTest(const TReal32* aArgs, TReal32* aResults);
+typedef void TDblTest(const TReal64* aArgs, TReal64* aResults);
+
+TBool DetectVFP()
+	{
+	TInt r = UserSvr::HalFunction(EHalGroupKernel, EKernelHalFloatingPointSystemId, &FPSID, NULL);
+	return (r==KErrNone);
+	}
+
+TInt TestVFPInitThreadFn(TAny* aPtr)
+	{
+	UserSvr::HalFunction(EHalGroupKernel, EKernelHalLockThreadToCpu, (TAny*)CurrentCpu1, 0);
+	TReal32* p = (TReal32*)aPtr;
+	TInt i;
+	for (i=0; i<32; ++i)
+		*p++ = Vfp::SReg(i);
+	return 0;
+	}
+
+void TestVFPInitialState()
+	{
+	for (CurrentCpu1 = 0; CurrentCpu1 < CPUs; CurrentCpu1++)
+		{
+		TReal32 f[32];
+		RThread t;
+		TInt r = t.Create(KNullDesC, &TestVFPInitThreadFn, 0x1000, NULL, f);
+		test(r==KErrNone);
+		TRequestStatus s;
+		t.Logon(s);
+		t.Resume();
+		User::WaitForRequest(s);
+		TInt xt = t.ExitType();
+		TInt xr = t.ExitReason();
+		test(xt == EExitKill && xr == KErrNone);
+		CLOSE_AND_WAIT(t);
+		UserSvr::HalFunction(EHalGroupKernel, EKernelHalLockThreadToCpu, (TAny*)CurrentCpu1, 0);
+		test.Printf(_L("FPSCR = %08x for core %d\n"), Vfp::Fpscr(), CurrentCpu1);
+		const TUint32* p = (const TUint32*)f;
+		for (TInt i=0; i<32; ++i)
+			{
+			if (f[i] != 0.0f)
+				{
+				test.Printf(_L("S%d = 0x%08x\n"), i, p[i]);
+				test(f[i] == 0.0f);
+				}
+			}
+		}
+	}
+
+void TestVFPSglRegs(TInt aIter=2)
+	{
+	TInt i;
+	TInt j;
+	TInt nSglRegs=0; 
+
+	switch(ArchVersion)	
+		{ 
+		case ARCH_VERSION_VFPV2:
+		case ARCH_VERSION_VFPV3_SUBARCH_V2:
+		case ARCH_VERSION_VFPV3_SUBARCH_NULL:
+		case ARCH_VERSION_VFPV3_SUBARCH_V3:
+			nSglRegs = 32;
+			break; 		
+		case 0:
+		default:
+			__ASSERT_ALWAYS(0, User::Panic(_L("Bad VFP version"),__LINE__)); 
+			/* NOTREACHED */
+		} 
+
+	for (i=0; i<aIter; ++i)
+		{
+		for (j=0; j<nSglRegs; ++j)
+			{
+			TInt32 f = i + j;
+			Vfp::SetSReg(f, j);
+			}
+		for (j=0; j<nSglRegs; ++j)
+			{
+			TInt32 f = i + j;
+			TInt32 g = Vfp::SRegInt(j);
+			test(f == g);
+			}
+		}
+	}
+
+TInt TestVFPSglRegsThread(TAny*)
+	{
+	UserSvr::HalFunction(EHalGroupKernel, EKernelHalLockThreadToCpu, (TAny*)CurrentCpu1, 0);
+	TestVFPSglRegs(KMaxTInt);
+	return 0;
+	}
+
+void TestVFPDblRegs(TInt aIter=2)
+	{
+	TInt i;
+	TInt j;
+	TInt nDblRegs=0; 
+
+	switch(ArchVersion)
+		{ 
+		case ARCH_VERSION_VFPV2:
+			{
+			nDblRegs = 16;
+			break;
+			}
+		case ARCH_VERSION_VFPV3_SUBARCH_V2:
+		case ARCH_VERSION_VFPV3_SUBARCH_NULL:
+		case ARCH_VERSION_VFPV3_SUBARCH_V3:
+			{
+			TInt vfpType;
+			TInt ret = HAL::Get(HALData::EHardwareFloatingPoint, vfpType);
+			if (ret == KErrNone && vfpType == EFpTypeVFPv3)
+				nDblRegs = 32;
+			else
+				nDblRegs = 16;
+			break;
+				}
+		case 0:
+		default:
+			__ASSERT_ALWAYS(0, User::Panic(_L("Bad VFP version"),__LINE__)); 
+		} 
+
+
+	for (i=0; i<aIter; ++i)
+		{
+		for (j=0; j<nDblRegs; ++j)
+			{
+			TInt64 f = i + j + KMaxTUint;
+			Vfp::SetDReg(f, j);
+			}
+		for (j=0; j<nDblRegs; ++j)
+			{
+			TInt64 f = i + j + KMaxTUint;
+			TInt64 g = Vfp::DRegInt(j);
+			test(f == g);
+			}
+		}
+	}
+
+TInt TestVFPDblRegsThread(TAny*)
+	{
+	UserSvr::HalFunction(EHalGroupKernel, EKernelHalLockThreadToCpu, (TAny*)CurrentCpu2, 0);
+	TestVFPDblRegs(KMaxTInt);
+	return 0;
+	}
+
+void TestVFPContextSave()
+	{
+	for (CurrentCpu2 = 0; CurrentCpu2 < CPUs; CurrentCpu2++)
+		{
+		for (CurrentCpu1 = 0; CurrentCpu1 < CPUs; CurrentCpu1++)
+			{
+			TThreadFunction tf1 = &TestVFPSglRegsThread;
+			TThreadFunction tf2 = Double ? &TestVFPDblRegsThread : &TestVFPSglRegsThread;
+			RThread t1, t2;
+			TInt r;
+			r = t1.Create(KNullDesC, tf1, 0x1000, 0x1000, 0x1000, NULL);
+			test(r==KErrNone);
+			t1.SetPriority(EPriorityLess);
+			r = t2.Create(KNullDesC, tf2, 0x1000, 0x1000, 0x1000, NULL);
+			test(r==KErrNone);
+			t2.SetPriority(EPriorityLess);
+			TRequestStatus s1, s2;
+			t1.Logon(s1);
+			t2.Logon(s2);
+			t1.Resume();
+			t2.Resume();
+			test.Printf(_L("Let threads run concurrently (cores %d and %d)\n"), CurrentCpu1, CurrentCpu2);
+			User::After(20*1000*1000/CPUs);
+
+			test.Printf(_L("Kill threads\n"));
+			t1.Kill(0);
+			t2.Kill(0);
+			User::WaitForRequest(s1);
+			User::WaitForRequest(s2);
+			test(t1.ExitType()==EExitKill && t1.ExitReason()==KErrNone);
+			test(t2.ExitType()==EExitKill && t2.ExitReason()==KErrNone);
+			CLOSE_AND_WAIT(t1);
+			CLOSE_AND_WAIT(t2);
+			}
+		}
+	}
+
+TInt TestBounceCtxThread1(TAny*)
+	{
+	for(TInt iter=0; iter<KMaxTInt; ++iter)
+		{
+		Vfp::SReg(0);
+		}
+	return KErrNone;
+	}
+
+TInt TestBounceCtxThread2(TAny*)
+	{
+	TInt start_rep = 0x00800000; // smallest single precision normal number, 1*2^-126
+	TReal32 start = *(TReal32*)&start_rep;
+	for(TInt iter=0; iter<KMaxTInt; ++iter)
+		{
+		Vfp::SetSReg(start, 1);
+		Vfp::SetSReg(2.0f, 2);
+		Vfp::DivS();
+		Vfp::CpyS0(1);
+		Vfp::MulS();
+		Vfp::CpyS0(1);
+		TReal32 end = Vfp::SReg(0);
+		TInt end_rep = *(TInt*)&end;
+		if (start_rep != end_rep)
+			{
+			RDebug::Printf("mismatch in iter %d, start %08x end %08x\n", iter, start_rep, end_rep);
+			test(0);
+			}
+		}
+	return KErrNone;
+	}
+
+void DoBounceContextSwitchTests()
+	{
+	RThread t1, t2;
+	TInt r;
+	r = t1.Create(KNullDesC, &TestBounceCtxThread1, 0x1000, 0x1000, 0x1000, NULL);
+	test(r==KErrNone);
+	t1.SetPriority(EPriorityLess);
+	r = t2.Create(KNullDesC, &TestBounceCtxThread2, 0x1000, 0x1000, 0x1000, NULL);
+	test(r==KErrNone);
+	t2.SetPriority(EPriorityLess);
+	TRequestStatus s1, s2;
+	t1.Logon(s1);
+	t2.Logon(s2);
+	t1.Resume();
+	t2.Resume();
+	test.Printf(_L("Let threads run concurrently ...\n"));
+	User::After(20*1000*1000);
+
+	test.Printf(_L("Kill threads\n"));
+	t1.Kill(0);
+	t2.Kill(0);
+	User::WaitForRequest(s1);
+	User::WaitForRequest(s2);
+	test(t1.ExitType()==EExitKill && t1.ExitReason()==KErrNone);
+	test(t2.ExitType()==EExitKill && t2.ExitReason()==KErrNone);
+	CLOSE_AND_WAIT(t1);
+	CLOSE_AND_WAIT(t2);
+	}
+
+void TestAbsS(const TReal32* a, TReal32* r)
+	{
+	Vfp::SetSReg(a[0], 1);
+	Vfp::AbsS();
+	r[0] = Vfp::SReg(0);
+	r[1] = Abs(a[0]);
+	}
+
+void TestAddS(const TReal32* a, TReal32* r)
+	{
+	Vfp::SetSReg(a[0], 1);
+	Vfp::SetSReg(a[1], 2);
+	Vfp::AddS();
+	r[0] = Vfp::SReg(0);
+	r[1] = a[0] + a[1];
+	}
+
+void TestDivS(const TReal32* a, TReal32* r)
+	{
+	Vfp::SetSReg(a[0], 1);
+	Vfp::SetSReg(a[1], 2);
+	Vfp::DivS();
+	r[0] = Vfp::SReg(0);
+	TRealX x(a[0]);
+	TRealX y(a[1]);
+	x.DivEq(y);
+	r[1] = (TReal32)x;
+	}
+
+void TestMacS(const TReal32* a, TReal32* r)
+	{
+	Vfp::SetSReg(a[0], 0);
+	Vfp::SetSReg(a[1], 1);
+	Vfp::SetSReg(a[2], 2);
+	Vfp::MacS();
+	r[0] = Vfp::SReg(0);
+	r[1] = a[0] + a[1] * a[2];
+	}
+
+void TestMscS(const TReal32* a, TReal32* r)
+	{
+	Vfp::SetSReg(a[0], 0);
+	Vfp::SetSReg(a[1], 1);
+	Vfp::SetSReg(a[2], 2);
+	Vfp::MscS();
+	r[0] = Vfp::SReg(0);
+	r[1] = a[1] * a[2] - a[0];
+	}
+
+void TestMulS(const TReal32* a, TReal32* r)
+	{
+	Vfp::SetSReg(a[0], 1);
+	Vfp::SetSReg(a[1], 2);
+	Vfp::MulS();
+	r[0] = Vfp::SReg(0);
+	TRealX x(a[0]);
+	TRealX y(a[1]);
+	x.MultEq(y);
+	r[1] = (TReal32)x;
+	}
+
+void TestNegS(const TReal32* a, TReal32* r)
+	{
+	Vfp::SetSReg(a[0], 1);
+	Vfp::NegS();
+	r[0] = Vfp::SReg(0);
+	r[1] = -a[0];
+	}
+
+void TestNMacS(const TReal32* a, TReal32* r)
+	{
+	Vfp::SetSReg(a[0], 0);
+	Vfp::SetSReg(a[1], 1);
+	Vfp::SetSReg(a[2], 2);
+	Vfp::NMacS();
+	r[0] = Vfp::SReg(0);
+	r[1] = a[0] - a[1] * a[2];
+	}
+
+void TestNMscS(const TReal32* a, TReal32* r)
+	{
+	Vfp::SetSReg(a[0], 0);
+	Vfp::SetSReg(a[1], 1);
+	Vfp::SetSReg(a[2], 2);
+	Vfp::NMscS();
+	r[0] = Vfp::SReg(0);
+	r[1] = -a[1] * a[2] - a[0];
+	}
+
+void TestNMulS(const TReal32* a, TReal32* r)
+	{
+	Vfp::SetSReg(a[0], 1);
+	Vfp::SetSReg(a[1], 2);
+	Vfp::NMulS();
+	r[0] = Vfp::SReg(0);
+	TRealX x(a[0]);
+	TRealX y(a[1]);
+	x.MultEq(y);
+	r[1] = -(TReal32)x;
+	}
+
+void TestSqrtS(const TReal32* a, TReal32* r)
+	{
+	Vfp::SetSReg(a[0], 1);
+	Vfp::SqrtS();
+	r[0] = Vfp::SReg(0);
+	TReal x = a[0];
+	TReal y;
+	Math::Sqrt(y, x);
+	r[1] = (TReal32)y;
+	}
+
+void TestSubS(const TReal32* a, TReal32* r)
+	{
+	Vfp::SetSReg(a[0], 1);
+	Vfp::SetSReg(a[1], 2);
+	Vfp::SubS();
+	r[0] = Vfp::SReg(0);
+	r[1] = a[0] - a[1];
+	}
+
+
+
+void TestAbsD(const TReal64* a, TReal64* r)
+	{
+	Vfp::SetDReg(a[0], 1);
+	Vfp::AbsD();
+	r[0] = Vfp::DReg(0);
+	r[1] = Abs(a[0]);
+	}
+
+void TestAddD(const TReal64* a, TReal64* r)
+	{
+	Vfp::SetDReg(a[0], 1);
+	Vfp::SetDReg(a[1], 2);
+	Vfp::AddD();
+	r[0] = Vfp::DReg(0);
+	r[1] = a[0] + a[1];
+	}
+
+void TestDivD(const TReal64* a, TReal64* r)
+	{
+	Vfp::SetDReg(a[0], 1);
+	Vfp::SetDReg(a[1], 2);
+	Vfp::DivD();
+	r[0] = Vfp::DReg(0);
+	TRealX x(a[0]);
+	TRealX y(a[1]);
+	x.DivEq(y);
+	r[1] = (TReal64)x;
+	}
+
+void TestMacD(const TReal64* a, TReal64* r)
+	{
+	Vfp::SetDReg(a[0], 0);
+	Vfp::SetDReg(a[1], 1);
+	Vfp::SetDReg(a[2], 2);
+	Vfp::MacD();
+	r[0] = Vfp::DReg(0);
+	r[1] = a[0] + a[1] * a[2];
+	}
+
+void TestMscD(const TReal64* a, TReal64* r)
+	{
+	Vfp::SetDReg(a[0], 0);
+	Vfp::SetDReg(a[1], 1);
+	Vfp::SetDReg(a[2], 2);
+	Vfp::MscD();
+	r[0] = Vfp::DReg(0);
+	r[1] = a[1] * a[2] - a[0];
+	}
+
+void TestMulD(const TReal64* a, TReal64* r)
+	{
+	Vfp::SetDReg(a[0], 1);
+	Vfp::SetDReg(a[1], 2);
+	Vfp::MulD();
+	r[0] = Vfp::DReg(0);
+	TRealX x(a[0]);
+	TRealX y(a[1]);
+	x.MultEq(y);
+	r[1] = (TReal64)x;
+	}
+
+void TestNegD(const TReal64* a, TReal64* r)
+	{
+	Vfp::SetDReg(a[0], 1);
+	Vfp::NegD();
+	r[0] = Vfp::DReg(0);
+	r[1] = -a[0];
+	}
+
+void TestNMacD(const TReal64* a, TReal64* r)
+	{
+	Vfp::SetDReg(a[0], 0);
+	Vfp::SetDReg(a[1], 1);
+	Vfp::SetDReg(a[2], 2);
+	Vfp::NMacD();
+	r[0] = Vfp::DReg(0);
+	r[1] = a[0] - a[1] * a[2];
+	}
+
+void TestNMscD(const TReal64* a, TReal64* r)
+	{
+	Vfp::SetDReg(a[0], 0);
+	Vfp::SetDReg(a[1], 1);
+	Vfp::SetDReg(a[2], 2);
+	Vfp::NMscD();
+	r[0] = Vfp::DReg(0);
+	r[1] = -a[1] * a[2] - a[0];
+	}
+
+void TestNMulD(const TReal64* a, TReal64* r)
+	{
+	Vfp::SetDReg(a[0], 1);
+	Vfp::SetDReg(a[1], 2);
+	Vfp::NMulD();
+	r[0] = Vfp::DReg(0);
+	TRealX x(a[0]);
+	TRealX y(a[1]);
+	x.MultEq(y);
+	r[1] = -(TReal64)x;
+	}
+
+void TestSqrtD(const TReal64* a, TReal64* r)
+	{
+	Vfp::SetDReg(a[0], 1);
+	Vfp::SqrtD();
+	r[0] = Vfp::DReg(0);
+	TReal x = a[0];
+	TReal y;
+	Math::Sqrt(y, x);
+	r[1] = (TReal64)y;
+	}
+
+void TestSubD(const TReal64* a, TReal64* r)
+	{
+	Vfp::SetDReg(a[0], 1);
+	Vfp::SetDReg(a[1], 2);
+	Vfp::SubD();
+	r[0] = Vfp::DReg(0);
+	r[1] = a[0] - a[1];
+	}
+
+#define DO_SGL_TEST1(name, func, a1)			DoSglTest(name, __LINE__, func, a1)
+#define DO_SGL_TEST2(name, func, a1, a2)		DoSglTest(name, __LINE__, func, a1, a2)
+#define DO_SGL_TEST3(name, func, a1, a2, a3)	DoSglTest(name, __LINE__, func, a1, a2, a3)
+void DoSglTest(const char* aName, TInt aLine, TSglTest aFunc, TReal32 a1, TReal32 a2=0.0f, TReal32 a3=0.0f)
+	{
+	TPtrC8 name8((const TText8*)aName);
+	TBuf<128> name16;
+	name16.Copy(name8);
+	test.Printf(_L("%S(%g,%g,%g)\n"), &name16, a1, a2, a3);
+	TReal32 args[3] = {a1, a2, a3};
+	TReal32 results[2];
+	(*aFunc)(args, results);
+	if (IEEEMode)
+		{
+		if (*((TUint32*)&(results[0])) == *((TUint32*)&(results[1])))
+			return;
+		}
+	else
+		{
+		if (results[0] == results[1])
+			return;
+		}
+	const TUint32* pa = (const TUint32*)args;
+	const TUint32* pr = (const TUint32*)results;
+	test.Printf(_L("a1=%08x a2=%08x a3=%08x\n"), pa[0], pa[1], pa[2]);
+	test.Printf(_L("actual result = %08x (%g)\nexpected result = %08x (%g)\n"), pr[0], results[0], pr[1], results[1]);
+	test.Printf(_L("Test at line %d failed\n"), aLine);
+	test(0);
+	}
+
+void DoSglTests()
+	{
+	// ABS
+	DO_SGL_TEST1("ABS", &TestAbsS, 1.0f);
+	DO_SGL_TEST1("ABS", &TestAbsS, -1.0f);
+	DO_SGL_TEST1("ABS", &TestAbsS, 0.0f);
+	DO_SGL_TEST1("ABS", &TestAbsS, -3.1415926536f);
+
+	// NEG
+	DO_SGL_TEST1("NEG", &TestNegS, 1.0f);
+	DO_SGL_TEST1("NEG", &TestNegS, -1.0f);
+	DO_SGL_TEST1("NEG", &TestNegS, 0.0f);
+	DO_SGL_TEST1("NEG", &TestNegS, -3.1415926536f);
+
+	// ADD
+	DO_SGL_TEST2("ADD", &TestAddS, 0.0f, 0.0f);
+	DO_SGL_TEST2("ADD", &TestAddS, 0.0f, 1.0f);
+	DO_SGL_TEST2("ADD", &TestAddS, -1.0f, 1.0f);
+	DO_SGL_TEST2("ADD", &TestAddS, 1.0f, 2.5f);
+	DO_SGL_TEST2("ADD", &TestAddS, 1.0f, 6.022045e23f);
+	DO_SGL_TEST2("ADD", &TestAddS, -7.3890561f, 1.414213562f);
+	DO_SGL_TEST2("ADD", &TestAddS, -7.3890561f, -1.414213562f);
+
+	// SUB
+	DO_SGL_TEST2("SUB", &TestSubS, 0.0f, 0.0f);
+	DO_SGL_TEST2("SUB", &TestSubS, 0.0f, 1.0f);
+	DO_SGL_TEST2("SUB", &TestSubS, 1.0f, 1.0f);
+	DO_SGL_TEST2("SUB", &TestSubS, 1.0f, 2.5f);
+	DO_SGL_TEST2("SUB", &TestSubS, 91.0f, 2.5f);
+	DO_SGL_TEST2("SUB", &TestSubS, 1.0f, 6.022045e23f);
+	DO_SGL_TEST2("SUB", &TestSubS, -7.3890561f, 1.414213562f);
+	DO_SGL_TEST2("SUB", &TestSubS, -7.3890561f, -1.414213562f);
+
+	// MUL
+	DO_SGL_TEST2("MUL", &TestMulS, 0.0f, 0.0f);
+	DO_SGL_TEST2("MUL", &TestMulS, 1.0f, 0.0f);
+	DO_SGL_TEST2("MUL", &TestMulS, 0.0f, 1.0f);
+	DO_SGL_TEST2("MUL", &TestMulS, 2.5f, 6.5f);
+	DO_SGL_TEST2("MUL", &TestMulS, -39.6f, 19.72f);
+	DO_SGL_TEST2("MUL", &TestMulS, -10.1f, -20.1f);
+	DO_SGL_TEST2("MUL", &TestMulS, 1e20f, 1e20f);
+	DO_SGL_TEST2("MUL", &TestMulS, 1e-30f, 1e-30f);
+
+	// DIV
+	DO_SGL_TEST2("DIV", &TestDivS, 0.0f, 1.0f);
+	DO_SGL_TEST2("DIV", &TestDivS, 1.0f, 5.0f);
+	DO_SGL_TEST2("DIV", &TestDivS, 1.0f, -5.0f);
+	DO_SGL_TEST2("DIV", &TestDivS, -1.0f, 5.0f);
+	DO_SGL_TEST2("DIV", &TestDivS, -1.0f, -5.0f);
+	DO_SGL_TEST2("DIV", &TestDivS, 7.3890561f, 2.7182818f);
+	DO_SGL_TEST2("DIV", &TestDivS, 1e20f, 1e-20f);
+	DO_SGL_TEST2("DIV", &TestDivS, 1e-30f, 1e30f);
+
+	// NMUL
+	DO_SGL_TEST2("NMUL", &TestNMulS, 0.0f, 0.0f);
+	DO_SGL_TEST2("NMUL", &TestNMulS, 1.0f, 0.0f);
+	DO_SGL_TEST2("NMUL", &TestNMulS, 0.0f, 1.0f);
+	DO_SGL_TEST2("NMUL", &TestNMulS, 2.5f, 6.5f);
+	DO_SGL_TEST2("NMUL", &TestNMulS, -39.6f, 19.72f);
+	DO_SGL_TEST2("NMUL", &TestNMulS, -10.1f, -20.1f);
+	DO_SGL_TEST2("NMUL", &TestNMulS, 1e20f, 1e20f);
+	DO_SGL_TEST2("NMUL", &TestNMulS, 1e-30f, 1e-30f);
+
+	// SQRT
+	DO_SGL_TEST1("SQRT", &TestSqrtS, 0.0f);
+	DO_SGL_TEST1("SQRT", &TestSqrtS, 1.0f);
+	DO_SGL_TEST1("SQRT", &TestSqrtS, 2.0f);
+	DO_SGL_TEST1("SQRT", &TestSqrtS, 3.0f);
+	DO_SGL_TEST1("SQRT", &TestSqrtS, 9096256.0f);
+	DO_SGL_TEST1("SQRT", &TestSqrtS, 1e36f);
+	DO_SGL_TEST1("SQRT", &TestSqrtS, 1e-36f);
+
+	// MAC
+	DO_SGL_TEST3("MAC", &TestMacS, 0.0f, 0.0f, 0.0f);
+	DO_SGL_TEST3("MAC", &TestMacS, 0.0f, 1.0f, 0.0f);
+	DO_SGL_TEST3("MAC", &TestMacS, 0.0f, 1.0f, 1.0f);
+	DO_SGL_TEST3("MAC", &TestMacS, -1.0f, 1.0f, 1.0f);
+	DO_SGL_TEST3("MAC", &TestMacS, 0.8f, 0.1f, 8.0f);
+	DO_SGL_TEST3("MAC", &TestMacS, 0.8f, -0.1f, 8.0f);
+	DO_SGL_TEST3("MAC", &TestMacS, -0.8f, -0.1f, -8.0f);
+	DO_SGL_TEST3("MAC", &TestMacS, 0.8f, 0.3333333333f, 3.1415926536f);
+
+	// MSC
+	DO_SGL_TEST3("MSC", &TestMscS, 0.0f, 0.0f, 0.0f);
+	DO_SGL_TEST3("MSC", &TestMscS, 0.0f, 1.0f, 0.0f);
+	DO_SGL_TEST3("MSC", &TestMscS, 0.0f, 1.0f, 1.0f);
+	DO_SGL_TEST3("MSC", &TestMscS, -1.0f, 1.0f, 1.0f);
+	DO_SGL_TEST3("MSC", &TestMscS, 0.8f, 0.1f, 8.0f);
+	DO_SGL_TEST3("MSC", &TestMscS, 0.8f, -0.1f, 8.0f);
+	DO_SGL_TEST3("MSC", &TestMscS, -0.8f, -0.1f, -8.0f);
+	DO_SGL_TEST3("MSC", &TestMscS, 0.8f, 0.3333333333f, 3.1415926536f);
+
+	// NMAC
+	DO_SGL_TEST3("NMAC", &TestNMacS, 0.0f, 0.0f, 0.0f);
+	DO_SGL_TEST3("NMAC", &TestNMacS, 0.0f, 1.0f, 0.0f);
+	DO_SGL_TEST3("NMAC", &TestNMacS, 0.0f, 1.0f, 1.0f);
+	DO_SGL_TEST3("NMAC", &TestNMacS, -1.0f, 1.0f, 1.0f);
+	DO_SGL_TEST3("NMAC", &TestNMacS, 0.8f, 0.1f, 8.0f);
+	DO_SGL_TEST3("NMAC", &TestNMacS, 0.8f, -0.1f, 8.0f);
+	DO_SGL_TEST3("NMAC", &TestNMacS, -0.8f, -0.1f, -8.0f);
+	DO_SGL_TEST3("NMAC", &TestNMacS, 0.8f, 0.3333333333f, 3.1415926536f);
+
+	// NMSC
+	DO_SGL_TEST3("NMSC", &TestNMscS, 0.0f, 0.0f, 0.0f);
+	DO_SGL_TEST3("NMSC", &TestNMscS, 0.0f, 1.0f, 0.0f);
+	DO_SGL_TEST3("NMSC", &TestNMscS, 0.0f, 1.0f, 1.0f);
+	DO_SGL_TEST3("NMSC", &TestNMscS, -1.0f, 1.0f, 1.0f);
+	DO_SGL_TEST3("NMSC", &TestNMscS, 0.8f, 0.1f, 8.0f);
+	DO_SGL_TEST3("NMSC", &TestNMscS, 0.8f, -0.1f, 8.0f);
+	DO_SGL_TEST3("NMSC", &TestNMscS, -0.8f, -0.1f, -8.0f);
+	DO_SGL_TEST3("NMSC", &TestNMscS, 0.8f, 0.3333333333f, 3.1415926536f);
+	}
+
+#define DO_DBL_TEST1(name, func, a1)			DoDblTest(name, __LINE__, func, a1)
+#define DO_DBL_TEST2(name, func, a1, a2)		DoDblTest(name, __LINE__, func, a1, a2)
+#define DO_DBL_TEST3(name, func, a1, a2, a3)	DoDblTest(name, __LINE__, func, a1, a2, a3)
+void DoDblTest(const char* aName, TInt aLine, TDblTest aFunc, TReal64 a1, TReal64 a2=0.0, TReal64 a3=0.0)
+	{
+	TPtrC8 name8((const TText8*)aName);
+	TBuf<128> name16;
+	name16.Copy(name8);
+	test.Printf(_L("%S(%g,%g,%g)\n"), &name16, a1, a2, a3);
+	TReal64 args[3] = {a1, a2, a3};
+	TReal64 results[2];
+	SDouble sargs[3];
+	sargs[0] = a1;
+	sargs[1] = a2;
+	sargs[2] = a3;
+	(*aFunc)(args, results);
+	if (IEEEMode)
+		{
+		if (*((TUint64*)&(results[0])) == *((TUint64*)&(results[1])))
+			return;
+		}
+	else
+		{
+		if (results[0] == results[1])
+			return;
+		}
+	SDouble sres[3];
+	sres[0] = results[0];
+	sres[1] = results[1];
+	test.Printf(_L("a1=%08x %08x\na2=%08x %08x\na3=%08x %08x\n"), sargs[0].iData[1], sargs[0].iData[0],
+								sargs[1].iData[1], sargs[1].iData[0], sargs[2].iData[1], sargs[2].iData[0]);
+	test.Printf(_L("actual result = %08x %08x (%g)\nexpected result = %08x %08x (%g)\n"),
+			sres[0].iData[1], sres[0].iData[0], results[0], sres[1].iData[1], sres[1].iData[0], results[1]);
+	test.Printf(_L("Test at line %d failed\n"), aLine);
+	test(0);
+	}
+
+void DoDblTests()
+	{
+	// ABS
+	DO_DBL_TEST1("ABS", &TestAbsD, 1.0);
+	DO_DBL_TEST1("ABS", &TestAbsD, -1.0);
+	DO_DBL_TEST1("ABS", &TestAbsD, 0.0);
+	DO_DBL_TEST1("ABS", &TestAbsD, -3.1415926536);
+
+	// NEG
+	DO_DBL_TEST1("NEG", &TestNegD, 1.0);
+	DO_DBL_TEST1("NEG", &TestNegD, -1.0);
+	DO_DBL_TEST1("NEG", &TestNegD, 0.0);
+	DO_DBL_TEST1("NEG", &TestNegD, -3.1415926536);
+
+	// ADD
+	DO_DBL_TEST2("ADD", &TestAddD, 0.0, 0.0);
+	DO_DBL_TEST2("ADD", &TestAddD, 0.0, 1.0);
+	DO_DBL_TEST2("ADD", &TestAddD, -1.0, 1.0);
+	DO_DBL_TEST2("ADD", &TestAddD, 1.0, 2.5);
+	DO_DBL_TEST2("ADD", &TestAddD, 1.0, 6.022045e23);
+	DO_DBL_TEST2("ADD", &TestAddD, -7.3890561, 1.414213562);
+	DO_DBL_TEST2("ADD", &TestAddD, -7.3890561, -1.414213562);
+
+	// SUB
+	DO_DBL_TEST2("SUB", &TestSubD, 0.0, 0.0);
+	DO_DBL_TEST2("SUB", &TestSubD, 0.0, 1.0);
+	DO_DBL_TEST2("SUB", &TestSubD, 1.0, 1.0);
+	DO_DBL_TEST2("SUB", &TestSubD, 1.0, 2.5);
+	DO_DBL_TEST2("SUB", &TestSubD, 91.0, 2.5);
+	DO_DBL_TEST2("SUB", &TestSubD, 1.0, 6.022045e23);
+	DO_DBL_TEST2("SUB", &TestSubD, -7.3890561, 1.414213562);
+	DO_DBL_TEST2("SUB", &TestSubD, -7.3890561, -1.414213562);
+
+	// MUL
+	DO_DBL_TEST2("MUL", &TestMulD, 0.0, 0.0);
+	DO_DBL_TEST2("MUL", &TestMulD, 1.0, 0.0);
+	DO_DBL_TEST2("MUL", &TestMulD, 0.0, 1.0);
+	DO_DBL_TEST2("MUL", &TestMulD, 2.5, 6.5);
+	DO_DBL_TEST2("MUL", &TestMulD, -39.6, 19.72);
+	DO_DBL_TEST2("MUL", &TestMulD, -10.1, -20.1);
+	DO_DBL_TEST2("MUL", &TestMulD, 1e20, 1e20);
+	DO_DBL_TEST2("MUL", &TestMulD, 1e100, 1e300);
+	DO_DBL_TEST2("MUL", &TestMulD, 1e-20, 1e-20);
+	DO_DBL_TEST2("MUL", &TestMulD, 1e-200, 1e-300);
+
+	// DIV
+	DO_DBL_TEST2("DIV", &TestDivD, 0.0, 1.0);
+	DO_DBL_TEST2("DIV", &TestDivD, 1.0, 5.0);
+	DO_DBL_TEST2("DIV", &TestDivD, 1.0, -5.0);
+	DO_DBL_TEST2("DIV", &TestDivD, -1.0, 5.0);
+	DO_DBL_TEST2("DIV", &TestDivD, -1.0, -5.0);
+	DO_DBL_TEST2("DIV", &TestDivD, 7.3890561, 2.7182818);
+	DO_DBL_TEST2("DIV", &TestDivD, 1e20, 1e-20);
+	DO_DBL_TEST2("DIV", &TestDivD, 1e-20, 1e20);
+	DO_DBL_TEST2("DIV", &TestDivD, 1e-50, 1e300);
+
+	// NMUL
+	DO_DBL_TEST2("NMUL", &TestNMulD, 0.0, 0.0);
+	DO_DBL_TEST2("NMUL", &TestNMulD, 1.0, 0.0);
+	DO_DBL_TEST2("NMUL", &TestNMulD, 0.0, 1.0);
+	DO_DBL_TEST2("NMUL", &TestNMulD, 2.5, 6.5);
+	DO_DBL_TEST2("NMUL", &TestNMulD, -39.6, 19.72);
+	DO_DBL_TEST2("NMUL", &TestNMulD, -10.1, -20.1);
+	DO_DBL_TEST2("NMUL", &TestNMulD, 1e20, 1e20);
+	DO_DBL_TEST2("NMUL", &TestNMulD, 1e100, 1e300);
+	DO_DBL_TEST2("NMUL", &TestNMulD, 1e-20, 1e-20);
+	DO_DBL_TEST2("NMUL", &TestNMulD, 1e-200, 1e-300);
+
+	// SQRT
+	DO_DBL_TEST1("SQRT", &TestSqrtD, 0.0);
+	DO_DBL_TEST1("SQRT", &TestSqrtD, 1.0);
+	DO_DBL_TEST1("SQRT", &TestSqrtD, 2.0);
+	DO_DBL_TEST1("SQRT", &TestSqrtD, 3.0);
+	DO_DBL_TEST1("SQRT", &TestSqrtD, 9096256.0);
+	DO_DBL_TEST1("SQRT", &TestSqrtD, 1e36);
+	DO_DBL_TEST1("SQRT", &TestSqrtD, 1e-36);
+
+	// MAC
+	DO_DBL_TEST3("MAC", &TestMacD, 0.0, 0.0, 0.0);
+	DO_DBL_TEST3("MAC", &TestMacD, 0.0, 1.0, 0.0);
+	DO_DBL_TEST3("MAC", &TestMacD, 0.0, 1.0, 1.0);
+	DO_DBL_TEST3("MAC", &TestMacD, -1.0, 1.0, 1.0);
+	DO_DBL_TEST3("MAC", &TestMacD, 0.8, 0.1, 8.0);
+	DO_DBL_TEST3("MAC", &TestMacD, 0.8, -0.1, 8.0);
+	DO_DBL_TEST3("MAC", &TestMacD, -0.8, -0.1, -8.0);
+	DO_DBL_TEST3("MAC", &TestMacD, 0.8, 0.3333333333, 3.1415926536);
+
+	// MSC
+	DO_DBL_TEST3("MSC", &TestMscD, 0.0, 0.0, 0.0);
+	DO_DBL_TEST3("MSC", &TestMscD, 0.0, 1.0, 0.0);
+	DO_DBL_TEST3("MSC", &TestMscD, 0.0, 1.0, 1.0);
+	DO_DBL_TEST3("MSC", &TestMscD, -1.0, 1.0, 1.0);
+	DO_DBL_TEST3("MSC", &TestMscD, 0.8, 0.1, 8.0);
+	DO_DBL_TEST3("MSC", &TestMscD, 0.8, -0.1, 8.0);
+	DO_DBL_TEST3("MSC", &TestMscD, -0.8, -0.1, -8.0);
+	DO_DBL_TEST3("MSC", &TestMscD, 0.8, 0.3333333333, 3.1415926536);
+
+	// NMAC
+	DO_DBL_TEST3("NMAC", &TestNMacD, 0.0, 0.0, 0.0);
+	DO_DBL_TEST3("NMAC", &TestNMacD, 0.0, 1.0, 0.0);
+	DO_DBL_TEST3("NMAC", &TestNMacD, 0.0, 1.0, 1.0);
+	DO_DBL_TEST3("NMAC", &TestNMacD, -1.0, 1.0, 1.0);
+	DO_DBL_TEST3("NMAC", &TestNMacD, 0.8, 0.1, 8.0);
+	DO_DBL_TEST3("NMAC", &TestNMacD, 0.8, -0.1, 8.0);
+	DO_DBL_TEST3("NMAC", &TestNMacD, -0.8, -0.1, -8.0);
+	DO_DBL_TEST3("NMAC", &TestNMacD, 0.8, 0.3333333333, 3.1415926536);
+
+	// NMSC
+	DO_DBL_TEST3("NMSC", &TestNMscD, 0.0, 0.0, 0.0);
+	DO_DBL_TEST3("NMSC", &TestNMscD, 0.0, 1.0, 0.0);
+	DO_DBL_TEST3("NMSC", &TestNMscD, 0.0, 1.0, 1.0);
+	DO_DBL_TEST3("NMSC", &TestNMscD, -1.0, 1.0, 1.0);
+	DO_DBL_TEST3("NMSC", &TestNMscD, 0.8, 0.1, 8.0);
+	DO_DBL_TEST3("NMSC", &TestNMscD, 0.8, -0.1, 8.0);
+	DO_DBL_TEST3("NMSC", &TestNMscD, -0.8, -0.1, -8.0);
+	DO_DBL_TEST3("NMSC", &TestNMscD, 0.8, 0.3333333333, 3.1415926536);
+	}
+
+void DoBounceTests()
+	{
+	test.Next(_L("Test denormal handling - single"));
+	DO_SGL_TEST2("ADD", &TestAddS, 1e-39f, 1e-39f);
+	test.Next(_L("Test potential underflow - single"));
+	DO_SGL_TEST2("MUL", &TestMulS, 3.162e-20f, 3.162e-20f);
+// fails on VFPv2 hardware. ARM's library should be fixed
+//	test.Next(_L("Test NaN input - single"));
+//	TReal32 aSingleNaN;
+//	*((TUint32*)&aSingleNaN) = 0x7F9ABCDE;
+//	Vfp::SetSReg(aSingleNaN, 1);
+//	Vfp::SetSReg(aSingleNaN, 2);
+//	Vfp::AddS();
+//	TReal32 aSingleResult = Vfp::SReg(0);
+//	test(*((TUint32*)&aSingleResult) == 0x7FDABCDE);
+
+	if (Double)
+		{
+		test.Next(_L("Test denormal handling - double"));
+		DO_DBL_TEST2("ADD", &TestAddD, 3.1234e-322, 3.1234e-322);
+		test.Next(_L("Test potential underflow - double"));
+		DO_DBL_TEST2("MUL", &TestMulD, 1.767e-161, 1.767e-161);
+// fails on VFPv2 hardware. ARM's library should be fixed
+//		test.Next(_L("Test NaN input - double"));
+//		TReal64 aDoubleNaN;
+//		*((TUint64*)&aDoubleNaN) = 0x7FF0123456789ABCll;
+//		Vfp::SetDReg(aDoubleNaN, 1);
+//		Vfp::SetDReg(aDoubleNaN, 2);
+//		Vfp::AddD();
+//		TReal64 aDoubleResult = Vfp::DReg(0);
+//		test(*((TUint64*)&aDoubleResult) == 0x7FF8123456789ABC);
+		}
+	}
+
+void DoRunFastTests()
+	{
+	test.Next(_L("Test flushing denormals to zero - single"));
+	Vfp::SetSReg(1e-39f, 1);
+	Vfp::SetSReg(1e-39f, 2);
+	Vfp::AddS();
+	test(Vfp::SReg(0)==0);
+
+	test.Next(_L("Test flushing underflow to zero - single"));
+	Vfp::SetSReg(3.162e-20f, 1);
+	Vfp::SetSReg(3.162e-20f, 2);
+	Vfp::MulS();
+	test(Vfp::SReg(0)==0);
+
+	test.Next(_L("Test default NaNs - single"));
+	TReal32 aSingleNaN;
+	*((TUint32*)&aSingleNaN) = 0x7F9ABCDE;
+	Vfp::SetSReg(aSingleNaN, 1);
+	Vfp::SetSReg(aSingleNaN, 2);
+	Vfp::AddS();
+	TReal32 aSingleResult = Vfp::SReg(0);
+	test(*((TUint32*)&aSingleResult) == 0x7FC00000);
+
+	if (Double)
+		{
+		test.Next(_L("Test flushing denormals to zero - double"));
+		Vfp::SetDReg(3.1234e-322, 1);
+		Vfp::SetDReg(3.1234e-322, 2);
+		Vfp::AddD();
+		test(Vfp::DReg(0)==0);
+	
+		test.Next(_L("Test flushing underflow to zero - double"));
+		Vfp::SetDReg(1.767e-161, 1);
+		Vfp::SetDReg(1.767e-161, 2);
+		Vfp::MulD();
+		test(Vfp::DReg(0)==0);
+
+		test.Next(_L("Test default NaNs - double"));
+		TReal64 aDoubleNaN;
+		*((TUint64*)&aDoubleNaN) = 0x7FF0123456789ABCll;
+		Vfp::SetDReg(aDoubleNaN, 1);
+		Vfp::SetDReg(aDoubleNaN, 2);
+		Vfp::AddD();
+		TReal64 aDoubleResult = Vfp::DReg(0);
+		test(*((TUint64*)&aDoubleResult) == 0x7FF8000000000000ll);
+		}
+	}
+
+void TestAddSResult(const TReal32 a, const TReal32 b, const TReal32 r)
+	{
+	Vfp::SetSReg(a, 1);
+	Vfp::SetSReg(b, 2);
+	Vfp::AddS();
+	test(Vfp::SReg(0) == r);
+	}
+
+void DoRoundingTests()
+	{
+	TFloatingPointMode fpmode = IEEEMode ? EFpModeIEEENoExceptions : EFpModeRunFast;
+	test.Next(_L("Check default rounding to nearest"));
+	test(User::SetFloatingPointMode(fpmode) == KErrNone);
+	test.Next(_L("Check nearest-downward"));
+	TestAddSResult(16777215, 0.49f, 16777215);
+	test.Next(_L("Check nearest-upward"));
+	TestAddSResult(16777215, 0.51f, 16777216);
+	test.Next(_L("Set rounding mode to toward-plus-infinity"));
+	test(User::SetFloatingPointMode(fpmode, EFpRoundToPlusInfinity) == KErrNone);
+	test.Next(_L("Check positive rounding goes upward"));
+	TestAddSResult(16777215, 0.49f, 16777216);
+	test.Next(_L("Check negative rounding goes upward"));
+	TestAddSResult(-16777215, -0.51f, -16777215);
+	test.Next(_L("Set rounding mode to toward-minus-infinity"));
+	test(User::SetFloatingPointMode(fpmode, EFpRoundToMinusInfinity) == KErrNone);
+	test.Next(_L("Check positive rounding goes downward"));
+	TestAddSResult(16777215, 0.51f, 16777215);
+	test.Next(_L("Check negative rounding goes downward"));
+	TestAddSResult(-16777215, -0.49f, -16777216);
+	test.Next(_L("Set rounding mode to toward-zero"));
+	test(User::SetFloatingPointMode(fpmode, EFpRoundToZero) == KErrNone);
+	test.Next(_L("Check positive rounding goes downward"));
+	TestAddSResult(16777215, 0.51f, 16777215);
+	test.Next(_L("Check negative rounding goes upward"));
+	TestAddSResult(-16777215, -0.51f, -16777215);
+	}
+
+TInt RunFastThread(TAny* /*unused*/)
+	{
+	Vfp::SetSReg(1e-39f, 1);
+	Vfp::SetSReg(1e-39f, 2);
+	Vfp::AddS();
+	return (Vfp::SReg(0)==0) ? KErrNone : KErrGeneral;
+	}
+
+TInt IEEECompliantThread(TAny* /*unused*/)
+	{
+	Vfp::SetSReg(1e-39f, 1);
+	Vfp::SetSReg(1e-39f, 2);
+	Vfp::AddS();
+	return (Vfp::SReg(0)==2e-39f) ? KErrNone : KErrGeneral;
+	}
+
+void TestVFPModeInheritance()
+	{
+	test.Printf(_L("Set floating point mode to RunFast\n"));
+	test(User::SetFloatingPointMode(EFpModeRunFast)==KErrNone);
+	RThread t;
+	TInt r = t.Create(KNullDesC, &RunFastThread, 0x1000, NULL, NULL);
+	test(r==KErrNone);
+	TRequestStatus s;
+	t.Logon(s);
+	test.Printf(_L("Run RunFast test in another thread...\n"));
+	t.Resume();
+	test.Printf(_L("Wait for other thread to terminate\n"));
+	User::WaitForRequest(s);
+	test(t.ExitType() == EExitKill);
+	test(s == KErrNone);
+	CLOSE_AND_WAIT(t);
+	test.Printf(_L("Set floating point mode to IEEE\n"));
+	test(User::SetFloatingPointMode(EFpModeIEEENoExceptions)==KErrNone);
+	r = t.Create(KNullDesC, &IEEECompliantThread, 0x1000, NULL, NULL);
+	test(r==KErrNone);
+	t.Logon(s);
+	test.Printf(_L("Run IEEE test in another thread...\n"));
+	t.Resume();
+	test.Printf(_L("Wait for other thread to terminate\n"));
+	User::WaitForRequest(s);
+	test(t.ExitType() == EExitKill);
+	test(s == KErrNone);
+	CLOSE_AND_WAIT(t);
+	}
+
+
+void TestVFPv3()
+	{
+	test.Next(_L("Transferring to and from fixed point"));
+	
+	Vfp::SetSReg(2.5f, 0);
+	test(Vfp::SReg(0)==2.5f);
+	Vfp::ToFixedS(3);				// Convert to fixed (3) precision
+	test(Vfp::SRegInt(0)==0x14);	// 10.100 in binary fixed(3) format
+	Vfp::FromFixedS(3);				//Convert from fixed (3) precision
+	test(Vfp::SReg(0)==2.5f);
+
+	
+	test.Next(_L("Setting immediate value to floating point registers"));
+	
+	Vfp::SetSReg(5.0f, 0);
+	test(Vfp::SReg(0) == 5.0f);
+	Vfp::TconstS2();
+	test(Vfp::SReg(0) == 2.0f);
+	Vfp::SetSReg(5.0f, 0);
+	Vfp::TconstS2_8();
+	test(Vfp::SReg(0) == 2.875f);
+	
+	Vfp::SetDReg(5.0f, 0);
+	test(Vfp::DReg(0) == 5.0f);
+	Vfp::TconstD2();
+	test(Vfp::DReg(0) == 2.0f);
+	Vfp::TconstD2_8();
+	test(Vfp::DReg(0) == 2.875f);
+	}
+
+void TestNEON()
+	{
+	RThread t;
+	TRequestStatus s;
+	test.Next(_L("Test creating a thread to execute an F2-prefix instruction"));
+	test_KErrNone(t.Create(KNullDesC, &NeonWithF2, 0x1000, NULL, NULL));
+	t.Logon(s);
+	t.Resume();
+	User::WaitForRequest(s);
+	test(t.ExitType() == EExitKill);
+	test(s == KErrNone);
+	t.Close();
+	test.Next(_L("Test creating a thread to execute an F3-prefix instruction"));
+	test_KErrNone(t.Create(KNullDesC, &NeonWithF3, 0x1000, NULL, NULL));
+	t.Logon(s);
+	t.Resume();
+	User::WaitForRequest(s);
+	test(t.ExitType() == EExitKill);
+	test(s == KErrNone);
+	t.Close();
+	test.Next(_L("Test creating a thread to execute an F4x-prefix instruction"));
+	test_KErrNone(t.Create(KNullDesC, &NeonWithF4x, 0x1000, NULL, NULL));
+	t.Logon(s);
+	t.Resume();
+	User::WaitForRequest(s);
+	test(t.ExitType() == EExitKill);
+	test(s == KErrNone);
+	t.Close();
+	}
+
+void TestThumb()
+	{
+	RThread t;
+	TRequestStatus s;
+	TInt testStep = 0;
+	do {
+		test_KErrNone(t.Create(KNullDesC, &ThumbMode, 0x1000, NULL, (TAny*)testStep++));
+		t.Logon(s);
+		t.Resume();
+		User::WaitForRequest(s);
+		test(s == KErrNone || s == 1);
+		test(t.ExitType() == EExitKill);
+		t.Close();
+		}
+	while (s == KErrNone);
+
+	test(s == 1);
+	test(testStep == 7);
+	}
+
+TInt E32Main()
+	{
+	test.Title();
+
+	test.Start(_L("Ask HAL if we have hardware floating point"));
+
+	CPUs = UserSvr::HalFunction(EHalGroupKernel, EKernelHalNumLogicalCpus, 0, 0);
+	TInt supportedTypes;
+	TInt HalVfp = HAL::Get(HALData::EHardwareFloatingPoint, supportedTypes);
+	if (HalVfp == KErrNone) 
+		{ 
+		if (supportedTypes == EFpTypeVFPv2) 
+			{ 
+			test.Printf(_L("HAL reports VFPv2\n"));
+			} 
+		else if (supportedTypes == EFpTypeVFPv3)
+			{ 
+			test.Printf(_L("HAL reports VFPv3\n"));
+			} 
+		else if (supportedTypes == EFpTypeVFPv3D16)
+			{ 
+			test.Printf(_L("HAL reports VFPv3-D16\n"));
+			} 
+		else
+			{
+			test.Printf(_L("HAL reports an unknown floating point type\n"));
+			test(0);
+			}
+		} 
+	else
+		{ 
+		test.Printf(_L("HAL reports no VFP support\n"));
+		} 
+		
+	test.Next(_L("Check VFP present"));
+	TBool present = DetectVFP();
+	if (!present)
+		{
+		test.Printf(_L("No VFP detected\n"));
+		test(HalVfp == KErrNotSupported || 
+						((supportedTypes != EFpTypeVFPv2) && 
+						(supportedTypes != EFpTypeVFPv3) && 
+						(supportedTypes != EFpTypeVFPv3D16))
+						);
+		test.End();
+		return 0;
+		}
+	
+	test.Printf(_L("VFP detected. FPSID = %08x\n"), FPSID);
+	test(HalVfp == KErrNone);
+
+	// Verify that the HAL architecture ID matches the FPSID values
+	// ARMv7 redefines some of these bits so the masks are different :(
+	if (supportedTypes == EFpTypeVFPv2)
+		{
+		// assume armv5/6's bit definitions, where 19:16 are the arch version
+		// and 20 is the single-precision-only bit
+		ArchVersion = (FPSID >> 16) & 0xf;
+		test(ArchVersion == ARCH_VERSION_VFPV2);
+		Double = !(FPSID & VFP_FPSID_SNG);
+		}
+	else if (supportedTypes == EFpTypeVFPv3 || supportedTypes == EFpTypeVFPv3D16)
+		{
+		// assume armv7's bit definitions, where 22:16 are the arch version
+		ArchVersion = (FPSID >> 16) & 0x7f;
+		test(ArchVersion == ARCH_VERSION_VFPV3_SUBARCH_V2
+		  || ArchVersion == ARCH_VERSION_VFPV3_SUBARCH_NULL
+		  || ArchVersion == ARCH_VERSION_VFPV3_SUBARCH_V3); 
+		// there are bits for this in MVFR0 but ARM implementations should always have it?
+		Double = ETrue;
+		}
+
+	if (Double)
+		test.Printf(_L("Both single and double precision supported\n"), FPSID);
+	else
+		test.Printf(_L("Only single precision supported\n"), FPSID);
+
+	test.Next(_L("Test VFP Initial State"));
+	TestVFPInitialState();
+
+	test.Next(_L("Test setting VFP to IEEE no exceptions mode"));
+	IEEEMode = User::SetFloatingPointMode(EFpModeIEEENoExceptions) == KErrNone;
+	if (!IEEEMode)
+		test.Printf(_L("IEEE no exceptions mode not supported, continuing in RunFast\n"));
+
+	test.Next(_L("Test VFP calculations - single"));
+	DoSglTests();
+	if (Double)
+		{
+		test.Next(_L("Test VFP calculations - double"));
+		DoDblTests();
+		}
+
+	test.Next(_L("Test VFP Context Save"));
+	TestVFPContextSave();
+
+	if (IEEEMode)
+		{
+		test.Next(_L("Test bounce handling"));
+		DoBounceTests();
+		test.Next(_L("Test bouncing while context switching"));
+		DoBounceContextSwitchTests();
+		test.Next(_L("Test setting VFP to RunFast mode"));
+		test(User::SetFloatingPointMode(EFpModeRunFast) == KErrNone);
+		DoRunFastTests();
+		}
+
+	test.Next(_L("Test VFP rounding modes"));
+	DoRoundingTests();
+
+	if (IEEEMode)
+		{
+		test.Next(_L("Test VFP mode inheritance between threads"));
+		TestVFPModeInheritance();
+		}
+
+	if (supportedTypes == EFpTypeVFPv3 || supportedTypes == EFpTypeVFPv3D16)
+		{
+		test.Next(_L("Test VFPv3"));
+		TestVFPv3();
+
+		if (supportedTypes == EFpTypeVFPv3)
+			{
+			test.Next(_L("Test NEON"));
+			TestNEON();
+
+#if defined(__SUPPORT_THUMB_INTERWORKING)
+			test.Next(_L("Test Thumb Decode"));
+			TestThumb();
+#endif
+			}
+		}
+
+	test.End();
+	return 0;
+	}