1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/kernelhwsrv/kerneltest/e32test/math/t_vfp.cpp Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,1289 @@
1.4 +// Copyright (c) 2003-2009 Nokia Corporation and/or its subsidiary(-ies).
1.5 +// All rights reserved.
1.6 +// This component and the accompanying materials are made available
1.7 +// under the terms of the License "Eclipse Public License v1.0"
1.8 +// which accompanies this distribution, and is available
1.9 +// at the URL "http://www.eclipse.org/legal/epl-v10.html".
1.10 +//
1.11 +// Initial Contributors:
1.12 +// Nokia Corporation - initial contribution.
1.13 +//
1.14 +// Contributors:
1.15 +//
1.16 +// Description:
1.17 +// e32test\math\t_vfp.cpp
1.18 +// Overview:
1.19 +// Test the ARM Vector Floating Point operations.
1.20 +// API Information:
1.21 +// VFP
1.22 +// Details:
1.23 +// - Check that the HAL agrees with the hardware about whether
1.24 +// VFP is supported.
1.25 +// - Test setting VFP to IEEE with no exceptions mode, if IEEE mode is
1.26 +// supported, otherwise leave the mode alone.
1.27 +// - Test single and double precision vector floating point operations:
1.28 +// ABS, NEG, ADD, SUB, MUL, DIV, NMUL, SQRT, MAC, MSC, NMAC and NMSC.
1.29 +// Verify results are as expected - if IEEE mode was set, verify
1.30 +// bit-for-bit, in accordance with the IEEE specification, otherwise
1.31 +// use normal floating point equality.
1.32 +// - Test VFP context save.
1.33 +// - Test various VFP operations that cause bounces to support code if
1.34 +// IEEE mode is supported.
1.35 +// - Test setting VFP to RunFast mode if RunFast mode is supported.
1.36 +// - Test setting VFP rounding mode.
1.37 +// - Test inheriting VFP mode to created threads.
1.38 +// Platforms/Drives/Compatibility:
1.39 +// All
1.40 +// Assumptions/Requirement/Pre-requisites:
1.41 +// Failures and causes:
1.42 +// Base Port information:
1.43 +//
1.44 +//
1.45 +
1.46 +//! @file
1.47 +//! @SYMTestCaseID KBASE-0017-T_VFP
1.48 +//! @SYMTestCaseDesc VFPv2 general functionality and bounce handling
1.49 +//! @SYMREQ 5159
1.50 +//! @SYMTestPriority Critical
1.51 +//! @SYMTestActions Check VFP functions correctly in all modes and that mode switching works correctly.
1.52 +//! @SYMTestExpectedResults Test runs until this message is emitted: RTEST: SUCCESS : T_VFP test completed O.K.
1.53 +//! @SYMTestType UT
1.54 +
1.55 +#include "t_vfp.h"
1.56 +#define __E32TEST_EXTENSION__
1.57 +#include <e32test.h>
1.58 +#include <e32math.h>
1.59 +#include <hal.h>
1.60 +#include <e32svr.h>
1.61 +#include <u32hal.h>
1.62 +
1.63 +RTest test(_L("T_VFP"));
1.64 +TUint32 FPSID;
1.65 +TUint32 ArchVersion;
1.66 +TBool Double;
1.67 +TBool IEEEMode;
1.68 +TInt CPUs;
1.69 +TInt CurrentCpu1;
1.70 +TInt CurrentCpu2;
1.71 +
1.72 +typedef void TSglTest(const TReal32* aArgs, TReal32* aResults);
1.73 +typedef void TDblTest(const TReal64* aArgs, TReal64* aResults);
1.74 +
1.75 +TBool DetectVFP()
1.76 + {
1.77 + TInt r = UserSvr::HalFunction(EHalGroupKernel, EKernelHalFloatingPointSystemId, &FPSID, NULL);
1.78 + return (r==KErrNone);
1.79 + }
1.80 +
1.81 +TInt TestVFPInitThreadFn(TAny* aPtr)
1.82 + {
1.83 + UserSvr::HalFunction(EHalGroupKernel, EKernelHalLockThreadToCpu, (TAny*)CurrentCpu1, 0);
1.84 + TReal32* p = (TReal32*)aPtr;
1.85 + TInt i;
1.86 + for (i=0; i<32; ++i)
1.87 + *p++ = Vfp::SReg(i);
1.88 + return 0;
1.89 + }
1.90 +
1.91 +void TestVFPInitialState()
1.92 + {
1.93 + for (CurrentCpu1 = 0; CurrentCpu1 < CPUs; CurrentCpu1++)
1.94 + {
1.95 + TReal32 f[32];
1.96 + RThread t;
1.97 + TInt r = t.Create(KNullDesC, &TestVFPInitThreadFn, 0x1000, NULL, f);
1.98 + test(r==KErrNone);
1.99 + TRequestStatus s;
1.100 + t.Logon(s);
1.101 + t.Resume();
1.102 + User::WaitForRequest(s);
1.103 + TInt xt = t.ExitType();
1.104 + TInt xr = t.ExitReason();
1.105 + test(xt == EExitKill && xr == KErrNone);
1.106 + CLOSE_AND_WAIT(t);
1.107 + UserSvr::HalFunction(EHalGroupKernel, EKernelHalLockThreadToCpu, (TAny*)CurrentCpu1, 0);
1.108 + test.Printf(_L("FPSCR = %08x for core %d\n"), Vfp::Fpscr(), CurrentCpu1);
1.109 + const TUint32* p = (const TUint32*)f;
1.110 + for (TInt i=0; i<32; ++i)
1.111 + {
1.112 + if (f[i] != 0.0f)
1.113 + {
1.114 + test.Printf(_L("S%d = 0x%08x\n"), i, p[i]);
1.115 + test(f[i] == 0.0f);
1.116 + }
1.117 + }
1.118 + }
1.119 + }
1.120 +
1.121 +void TestVFPSglRegs(TInt aIter=2)
1.122 + {
1.123 + TInt i;
1.124 + TInt j;
1.125 + TInt nSglRegs=0;
1.126 +
1.127 + switch(ArchVersion)
1.128 + {
1.129 + case ARCH_VERSION_VFPV2:
1.130 + case ARCH_VERSION_VFPV3_SUBARCH_V2:
1.131 + case ARCH_VERSION_VFPV3_SUBARCH_NULL:
1.132 + case ARCH_VERSION_VFPV3_SUBARCH_V3:
1.133 + nSglRegs = 32;
1.134 + break;
1.135 + case 0:
1.136 + default:
1.137 + __ASSERT_ALWAYS(0, User::Panic(_L("Bad VFP version"),__LINE__));
1.138 + /* NOTREACHED */
1.139 + }
1.140 +
1.141 + for (i=0; i<aIter; ++i)
1.142 + {
1.143 + for (j=0; j<nSglRegs; ++j)
1.144 + {
1.145 + TInt32 f = i + j;
1.146 + Vfp::SetSReg(f, j);
1.147 + }
1.148 + for (j=0; j<nSglRegs; ++j)
1.149 + {
1.150 + TInt32 f = i + j;
1.151 + TInt32 g = Vfp::SRegInt(j);
1.152 + test(f == g);
1.153 + }
1.154 + }
1.155 + }
1.156 +
1.157 +TInt TestVFPSglRegsThread(TAny*)
1.158 + {
1.159 + UserSvr::HalFunction(EHalGroupKernel, EKernelHalLockThreadToCpu, (TAny*)CurrentCpu1, 0);
1.160 + TestVFPSglRegs(KMaxTInt);
1.161 + return 0;
1.162 + }
1.163 +
1.164 +void TestVFPDblRegs(TInt aIter=2)
1.165 + {
1.166 + TInt i;
1.167 + TInt j;
1.168 + TInt nDblRegs=0;
1.169 +
1.170 + switch(ArchVersion)
1.171 + {
1.172 + case ARCH_VERSION_VFPV2:
1.173 + {
1.174 + nDblRegs = 16;
1.175 + break;
1.176 + }
1.177 + case ARCH_VERSION_VFPV3_SUBARCH_V2:
1.178 + case ARCH_VERSION_VFPV3_SUBARCH_NULL:
1.179 + case ARCH_VERSION_VFPV3_SUBARCH_V3:
1.180 + {
1.181 + TInt vfpType;
1.182 + TInt ret = HAL::Get(HALData::EHardwareFloatingPoint, vfpType);
1.183 + if (ret == KErrNone && vfpType == EFpTypeVFPv3)
1.184 + nDblRegs = 32;
1.185 + else
1.186 + nDblRegs = 16;
1.187 + break;
1.188 + }
1.189 + case 0:
1.190 + default:
1.191 + __ASSERT_ALWAYS(0, User::Panic(_L("Bad VFP version"),__LINE__));
1.192 + }
1.193 +
1.194 +
1.195 + for (i=0; i<aIter; ++i)
1.196 + {
1.197 + for (j=0; j<nDblRegs; ++j)
1.198 + {
1.199 + TInt64 f = i + j + KMaxTUint;
1.200 + Vfp::SetDReg(f, j);
1.201 + }
1.202 + for (j=0; j<nDblRegs; ++j)
1.203 + {
1.204 + TInt64 f = i + j + KMaxTUint;
1.205 + TInt64 g = Vfp::DRegInt(j);
1.206 + test(f == g);
1.207 + }
1.208 + }
1.209 + }
1.210 +
1.211 +TInt TestVFPDblRegsThread(TAny*)
1.212 + {
1.213 + UserSvr::HalFunction(EHalGroupKernel, EKernelHalLockThreadToCpu, (TAny*)CurrentCpu2, 0);
1.214 + TestVFPDblRegs(KMaxTInt);
1.215 + return 0;
1.216 + }
1.217 +
1.218 +void TestVFPContextSave()
1.219 + {
1.220 + for (CurrentCpu2 = 0; CurrentCpu2 < CPUs; CurrentCpu2++)
1.221 + {
1.222 + for (CurrentCpu1 = 0; CurrentCpu1 < CPUs; CurrentCpu1++)
1.223 + {
1.224 + TThreadFunction tf1 = &TestVFPSglRegsThread;
1.225 + TThreadFunction tf2 = Double ? &TestVFPDblRegsThread : &TestVFPSglRegsThread;
1.226 + RThread t1, t2;
1.227 + TInt r;
1.228 + r = t1.Create(KNullDesC, tf1, 0x1000, 0x1000, 0x1000, NULL);
1.229 + test(r==KErrNone);
1.230 + t1.SetPriority(EPriorityLess);
1.231 + r = t2.Create(KNullDesC, tf2, 0x1000, 0x1000, 0x1000, NULL);
1.232 + test(r==KErrNone);
1.233 + t2.SetPriority(EPriorityLess);
1.234 + TRequestStatus s1, s2;
1.235 + t1.Logon(s1);
1.236 + t2.Logon(s2);
1.237 + t1.Resume();
1.238 + t2.Resume();
1.239 + test.Printf(_L("Let threads run concurrently (cores %d and %d)\n"), CurrentCpu1, CurrentCpu2);
1.240 + User::After(20*1000*1000/CPUs);
1.241 +
1.242 + test.Printf(_L("Kill threads\n"));
1.243 + t1.Kill(0);
1.244 + t2.Kill(0);
1.245 + User::WaitForRequest(s1);
1.246 + User::WaitForRequest(s2);
1.247 + test(t1.ExitType()==EExitKill && t1.ExitReason()==KErrNone);
1.248 + test(t2.ExitType()==EExitKill && t2.ExitReason()==KErrNone);
1.249 + CLOSE_AND_WAIT(t1);
1.250 + CLOSE_AND_WAIT(t2);
1.251 + }
1.252 + }
1.253 + }
1.254 +
1.255 +TInt TestBounceCtxThread1(TAny*)
1.256 + {
1.257 + UserSvr::HalFunction(EHalGroupKernel, EKernelHalLockThreadToCpu, (TAny*)Max(CPUs-1, 0), 0);
1.258 + for(TInt iter=0; iter<KMaxTInt; ++iter)
1.259 + {
1.260 + Vfp::SReg(0);
1.261 + }
1.262 + return KErrNone;
1.263 + }
1.264 +
1.265 +TInt TestBounceCtxThread2(TAny*)
1.266 + {
1.267 + UserSvr::HalFunction(EHalGroupKernel, EKernelHalLockThreadToCpu, (TAny*)Max(CPUs-1, 0), 0);
1.268 + TInt start_rep = 0x00800000; // smallest single precision normal number, 1*2^-126
1.269 + TReal32 start = *(TReal32*)&start_rep;
1.270 + for(TInt iter=0; iter<KMaxTInt; ++iter)
1.271 + {
1.272 + Vfp::SetSReg(start, 1);
1.273 + Vfp::SetSReg(2.0f, 2);
1.274 + Vfp::DivS();
1.275 + Vfp::CpyS0(1);
1.276 + Vfp::MulS();
1.277 + Vfp::CpyS0(1);
1.278 + TReal32 end = Vfp::SReg(0);
1.279 + TInt end_rep = *(TInt*)&end;
1.280 + if (start_rep != end_rep)
1.281 + {
1.282 + RDebug::Printf("mismatch in iter %d, start %08x end %08x\n", iter, start_rep, end_rep);
1.283 + test(0);
1.284 + }
1.285 + }
1.286 + return KErrNone;
1.287 + }
1.288 +
1.289 +void DoBounceContextSwitchTests()
1.290 + {
1.291 + UserSvr::HalFunction(EHalGroupKernel, EKernelHalLockThreadToCpu, 0, 0);
1.292 + RThread t1, t2;
1.293 + TInt r;
1.294 + r = t1.Create(KNullDesC, &TestBounceCtxThread1, 0x1000, 0x1000, 0x1000, NULL);
1.295 + test(r==KErrNone);
1.296 + t1.SetPriority(EPriorityLess);
1.297 + r = t2.Create(KNullDesC, &TestBounceCtxThread2, 0x1000, 0x1000, 0x1000, NULL);
1.298 + test(r==KErrNone);
1.299 + t2.SetPriority(EPriorityLess);
1.300 + TRequestStatus s1, s2;
1.301 + t1.Logon(s1);
1.302 + t2.Logon(s2);
1.303 + t1.Resume();
1.304 + t2.Resume();
1.305 + test.Printf(_L("Let threads run concurrently ...\n"));
1.306 + User::After(20*1000*1000);
1.307 +
1.308 + test.Printf(_L("Kill threads\n"));
1.309 + t1.Kill(0);
1.310 + t2.Kill(0);
1.311 + User::WaitForRequest(s1);
1.312 + User::WaitForRequest(s2);
1.313 + test(t1.ExitType()==EExitKill && t1.ExitReason()==KErrNone);
1.314 + test(t2.ExitType()==EExitKill && t2.ExitReason()==KErrNone);
1.315 + CLOSE_AND_WAIT(t1);
1.316 + CLOSE_AND_WAIT(t2);
1.317 + }
1.318 +
1.319 +void TestAbsS(const TReal32* a, TReal32* r)
1.320 + {
1.321 + Vfp::SetSReg(a[0], 1);
1.322 + Vfp::AbsS();
1.323 + r[0] = Vfp::SReg(0);
1.324 + r[1] = Abs(a[0]);
1.325 + }
1.326 +
1.327 +void TestAddS(const TReal32* a, TReal32* r)
1.328 + {
1.329 + Vfp::SetSReg(a[0], 1);
1.330 + Vfp::SetSReg(a[1], 2);
1.331 + Vfp::AddS();
1.332 + r[0] = Vfp::SReg(0);
1.333 + r[1] = a[0] + a[1];
1.334 + }
1.335 +
1.336 +void TestDivS(const TReal32* a, TReal32* r)
1.337 + {
1.338 + Vfp::SetSReg(a[0], 1);
1.339 + Vfp::SetSReg(a[1], 2);
1.340 + Vfp::DivS();
1.341 + r[0] = Vfp::SReg(0);
1.342 + TRealX x(a[0]);
1.343 + TRealX y(a[1]);
1.344 + x.DivEq(y);
1.345 + r[1] = (TReal32)x;
1.346 + }
1.347 +
1.348 +void TestMacS(const TReal32* a, TReal32* r)
1.349 + {
1.350 + Vfp::SetSReg(a[0], 0);
1.351 + Vfp::SetSReg(a[1], 1);
1.352 + Vfp::SetSReg(a[2], 2);
1.353 + Vfp::MacS();
1.354 + r[0] = Vfp::SReg(0);
1.355 + r[1] = a[0] + a[1] * a[2];
1.356 + }
1.357 +
1.358 +void TestMscS(const TReal32* a, TReal32* r)
1.359 + {
1.360 + Vfp::SetSReg(a[0], 0);
1.361 + Vfp::SetSReg(a[1], 1);
1.362 + Vfp::SetSReg(a[2], 2);
1.363 + Vfp::MscS();
1.364 + r[0] = Vfp::SReg(0);
1.365 + r[1] = a[1] * a[2] - a[0];
1.366 + }
1.367 +
1.368 +void TestMulS(const TReal32* a, TReal32* r)
1.369 + {
1.370 + Vfp::SetSReg(a[0], 1);
1.371 + Vfp::SetSReg(a[1], 2);
1.372 + Vfp::MulS();
1.373 + r[0] = Vfp::SReg(0);
1.374 + TRealX x(a[0]);
1.375 + TRealX y(a[1]);
1.376 + x.MultEq(y);
1.377 + r[1] = (TReal32)x;
1.378 + }
1.379 +
1.380 +void TestNegS(const TReal32* a, TReal32* r)
1.381 + {
1.382 + Vfp::SetSReg(a[0], 1);
1.383 + Vfp::NegS();
1.384 + r[0] = Vfp::SReg(0);
1.385 + r[1] = -a[0];
1.386 + }
1.387 +
1.388 +void TestNMacS(const TReal32* a, TReal32* r)
1.389 + {
1.390 + Vfp::SetSReg(a[0], 0);
1.391 + Vfp::SetSReg(a[1], 1);
1.392 + Vfp::SetSReg(a[2], 2);
1.393 + Vfp::NMacS();
1.394 + r[0] = Vfp::SReg(0);
1.395 + r[1] = a[0] - a[1] * a[2];
1.396 + }
1.397 +
1.398 +void TestNMscS(const TReal32* a, TReal32* r)
1.399 + {
1.400 + Vfp::SetSReg(a[0], 0);
1.401 + Vfp::SetSReg(a[1], 1);
1.402 + Vfp::SetSReg(a[2], 2);
1.403 + Vfp::NMscS();
1.404 + r[0] = Vfp::SReg(0);
1.405 + r[1] = -a[1] * a[2] - a[0];
1.406 + }
1.407 +
1.408 +void TestNMulS(const TReal32* a, TReal32* r)
1.409 + {
1.410 + Vfp::SetSReg(a[0], 1);
1.411 + Vfp::SetSReg(a[1], 2);
1.412 + Vfp::NMulS();
1.413 + r[0] = Vfp::SReg(0);
1.414 + TRealX x(a[0]);
1.415 + TRealX y(a[1]);
1.416 + x.MultEq(y);
1.417 + r[1] = -(TReal32)x;
1.418 + }
1.419 +
1.420 +void TestSqrtS(const TReal32* a, TReal32* r)
1.421 + {
1.422 + Vfp::SetSReg(a[0], 1);
1.423 + Vfp::SqrtS();
1.424 + r[0] = Vfp::SReg(0);
1.425 + TReal x = a[0];
1.426 + TReal y;
1.427 + Math::Sqrt(y, x);
1.428 + r[1] = (TReal32)y;
1.429 + }
1.430 +
1.431 +void TestSubS(const TReal32* a, TReal32* r)
1.432 + {
1.433 + Vfp::SetSReg(a[0], 1);
1.434 + Vfp::SetSReg(a[1], 2);
1.435 + Vfp::SubS();
1.436 + r[0] = Vfp::SReg(0);
1.437 + r[1] = a[0] - a[1];
1.438 + }
1.439 +
1.440 +
1.441 +
1.442 +void TestAbsD(const TReal64* a, TReal64* r)
1.443 + {
1.444 + Vfp::SetDReg(a[0], 1);
1.445 + Vfp::AbsD();
1.446 + r[0] = Vfp::DReg(0);
1.447 + r[1] = Abs(a[0]);
1.448 + }
1.449 +
1.450 +void TestAddD(const TReal64* a, TReal64* r)
1.451 + {
1.452 + Vfp::SetDReg(a[0], 1);
1.453 + Vfp::SetDReg(a[1], 2);
1.454 + Vfp::AddD();
1.455 + r[0] = Vfp::DReg(0);
1.456 + r[1] = a[0] + a[1];
1.457 + }
1.458 +
1.459 +void TestDivD(const TReal64* a, TReal64* r)
1.460 + {
1.461 + Vfp::SetDReg(a[0], 1);
1.462 + Vfp::SetDReg(a[1], 2);
1.463 + Vfp::DivD();
1.464 + r[0] = Vfp::DReg(0);
1.465 + TRealX x(a[0]);
1.466 + TRealX y(a[1]);
1.467 + x.DivEq(y);
1.468 + r[1] = (TReal64)x;
1.469 + }
1.470 +
1.471 +void TestMacD(const TReal64* a, TReal64* r)
1.472 + {
1.473 + Vfp::SetDReg(a[0], 0);
1.474 + Vfp::SetDReg(a[1], 1);
1.475 + Vfp::SetDReg(a[2], 2);
1.476 + Vfp::MacD();
1.477 + r[0] = Vfp::DReg(0);
1.478 + r[1] = a[0] + a[1] * a[2];
1.479 + }
1.480 +
1.481 +void TestMscD(const TReal64* a, TReal64* r)
1.482 + {
1.483 + Vfp::SetDReg(a[0], 0);
1.484 + Vfp::SetDReg(a[1], 1);
1.485 + Vfp::SetDReg(a[2], 2);
1.486 + Vfp::MscD();
1.487 + r[0] = Vfp::DReg(0);
1.488 + r[1] = a[1] * a[2] - a[0];
1.489 + }
1.490 +
1.491 +void TestMulD(const TReal64* a, TReal64* r)
1.492 + {
1.493 + Vfp::SetDReg(a[0], 1);
1.494 + Vfp::SetDReg(a[1], 2);
1.495 + Vfp::MulD();
1.496 + r[0] = Vfp::DReg(0);
1.497 + TRealX x(a[0]);
1.498 + TRealX y(a[1]);
1.499 + x.MultEq(y);
1.500 + r[1] = (TReal64)x;
1.501 + }
1.502 +
1.503 +void TestNegD(const TReal64* a, TReal64* r)
1.504 + {
1.505 + Vfp::SetDReg(a[0], 1);
1.506 + Vfp::NegD();
1.507 + r[0] = Vfp::DReg(0);
1.508 + r[1] = -a[0];
1.509 + }
1.510 +
1.511 +void TestNMacD(const TReal64* a, TReal64* r)
1.512 + {
1.513 + Vfp::SetDReg(a[0], 0);
1.514 + Vfp::SetDReg(a[1], 1);
1.515 + Vfp::SetDReg(a[2], 2);
1.516 + Vfp::NMacD();
1.517 + r[0] = Vfp::DReg(0);
1.518 + r[1] = a[0] - a[1] * a[2];
1.519 + }
1.520 +
1.521 +void TestNMscD(const TReal64* a, TReal64* r)
1.522 + {
1.523 + Vfp::SetDReg(a[0], 0);
1.524 + Vfp::SetDReg(a[1], 1);
1.525 + Vfp::SetDReg(a[2], 2);
1.526 + Vfp::NMscD();
1.527 + r[0] = Vfp::DReg(0);
1.528 + r[1] = -a[1] * a[2] - a[0];
1.529 + }
1.530 +
1.531 +void TestNMulD(const TReal64* a, TReal64* r)
1.532 + {
1.533 + Vfp::SetDReg(a[0], 1);
1.534 + Vfp::SetDReg(a[1], 2);
1.535 + Vfp::NMulD();
1.536 + r[0] = Vfp::DReg(0);
1.537 + TRealX x(a[0]);
1.538 + TRealX y(a[1]);
1.539 + x.MultEq(y);
1.540 + r[1] = -(TReal64)x;
1.541 + }
1.542 +
1.543 +void TestSqrtD(const TReal64* a, TReal64* r)
1.544 + {
1.545 + Vfp::SetDReg(a[0], 1);
1.546 + Vfp::SqrtD();
1.547 + r[0] = Vfp::DReg(0);
1.548 + TReal x = a[0];
1.549 + TReal y;
1.550 + Math::Sqrt(y, x);
1.551 + r[1] = (TReal64)y;
1.552 + }
1.553 +
1.554 +void TestSubD(const TReal64* a, TReal64* r)
1.555 + {
1.556 + Vfp::SetDReg(a[0], 1);
1.557 + Vfp::SetDReg(a[1], 2);
1.558 + Vfp::SubD();
1.559 + r[0] = Vfp::DReg(0);
1.560 + r[1] = a[0] - a[1];
1.561 + }
1.562 +
1.563 +#define DO_SGL_TEST1(name, func, a1) DoSglTest(name, __LINE__, func, a1)
1.564 +#define DO_SGL_TEST2(name, func, a1, a2) DoSglTest(name, __LINE__, func, a1, a2)
1.565 +#define DO_SGL_TEST3(name, func, a1, a2, a3) DoSglTest(name, __LINE__, func, a1, a2, a3)
1.566 +void DoSglTest(const char* aName, TInt aLine, TSglTest aFunc, TReal32 a1, TReal32 a2=0.0f, TReal32 a3=0.0f)
1.567 + {
1.568 + TPtrC8 name8((const TText8*)aName);
1.569 + TBuf<128> name16;
1.570 + name16.Copy(name8);
1.571 + test.Printf(_L("%S(%g,%g,%g)\n"), &name16, a1, a2, a3);
1.572 + TReal32 args[3] = {a1, a2, a3};
1.573 + TReal32 results[2];
1.574 + (*aFunc)(args, results);
1.575 + if (IEEEMode)
1.576 + {
1.577 + if (*((TUint32*)&(results[0])) == *((TUint32*)&(results[1])))
1.578 + return;
1.579 + }
1.580 + else
1.581 + {
1.582 + if (results[0] == results[1])
1.583 + return;
1.584 + }
1.585 + const TUint32* pa = (const TUint32*)args;
1.586 + const TUint32* pr = (const TUint32*)results;
1.587 + test.Printf(_L("a1=%08x a2=%08x a3=%08x\n"), pa[0], pa[1], pa[2]);
1.588 + test.Printf(_L("actual result = %08x (%g)\nexpected result = %08x (%g)\n"), pr[0], results[0], pr[1], results[1]);
1.589 + test.Printf(_L("Test at line %d failed\n"), aLine);
1.590 + test(0);
1.591 + }
1.592 +
1.593 +void DoSglTests()
1.594 + {
1.595 + // ABS
1.596 + DO_SGL_TEST1("ABS", &TestAbsS, 1.0f);
1.597 + DO_SGL_TEST1("ABS", &TestAbsS, -1.0f);
1.598 + DO_SGL_TEST1("ABS", &TestAbsS, 0.0f);
1.599 + DO_SGL_TEST1("ABS", &TestAbsS, -3.1415926536f);
1.600 +
1.601 + // NEG
1.602 + DO_SGL_TEST1("NEG", &TestNegS, 1.0f);
1.603 + DO_SGL_TEST1("NEG", &TestNegS, -1.0f);
1.604 + DO_SGL_TEST1("NEG", &TestNegS, 0.0f);
1.605 + DO_SGL_TEST1("NEG", &TestNegS, -3.1415926536f);
1.606 +
1.607 + // ADD
1.608 + DO_SGL_TEST2("ADD", &TestAddS, 0.0f, 0.0f);
1.609 + DO_SGL_TEST2("ADD", &TestAddS, 0.0f, 1.0f);
1.610 + DO_SGL_TEST2("ADD", &TestAddS, -1.0f, 1.0f);
1.611 + DO_SGL_TEST2("ADD", &TestAddS, 1.0f, 2.5f);
1.612 + DO_SGL_TEST2("ADD", &TestAddS, 1.0f, 6.022045e23f);
1.613 + DO_SGL_TEST2("ADD", &TestAddS, -7.3890561f, 1.414213562f);
1.614 + DO_SGL_TEST2("ADD", &TestAddS, -7.3890561f, -1.414213562f);
1.615 +
1.616 + // SUB
1.617 + DO_SGL_TEST2("SUB", &TestSubS, 0.0f, 0.0f);
1.618 + DO_SGL_TEST2("SUB", &TestSubS, 0.0f, 1.0f);
1.619 + DO_SGL_TEST2("SUB", &TestSubS, 1.0f, 1.0f);
1.620 + DO_SGL_TEST2("SUB", &TestSubS, 1.0f, 2.5f);
1.621 + DO_SGL_TEST2("SUB", &TestSubS, 91.0f, 2.5f);
1.622 + DO_SGL_TEST2("SUB", &TestSubS, 1.0f, 6.022045e23f);
1.623 + DO_SGL_TEST2("SUB", &TestSubS, -7.3890561f, 1.414213562f);
1.624 + DO_SGL_TEST2("SUB", &TestSubS, -7.3890561f, -1.414213562f);
1.625 +
1.626 + // MUL
1.627 + DO_SGL_TEST2("MUL", &TestMulS, 0.0f, 0.0f);
1.628 + DO_SGL_TEST2("MUL", &TestMulS, 1.0f, 0.0f);
1.629 + DO_SGL_TEST2("MUL", &TestMulS, 0.0f, 1.0f);
1.630 + DO_SGL_TEST2("MUL", &TestMulS, 2.5f, 6.5f);
1.631 + DO_SGL_TEST2("MUL", &TestMulS, -39.6f, 19.72f);
1.632 + DO_SGL_TEST2("MUL", &TestMulS, -10.1f, -20.1f);
1.633 + DO_SGL_TEST2("MUL", &TestMulS, 1e20f, 1e20f);
1.634 + DO_SGL_TEST2("MUL", &TestMulS, 1e-30f, 1e-30f);
1.635 +
1.636 + // DIV
1.637 + DO_SGL_TEST2("DIV", &TestDivS, 0.0f, 1.0f);
1.638 + DO_SGL_TEST2("DIV", &TestDivS, 1.0f, 5.0f);
1.639 + DO_SGL_TEST2("DIV", &TestDivS, 1.0f, -5.0f);
1.640 + DO_SGL_TEST2("DIV", &TestDivS, -1.0f, 5.0f);
1.641 + DO_SGL_TEST2("DIV", &TestDivS, -1.0f, -5.0f);
1.642 + DO_SGL_TEST2("DIV", &TestDivS, 7.3890561f, 2.7182818f);
1.643 + DO_SGL_TEST2("DIV", &TestDivS, 1e20f, 1e-20f);
1.644 + DO_SGL_TEST2("DIV", &TestDivS, 1e-30f, 1e30f);
1.645 +
1.646 + // NMUL
1.647 + DO_SGL_TEST2("NMUL", &TestNMulS, 0.0f, 0.0f);
1.648 + DO_SGL_TEST2("NMUL", &TestNMulS, 1.0f, 0.0f);
1.649 + DO_SGL_TEST2("NMUL", &TestNMulS, 0.0f, 1.0f);
1.650 + DO_SGL_TEST2("NMUL", &TestNMulS, 2.5f, 6.5f);
1.651 + DO_SGL_TEST2("NMUL", &TestNMulS, -39.6f, 19.72f);
1.652 + DO_SGL_TEST2("NMUL", &TestNMulS, -10.1f, -20.1f);
1.653 + DO_SGL_TEST2("NMUL", &TestNMulS, 1e20f, 1e20f);
1.654 + DO_SGL_TEST2("NMUL", &TestNMulS, 1e-30f, 1e-30f);
1.655 +
1.656 + // SQRT
1.657 + DO_SGL_TEST1("SQRT", &TestSqrtS, 0.0f);
1.658 + DO_SGL_TEST1("SQRT", &TestSqrtS, 1.0f);
1.659 + DO_SGL_TEST1("SQRT", &TestSqrtS, 2.0f);
1.660 + DO_SGL_TEST1("SQRT", &TestSqrtS, 3.0f);
1.661 + DO_SGL_TEST1("SQRT", &TestSqrtS, 9096256.0f);
1.662 + DO_SGL_TEST1("SQRT", &TestSqrtS, 1e36f);
1.663 + DO_SGL_TEST1("SQRT", &TestSqrtS, 1e-36f);
1.664 +
1.665 + // MAC
1.666 + DO_SGL_TEST3("MAC", &TestMacS, 0.0f, 0.0f, 0.0f);
1.667 + DO_SGL_TEST3("MAC", &TestMacS, 0.0f, 1.0f, 0.0f);
1.668 + DO_SGL_TEST3("MAC", &TestMacS, 0.0f, 1.0f, 1.0f);
1.669 + DO_SGL_TEST3("MAC", &TestMacS, -1.0f, 1.0f, 1.0f);
1.670 + DO_SGL_TEST3("MAC", &TestMacS, 0.8f, 0.1f, 8.0f);
1.671 + DO_SGL_TEST3("MAC", &TestMacS, 0.8f, -0.1f, 8.0f);
1.672 + DO_SGL_TEST3("MAC", &TestMacS, -0.8f, -0.1f, -8.0f);
1.673 + DO_SGL_TEST3("MAC", &TestMacS, 0.8f, 0.3333333333f, 3.1415926536f);
1.674 +
1.675 + // MSC
1.676 + DO_SGL_TEST3("MSC", &TestMscS, 0.0f, 0.0f, 0.0f);
1.677 + DO_SGL_TEST3("MSC", &TestMscS, 0.0f, 1.0f, 0.0f);
1.678 + DO_SGL_TEST3("MSC", &TestMscS, 0.0f, 1.0f, 1.0f);
1.679 + DO_SGL_TEST3("MSC", &TestMscS, -1.0f, 1.0f, 1.0f);
1.680 + DO_SGL_TEST3("MSC", &TestMscS, 0.8f, 0.1f, 8.0f);
1.681 + DO_SGL_TEST3("MSC", &TestMscS, 0.8f, -0.1f, 8.0f);
1.682 + DO_SGL_TEST3("MSC", &TestMscS, -0.8f, -0.1f, -8.0f);
1.683 + DO_SGL_TEST3("MSC", &TestMscS, 0.8f, 0.3333333333f, 3.1415926536f);
1.684 +
1.685 + // NMAC
1.686 + DO_SGL_TEST3("NMAC", &TestNMacS, 0.0f, 0.0f, 0.0f);
1.687 + DO_SGL_TEST3("NMAC", &TestNMacS, 0.0f, 1.0f, 0.0f);
1.688 + DO_SGL_TEST3("NMAC", &TestNMacS, 0.0f, 1.0f, 1.0f);
1.689 + DO_SGL_TEST3("NMAC", &TestNMacS, -1.0f, 1.0f, 1.0f);
1.690 + DO_SGL_TEST3("NMAC", &TestNMacS, 0.8f, 0.1f, 8.0f);
1.691 + DO_SGL_TEST3("NMAC", &TestNMacS, 0.8f, -0.1f, 8.0f);
1.692 + DO_SGL_TEST3("NMAC", &TestNMacS, -0.8f, -0.1f, -8.0f);
1.693 + DO_SGL_TEST3("NMAC", &TestNMacS, 0.8f, 0.3333333333f, 3.1415926536f);
1.694 +
1.695 + // NMSC
1.696 + DO_SGL_TEST3("NMSC", &TestNMscS, 0.0f, 0.0f, 0.0f);
1.697 + DO_SGL_TEST3("NMSC", &TestNMscS, 0.0f, 1.0f, 0.0f);
1.698 + DO_SGL_TEST3("NMSC", &TestNMscS, 0.0f, 1.0f, 1.0f);
1.699 + DO_SGL_TEST3("NMSC", &TestNMscS, -1.0f, 1.0f, 1.0f);
1.700 + DO_SGL_TEST3("NMSC", &TestNMscS, 0.8f, 0.1f, 8.0f);
1.701 + DO_SGL_TEST3("NMSC", &TestNMscS, 0.8f, -0.1f, 8.0f);
1.702 + DO_SGL_TEST3("NMSC", &TestNMscS, -0.8f, -0.1f, -8.0f);
1.703 + DO_SGL_TEST3("NMSC", &TestNMscS, 0.8f, 0.3333333333f, 3.1415926536f);
1.704 + }
1.705 +
1.706 +#define DO_DBL_TEST1(name, func, a1) DoDblTest(name, __LINE__, func, a1)
1.707 +#define DO_DBL_TEST2(name, func, a1, a2) DoDblTest(name, __LINE__, func, a1, a2)
1.708 +#define DO_DBL_TEST3(name, func, a1, a2, a3) DoDblTest(name, __LINE__, func, a1, a2, a3)
1.709 +void DoDblTest(const char* aName, TInt aLine, TDblTest aFunc, TReal64 a1, TReal64 a2=0.0, TReal64 a3=0.0)
1.710 + {
1.711 + TPtrC8 name8((const TText8*)aName);
1.712 + TBuf<128> name16;
1.713 + name16.Copy(name8);
1.714 + test.Printf(_L("%S(%g,%g,%g)\n"), &name16, a1, a2, a3);
1.715 + TReal64 args[3] = {a1, a2, a3};
1.716 + TReal64 results[2];
1.717 + SDouble sargs[3];
1.718 + sargs[0] = a1;
1.719 + sargs[1] = a2;
1.720 + sargs[2] = a3;
1.721 + (*aFunc)(args, results);
1.722 + if (IEEEMode)
1.723 + {
1.724 + if (*((TUint64*)&(results[0])) == *((TUint64*)&(results[1])))
1.725 + return;
1.726 + }
1.727 + else
1.728 + {
1.729 + if (results[0] == results[1])
1.730 + return;
1.731 + }
1.732 + SDouble sres[3];
1.733 + sres[0] = results[0];
1.734 + sres[1] = results[1];
1.735 + test.Printf(_L("a1=%08x %08x\na2=%08x %08x\na3=%08x %08x\n"), sargs[0].iData[1], sargs[0].iData[0],
1.736 + sargs[1].iData[1], sargs[1].iData[0], sargs[2].iData[1], sargs[2].iData[0]);
1.737 + test.Printf(_L("actual result = %08x %08x (%g)\nexpected result = %08x %08x (%g)\n"),
1.738 + sres[0].iData[1], sres[0].iData[0], results[0], sres[1].iData[1], sres[1].iData[0], results[1]);
1.739 + test.Printf(_L("Test at line %d failed\n"), aLine);
1.740 + test(0);
1.741 + }
1.742 +
1.743 +void DoDblTests()
1.744 + {
1.745 + // ABS
1.746 + DO_DBL_TEST1("ABS", &TestAbsD, 1.0);
1.747 + DO_DBL_TEST1("ABS", &TestAbsD, -1.0);
1.748 + DO_DBL_TEST1("ABS", &TestAbsD, 0.0);
1.749 + DO_DBL_TEST1("ABS", &TestAbsD, -3.1415926536);
1.750 +
1.751 + // NEG
1.752 + DO_DBL_TEST1("NEG", &TestNegD, 1.0);
1.753 + DO_DBL_TEST1("NEG", &TestNegD, -1.0);
1.754 + DO_DBL_TEST1("NEG", &TestNegD, 0.0);
1.755 + DO_DBL_TEST1("NEG", &TestNegD, -3.1415926536);
1.756 +
1.757 + // ADD
1.758 + DO_DBL_TEST2("ADD", &TestAddD, 0.0, 0.0);
1.759 + DO_DBL_TEST2("ADD", &TestAddD, 0.0, 1.0);
1.760 + DO_DBL_TEST2("ADD", &TestAddD, -1.0, 1.0);
1.761 + DO_DBL_TEST2("ADD", &TestAddD, 1.0, 2.5);
1.762 + DO_DBL_TEST2("ADD", &TestAddD, 1.0, 6.022045e23);
1.763 + DO_DBL_TEST2("ADD", &TestAddD, -7.3890561, 1.414213562);
1.764 + DO_DBL_TEST2("ADD", &TestAddD, -7.3890561, -1.414213562);
1.765 +
1.766 + // SUB
1.767 + DO_DBL_TEST2("SUB", &TestSubD, 0.0, 0.0);
1.768 + DO_DBL_TEST2("SUB", &TestSubD, 0.0, 1.0);
1.769 + DO_DBL_TEST2("SUB", &TestSubD, 1.0, 1.0);
1.770 + DO_DBL_TEST2("SUB", &TestSubD, 1.0, 2.5);
1.771 + DO_DBL_TEST2("SUB", &TestSubD, 91.0, 2.5);
1.772 + DO_DBL_TEST2("SUB", &TestSubD, 1.0, 6.022045e23);
1.773 + DO_DBL_TEST2("SUB", &TestSubD, -7.3890561, 1.414213562);
1.774 + DO_DBL_TEST2("SUB", &TestSubD, -7.3890561, -1.414213562);
1.775 +
1.776 + // MUL
1.777 + DO_DBL_TEST2("MUL", &TestMulD, 0.0, 0.0);
1.778 + DO_DBL_TEST2("MUL", &TestMulD, 1.0, 0.0);
1.779 + DO_DBL_TEST2("MUL", &TestMulD, 0.0, 1.0);
1.780 + DO_DBL_TEST2("MUL", &TestMulD, 2.5, 6.5);
1.781 + DO_DBL_TEST2("MUL", &TestMulD, -39.6, 19.72);
1.782 + DO_DBL_TEST2("MUL", &TestMulD, -10.1, -20.1);
1.783 + DO_DBL_TEST2("MUL", &TestMulD, 1e20, 1e20);
1.784 + DO_DBL_TEST2("MUL", &TestMulD, 1e100, 1e300);
1.785 + DO_DBL_TEST2("MUL", &TestMulD, 1e-20, 1e-20);
1.786 + DO_DBL_TEST2("MUL", &TestMulD, 1e-200, 1e-300);
1.787 +
1.788 + // DIV
1.789 + DO_DBL_TEST2("DIV", &TestDivD, 0.0, 1.0);
1.790 + DO_DBL_TEST2("DIV", &TestDivD, 1.0, 5.0);
1.791 + DO_DBL_TEST2("DIV", &TestDivD, 1.0, -5.0);
1.792 + DO_DBL_TEST2("DIV", &TestDivD, -1.0, 5.0);
1.793 + DO_DBL_TEST2("DIV", &TestDivD, -1.0, -5.0);
1.794 + DO_DBL_TEST2("DIV", &TestDivD, 7.3890561, 2.7182818);
1.795 + DO_DBL_TEST2("DIV", &TestDivD, 1e20, 1e-20);
1.796 + DO_DBL_TEST2("DIV", &TestDivD, 1e-20, 1e20);
1.797 + DO_DBL_TEST2("DIV", &TestDivD, 1e-50, 1e300);
1.798 +
1.799 + // NMUL
1.800 + DO_DBL_TEST2("NMUL", &TestNMulD, 0.0, 0.0);
1.801 + DO_DBL_TEST2("NMUL", &TestNMulD, 1.0, 0.0);
1.802 + DO_DBL_TEST2("NMUL", &TestNMulD, 0.0, 1.0);
1.803 + DO_DBL_TEST2("NMUL", &TestNMulD, 2.5, 6.5);
1.804 + DO_DBL_TEST2("NMUL", &TestNMulD, -39.6, 19.72);
1.805 + DO_DBL_TEST2("NMUL", &TestNMulD, -10.1, -20.1);
1.806 + DO_DBL_TEST2("NMUL", &TestNMulD, 1e20, 1e20);
1.807 + DO_DBL_TEST2("NMUL", &TestNMulD, 1e100, 1e300);
1.808 + DO_DBL_TEST2("NMUL", &TestNMulD, 1e-20, 1e-20);
1.809 + DO_DBL_TEST2("NMUL", &TestNMulD, 1e-200, 1e-300);
1.810 +
1.811 + // SQRT
1.812 + DO_DBL_TEST1("SQRT", &TestSqrtD, 0.0);
1.813 + DO_DBL_TEST1("SQRT", &TestSqrtD, 1.0);
1.814 + DO_DBL_TEST1("SQRT", &TestSqrtD, 2.0);
1.815 + DO_DBL_TEST1("SQRT", &TestSqrtD, 3.0);
1.816 + DO_DBL_TEST1("SQRT", &TestSqrtD, 9096256.0);
1.817 + DO_DBL_TEST1("SQRT", &TestSqrtD, 1e36);
1.818 + DO_DBL_TEST1("SQRT", &TestSqrtD, 1e-36);
1.819 +
1.820 + // MAC
1.821 + DO_DBL_TEST3("MAC", &TestMacD, 0.0, 0.0, 0.0);
1.822 + DO_DBL_TEST3("MAC", &TestMacD, 0.0, 1.0, 0.0);
1.823 + DO_DBL_TEST3("MAC", &TestMacD, 0.0, 1.0, 1.0);
1.824 + DO_DBL_TEST3("MAC", &TestMacD, -1.0, 1.0, 1.0);
1.825 + DO_DBL_TEST3("MAC", &TestMacD, 0.8, 0.1, 8.0);
1.826 + DO_DBL_TEST3("MAC", &TestMacD, 0.8, -0.1, 8.0);
1.827 + DO_DBL_TEST3("MAC", &TestMacD, -0.8, -0.1, -8.0);
1.828 + DO_DBL_TEST3("MAC", &TestMacD, 0.8, 0.3333333333, 3.1415926536);
1.829 +
1.830 + // MSC
1.831 + DO_DBL_TEST3("MSC", &TestMscD, 0.0, 0.0, 0.0);
1.832 + DO_DBL_TEST3("MSC", &TestMscD, 0.0, 1.0, 0.0);
1.833 + DO_DBL_TEST3("MSC", &TestMscD, 0.0, 1.0, 1.0);
1.834 + DO_DBL_TEST3("MSC", &TestMscD, -1.0, 1.0, 1.0);
1.835 + DO_DBL_TEST3("MSC", &TestMscD, 0.8, 0.1, 8.0);
1.836 + DO_DBL_TEST3("MSC", &TestMscD, 0.8, -0.1, 8.0);
1.837 + DO_DBL_TEST3("MSC", &TestMscD, -0.8, -0.1, -8.0);
1.838 + DO_DBL_TEST3("MSC", &TestMscD, 0.8, 0.3333333333, 3.1415926536);
1.839 +
1.840 + // NMAC
1.841 + DO_DBL_TEST3("NMAC", &TestNMacD, 0.0, 0.0, 0.0);
1.842 + DO_DBL_TEST3("NMAC", &TestNMacD, 0.0, 1.0, 0.0);
1.843 + DO_DBL_TEST3("NMAC", &TestNMacD, 0.0, 1.0, 1.0);
1.844 + DO_DBL_TEST3("NMAC", &TestNMacD, -1.0, 1.0, 1.0);
1.845 + DO_DBL_TEST3("NMAC", &TestNMacD, 0.8, 0.1, 8.0);
1.846 + DO_DBL_TEST3("NMAC", &TestNMacD, 0.8, -0.1, 8.0);
1.847 + DO_DBL_TEST3("NMAC", &TestNMacD, -0.8, -0.1, -8.0);
1.848 + DO_DBL_TEST3("NMAC", &TestNMacD, 0.8, 0.3333333333, 3.1415926536);
1.849 +
1.850 + // NMSC
1.851 + DO_DBL_TEST3("NMSC", &TestNMscD, 0.0, 0.0, 0.0);
1.852 + DO_DBL_TEST3("NMSC", &TestNMscD, 0.0, 1.0, 0.0);
1.853 + DO_DBL_TEST3("NMSC", &TestNMscD, 0.0, 1.0, 1.0);
1.854 + DO_DBL_TEST3("NMSC", &TestNMscD, -1.0, 1.0, 1.0);
1.855 + DO_DBL_TEST3("NMSC", &TestNMscD, 0.8, 0.1, 8.0);
1.856 + DO_DBL_TEST3("NMSC", &TestNMscD, 0.8, -0.1, 8.0);
1.857 + DO_DBL_TEST3("NMSC", &TestNMscD, -0.8, -0.1, -8.0);
1.858 + DO_DBL_TEST3("NMSC", &TestNMscD, 0.8, 0.3333333333, 3.1415926536);
1.859 + }
1.860 +
1.861 +void DoBounceTests()
1.862 + {
1.863 + test.Next(_L("Test denormal handling - single"));
1.864 + DO_SGL_TEST2("ADD", &TestAddS, 1e-39f, 1e-39f);
1.865 + test.Next(_L("Test potential underflow - single"));
1.866 + DO_SGL_TEST2("MUL", &TestMulS, 3.162e-20f, 3.162e-20f);
1.867 +// fails on VFPv2 hardware. ARM's library should be fixed
1.868 +// test.Next(_L("Test NaN input - single"));
1.869 +// TReal32 aSingleNaN;
1.870 +// *((TUint32*)&aSingleNaN) = 0x7F9ABCDE;
1.871 +// Vfp::SetSReg(aSingleNaN, 1);
1.872 +// Vfp::SetSReg(aSingleNaN, 2);
1.873 +// Vfp::AddS();
1.874 +// TReal32 aSingleResult = Vfp::SReg(0);
1.875 +// test(*((TUint32*)&aSingleResult) == 0x7FDABCDE);
1.876 +
1.877 + if (Double)
1.878 + {
1.879 + test.Next(_L("Test denormal handling - double"));
1.880 + DO_DBL_TEST2("ADD", &TestAddD, 3.1234e-322, 3.1234e-322);
1.881 + test.Next(_L("Test potential underflow - double"));
1.882 + DO_DBL_TEST2("MUL", &TestMulD, 1.767e-161, 1.767e-161);
1.883 +// fails on VFPv2 hardware. ARM's library should be fixed
1.884 +// test.Next(_L("Test NaN input - double"));
1.885 +// TReal64 aDoubleNaN;
1.886 +// *((TUint64*)&aDoubleNaN) = 0x7FF0123456789ABCll;
1.887 +// Vfp::SetDReg(aDoubleNaN, 1);
1.888 +// Vfp::SetDReg(aDoubleNaN, 2);
1.889 +// Vfp::AddD();
1.890 +// TReal64 aDoubleResult = Vfp::DReg(0);
1.891 +// test(*((TUint64*)&aDoubleResult) == 0x7FF8123456789ABC);
1.892 + }
1.893 + }
1.894 +
1.895 +void DoRunFastTests()
1.896 + {
1.897 + test.Next(_L("Test flushing denormals to zero - single"));
1.898 + Vfp::SetSReg(1e-39f, 1);
1.899 + Vfp::SetSReg(1e-39f, 2);
1.900 + Vfp::AddS();
1.901 + test(Vfp::SReg(0)==0);
1.902 +
1.903 + test.Next(_L("Test flushing underflow to zero - single"));
1.904 + Vfp::SetSReg(3.162e-20f, 1);
1.905 + Vfp::SetSReg(3.162e-20f, 2);
1.906 + Vfp::MulS();
1.907 + test(Vfp::SReg(0)==0);
1.908 +
1.909 + test.Next(_L("Test default NaNs - single"));
1.910 + TReal32 aSingleNaN;
1.911 + *((TUint32*)&aSingleNaN) = 0x7F9ABCDE;
1.912 + Vfp::SetSReg(aSingleNaN, 1);
1.913 + Vfp::SetSReg(aSingleNaN, 2);
1.914 + Vfp::AddS();
1.915 + TReal32 aSingleResult = Vfp::SReg(0);
1.916 + test(*((TUint32*)&aSingleResult) == 0x7FC00000);
1.917 +
1.918 + if (Double)
1.919 + {
1.920 + test.Next(_L("Test flushing denormals to zero - double"));
1.921 + Vfp::SetDReg(3.1234e-322, 1);
1.922 + Vfp::SetDReg(3.1234e-322, 2);
1.923 + Vfp::AddD();
1.924 + test(Vfp::DReg(0)==0);
1.925 +
1.926 + test.Next(_L("Test flushing underflow to zero - double"));
1.927 + Vfp::SetDReg(1.767e-161, 1);
1.928 + Vfp::SetDReg(1.767e-161, 2);
1.929 + Vfp::MulD();
1.930 + test(Vfp::DReg(0)==0);
1.931 +
1.932 + test.Next(_L("Test default NaNs - double"));
1.933 + TReal64 aDoubleNaN;
1.934 + *((TUint64*)&aDoubleNaN) = 0x7FF0123456789ABCll;
1.935 + Vfp::SetDReg(aDoubleNaN, 1);
1.936 + Vfp::SetDReg(aDoubleNaN, 2);
1.937 + Vfp::AddD();
1.938 + TReal64 aDoubleResult = Vfp::DReg(0);
1.939 + test(*((TUint64*)&aDoubleResult) == 0x7FF8000000000000ll);
1.940 + }
1.941 + }
1.942 +
1.943 +void TestAddSResult(const TReal32 a, const TReal32 b, const TReal32 r)
1.944 + {
1.945 + Vfp::SetSReg(a, 1);
1.946 + Vfp::SetSReg(b, 2);
1.947 + Vfp::AddS();
1.948 + test(Vfp::SReg(0) == r);
1.949 + }
1.950 +
1.951 +void DoRoundingTests()
1.952 + {
1.953 + TFloatingPointMode fpmode = IEEEMode ? EFpModeIEEENoExceptions : EFpModeRunFast;
1.954 + test.Next(_L("Check default rounding to nearest"));
1.955 + test(User::SetFloatingPointMode(fpmode) == KErrNone);
1.956 + test.Next(_L("Check nearest-downward"));
1.957 + TestAddSResult(16777215, 0.49f, 16777215);
1.958 + test.Next(_L("Check nearest-upward"));
1.959 + TestAddSResult(16777215, 0.51f, 16777216);
1.960 + test.Next(_L("Set rounding mode to toward-plus-infinity"));
1.961 + test(User::SetFloatingPointMode(fpmode, EFpRoundToPlusInfinity) == KErrNone);
1.962 + test.Next(_L("Check positive rounding goes upward"));
1.963 + TestAddSResult(16777215, 0.49f, 16777216);
1.964 + test.Next(_L("Check negative rounding goes upward"));
1.965 + TestAddSResult(-16777215, -0.51f, -16777215);
1.966 + test.Next(_L("Set rounding mode to toward-minus-infinity"));
1.967 + test(User::SetFloatingPointMode(fpmode, EFpRoundToMinusInfinity) == KErrNone);
1.968 + test.Next(_L("Check positive rounding goes downward"));
1.969 + TestAddSResult(16777215, 0.51f, 16777215);
1.970 + test.Next(_L("Check negative rounding goes downward"));
1.971 + TestAddSResult(-16777215, -0.49f, -16777216);
1.972 + test.Next(_L("Set rounding mode to toward-zero"));
1.973 + test(User::SetFloatingPointMode(fpmode, EFpRoundToZero) == KErrNone);
1.974 + test.Next(_L("Check positive rounding goes downward"));
1.975 + TestAddSResult(16777215, 0.51f, 16777215);
1.976 + test.Next(_L("Check negative rounding goes upward"));
1.977 + TestAddSResult(-16777215, -0.51f, -16777215);
1.978 + }
1.979 +
1.980 +TInt RunFastThread(TAny* /*unused*/)
1.981 + {
1.982 + Vfp::SetSReg(1e-39f, 1);
1.983 + Vfp::SetSReg(1e-39f, 2);
1.984 + Vfp::AddS();
1.985 + return (Vfp::SReg(0)==0) ? KErrNone : KErrGeneral;
1.986 + }
1.987 +
1.988 +TInt IEEECompliantThread(TAny* /*unused*/)
1.989 + {
1.990 + Vfp::SetSReg(1e-39f, 1);
1.991 + Vfp::SetSReg(1e-39f, 2);
1.992 + Vfp::AddS();
1.993 + return (Vfp::SReg(0)==2e-39f) ? KErrNone : KErrGeneral;
1.994 + }
1.995 +
1.996 +void TestVFPModeInheritance()
1.997 + {
1.998 + test.Printf(_L("Set floating point mode to RunFast\n"));
1.999 + test(User::SetFloatingPointMode(EFpModeRunFast)==KErrNone);
1.1000 + RThread t;
1.1001 + TInt r = t.Create(KNullDesC, &RunFastThread, 0x1000, NULL, NULL);
1.1002 + test(r==KErrNone);
1.1003 + TRequestStatus s;
1.1004 + t.Logon(s);
1.1005 + test.Printf(_L("Run RunFast test in another thread...\n"));
1.1006 + t.Resume();
1.1007 + test.Printf(_L("Wait for other thread to terminate\n"));
1.1008 + User::WaitForRequest(s);
1.1009 + test(t.ExitType() == EExitKill);
1.1010 + test(s == KErrNone);
1.1011 + CLOSE_AND_WAIT(t);
1.1012 + test.Printf(_L("Set floating point mode to IEEE\n"));
1.1013 + test(User::SetFloatingPointMode(EFpModeIEEENoExceptions)==KErrNone);
1.1014 + r = t.Create(KNullDesC, &IEEECompliantThread, 0x1000, NULL, NULL);
1.1015 + test(r==KErrNone);
1.1016 + t.Logon(s);
1.1017 + test.Printf(_L("Run IEEE test in another thread...\n"));
1.1018 + t.Resume();
1.1019 + test.Printf(_L("Wait for other thread to terminate\n"));
1.1020 + User::WaitForRequest(s);
1.1021 + test(t.ExitType() == EExitKill);
1.1022 + test(s == KErrNone);
1.1023 + CLOSE_AND_WAIT(t);
1.1024 + }
1.1025 +
1.1026 +
1.1027 +void TestVFPv3()
1.1028 + {
1.1029 + test.Next(_L("Transferring to and from fixed point"));
1.1030 +
1.1031 + Vfp::SetSReg(2.5f, 0);
1.1032 + test(Vfp::SReg(0)==2.5f);
1.1033 + Vfp::ToFixedS(3); // Convert to fixed (3) precision
1.1034 + test(Vfp::SRegInt(0)==0x14); // 10.100 in binary fixed(3) format
1.1035 + Vfp::FromFixedS(3); //Convert from fixed (3) precision
1.1036 + test(Vfp::SReg(0)==2.5f);
1.1037 +
1.1038 +
1.1039 + test.Next(_L("Setting immediate value to floating point registers"));
1.1040 +
1.1041 + Vfp::SetSReg(5.0f, 0);
1.1042 + test(Vfp::SReg(0) == 5.0f);
1.1043 + Vfp::TconstS2();
1.1044 + test(Vfp::SReg(0) == 2.0f);
1.1045 + Vfp::SetSReg(5.0f, 0);
1.1046 + Vfp::TconstS2_8();
1.1047 + test(Vfp::SReg(0) == 2.875f);
1.1048 +
1.1049 + Vfp::SetDReg(5.0f, 0);
1.1050 + test(Vfp::DReg(0) == 5.0f);
1.1051 + Vfp::TconstD2();
1.1052 + test(Vfp::DReg(0) == 2.0f);
1.1053 + Vfp::TconstD2_8();
1.1054 + test(Vfp::DReg(0) == 2.875f);
1.1055 + }
1.1056 +
1.1057 +void TestNEON()
1.1058 + {
1.1059 + RThread t;
1.1060 + TRequestStatus s;
1.1061 + test.Next(_L("Test creating a thread to execute an F2-prefix instruction"));
1.1062 + test_KErrNone(t.Create(KNullDesC, &NeonWithF2, 0x1000, NULL, NULL));
1.1063 + t.Logon(s);
1.1064 + t.Resume();
1.1065 + User::WaitForRequest(s);
1.1066 + test(t.ExitType() == EExitKill);
1.1067 + test(s == KErrNone);
1.1068 + t.Close();
1.1069 + test.Next(_L("Test creating a thread to execute an F3-prefix instruction"));
1.1070 + test_KErrNone(t.Create(KNullDesC, &NeonWithF3, 0x1000, NULL, NULL));
1.1071 + t.Logon(s);
1.1072 + t.Resume();
1.1073 + User::WaitForRequest(s);
1.1074 + test(t.ExitType() == EExitKill);
1.1075 + test(s == KErrNone);
1.1076 + t.Close();
1.1077 + test.Next(_L("Test creating a thread to execute an F4x-prefix instruction"));
1.1078 + test_KErrNone(t.Create(KNullDesC, &NeonWithF4x, 0x1000, NULL, NULL));
1.1079 + t.Logon(s);
1.1080 + t.Resume();
1.1081 + User::WaitForRequest(s);
1.1082 + test(t.ExitType() == EExitKill);
1.1083 + test(s == KErrNone);
1.1084 + t.Close();
1.1085 + }
1.1086 +
1.1087 +void TestThumb()
1.1088 + {
1.1089 + RThread t;
1.1090 + TRequestStatus s;
1.1091 + TInt testStep = 0;
1.1092 + do {
1.1093 + test_KErrNone(t.Create(KNullDesC, &ThumbMode, 0x1000, NULL, (TAny*)testStep++));
1.1094 + t.Logon(s);
1.1095 + t.Resume();
1.1096 + User::WaitForRequest(s);
1.1097 + test(s == KErrNone || s == 1);
1.1098 + test(t.ExitType() == EExitKill);
1.1099 + t.Close();
1.1100 + }
1.1101 + while (s == KErrNone);
1.1102 +
1.1103 + test(s == 1);
1.1104 + test(testStep == 7);
1.1105 + }
1.1106 +
1.1107 +TInt TestThreadMigration(TAny* aPtr)
1.1108 + {
1.1109 + const TInt inc = (TInt)aPtr;
1.1110 + for (TInt32 switches = 0; switches < KMaxTInt; switches += inc)
1.1111 + {
1.1112 + Vfp::SetSReg(switches, switches % 16);
1.1113 + UserSvr::HalFunction(EHalGroupKernel, EKernelHalLockThreadToCpu, (TAny*)(switches % CPUs), 0);
1.1114 + test(Vfp::SRegInt(switches % 16) == switches);
1.1115 + }
1.1116 + return KErrNone;
1.1117 + }
1.1118 +
1.1119 +TInt E32Main()
1.1120 + {
1.1121 + test.Title();
1.1122 +
1.1123 + test.Start(_L("Ask HAL if we have hardware floating point"));
1.1124 +
1.1125 + CPUs = UserSvr::HalFunction(EHalGroupKernel, EKernelHalNumLogicalCpus, 0, 0);
1.1126 + TInt supportedTypes;
1.1127 + TInt HalVfp = HAL::Get(HALData::EHardwareFloatingPoint, supportedTypes);
1.1128 + if (HalVfp == KErrNone)
1.1129 + {
1.1130 + if (supportedTypes == EFpTypeVFPv2)
1.1131 + {
1.1132 + test.Printf(_L("HAL reports VFPv2\n"));
1.1133 + }
1.1134 + else if (supportedTypes == EFpTypeVFPv3)
1.1135 + {
1.1136 + test.Printf(_L("HAL reports VFPv3\n"));
1.1137 + }
1.1138 + else if (supportedTypes == EFpTypeVFPv3D16)
1.1139 + {
1.1140 + test.Printf(_L("HAL reports VFPv3-D16\n"));
1.1141 + }
1.1142 + else
1.1143 + {
1.1144 + test.Printf(_L("HAL reports an unknown floating point type\n"));
1.1145 + test(0);
1.1146 + }
1.1147 + }
1.1148 + else
1.1149 + {
1.1150 + test.Printf(_L("HAL reports no VFP support\n"));
1.1151 + }
1.1152 +
1.1153 + test.Next(_L("Check VFP present"));
1.1154 + TBool present = DetectVFP();
1.1155 + if (!present)
1.1156 + {
1.1157 + test.Printf(_L("No VFP detected\n"));
1.1158 + test(HalVfp == KErrNotSupported ||
1.1159 + ((supportedTypes != EFpTypeVFPv2) &&
1.1160 + (supportedTypes != EFpTypeVFPv3) &&
1.1161 + (supportedTypes != EFpTypeVFPv3D16))
1.1162 + );
1.1163 + test.End();
1.1164 + return 0;
1.1165 + }
1.1166 +
1.1167 + test.Printf(_L("VFP detected. FPSID = %08x\n"), FPSID);
1.1168 + test(HalVfp == KErrNone);
1.1169 +
1.1170 + // Verify that the HAL architecture ID matches the FPSID values
1.1171 + // ARMv7 redefines some of these bits so the masks are different :(
1.1172 + if (supportedTypes == EFpTypeVFPv2)
1.1173 + {
1.1174 + // assume armv5/6's bit definitions, where 19:16 are the arch version
1.1175 + // and 20 is the single-precision-only bit
1.1176 + ArchVersion = (FPSID >> 16) & 0xf;
1.1177 + test(ArchVersion == ARCH_VERSION_VFPV2);
1.1178 + Double = !(FPSID & VFP_FPSID_SNG);
1.1179 + }
1.1180 + else if (supportedTypes == EFpTypeVFPv3 || supportedTypes == EFpTypeVFPv3D16)
1.1181 + {
1.1182 + // assume armv7's bit definitions, where 22:16 are the arch version
1.1183 + ArchVersion = (FPSID >> 16) & 0x7f;
1.1184 + test(ArchVersion == ARCH_VERSION_VFPV3_SUBARCH_V2
1.1185 + || ArchVersion == ARCH_VERSION_VFPV3_SUBARCH_NULL
1.1186 + || ArchVersion == ARCH_VERSION_VFPV3_SUBARCH_V3);
1.1187 + // there are bits for this in MVFR0 but ARM implementations should always have it?
1.1188 + Double = ETrue;
1.1189 + }
1.1190 +
1.1191 + if (Double)
1.1192 + test.Printf(_L("Both single and double precision supported\n"), FPSID);
1.1193 + else
1.1194 + test.Printf(_L("Only single precision supported\n"), FPSID);
1.1195 +
1.1196 + test.Next(_L("Test VFP Initial State"));
1.1197 + TestVFPInitialState();
1.1198 +
1.1199 + test.Next(_L("Test setting VFP to IEEE no exceptions mode"));
1.1200 + IEEEMode = User::SetFloatingPointMode(EFpModeIEEENoExceptions) == KErrNone;
1.1201 + if (!IEEEMode)
1.1202 + test.Printf(_L("IEEE no exceptions mode not supported, continuing in RunFast\n"));
1.1203 +
1.1204 + test.Next(_L("Test VFP calculations - single"));
1.1205 + DoSglTests();
1.1206 + if (Double)
1.1207 + {
1.1208 + test.Next(_L("Test VFP calculations - double"));
1.1209 + DoDblTests();
1.1210 + }
1.1211 +
1.1212 + test.Next(_L("Test VFP Context Save"));
1.1213 + TestVFPContextSave();
1.1214 +
1.1215 + if (IEEEMode)
1.1216 + {
1.1217 + test.Next(_L("Test bounce handling"));
1.1218 + DoBounceTests();
1.1219 + test.Next(_L("Test bouncing while context switching"));
1.1220 + DoBounceContextSwitchTests();
1.1221 + test.Next(_L("Test setting VFP to RunFast mode"));
1.1222 + test(User::SetFloatingPointMode(EFpModeRunFast) == KErrNone);
1.1223 + DoRunFastTests();
1.1224 + }
1.1225 +
1.1226 + test.Next(_L("Test VFP rounding modes"));
1.1227 + DoRoundingTests();
1.1228 +
1.1229 + if (IEEEMode)
1.1230 + {
1.1231 + test.Next(_L("Test VFP mode inheritance between threads"));
1.1232 + TestVFPModeInheritance();
1.1233 + }
1.1234 +
1.1235 + if (supportedTypes == EFpTypeVFPv3 || supportedTypes == EFpTypeVFPv3D16)
1.1236 + {
1.1237 + test.Next(_L("Test VFPv3"));
1.1238 + TestVFPv3();
1.1239 +
1.1240 + if (supportedTypes == EFpTypeVFPv3)
1.1241 + {
1.1242 + test.Next(_L("Test NEON"));
1.1243 + TestNEON();
1.1244 +
1.1245 +#if defined(__SUPPORT_THUMB_INTERWORKING)
1.1246 + test.Next(_L("Test Thumb Decode"));
1.1247 + TestThumb();
1.1248 +#endif
1.1249 + }
1.1250 + }
1.1251 +
1.1252 + if (CPUs > 1)
1.1253 + {
1.1254 + test.Next(_L("Test SMP Thread Migration"));
1.1255 + TInt inc = 1;
1.1256 + RThread t[8];
1.1257 + TRequestStatus s[8];
1.1258 + TInt count;
1.1259 + for (count = 0; count < CPUs + 1; count++)
1.1260 + {
1.1261 + TInt r = t[count].Create(KNullDesC, &TestThreadMigration, 0x1000, NULL, (TAny*)(inc++));
1.1262 + test(r==KErrNone);
1.1263 + t[count].Logon(s[count]);
1.1264 + }
1.1265 + for (count = 0; count < CPUs + 1; count++)
1.1266 + {
1.1267 + t[count].Resume();
1.1268 + }
1.1269 + User::After(10*1000*1000);
1.1270 + for (count = 0; count < CPUs + 1; count++)
1.1271 + {
1.1272 + t[count].Kill(0);
1.1273 + }
1.1274 + for (count = 0; count < CPUs + 1; count++)
1.1275 + {
1.1276 + User::WaitForAnyRequest();
1.1277 + }
1.1278 + for (count = 0; count < CPUs + 1; count++)
1.1279 + {
1.1280 + TInt xt = t[count].ExitType();
1.1281 + TInt xr = t[count].ExitReason();
1.1282 + test(xt == EExitKill && xr == KErrNone);
1.1283 + }
1.1284 + for (count = 0; count < CPUs + 1; count++)
1.1285 + {
1.1286 + CLOSE_AND_WAIT(t[count]);
1.1287 + }
1.1288 + }
1.1289 +
1.1290 + test.End();
1.1291 + return 0;
1.1292 + }