|
1 // Copyright (c) 2003-2009 Nokia Corporation and/or its subsidiary(-ies). |
|
2 // All rights reserved. |
|
3 // This component and the accompanying materials are made available |
|
4 // under the terms of the License "Eclipse Public License v1.0" |
|
5 // which accompanies this distribution, and is available |
|
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
7 // |
|
8 // Initial Contributors: |
|
9 // Nokia Corporation - initial contribution. |
|
10 // |
|
11 // Contributors: |
|
12 // |
|
13 // Description: |
|
14 // e32test\math\t_vfp.cpp |
|
15 // Overview: |
|
16 // Test the ARM Vector Floating Point operations. |
|
17 // API Information: |
|
18 // VFP |
|
19 // Details: |
|
20 // - Check that the HAL agrees with the hardware about whether |
|
21 // VFP is supported. |
|
22 // - Test setting VFP to IEEE with no exceptions mode, if IEEE mode is |
|
23 // supported, otherwise leave the mode alone. |
|
24 // - Test single and double precision vector floating point operations: |
|
25 // ABS, NEG, ADD, SUB, MUL, DIV, NMUL, SQRT, MAC, MSC, NMAC and NMSC. |
|
26 // Verify results are as expected - if IEEE mode was set, verify |
|
27 // bit-for-bit, in accordance with the IEEE specification, otherwise |
|
28 // use normal floating point equality. |
|
29 // - Test VFP context save. |
|
30 // - Test various VFP operations that cause bounces to support code if |
|
31 // IEEE mode is supported. |
|
32 // - Test setting VFP to RunFast mode if RunFast mode is supported. |
|
33 // - Test setting VFP rounding mode. |
|
34 // - Test inheriting VFP mode to created threads. |
|
35 // Platforms/Drives/Compatibility: |
|
36 // All |
|
37 // Assumptions/Requirement/Pre-requisites: |
|
38 // Failures and causes: |
|
39 // Base Port information: |
|
40 // |
|
41 // |
|
42 |
|
43 //! @file |
|
44 //! @SYMTestCaseID KBASE-0017-T_VFP |
|
45 //! @SYMTestCaseDesc VFPv2 general functionality and bounce handling |
|
46 //! @SYMREQ 5159 |
|
47 //! @SYMTestPriority Critical |
|
48 //! @SYMTestActions Check VFP functions correctly in all modes and that mode switching works correctly. |
|
49 //! @SYMTestExpectedResults Test runs until this message is emitted: RTEST: SUCCESS : T_VFP test completed O.K. |
|
50 //! @SYMTestType UT |
|
51 |
|
52 #include "t_vfp.h" |
|
53 #define __E32TEST_EXTENSION__ |
|
54 #include <e32test.h> |
|
55 #include <e32math.h> |
|
56 #include <hal.h> |
|
57 #include <e32svr.h> |
|
58 #include <u32hal.h> |
|
59 |
|
60 RTest test(_L("T_VFP")); |
|
61 TUint32 FPSID; |
|
62 TUint32 ArchVersion; |
|
63 TBool Double; |
|
64 TBool IEEEMode; |
|
65 TInt CPUs; |
|
66 TInt CurrentCpu1; |
|
67 TInt CurrentCpu2; |
|
68 |
|
69 typedef void TSglTest(const TReal32* aArgs, TReal32* aResults); |
|
70 typedef void TDblTest(const TReal64* aArgs, TReal64* aResults); |
|
71 |
|
72 TBool DetectVFP() |
|
73 { |
|
74 TInt r = UserSvr::HalFunction(EHalGroupKernel, EKernelHalFloatingPointSystemId, &FPSID, NULL); |
|
75 return (r==KErrNone); |
|
76 } |
|
77 |
|
78 TInt TestVFPInitThreadFn(TAny* aPtr) |
|
79 { |
|
80 UserSvr::HalFunction(EHalGroupKernel, EKernelHalLockThreadToCpu, (TAny*)CurrentCpu1, 0); |
|
81 TReal32* p = (TReal32*)aPtr; |
|
82 TInt i; |
|
83 for (i=0; i<32; ++i) |
|
84 *p++ = Vfp::SReg(i); |
|
85 return 0; |
|
86 } |
|
87 |
|
88 void TestVFPInitialState() |
|
89 { |
|
90 for (CurrentCpu1 = 0; CurrentCpu1 < CPUs; CurrentCpu1++) |
|
91 { |
|
92 TReal32 f[32]; |
|
93 RThread t; |
|
94 TInt r = t.Create(KNullDesC, &TestVFPInitThreadFn, 0x1000, NULL, f); |
|
95 test(r==KErrNone); |
|
96 TRequestStatus s; |
|
97 t.Logon(s); |
|
98 t.Resume(); |
|
99 User::WaitForRequest(s); |
|
100 TInt xt = t.ExitType(); |
|
101 TInt xr = t.ExitReason(); |
|
102 test(xt == EExitKill && xr == KErrNone); |
|
103 CLOSE_AND_WAIT(t); |
|
104 UserSvr::HalFunction(EHalGroupKernel, EKernelHalLockThreadToCpu, (TAny*)CurrentCpu1, 0); |
|
105 test.Printf(_L("FPSCR = %08x for core %d\n"), Vfp::Fpscr(), CurrentCpu1); |
|
106 const TUint32* p = (const TUint32*)f; |
|
107 for (TInt i=0; i<32; ++i) |
|
108 { |
|
109 if (f[i] != 0.0f) |
|
110 { |
|
111 test.Printf(_L("S%d = 0x%08x\n"), i, p[i]); |
|
112 test(f[i] == 0.0f); |
|
113 } |
|
114 } |
|
115 } |
|
116 } |
|
117 |
|
118 void TestVFPSglRegs(TInt aIter=2) |
|
119 { |
|
120 TInt i; |
|
121 TInt j; |
|
122 TInt nSglRegs=0; |
|
123 |
|
124 switch(ArchVersion) |
|
125 { |
|
126 case ARCH_VERSION_VFPV2: |
|
127 case ARCH_VERSION_VFPV3_SUBARCH_V2: |
|
128 case ARCH_VERSION_VFPV3_SUBARCH_NULL: |
|
129 case ARCH_VERSION_VFPV3_SUBARCH_V3: |
|
130 nSglRegs = 32; |
|
131 break; |
|
132 case 0: |
|
133 default: |
|
134 __ASSERT_ALWAYS(0, User::Panic(_L("Bad VFP version"),__LINE__)); |
|
135 /* NOTREACHED */ |
|
136 } |
|
137 |
|
138 for (i=0; i<aIter; ++i) |
|
139 { |
|
140 for (j=0; j<nSglRegs; ++j) |
|
141 { |
|
142 TInt32 f = i + j; |
|
143 Vfp::SetSReg(f, j); |
|
144 } |
|
145 for (j=0; j<nSglRegs; ++j) |
|
146 { |
|
147 TInt32 f = i + j; |
|
148 TInt32 g = Vfp::SRegInt(j); |
|
149 test(f == g); |
|
150 } |
|
151 } |
|
152 } |
|
153 |
|
154 TInt TestVFPSglRegsThread(TAny*) |
|
155 { |
|
156 UserSvr::HalFunction(EHalGroupKernel, EKernelHalLockThreadToCpu, (TAny*)CurrentCpu1, 0); |
|
157 TestVFPSglRegs(KMaxTInt); |
|
158 return 0; |
|
159 } |
|
160 |
|
161 void TestVFPDblRegs(TInt aIter=2) |
|
162 { |
|
163 TInt i; |
|
164 TInt j; |
|
165 TInt nDblRegs=0; |
|
166 |
|
167 switch(ArchVersion) |
|
168 { |
|
169 case ARCH_VERSION_VFPV2: |
|
170 { |
|
171 nDblRegs = 16; |
|
172 break; |
|
173 } |
|
174 case ARCH_VERSION_VFPV3_SUBARCH_V2: |
|
175 case ARCH_VERSION_VFPV3_SUBARCH_NULL: |
|
176 case ARCH_VERSION_VFPV3_SUBARCH_V3: |
|
177 { |
|
178 TInt vfpType; |
|
179 TInt ret = HAL::Get(HALData::EHardwareFloatingPoint, vfpType); |
|
180 if (ret == KErrNone && vfpType == EFpTypeVFPv3) |
|
181 nDblRegs = 32; |
|
182 else |
|
183 nDblRegs = 16; |
|
184 break; |
|
185 } |
|
186 case 0: |
|
187 default: |
|
188 __ASSERT_ALWAYS(0, User::Panic(_L("Bad VFP version"),__LINE__)); |
|
189 } |
|
190 |
|
191 |
|
192 for (i=0; i<aIter; ++i) |
|
193 { |
|
194 for (j=0; j<nDblRegs; ++j) |
|
195 { |
|
196 TInt64 f = i + j + KMaxTUint; |
|
197 Vfp::SetDReg(f, j); |
|
198 } |
|
199 for (j=0; j<nDblRegs; ++j) |
|
200 { |
|
201 TInt64 f = i + j + KMaxTUint; |
|
202 TInt64 g = Vfp::DRegInt(j); |
|
203 test(f == g); |
|
204 } |
|
205 } |
|
206 } |
|
207 |
|
208 TInt TestVFPDblRegsThread(TAny*) |
|
209 { |
|
210 UserSvr::HalFunction(EHalGroupKernel, EKernelHalLockThreadToCpu, (TAny*)CurrentCpu2, 0); |
|
211 TestVFPDblRegs(KMaxTInt); |
|
212 return 0; |
|
213 } |
|
214 |
|
215 void TestVFPContextSave() |
|
216 { |
|
217 for (CurrentCpu2 = 0; CurrentCpu2 < CPUs; CurrentCpu2++) |
|
218 { |
|
219 for (CurrentCpu1 = 0; CurrentCpu1 < CPUs; CurrentCpu1++) |
|
220 { |
|
221 TThreadFunction tf1 = &TestVFPSglRegsThread; |
|
222 TThreadFunction tf2 = Double ? &TestVFPDblRegsThread : &TestVFPSglRegsThread; |
|
223 RThread t1, t2; |
|
224 TInt r; |
|
225 r = t1.Create(KNullDesC, tf1, 0x1000, 0x1000, 0x1000, NULL); |
|
226 test(r==KErrNone); |
|
227 t1.SetPriority(EPriorityLess); |
|
228 r = t2.Create(KNullDesC, tf2, 0x1000, 0x1000, 0x1000, NULL); |
|
229 test(r==KErrNone); |
|
230 t2.SetPriority(EPriorityLess); |
|
231 TRequestStatus s1, s2; |
|
232 t1.Logon(s1); |
|
233 t2.Logon(s2); |
|
234 t1.Resume(); |
|
235 t2.Resume(); |
|
236 test.Printf(_L("Let threads run concurrently (cores %d and %d)\n"), CurrentCpu1, CurrentCpu2); |
|
237 User::After(20*1000*1000/CPUs); |
|
238 |
|
239 test.Printf(_L("Kill threads\n")); |
|
240 t1.Kill(0); |
|
241 t2.Kill(0); |
|
242 User::WaitForRequest(s1); |
|
243 User::WaitForRequest(s2); |
|
244 test(t1.ExitType()==EExitKill && t1.ExitReason()==KErrNone); |
|
245 test(t2.ExitType()==EExitKill && t2.ExitReason()==KErrNone); |
|
246 CLOSE_AND_WAIT(t1); |
|
247 CLOSE_AND_WAIT(t2); |
|
248 } |
|
249 } |
|
250 } |
|
251 |
|
252 TInt TestBounceCtxThread1(TAny*) |
|
253 { |
|
254 UserSvr::HalFunction(EHalGroupKernel, EKernelHalLockThreadToCpu, (TAny*)Max(CPUs-1, 0), 0); |
|
255 for(TInt iter=0; iter<KMaxTInt; ++iter) |
|
256 { |
|
257 Vfp::SReg(0); |
|
258 } |
|
259 return KErrNone; |
|
260 } |
|
261 |
|
262 TInt TestBounceCtxThread2(TAny*) |
|
263 { |
|
264 UserSvr::HalFunction(EHalGroupKernel, EKernelHalLockThreadToCpu, (TAny*)Max(CPUs-1, 0), 0); |
|
265 TInt start_rep = 0x00800000; // smallest single precision normal number, 1*2^-126 |
|
266 TReal32 start = *(TReal32*)&start_rep; |
|
267 for(TInt iter=0; iter<KMaxTInt; ++iter) |
|
268 { |
|
269 Vfp::SetSReg(start, 1); |
|
270 Vfp::SetSReg(2.0f, 2); |
|
271 Vfp::DivS(); |
|
272 Vfp::CpyS0(1); |
|
273 Vfp::MulS(); |
|
274 Vfp::CpyS0(1); |
|
275 TReal32 end = Vfp::SReg(0); |
|
276 TInt end_rep = *(TInt*)&end; |
|
277 if (start_rep != end_rep) |
|
278 { |
|
279 RDebug::Printf("mismatch in iter %d, start %08x end %08x\n", iter, start_rep, end_rep); |
|
280 test(0); |
|
281 } |
|
282 } |
|
283 return KErrNone; |
|
284 } |
|
285 |
|
286 void DoBounceContextSwitchTests() |
|
287 { |
|
288 UserSvr::HalFunction(EHalGroupKernel, EKernelHalLockThreadToCpu, 0, 0); |
|
289 RThread t1, t2; |
|
290 TInt r; |
|
291 r = t1.Create(KNullDesC, &TestBounceCtxThread1, 0x1000, 0x1000, 0x1000, NULL); |
|
292 test(r==KErrNone); |
|
293 t1.SetPriority(EPriorityLess); |
|
294 r = t2.Create(KNullDesC, &TestBounceCtxThread2, 0x1000, 0x1000, 0x1000, NULL); |
|
295 test(r==KErrNone); |
|
296 t2.SetPriority(EPriorityLess); |
|
297 TRequestStatus s1, s2; |
|
298 t1.Logon(s1); |
|
299 t2.Logon(s2); |
|
300 t1.Resume(); |
|
301 t2.Resume(); |
|
302 test.Printf(_L("Let threads run concurrently ...\n")); |
|
303 User::After(20*1000*1000); |
|
304 |
|
305 test.Printf(_L("Kill threads\n")); |
|
306 t1.Kill(0); |
|
307 t2.Kill(0); |
|
308 User::WaitForRequest(s1); |
|
309 User::WaitForRequest(s2); |
|
310 test(t1.ExitType()==EExitKill && t1.ExitReason()==KErrNone); |
|
311 test(t2.ExitType()==EExitKill && t2.ExitReason()==KErrNone); |
|
312 CLOSE_AND_WAIT(t1); |
|
313 CLOSE_AND_WAIT(t2); |
|
314 } |
|
315 |
|
316 void TestAbsS(const TReal32* a, TReal32* r) |
|
317 { |
|
318 Vfp::SetSReg(a[0], 1); |
|
319 Vfp::AbsS(); |
|
320 r[0] = Vfp::SReg(0); |
|
321 r[1] = Abs(a[0]); |
|
322 } |
|
323 |
|
324 void TestAddS(const TReal32* a, TReal32* r) |
|
325 { |
|
326 Vfp::SetSReg(a[0], 1); |
|
327 Vfp::SetSReg(a[1], 2); |
|
328 Vfp::AddS(); |
|
329 r[0] = Vfp::SReg(0); |
|
330 r[1] = a[0] + a[1]; |
|
331 } |
|
332 |
|
333 void TestDivS(const TReal32* a, TReal32* r) |
|
334 { |
|
335 Vfp::SetSReg(a[0], 1); |
|
336 Vfp::SetSReg(a[1], 2); |
|
337 Vfp::DivS(); |
|
338 r[0] = Vfp::SReg(0); |
|
339 TRealX x(a[0]); |
|
340 TRealX y(a[1]); |
|
341 x.DivEq(y); |
|
342 r[1] = (TReal32)x; |
|
343 } |
|
344 |
|
345 void TestMacS(const TReal32* a, TReal32* r) |
|
346 { |
|
347 Vfp::SetSReg(a[0], 0); |
|
348 Vfp::SetSReg(a[1], 1); |
|
349 Vfp::SetSReg(a[2], 2); |
|
350 Vfp::MacS(); |
|
351 r[0] = Vfp::SReg(0); |
|
352 r[1] = a[0] + a[1] * a[2]; |
|
353 } |
|
354 |
|
355 void TestMscS(const TReal32* a, TReal32* r) |
|
356 { |
|
357 Vfp::SetSReg(a[0], 0); |
|
358 Vfp::SetSReg(a[1], 1); |
|
359 Vfp::SetSReg(a[2], 2); |
|
360 Vfp::MscS(); |
|
361 r[0] = Vfp::SReg(0); |
|
362 r[1] = a[1] * a[2] - a[0]; |
|
363 } |
|
364 |
|
365 void TestMulS(const TReal32* a, TReal32* r) |
|
366 { |
|
367 Vfp::SetSReg(a[0], 1); |
|
368 Vfp::SetSReg(a[1], 2); |
|
369 Vfp::MulS(); |
|
370 r[0] = Vfp::SReg(0); |
|
371 TRealX x(a[0]); |
|
372 TRealX y(a[1]); |
|
373 x.MultEq(y); |
|
374 r[1] = (TReal32)x; |
|
375 } |
|
376 |
|
377 void TestNegS(const TReal32* a, TReal32* r) |
|
378 { |
|
379 Vfp::SetSReg(a[0], 1); |
|
380 Vfp::NegS(); |
|
381 r[0] = Vfp::SReg(0); |
|
382 r[1] = -a[0]; |
|
383 } |
|
384 |
|
385 void TestNMacS(const TReal32* a, TReal32* r) |
|
386 { |
|
387 Vfp::SetSReg(a[0], 0); |
|
388 Vfp::SetSReg(a[1], 1); |
|
389 Vfp::SetSReg(a[2], 2); |
|
390 Vfp::NMacS(); |
|
391 r[0] = Vfp::SReg(0); |
|
392 r[1] = a[0] - a[1] * a[2]; |
|
393 } |
|
394 |
|
395 void TestNMscS(const TReal32* a, TReal32* r) |
|
396 { |
|
397 Vfp::SetSReg(a[0], 0); |
|
398 Vfp::SetSReg(a[1], 1); |
|
399 Vfp::SetSReg(a[2], 2); |
|
400 Vfp::NMscS(); |
|
401 r[0] = Vfp::SReg(0); |
|
402 r[1] = -a[1] * a[2] - a[0]; |
|
403 } |
|
404 |
|
405 void TestNMulS(const TReal32* a, TReal32* r) |
|
406 { |
|
407 Vfp::SetSReg(a[0], 1); |
|
408 Vfp::SetSReg(a[1], 2); |
|
409 Vfp::NMulS(); |
|
410 r[0] = Vfp::SReg(0); |
|
411 TRealX x(a[0]); |
|
412 TRealX y(a[1]); |
|
413 x.MultEq(y); |
|
414 r[1] = -(TReal32)x; |
|
415 } |
|
416 |
|
417 void TestSqrtS(const TReal32* a, TReal32* r) |
|
418 { |
|
419 Vfp::SetSReg(a[0], 1); |
|
420 Vfp::SqrtS(); |
|
421 r[0] = Vfp::SReg(0); |
|
422 TReal x = a[0]; |
|
423 TReal y; |
|
424 Math::Sqrt(y, x); |
|
425 r[1] = (TReal32)y; |
|
426 } |
|
427 |
|
428 void TestSubS(const TReal32* a, TReal32* r) |
|
429 { |
|
430 Vfp::SetSReg(a[0], 1); |
|
431 Vfp::SetSReg(a[1], 2); |
|
432 Vfp::SubS(); |
|
433 r[0] = Vfp::SReg(0); |
|
434 r[1] = a[0] - a[1]; |
|
435 } |
|
436 |
|
437 |
|
438 |
|
439 void TestAbsD(const TReal64* a, TReal64* r) |
|
440 { |
|
441 Vfp::SetDReg(a[0], 1); |
|
442 Vfp::AbsD(); |
|
443 r[0] = Vfp::DReg(0); |
|
444 r[1] = Abs(a[0]); |
|
445 } |
|
446 |
|
447 void TestAddD(const TReal64* a, TReal64* r) |
|
448 { |
|
449 Vfp::SetDReg(a[0], 1); |
|
450 Vfp::SetDReg(a[1], 2); |
|
451 Vfp::AddD(); |
|
452 r[0] = Vfp::DReg(0); |
|
453 r[1] = a[0] + a[1]; |
|
454 } |
|
455 |
|
456 void TestDivD(const TReal64* a, TReal64* r) |
|
457 { |
|
458 Vfp::SetDReg(a[0], 1); |
|
459 Vfp::SetDReg(a[1], 2); |
|
460 Vfp::DivD(); |
|
461 r[0] = Vfp::DReg(0); |
|
462 TRealX x(a[0]); |
|
463 TRealX y(a[1]); |
|
464 x.DivEq(y); |
|
465 r[1] = (TReal64)x; |
|
466 } |
|
467 |
|
468 void TestMacD(const TReal64* a, TReal64* r) |
|
469 { |
|
470 Vfp::SetDReg(a[0], 0); |
|
471 Vfp::SetDReg(a[1], 1); |
|
472 Vfp::SetDReg(a[2], 2); |
|
473 Vfp::MacD(); |
|
474 r[0] = Vfp::DReg(0); |
|
475 r[1] = a[0] + a[1] * a[2]; |
|
476 } |
|
477 |
|
478 void TestMscD(const TReal64* a, TReal64* r) |
|
479 { |
|
480 Vfp::SetDReg(a[0], 0); |
|
481 Vfp::SetDReg(a[1], 1); |
|
482 Vfp::SetDReg(a[2], 2); |
|
483 Vfp::MscD(); |
|
484 r[0] = Vfp::DReg(0); |
|
485 r[1] = a[1] * a[2] - a[0]; |
|
486 } |
|
487 |
|
488 void TestMulD(const TReal64* a, TReal64* r) |
|
489 { |
|
490 Vfp::SetDReg(a[0], 1); |
|
491 Vfp::SetDReg(a[1], 2); |
|
492 Vfp::MulD(); |
|
493 r[0] = Vfp::DReg(0); |
|
494 TRealX x(a[0]); |
|
495 TRealX y(a[1]); |
|
496 x.MultEq(y); |
|
497 r[1] = (TReal64)x; |
|
498 } |
|
499 |
|
500 void TestNegD(const TReal64* a, TReal64* r) |
|
501 { |
|
502 Vfp::SetDReg(a[0], 1); |
|
503 Vfp::NegD(); |
|
504 r[0] = Vfp::DReg(0); |
|
505 r[1] = -a[0]; |
|
506 } |
|
507 |
|
508 void TestNMacD(const TReal64* a, TReal64* r) |
|
509 { |
|
510 Vfp::SetDReg(a[0], 0); |
|
511 Vfp::SetDReg(a[1], 1); |
|
512 Vfp::SetDReg(a[2], 2); |
|
513 Vfp::NMacD(); |
|
514 r[0] = Vfp::DReg(0); |
|
515 r[1] = a[0] - a[1] * a[2]; |
|
516 } |
|
517 |
|
518 void TestNMscD(const TReal64* a, TReal64* r) |
|
519 { |
|
520 Vfp::SetDReg(a[0], 0); |
|
521 Vfp::SetDReg(a[1], 1); |
|
522 Vfp::SetDReg(a[2], 2); |
|
523 Vfp::NMscD(); |
|
524 r[0] = Vfp::DReg(0); |
|
525 r[1] = -a[1] * a[2] - a[0]; |
|
526 } |
|
527 |
|
528 void TestNMulD(const TReal64* a, TReal64* r) |
|
529 { |
|
530 Vfp::SetDReg(a[0], 1); |
|
531 Vfp::SetDReg(a[1], 2); |
|
532 Vfp::NMulD(); |
|
533 r[0] = Vfp::DReg(0); |
|
534 TRealX x(a[0]); |
|
535 TRealX y(a[1]); |
|
536 x.MultEq(y); |
|
537 r[1] = -(TReal64)x; |
|
538 } |
|
539 |
|
540 void TestSqrtD(const TReal64* a, TReal64* r) |
|
541 { |
|
542 Vfp::SetDReg(a[0], 1); |
|
543 Vfp::SqrtD(); |
|
544 r[0] = Vfp::DReg(0); |
|
545 TReal x = a[0]; |
|
546 TReal y; |
|
547 Math::Sqrt(y, x); |
|
548 r[1] = (TReal64)y; |
|
549 } |
|
550 |
|
551 void TestSubD(const TReal64* a, TReal64* r) |
|
552 { |
|
553 Vfp::SetDReg(a[0], 1); |
|
554 Vfp::SetDReg(a[1], 2); |
|
555 Vfp::SubD(); |
|
556 r[0] = Vfp::DReg(0); |
|
557 r[1] = a[0] - a[1]; |
|
558 } |
|
559 |
|
560 #define DO_SGL_TEST1(name, func, a1) DoSglTest(name, __LINE__, func, a1) |
|
561 #define DO_SGL_TEST2(name, func, a1, a2) DoSglTest(name, __LINE__, func, a1, a2) |
|
562 #define DO_SGL_TEST3(name, func, a1, a2, a3) DoSglTest(name, __LINE__, func, a1, a2, a3) |
|
563 void DoSglTest(const char* aName, TInt aLine, TSglTest aFunc, TReal32 a1, TReal32 a2=0.0f, TReal32 a3=0.0f) |
|
564 { |
|
565 TPtrC8 name8((const TText8*)aName); |
|
566 TBuf<128> name16; |
|
567 name16.Copy(name8); |
|
568 test.Printf(_L("%S(%g,%g,%g)\n"), &name16, a1, a2, a3); |
|
569 TReal32 args[3] = {a1, a2, a3}; |
|
570 TReal32 results[2]; |
|
571 (*aFunc)(args, results); |
|
572 if (IEEEMode) |
|
573 { |
|
574 if (*((TUint32*)&(results[0])) == *((TUint32*)&(results[1]))) |
|
575 return; |
|
576 } |
|
577 else |
|
578 { |
|
579 if (results[0] == results[1]) |
|
580 return; |
|
581 } |
|
582 const TUint32* pa = (const TUint32*)args; |
|
583 const TUint32* pr = (const TUint32*)results; |
|
584 test.Printf(_L("a1=%08x a2=%08x a3=%08x\n"), pa[0], pa[1], pa[2]); |
|
585 test.Printf(_L("actual result = %08x (%g)\nexpected result = %08x (%g)\n"), pr[0], results[0], pr[1], results[1]); |
|
586 test.Printf(_L("Test at line %d failed\n"), aLine); |
|
587 test(0); |
|
588 } |
|
589 |
|
590 void DoSglTests() |
|
591 { |
|
592 // ABS |
|
593 DO_SGL_TEST1("ABS", &TestAbsS, 1.0f); |
|
594 DO_SGL_TEST1("ABS", &TestAbsS, -1.0f); |
|
595 DO_SGL_TEST1("ABS", &TestAbsS, 0.0f); |
|
596 DO_SGL_TEST1("ABS", &TestAbsS, -3.1415926536f); |
|
597 |
|
598 // NEG |
|
599 DO_SGL_TEST1("NEG", &TestNegS, 1.0f); |
|
600 DO_SGL_TEST1("NEG", &TestNegS, -1.0f); |
|
601 DO_SGL_TEST1("NEG", &TestNegS, 0.0f); |
|
602 DO_SGL_TEST1("NEG", &TestNegS, -3.1415926536f); |
|
603 |
|
604 // ADD |
|
605 DO_SGL_TEST2("ADD", &TestAddS, 0.0f, 0.0f); |
|
606 DO_SGL_TEST2("ADD", &TestAddS, 0.0f, 1.0f); |
|
607 DO_SGL_TEST2("ADD", &TestAddS, -1.0f, 1.0f); |
|
608 DO_SGL_TEST2("ADD", &TestAddS, 1.0f, 2.5f); |
|
609 DO_SGL_TEST2("ADD", &TestAddS, 1.0f, 6.022045e23f); |
|
610 DO_SGL_TEST2("ADD", &TestAddS, -7.3890561f, 1.414213562f); |
|
611 DO_SGL_TEST2("ADD", &TestAddS, -7.3890561f, -1.414213562f); |
|
612 |
|
613 // SUB |
|
614 DO_SGL_TEST2("SUB", &TestSubS, 0.0f, 0.0f); |
|
615 DO_SGL_TEST2("SUB", &TestSubS, 0.0f, 1.0f); |
|
616 DO_SGL_TEST2("SUB", &TestSubS, 1.0f, 1.0f); |
|
617 DO_SGL_TEST2("SUB", &TestSubS, 1.0f, 2.5f); |
|
618 DO_SGL_TEST2("SUB", &TestSubS, 91.0f, 2.5f); |
|
619 DO_SGL_TEST2("SUB", &TestSubS, 1.0f, 6.022045e23f); |
|
620 DO_SGL_TEST2("SUB", &TestSubS, -7.3890561f, 1.414213562f); |
|
621 DO_SGL_TEST2("SUB", &TestSubS, -7.3890561f, -1.414213562f); |
|
622 |
|
623 // MUL |
|
624 DO_SGL_TEST2("MUL", &TestMulS, 0.0f, 0.0f); |
|
625 DO_SGL_TEST2("MUL", &TestMulS, 1.0f, 0.0f); |
|
626 DO_SGL_TEST2("MUL", &TestMulS, 0.0f, 1.0f); |
|
627 DO_SGL_TEST2("MUL", &TestMulS, 2.5f, 6.5f); |
|
628 DO_SGL_TEST2("MUL", &TestMulS, -39.6f, 19.72f); |
|
629 DO_SGL_TEST2("MUL", &TestMulS, -10.1f, -20.1f); |
|
630 DO_SGL_TEST2("MUL", &TestMulS, 1e20f, 1e20f); |
|
631 DO_SGL_TEST2("MUL", &TestMulS, 1e-30f, 1e-30f); |
|
632 |
|
633 // DIV |
|
634 DO_SGL_TEST2("DIV", &TestDivS, 0.0f, 1.0f); |
|
635 DO_SGL_TEST2("DIV", &TestDivS, 1.0f, 5.0f); |
|
636 DO_SGL_TEST2("DIV", &TestDivS, 1.0f, -5.0f); |
|
637 DO_SGL_TEST2("DIV", &TestDivS, -1.0f, 5.0f); |
|
638 DO_SGL_TEST2("DIV", &TestDivS, -1.0f, -5.0f); |
|
639 DO_SGL_TEST2("DIV", &TestDivS, 7.3890561f, 2.7182818f); |
|
640 DO_SGL_TEST2("DIV", &TestDivS, 1e20f, 1e-20f); |
|
641 DO_SGL_TEST2("DIV", &TestDivS, 1e-30f, 1e30f); |
|
642 |
|
643 // NMUL |
|
644 DO_SGL_TEST2("NMUL", &TestNMulS, 0.0f, 0.0f); |
|
645 DO_SGL_TEST2("NMUL", &TestNMulS, 1.0f, 0.0f); |
|
646 DO_SGL_TEST2("NMUL", &TestNMulS, 0.0f, 1.0f); |
|
647 DO_SGL_TEST2("NMUL", &TestNMulS, 2.5f, 6.5f); |
|
648 DO_SGL_TEST2("NMUL", &TestNMulS, -39.6f, 19.72f); |
|
649 DO_SGL_TEST2("NMUL", &TestNMulS, -10.1f, -20.1f); |
|
650 DO_SGL_TEST2("NMUL", &TestNMulS, 1e20f, 1e20f); |
|
651 DO_SGL_TEST2("NMUL", &TestNMulS, 1e-30f, 1e-30f); |
|
652 |
|
653 // SQRT |
|
654 DO_SGL_TEST1("SQRT", &TestSqrtS, 0.0f); |
|
655 DO_SGL_TEST1("SQRT", &TestSqrtS, 1.0f); |
|
656 DO_SGL_TEST1("SQRT", &TestSqrtS, 2.0f); |
|
657 DO_SGL_TEST1("SQRT", &TestSqrtS, 3.0f); |
|
658 DO_SGL_TEST1("SQRT", &TestSqrtS, 9096256.0f); |
|
659 DO_SGL_TEST1("SQRT", &TestSqrtS, 1e36f); |
|
660 DO_SGL_TEST1("SQRT", &TestSqrtS, 1e-36f); |
|
661 |
|
662 // MAC |
|
663 DO_SGL_TEST3("MAC", &TestMacS, 0.0f, 0.0f, 0.0f); |
|
664 DO_SGL_TEST3("MAC", &TestMacS, 0.0f, 1.0f, 0.0f); |
|
665 DO_SGL_TEST3("MAC", &TestMacS, 0.0f, 1.0f, 1.0f); |
|
666 DO_SGL_TEST3("MAC", &TestMacS, -1.0f, 1.0f, 1.0f); |
|
667 DO_SGL_TEST3("MAC", &TestMacS, 0.8f, 0.1f, 8.0f); |
|
668 DO_SGL_TEST3("MAC", &TestMacS, 0.8f, -0.1f, 8.0f); |
|
669 DO_SGL_TEST3("MAC", &TestMacS, -0.8f, -0.1f, -8.0f); |
|
670 DO_SGL_TEST3("MAC", &TestMacS, 0.8f, 0.3333333333f, 3.1415926536f); |
|
671 |
|
672 // MSC |
|
673 DO_SGL_TEST3("MSC", &TestMscS, 0.0f, 0.0f, 0.0f); |
|
674 DO_SGL_TEST3("MSC", &TestMscS, 0.0f, 1.0f, 0.0f); |
|
675 DO_SGL_TEST3("MSC", &TestMscS, 0.0f, 1.0f, 1.0f); |
|
676 DO_SGL_TEST3("MSC", &TestMscS, -1.0f, 1.0f, 1.0f); |
|
677 DO_SGL_TEST3("MSC", &TestMscS, 0.8f, 0.1f, 8.0f); |
|
678 DO_SGL_TEST3("MSC", &TestMscS, 0.8f, -0.1f, 8.0f); |
|
679 DO_SGL_TEST3("MSC", &TestMscS, -0.8f, -0.1f, -8.0f); |
|
680 DO_SGL_TEST3("MSC", &TestMscS, 0.8f, 0.3333333333f, 3.1415926536f); |
|
681 |
|
682 // NMAC |
|
683 DO_SGL_TEST3("NMAC", &TestNMacS, 0.0f, 0.0f, 0.0f); |
|
684 DO_SGL_TEST3("NMAC", &TestNMacS, 0.0f, 1.0f, 0.0f); |
|
685 DO_SGL_TEST3("NMAC", &TestNMacS, 0.0f, 1.0f, 1.0f); |
|
686 DO_SGL_TEST3("NMAC", &TestNMacS, -1.0f, 1.0f, 1.0f); |
|
687 DO_SGL_TEST3("NMAC", &TestNMacS, 0.8f, 0.1f, 8.0f); |
|
688 DO_SGL_TEST3("NMAC", &TestNMacS, 0.8f, -0.1f, 8.0f); |
|
689 DO_SGL_TEST3("NMAC", &TestNMacS, -0.8f, -0.1f, -8.0f); |
|
690 DO_SGL_TEST3("NMAC", &TestNMacS, 0.8f, 0.3333333333f, 3.1415926536f); |
|
691 |
|
692 // NMSC |
|
693 DO_SGL_TEST3("NMSC", &TestNMscS, 0.0f, 0.0f, 0.0f); |
|
694 DO_SGL_TEST3("NMSC", &TestNMscS, 0.0f, 1.0f, 0.0f); |
|
695 DO_SGL_TEST3("NMSC", &TestNMscS, 0.0f, 1.0f, 1.0f); |
|
696 DO_SGL_TEST3("NMSC", &TestNMscS, -1.0f, 1.0f, 1.0f); |
|
697 DO_SGL_TEST3("NMSC", &TestNMscS, 0.8f, 0.1f, 8.0f); |
|
698 DO_SGL_TEST3("NMSC", &TestNMscS, 0.8f, -0.1f, 8.0f); |
|
699 DO_SGL_TEST3("NMSC", &TestNMscS, -0.8f, -0.1f, -8.0f); |
|
700 DO_SGL_TEST3("NMSC", &TestNMscS, 0.8f, 0.3333333333f, 3.1415926536f); |
|
701 } |
|
702 |
|
703 #define DO_DBL_TEST1(name, func, a1) DoDblTest(name, __LINE__, func, a1) |
|
704 #define DO_DBL_TEST2(name, func, a1, a2) DoDblTest(name, __LINE__, func, a1, a2) |
|
705 #define DO_DBL_TEST3(name, func, a1, a2, a3) DoDblTest(name, __LINE__, func, a1, a2, a3) |
|
706 void DoDblTest(const char* aName, TInt aLine, TDblTest aFunc, TReal64 a1, TReal64 a2=0.0, TReal64 a3=0.0) |
|
707 { |
|
708 TPtrC8 name8((const TText8*)aName); |
|
709 TBuf<128> name16; |
|
710 name16.Copy(name8); |
|
711 test.Printf(_L("%S(%g,%g,%g)\n"), &name16, a1, a2, a3); |
|
712 TReal64 args[3] = {a1, a2, a3}; |
|
713 TReal64 results[2]; |
|
714 SDouble sargs[3]; |
|
715 sargs[0] = a1; |
|
716 sargs[1] = a2; |
|
717 sargs[2] = a3; |
|
718 (*aFunc)(args, results); |
|
719 if (IEEEMode) |
|
720 { |
|
721 if (*((TUint64*)&(results[0])) == *((TUint64*)&(results[1]))) |
|
722 return; |
|
723 } |
|
724 else |
|
725 { |
|
726 if (results[0] == results[1]) |
|
727 return; |
|
728 } |
|
729 SDouble sres[3]; |
|
730 sres[0] = results[0]; |
|
731 sres[1] = results[1]; |
|
732 test.Printf(_L("a1=%08x %08x\na2=%08x %08x\na3=%08x %08x\n"), sargs[0].iData[1], sargs[0].iData[0], |
|
733 sargs[1].iData[1], sargs[1].iData[0], sargs[2].iData[1], sargs[2].iData[0]); |
|
734 test.Printf(_L("actual result = %08x %08x (%g)\nexpected result = %08x %08x (%g)\n"), |
|
735 sres[0].iData[1], sres[0].iData[0], results[0], sres[1].iData[1], sres[1].iData[0], results[1]); |
|
736 test.Printf(_L("Test at line %d failed\n"), aLine); |
|
737 test(0); |
|
738 } |
|
739 |
|
740 void DoDblTests() |
|
741 { |
|
742 // ABS |
|
743 DO_DBL_TEST1("ABS", &TestAbsD, 1.0); |
|
744 DO_DBL_TEST1("ABS", &TestAbsD, -1.0); |
|
745 DO_DBL_TEST1("ABS", &TestAbsD, 0.0); |
|
746 DO_DBL_TEST1("ABS", &TestAbsD, -3.1415926536); |
|
747 |
|
748 // NEG |
|
749 DO_DBL_TEST1("NEG", &TestNegD, 1.0); |
|
750 DO_DBL_TEST1("NEG", &TestNegD, -1.0); |
|
751 DO_DBL_TEST1("NEG", &TestNegD, 0.0); |
|
752 DO_DBL_TEST1("NEG", &TestNegD, -3.1415926536); |
|
753 |
|
754 // ADD |
|
755 DO_DBL_TEST2("ADD", &TestAddD, 0.0, 0.0); |
|
756 DO_DBL_TEST2("ADD", &TestAddD, 0.0, 1.0); |
|
757 DO_DBL_TEST2("ADD", &TestAddD, -1.0, 1.0); |
|
758 DO_DBL_TEST2("ADD", &TestAddD, 1.0, 2.5); |
|
759 DO_DBL_TEST2("ADD", &TestAddD, 1.0, 6.022045e23); |
|
760 DO_DBL_TEST2("ADD", &TestAddD, -7.3890561, 1.414213562); |
|
761 DO_DBL_TEST2("ADD", &TestAddD, -7.3890561, -1.414213562); |
|
762 |
|
763 // SUB |
|
764 DO_DBL_TEST2("SUB", &TestSubD, 0.0, 0.0); |
|
765 DO_DBL_TEST2("SUB", &TestSubD, 0.0, 1.0); |
|
766 DO_DBL_TEST2("SUB", &TestSubD, 1.0, 1.0); |
|
767 DO_DBL_TEST2("SUB", &TestSubD, 1.0, 2.5); |
|
768 DO_DBL_TEST2("SUB", &TestSubD, 91.0, 2.5); |
|
769 DO_DBL_TEST2("SUB", &TestSubD, 1.0, 6.022045e23); |
|
770 DO_DBL_TEST2("SUB", &TestSubD, -7.3890561, 1.414213562); |
|
771 DO_DBL_TEST2("SUB", &TestSubD, -7.3890561, -1.414213562); |
|
772 |
|
773 // MUL |
|
774 DO_DBL_TEST2("MUL", &TestMulD, 0.0, 0.0); |
|
775 DO_DBL_TEST2("MUL", &TestMulD, 1.0, 0.0); |
|
776 DO_DBL_TEST2("MUL", &TestMulD, 0.0, 1.0); |
|
777 DO_DBL_TEST2("MUL", &TestMulD, 2.5, 6.5); |
|
778 DO_DBL_TEST2("MUL", &TestMulD, -39.6, 19.72); |
|
779 DO_DBL_TEST2("MUL", &TestMulD, -10.1, -20.1); |
|
780 DO_DBL_TEST2("MUL", &TestMulD, 1e20, 1e20); |
|
781 DO_DBL_TEST2("MUL", &TestMulD, 1e100, 1e300); |
|
782 DO_DBL_TEST2("MUL", &TestMulD, 1e-20, 1e-20); |
|
783 DO_DBL_TEST2("MUL", &TestMulD, 1e-200, 1e-300); |
|
784 |
|
785 // DIV |
|
786 DO_DBL_TEST2("DIV", &TestDivD, 0.0, 1.0); |
|
787 DO_DBL_TEST2("DIV", &TestDivD, 1.0, 5.0); |
|
788 DO_DBL_TEST2("DIV", &TestDivD, 1.0, -5.0); |
|
789 DO_DBL_TEST2("DIV", &TestDivD, -1.0, 5.0); |
|
790 DO_DBL_TEST2("DIV", &TestDivD, -1.0, -5.0); |
|
791 DO_DBL_TEST2("DIV", &TestDivD, 7.3890561, 2.7182818); |
|
792 DO_DBL_TEST2("DIV", &TestDivD, 1e20, 1e-20); |
|
793 DO_DBL_TEST2("DIV", &TestDivD, 1e-20, 1e20); |
|
794 DO_DBL_TEST2("DIV", &TestDivD, 1e-50, 1e300); |
|
795 |
|
796 // NMUL |
|
797 DO_DBL_TEST2("NMUL", &TestNMulD, 0.0, 0.0); |
|
798 DO_DBL_TEST2("NMUL", &TestNMulD, 1.0, 0.0); |
|
799 DO_DBL_TEST2("NMUL", &TestNMulD, 0.0, 1.0); |
|
800 DO_DBL_TEST2("NMUL", &TestNMulD, 2.5, 6.5); |
|
801 DO_DBL_TEST2("NMUL", &TestNMulD, -39.6, 19.72); |
|
802 DO_DBL_TEST2("NMUL", &TestNMulD, -10.1, -20.1); |
|
803 DO_DBL_TEST2("NMUL", &TestNMulD, 1e20, 1e20); |
|
804 DO_DBL_TEST2("NMUL", &TestNMulD, 1e100, 1e300); |
|
805 DO_DBL_TEST2("NMUL", &TestNMulD, 1e-20, 1e-20); |
|
806 DO_DBL_TEST2("NMUL", &TestNMulD, 1e-200, 1e-300); |
|
807 |
|
808 // SQRT |
|
809 DO_DBL_TEST1("SQRT", &TestSqrtD, 0.0); |
|
810 DO_DBL_TEST1("SQRT", &TestSqrtD, 1.0); |
|
811 DO_DBL_TEST1("SQRT", &TestSqrtD, 2.0); |
|
812 DO_DBL_TEST1("SQRT", &TestSqrtD, 3.0); |
|
813 DO_DBL_TEST1("SQRT", &TestSqrtD, 9096256.0); |
|
814 DO_DBL_TEST1("SQRT", &TestSqrtD, 1e36); |
|
815 DO_DBL_TEST1("SQRT", &TestSqrtD, 1e-36); |
|
816 |
|
817 // MAC |
|
818 DO_DBL_TEST3("MAC", &TestMacD, 0.0, 0.0, 0.0); |
|
819 DO_DBL_TEST3("MAC", &TestMacD, 0.0, 1.0, 0.0); |
|
820 DO_DBL_TEST3("MAC", &TestMacD, 0.0, 1.0, 1.0); |
|
821 DO_DBL_TEST3("MAC", &TestMacD, -1.0, 1.0, 1.0); |
|
822 DO_DBL_TEST3("MAC", &TestMacD, 0.8, 0.1, 8.0); |
|
823 DO_DBL_TEST3("MAC", &TestMacD, 0.8, -0.1, 8.0); |
|
824 DO_DBL_TEST3("MAC", &TestMacD, -0.8, -0.1, -8.0); |
|
825 DO_DBL_TEST3("MAC", &TestMacD, 0.8, 0.3333333333, 3.1415926536); |
|
826 |
|
827 // MSC |
|
828 DO_DBL_TEST3("MSC", &TestMscD, 0.0, 0.0, 0.0); |
|
829 DO_DBL_TEST3("MSC", &TestMscD, 0.0, 1.0, 0.0); |
|
830 DO_DBL_TEST3("MSC", &TestMscD, 0.0, 1.0, 1.0); |
|
831 DO_DBL_TEST3("MSC", &TestMscD, -1.0, 1.0, 1.0); |
|
832 DO_DBL_TEST3("MSC", &TestMscD, 0.8, 0.1, 8.0); |
|
833 DO_DBL_TEST3("MSC", &TestMscD, 0.8, -0.1, 8.0); |
|
834 DO_DBL_TEST3("MSC", &TestMscD, -0.8, -0.1, -8.0); |
|
835 DO_DBL_TEST3("MSC", &TestMscD, 0.8, 0.3333333333, 3.1415926536); |
|
836 |
|
837 // NMAC |
|
838 DO_DBL_TEST3("NMAC", &TestNMacD, 0.0, 0.0, 0.0); |
|
839 DO_DBL_TEST3("NMAC", &TestNMacD, 0.0, 1.0, 0.0); |
|
840 DO_DBL_TEST3("NMAC", &TestNMacD, 0.0, 1.0, 1.0); |
|
841 DO_DBL_TEST3("NMAC", &TestNMacD, -1.0, 1.0, 1.0); |
|
842 DO_DBL_TEST3("NMAC", &TestNMacD, 0.8, 0.1, 8.0); |
|
843 DO_DBL_TEST3("NMAC", &TestNMacD, 0.8, -0.1, 8.0); |
|
844 DO_DBL_TEST3("NMAC", &TestNMacD, -0.8, -0.1, -8.0); |
|
845 DO_DBL_TEST3("NMAC", &TestNMacD, 0.8, 0.3333333333, 3.1415926536); |
|
846 |
|
847 // NMSC |
|
848 DO_DBL_TEST3("NMSC", &TestNMscD, 0.0, 0.0, 0.0); |
|
849 DO_DBL_TEST3("NMSC", &TestNMscD, 0.0, 1.0, 0.0); |
|
850 DO_DBL_TEST3("NMSC", &TestNMscD, 0.0, 1.0, 1.0); |
|
851 DO_DBL_TEST3("NMSC", &TestNMscD, -1.0, 1.0, 1.0); |
|
852 DO_DBL_TEST3("NMSC", &TestNMscD, 0.8, 0.1, 8.0); |
|
853 DO_DBL_TEST3("NMSC", &TestNMscD, 0.8, -0.1, 8.0); |
|
854 DO_DBL_TEST3("NMSC", &TestNMscD, -0.8, -0.1, -8.0); |
|
855 DO_DBL_TEST3("NMSC", &TestNMscD, 0.8, 0.3333333333, 3.1415926536); |
|
856 } |
|
857 |
|
858 void DoBounceTests() |
|
859 { |
|
860 test.Next(_L("Test denormal handling - single")); |
|
861 DO_SGL_TEST2("ADD", &TestAddS, 1e-39f, 1e-39f); |
|
862 test.Next(_L("Test potential underflow - single")); |
|
863 DO_SGL_TEST2("MUL", &TestMulS, 3.162e-20f, 3.162e-20f); |
|
864 // fails on VFPv2 hardware. ARM's library should be fixed |
|
865 // test.Next(_L("Test NaN input - single")); |
|
866 // TReal32 aSingleNaN; |
|
867 // *((TUint32*)&aSingleNaN) = 0x7F9ABCDE; |
|
868 // Vfp::SetSReg(aSingleNaN, 1); |
|
869 // Vfp::SetSReg(aSingleNaN, 2); |
|
870 // Vfp::AddS(); |
|
871 // TReal32 aSingleResult = Vfp::SReg(0); |
|
872 // test(*((TUint32*)&aSingleResult) == 0x7FDABCDE); |
|
873 |
|
874 if (Double) |
|
875 { |
|
876 test.Next(_L("Test denormal handling - double")); |
|
877 DO_DBL_TEST2("ADD", &TestAddD, 3.1234e-322, 3.1234e-322); |
|
878 test.Next(_L("Test potential underflow - double")); |
|
879 DO_DBL_TEST2("MUL", &TestMulD, 1.767e-161, 1.767e-161); |
|
880 // fails on VFPv2 hardware. ARM's library should be fixed |
|
881 // test.Next(_L("Test NaN input - double")); |
|
882 // TReal64 aDoubleNaN; |
|
883 // *((TUint64*)&aDoubleNaN) = 0x7FF0123456789ABCll; |
|
884 // Vfp::SetDReg(aDoubleNaN, 1); |
|
885 // Vfp::SetDReg(aDoubleNaN, 2); |
|
886 // Vfp::AddD(); |
|
887 // TReal64 aDoubleResult = Vfp::DReg(0); |
|
888 // test(*((TUint64*)&aDoubleResult) == 0x7FF8123456789ABC); |
|
889 } |
|
890 } |
|
891 |
|
892 void DoRunFastTests() |
|
893 { |
|
894 test.Next(_L("Test flushing denormals to zero - single")); |
|
895 Vfp::SetSReg(1e-39f, 1); |
|
896 Vfp::SetSReg(1e-39f, 2); |
|
897 Vfp::AddS(); |
|
898 test(Vfp::SReg(0)==0); |
|
899 |
|
900 test.Next(_L("Test flushing underflow to zero - single")); |
|
901 Vfp::SetSReg(3.162e-20f, 1); |
|
902 Vfp::SetSReg(3.162e-20f, 2); |
|
903 Vfp::MulS(); |
|
904 test(Vfp::SReg(0)==0); |
|
905 |
|
906 test.Next(_L("Test default NaNs - single")); |
|
907 TReal32 aSingleNaN; |
|
908 *((TUint32*)&aSingleNaN) = 0x7F9ABCDE; |
|
909 Vfp::SetSReg(aSingleNaN, 1); |
|
910 Vfp::SetSReg(aSingleNaN, 2); |
|
911 Vfp::AddS(); |
|
912 TReal32 aSingleResult = Vfp::SReg(0); |
|
913 test(*((TUint32*)&aSingleResult) == 0x7FC00000); |
|
914 |
|
915 if (Double) |
|
916 { |
|
917 test.Next(_L("Test flushing denormals to zero - double")); |
|
918 Vfp::SetDReg(3.1234e-322, 1); |
|
919 Vfp::SetDReg(3.1234e-322, 2); |
|
920 Vfp::AddD(); |
|
921 test(Vfp::DReg(0)==0); |
|
922 |
|
923 test.Next(_L("Test flushing underflow to zero - double")); |
|
924 Vfp::SetDReg(1.767e-161, 1); |
|
925 Vfp::SetDReg(1.767e-161, 2); |
|
926 Vfp::MulD(); |
|
927 test(Vfp::DReg(0)==0); |
|
928 |
|
929 test.Next(_L("Test default NaNs - double")); |
|
930 TReal64 aDoubleNaN; |
|
931 *((TUint64*)&aDoubleNaN) = 0x7FF0123456789ABCll; |
|
932 Vfp::SetDReg(aDoubleNaN, 1); |
|
933 Vfp::SetDReg(aDoubleNaN, 2); |
|
934 Vfp::AddD(); |
|
935 TReal64 aDoubleResult = Vfp::DReg(0); |
|
936 test(*((TUint64*)&aDoubleResult) == 0x7FF8000000000000ll); |
|
937 } |
|
938 } |
|
939 |
|
940 void TestAddSResult(const TReal32 a, const TReal32 b, const TReal32 r) |
|
941 { |
|
942 Vfp::SetSReg(a, 1); |
|
943 Vfp::SetSReg(b, 2); |
|
944 Vfp::AddS(); |
|
945 test(Vfp::SReg(0) == r); |
|
946 } |
|
947 |
|
948 void DoRoundingTests() |
|
949 { |
|
950 TFloatingPointMode fpmode = IEEEMode ? EFpModeIEEENoExceptions : EFpModeRunFast; |
|
951 test.Next(_L("Check default rounding to nearest")); |
|
952 test(User::SetFloatingPointMode(fpmode) == KErrNone); |
|
953 test.Next(_L("Check nearest-downward")); |
|
954 TestAddSResult(16777215, 0.49f, 16777215); |
|
955 test.Next(_L("Check nearest-upward")); |
|
956 TestAddSResult(16777215, 0.51f, 16777216); |
|
957 test.Next(_L("Set rounding mode to toward-plus-infinity")); |
|
958 test(User::SetFloatingPointMode(fpmode, EFpRoundToPlusInfinity) == KErrNone); |
|
959 test.Next(_L("Check positive rounding goes upward")); |
|
960 TestAddSResult(16777215, 0.49f, 16777216); |
|
961 test.Next(_L("Check negative rounding goes upward")); |
|
962 TestAddSResult(-16777215, -0.51f, -16777215); |
|
963 test.Next(_L("Set rounding mode to toward-minus-infinity")); |
|
964 test(User::SetFloatingPointMode(fpmode, EFpRoundToMinusInfinity) == KErrNone); |
|
965 test.Next(_L("Check positive rounding goes downward")); |
|
966 TestAddSResult(16777215, 0.51f, 16777215); |
|
967 test.Next(_L("Check negative rounding goes downward")); |
|
968 TestAddSResult(-16777215, -0.49f, -16777216); |
|
969 test.Next(_L("Set rounding mode to toward-zero")); |
|
970 test(User::SetFloatingPointMode(fpmode, EFpRoundToZero) == KErrNone); |
|
971 test.Next(_L("Check positive rounding goes downward")); |
|
972 TestAddSResult(16777215, 0.51f, 16777215); |
|
973 test.Next(_L("Check negative rounding goes upward")); |
|
974 TestAddSResult(-16777215, -0.51f, -16777215); |
|
975 } |
|
976 |
|
977 TInt RunFastThread(TAny* /*unused*/) |
|
978 { |
|
979 Vfp::SetSReg(1e-39f, 1); |
|
980 Vfp::SetSReg(1e-39f, 2); |
|
981 Vfp::AddS(); |
|
982 return (Vfp::SReg(0)==0) ? KErrNone : KErrGeneral; |
|
983 } |
|
984 |
|
985 TInt IEEECompliantThread(TAny* /*unused*/) |
|
986 { |
|
987 Vfp::SetSReg(1e-39f, 1); |
|
988 Vfp::SetSReg(1e-39f, 2); |
|
989 Vfp::AddS(); |
|
990 return (Vfp::SReg(0)==2e-39f) ? KErrNone : KErrGeneral; |
|
991 } |
|
992 |
|
993 void TestVFPModeInheritance() |
|
994 { |
|
995 test.Printf(_L("Set floating point mode to RunFast\n")); |
|
996 test(User::SetFloatingPointMode(EFpModeRunFast)==KErrNone); |
|
997 RThread t; |
|
998 TInt r = t.Create(KNullDesC, &RunFastThread, 0x1000, NULL, NULL); |
|
999 test(r==KErrNone); |
|
1000 TRequestStatus s; |
|
1001 t.Logon(s); |
|
1002 test.Printf(_L("Run RunFast test in another thread...\n")); |
|
1003 t.Resume(); |
|
1004 test.Printf(_L("Wait for other thread to terminate\n")); |
|
1005 User::WaitForRequest(s); |
|
1006 test(t.ExitType() == EExitKill); |
|
1007 test(s == KErrNone); |
|
1008 CLOSE_AND_WAIT(t); |
|
1009 test.Printf(_L("Set floating point mode to IEEE\n")); |
|
1010 test(User::SetFloatingPointMode(EFpModeIEEENoExceptions)==KErrNone); |
|
1011 r = t.Create(KNullDesC, &IEEECompliantThread, 0x1000, NULL, NULL); |
|
1012 test(r==KErrNone); |
|
1013 t.Logon(s); |
|
1014 test.Printf(_L("Run IEEE test in another thread...\n")); |
|
1015 t.Resume(); |
|
1016 test.Printf(_L("Wait for other thread to terminate\n")); |
|
1017 User::WaitForRequest(s); |
|
1018 test(t.ExitType() == EExitKill); |
|
1019 test(s == KErrNone); |
|
1020 CLOSE_AND_WAIT(t); |
|
1021 } |
|
1022 |
|
1023 |
|
1024 void TestVFPv3() |
|
1025 { |
|
1026 test.Next(_L("Transferring to and from fixed point")); |
|
1027 |
|
1028 Vfp::SetSReg(2.5f, 0); |
|
1029 test(Vfp::SReg(0)==2.5f); |
|
1030 Vfp::ToFixedS(3); // Convert to fixed (3) precision |
|
1031 test(Vfp::SRegInt(0)==0x14); // 10.100 in binary fixed(3) format |
|
1032 Vfp::FromFixedS(3); //Convert from fixed (3) precision |
|
1033 test(Vfp::SReg(0)==2.5f); |
|
1034 |
|
1035 |
|
1036 test.Next(_L("Setting immediate value to floating point registers")); |
|
1037 |
|
1038 Vfp::SetSReg(5.0f, 0); |
|
1039 test(Vfp::SReg(0) == 5.0f); |
|
1040 Vfp::TconstS2(); |
|
1041 test(Vfp::SReg(0) == 2.0f); |
|
1042 Vfp::SetSReg(5.0f, 0); |
|
1043 Vfp::TconstS2_8(); |
|
1044 test(Vfp::SReg(0) == 2.875f); |
|
1045 |
|
1046 Vfp::SetDReg(5.0f, 0); |
|
1047 test(Vfp::DReg(0) == 5.0f); |
|
1048 Vfp::TconstD2(); |
|
1049 test(Vfp::DReg(0) == 2.0f); |
|
1050 Vfp::TconstD2_8(); |
|
1051 test(Vfp::DReg(0) == 2.875f); |
|
1052 } |
|
1053 |
|
1054 void TestNEON() |
|
1055 { |
|
1056 RThread t; |
|
1057 TRequestStatus s; |
|
1058 test.Next(_L("Test creating a thread to execute an F2-prefix instruction")); |
|
1059 test_KErrNone(t.Create(KNullDesC, &NeonWithF2, 0x1000, NULL, NULL)); |
|
1060 t.Logon(s); |
|
1061 t.Resume(); |
|
1062 User::WaitForRequest(s); |
|
1063 test(t.ExitType() == EExitKill); |
|
1064 test(s == KErrNone); |
|
1065 t.Close(); |
|
1066 test.Next(_L("Test creating a thread to execute an F3-prefix instruction")); |
|
1067 test_KErrNone(t.Create(KNullDesC, &NeonWithF3, 0x1000, NULL, NULL)); |
|
1068 t.Logon(s); |
|
1069 t.Resume(); |
|
1070 User::WaitForRequest(s); |
|
1071 test(t.ExitType() == EExitKill); |
|
1072 test(s == KErrNone); |
|
1073 t.Close(); |
|
1074 test.Next(_L("Test creating a thread to execute an F4x-prefix instruction")); |
|
1075 test_KErrNone(t.Create(KNullDesC, &NeonWithF4x, 0x1000, NULL, NULL)); |
|
1076 t.Logon(s); |
|
1077 t.Resume(); |
|
1078 User::WaitForRequest(s); |
|
1079 test(t.ExitType() == EExitKill); |
|
1080 test(s == KErrNone); |
|
1081 t.Close(); |
|
1082 } |
|
1083 |
|
1084 void TestThumb() |
|
1085 { |
|
1086 RThread t; |
|
1087 TRequestStatus s; |
|
1088 TInt testStep = 0; |
|
1089 do { |
|
1090 test_KErrNone(t.Create(KNullDesC, &ThumbMode, 0x1000, NULL, (TAny*)testStep++)); |
|
1091 t.Logon(s); |
|
1092 t.Resume(); |
|
1093 User::WaitForRequest(s); |
|
1094 test(s == KErrNone || s == 1); |
|
1095 test(t.ExitType() == EExitKill); |
|
1096 t.Close(); |
|
1097 } |
|
1098 while (s == KErrNone); |
|
1099 |
|
1100 test(s == 1); |
|
1101 test(testStep == 7); |
|
1102 } |
|
1103 |
|
1104 TInt TestThreadMigration(TAny* aPtr) |
|
1105 { |
|
1106 const TInt inc = (TInt)aPtr; |
|
1107 for (TInt32 switches = 0; switches < KMaxTInt; switches += inc) |
|
1108 { |
|
1109 Vfp::SetSReg(switches, switches % 16); |
|
1110 UserSvr::HalFunction(EHalGroupKernel, EKernelHalLockThreadToCpu, (TAny*)(switches % CPUs), 0); |
|
1111 test(Vfp::SRegInt(switches % 16) == switches); |
|
1112 } |
|
1113 return KErrNone; |
|
1114 } |
|
1115 |
|
1116 TInt E32Main() |
|
1117 { |
|
1118 test.Title(); |
|
1119 |
|
1120 test.Start(_L("Ask HAL if we have hardware floating point")); |
|
1121 |
|
1122 CPUs = UserSvr::HalFunction(EHalGroupKernel, EKernelHalNumLogicalCpus, 0, 0); |
|
1123 TInt supportedTypes; |
|
1124 TInt HalVfp = HAL::Get(HALData::EHardwareFloatingPoint, supportedTypes); |
|
1125 if (HalVfp == KErrNone) |
|
1126 { |
|
1127 if (supportedTypes == EFpTypeVFPv2) |
|
1128 { |
|
1129 test.Printf(_L("HAL reports VFPv2\n")); |
|
1130 } |
|
1131 else if (supportedTypes == EFpTypeVFPv3) |
|
1132 { |
|
1133 test.Printf(_L("HAL reports VFPv3\n")); |
|
1134 } |
|
1135 else if (supportedTypes == EFpTypeVFPv3D16) |
|
1136 { |
|
1137 test.Printf(_L("HAL reports VFPv3-D16\n")); |
|
1138 } |
|
1139 else |
|
1140 { |
|
1141 test.Printf(_L("HAL reports an unknown floating point type\n")); |
|
1142 test(0); |
|
1143 } |
|
1144 } |
|
1145 else |
|
1146 { |
|
1147 test.Printf(_L("HAL reports no VFP support\n")); |
|
1148 } |
|
1149 |
|
1150 test.Next(_L("Check VFP present")); |
|
1151 TBool present = DetectVFP(); |
|
1152 if (!present) |
|
1153 { |
|
1154 test.Printf(_L("No VFP detected\n")); |
|
1155 test(HalVfp == KErrNotSupported || |
|
1156 ((supportedTypes != EFpTypeVFPv2) && |
|
1157 (supportedTypes != EFpTypeVFPv3) && |
|
1158 (supportedTypes != EFpTypeVFPv3D16)) |
|
1159 ); |
|
1160 test.End(); |
|
1161 return 0; |
|
1162 } |
|
1163 |
|
1164 test.Printf(_L("VFP detected. FPSID = %08x\n"), FPSID); |
|
1165 test(HalVfp == KErrNone); |
|
1166 |
|
1167 // Verify that the HAL architecture ID matches the FPSID values |
|
1168 // ARMv7 redefines some of these bits so the masks are different :( |
|
1169 if (supportedTypes == EFpTypeVFPv2) |
|
1170 { |
|
1171 // assume armv5/6's bit definitions, where 19:16 are the arch version |
|
1172 // and 20 is the single-precision-only bit |
|
1173 ArchVersion = (FPSID >> 16) & 0xf; |
|
1174 test(ArchVersion == ARCH_VERSION_VFPV2); |
|
1175 Double = !(FPSID & VFP_FPSID_SNG); |
|
1176 } |
|
1177 else if (supportedTypes == EFpTypeVFPv3 || supportedTypes == EFpTypeVFPv3D16) |
|
1178 { |
|
1179 // assume armv7's bit definitions, where 22:16 are the arch version |
|
1180 ArchVersion = (FPSID >> 16) & 0x7f; |
|
1181 test(ArchVersion == ARCH_VERSION_VFPV3_SUBARCH_V2 |
|
1182 || ArchVersion == ARCH_VERSION_VFPV3_SUBARCH_NULL |
|
1183 || ArchVersion == ARCH_VERSION_VFPV3_SUBARCH_V3); |
|
1184 // there are bits for this in MVFR0 but ARM implementations should always have it? |
|
1185 Double = ETrue; |
|
1186 } |
|
1187 |
|
1188 if (Double) |
|
1189 test.Printf(_L("Both single and double precision supported\n"), FPSID); |
|
1190 else |
|
1191 test.Printf(_L("Only single precision supported\n"), FPSID); |
|
1192 |
|
1193 test.Next(_L("Test VFP Initial State")); |
|
1194 TestVFPInitialState(); |
|
1195 |
|
1196 test.Next(_L("Test setting VFP to IEEE no exceptions mode")); |
|
1197 IEEEMode = User::SetFloatingPointMode(EFpModeIEEENoExceptions) == KErrNone; |
|
1198 if (!IEEEMode) |
|
1199 test.Printf(_L("IEEE no exceptions mode not supported, continuing in RunFast\n")); |
|
1200 |
|
1201 test.Next(_L("Test VFP calculations - single")); |
|
1202 DoSglTests(); |
|
1203 if (Double) |
|
1204 { |
|
1205 test.Next(_L("Test VFP calculations - double")); |
|
1206 DoDblTests(); |
|
1207 } |
|
1208 |
|
1209 test.Next(_L("Test VFP Context Save")); |
|
1210 TestVFPContextSave(); |
|
1211 |
|
1212 if (IEEEMode) |
|
1213 { |
|
1214 test.Next(_L("Test bounce handling")); |
|
1215 DoBounceTests(); |
|
1216 test.Next(_L("Test bouncing while context switching")); |
|
1217 DoBounceContextSwitchTests(); |
|
1218 test.Next(_L("Test setting VFP to RunFast mode")); |
|
1219 test(User::SetFloatingPointMode(EFpModeRunFast) == KErrNone); |
|
1220 DoRunFastTests(); |
|
1221 } |
|
1222 |
|
1223 test.Next(_L("Test VFP rounding modes")); |
|
1224 DoRoundingTests(); |
|
1225 |
|
1226 if (IEEEMode) |
|
1227 { |
|
1228 test.Next(_L("Test VFP mode inheritance between threads")); |
|
1229 TestVFPModeInheritance(); |
|
1230 } |
|
1231 |
|
1232 if (supportedTypes == EFpTypeVFPv3 || supportedTypes == EFpTypeVFPv3D16) |
|
1233 { |
|
1234 test.Next(_L("Test VFPv3")); |
|
1235 TestVFPv3(); |
|
1236 |
|
1237 if (supportedTypes == EFpTypeVFPv3) |
|
1238 { |
|
1239 test.Next(_L("Test NEON")); |
|
1240 TestNEON(); |
|
1241 |
|
1242 #if defined(__SUPPORT_THUMB_INTERWORKING) |
|
1243 test.Next(_L("Test Thumb Decode")); |
|
1244 TestThumb(); |
|
1245 #endif |
|
1246 } |
|
1247 } |
|
1248 |
|
1249 if (CPUs > 1) |
|
1250 { |
|
1251 test.Next(_L("Test SMP Thread Migration")); |
|
1252 TInt inc = 1; |
|
1253 RThread t[8]; |
|
1254 TRequestStatus s[8]; |
|
1255 TInt count; |
|
1256 for (count = 0; count < CPUs + 1; count++) |
|
1257 { |
|
1258 TInt r = t[count].Create(KNullDesC, &TestThreadMigration, 0x1000, NULL, (TAny*)(inc++)); |
|
1259 test(r==KErrNone); |
|
1260 t[count].Logon(s[count]); |
|
1261 } |
|
1262 for (count = 0; count < CPUs + 1; count++) |
|
1263 { |
|
1264 t[count].Resume(); |
|
1265 } |
|
1266 User::After(10*1000*1000); |
|
1267 for (count = 0; count < CPUs + 1; count++) |
|
1268 { |
|
1269 t[count].Kill(0); |
|
1270 } |
|
1271 for (count = 0; count < CPUs + 1; count++) |
|
1272 { |
|
1273 User::WaitForAnyRequest(); |
|
1274 } |
|
1275 for (count = 0; count < CPUs + 1; count++) |
|
1276 { |
|
1277 TInt xt = t[count].ExitType(); |
|
1278 TInt xr = t[count].ExitReason(); |
|
1279 test(xt == EExitKill && xr == KErrNone); |
|
1280 } |
|
1281 for (count = 0; count < CPUs + 1; count++) |
|
1282 { |
|
1283 CLOSE_AND_WAIT(t[count]); |
|
1284 } |
|
1285 } |
|
1286 |
|
1287 test.End(); |
|
1288 return 0; |
|
1289 } |