|
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 for(TInt iter=0; iter<KMaxTInt; ++iter) |
|
255 { |
|
256 Vfp::SReg(0); |
|
257 } |
|
258 return KErrNone; |
|
259 } |
|
260 |
|
261 TInt TestBounceCtxThread2(TAny*) |
|
262 { |
|
263 TInt start_rep = 0x00800000; // smallest single precision normal number, 1*2^-126 |
|
264 TReal32 start = *(TReal32*)&start_rep; |
|
265 for(TInt iter=0; iter<KMaxTInt; ++iter) |
|
266 { |
|
267 Vfp::SetSReg(start, 1); |
|
268 Vfp::SetSReg(2.0f, 2); |
|
269 Vfp::DivS(); |
|
270 Vfp::CpyS0(1); |
|
271 Vfp::MulS(); |
|
272 Vfp::CpyS0(1); |
|
273 TReal32 end = Vfp::SReg(0); |
|
274 TInt end_rep = *(TInt*)&end; |
|
275 if (start_rep != end_rep) |
|
276 { |
|
277 RDebug::Printf("mismatch in iter %d, start %08x end %08x\n", iter, start_rep, end_rep); |
|
278 test(0); |
|
279 } |
|
280 } |
|
281 return KErrNone; |
|
282 } |
|
283 |
|
284 void DoBounceContextSwitchTests() |
|
285 { |
|
286 RThread t1, t2; |
|
287 TInt r; |
|
288 r = t1.Create(KNullDesC, &TestBounceCtxThread1, 0x1000, 0x1000, 0x1000, NULL); |
|
289 test(r==KErrNone); |
|
290 t1.SetPriority(EPriorityLess); |
|
291 r = t2.Create(KNullDesC, &TestBounceCtxThread2, 0x1000, 0x1000, 0x1000, NULL); |
|
292 test(r==KErrNone); |
|
293 t2.SetPriority(EPriorityLess); |
|
294 TRequestStatus s1, s2; |
|
295 t1.Logon(s1); |
|
296 t2.Logon(s2); |
|
297 t1.Resume(); |
|
298 t2.Resume(); |
|
299 test.Printf(_L("Let threads run concurrently ...\n")); |
|
300 User::After(20*1000*1000); |
|
301 |
|
302 test.Printf(_L("Kill threads\n")); |
|
303 t1.Kill(0); |
|
304 t2.Kill(0); |
|
305 User::WaitForRequest(s1); |
|
306 User::WaitForRequest(s2); |
|
307 test(t1.ExitType()==EExitKill && t1.ExitReason()==KErrNone); |
|
308 test(t2.ExitType()==EExitKill && t2.ExitReason()==KErrNone); |
|
309 CLOSE_AND_WAIT(t1); |
|
310 CLOSE_AND_WAIT(t2); |
|
311 } |
|
312 |
|
313 void TestAbsS(const TReal32* a, TReal32* r) |
|
314 { |
|
315 Vfp::SetSReg(a[0], 1); |
|
316 Vfp::AbsS(); |
|
317 r[0] = Vfp::SReg(0); |
|
318 r[1] = Abs(a[0]); |
|
319 } |
|
320 |
|
321 void TestAddS(const TReal32* a, TReal32* r) |
|
322 { |
|
323 Vfp::SetSReg(a[0], 1); |
|
324 Vfp::SetSReg(a[1], 2); |
|
325 Vfp::AddS(); |
|
326 r[0] = Vfp::SReg(0); |
|
327 r[1] = a[0] + a[1]; |
|
328 } |
|
329 |
|
330 void TestDivS(const TReal32* a, TReal32* r) |
|
331 { |
|
332 Vfp::SetSReg(a[0], 1); |
|
333 Vfp::SetSReg(a[1], 2); |
|
334 Vfp::DivS(); |
|
335 r[0] = Vfp::SReg(0); |
|
336 TRealX x(a[0]); |
|
337 TRealX y(a[1]); |
|
338 x.DivEq(y); |
|
339 r[1] = (TReal32)x; |
|
340 } |
|
341 |
|
342 void TestMacS(const TReal32* a, TReal32* r) |
|
343 { |
|
344 Vfp::SetSReg(a[0], 0); |
|
345 Vfp::SetSReg(a[1], 1); |
|
346 Vfp::SetSReg(a[2], 2); |
|
347 Vfp::MacS(); |
|
348 r[0] = Vfp::SReg(0); |
|
349 r[1] = a[0] + a[1] * a[2]; |
|
350 } |
|
351 |
|
352 void TestMscS(const TReal32* a, TReal32* r) |
|
353 { |
|
354 Vfp::SetSReg(a[0], 0); |
|
355 Vfp::SetSReg(a[1], 1); |
|
356 Vfp::SetSReg(a[2], 2); |
|
357 Vfp::MscS(); |
|
358 r[0] = Vfp::SReg(0); |
|
359 r[1] = a[1] * a[2] - a[0]; |
|
360 } |
|
361 |
|
362 void TestMulS(const TReal32* a, TReal32* r) |
|
363 { |
|
364 Vfp::SetSReg(a[0], 1); |
|
365 Vfp::SetSReg(a[1], 2); |
|
366 Vfp::MulS(); |
|
367 r[0] = Vfp::SReg(0); |
|
368 TRealX x(a[0]); |
|
369 TRealX y(a[1]); |
|
370 x.MultEq(y); |
|
371 r[1] = (TReal32)x; |
|
372 } |
|
373 |
|
374 void TestNegS(const TReal32* a, TReal32* r) |
|
375 { |
|
376 Vfp::SetSReg(a[0], 1); |
|
377 Vfp::NegS(); |
|
378 r[0] = Vfp::SReg(0); |
|
379 r[1] = -a[0]; |
|
380 } |
|
381 |
|
382 void TestNMacS(const TReal32* a, TReal32* r) |
|
383 { |
|
384 Vfp::SetSReg(a[0], 0); |
|
385 Vfp::SetSReg(a[1], 1); |
|
386 Vfp::SetSReg(a[2], 2); |
|
387 Vfp::NMacS(); |
|
388 r[0] = Vfp::SReg(0); |
|
389 r[1] = a[0] - a[1] * a[2]; |
|
390 } |
|
391 |
|
392 void TestNMscS(const TReal32* a, TReal32* r) |
|
393 { |
|
394 Vfp::SetSReg(a[0], 0); |
|
395 Vfp::SetSReg(a[1], 1); |
|
396 Vfp::SetSReg(a[2], 2); |
|
397 Vfp::NMscS(); |
|
398 r[0] = Vfp::SReg(0); |
|
399 r[1] = -a[1] * a[2] - a[0]; |
|
400 } |
|
401 |
|
402 void TestNMulS(const TReal32* a, TReal32* r) |
|
403 { |
|
404 Vfp::SetSReg(a[0], 1); |
|
405 Vfp::SetSReg(a[1], 2); |
|
406 Vfp::NMulS(); |
|
407 r[0] = Vfp::SReg(0); |
|
408 TRealX x(a[0]); |
|
409 TRealX y(a[1]); |
|
410 x.MultEq(y); |
|
411 r[1] = -(TReal32)x; |
|
412 } |
|
413 |
|
414 void TestSqrtS(const TReal32* a, TReal32* r) |
|
415 { |
|
416 Vfp::SetSReg(a[0], 1); |
|
417 Vfp::SqrtS(); |
|
418 r[0] = Vfp::SReg(0); |
|
419 TReal x = a[0]; |
|
420 TReal y; |
|
421 Math::Sqrt(y, x); |
|
422 r[1] = (TReal32)y; |
|
423 } |
|
424 |
|
425 void TestSubS(const TReal32* a, TReal32* r) |
|
426 { |
|
427 Vfp::SetSReg(a[0], 1); |
|
428 Vfp::SetSReg(a[1], 2); |
|
429 Vfp::SubS(); |
|
430 r[0] = Vfp::SReg(0); |
|
431 r[1] = a[0] - a[1]; |
|
432 } |
|
433 |
|
434 |
|
435 |
|
436 void TestAbsD(const TReal64* a, TReal64* r) |
|
437 { |
|
438 Vfp::SetDReg(a[0], 1); |
|
439 Vfp::AbsD(); |
|
440 r[0] = Vfp::DReg(0); |
|
441 r[1] = Abs(a[0]); |
|
442 } |
|
443 |
|
444 void TestAddD(const TReal64* a, TReal64* r) |
|
445 { |
|
446 Vfp::SetDReg(a[0], 1); |
|
447 Vfp::SetDReg(a[1], 2); |
|
448 Vfp::AddD(); |
|
449 r[0] = Vfp::DReg(0); |
|
450 r[1] = a[0] + a[1]; |
|
451 } |
|
452 |
|
453 void TestDivD(const TReal64* a, TReal64* r) |
|
454 { |
|
455 Vfp::SetDReg(a[0], 1); |
|
456 Vfp::SetDReg(a[1], 2); |
|
457 Vfp::DivD(); |
|
458 r[0] = Vfp::DReg(0); |
|
459 TRealX x(a[0]); |
|
460 TRealX y(a[1]); |
|
461 x.DivEq(y); |
|
462 r[1] = (TReal64)x; |
|
463 } |
|
464 |
|
465 void TestMacD(const TReal64* a, TReal64* r) |
|
466 { |
|
467 Vfp::SetDReg(a[0], 0); |
|
468 Vfp::SetDReg(a[1], 1); |
|
469 Vfp::SetDReg(a[2], 2); |
|
470 Vfp::MacD(); |
|
471 r[0] = Vfp::DReg(0); |
|
472 r[1] = a[0] + a[1] * a[2]; |
|
473 } |
|
474 |
|
475 void TestMscD(const TReal64* a, TReal64* r) |
|
476 { |
|
477 Vfp::SetDReg(a[0], 0); |
|
478 Vfp::SetDReg(a[1], 1); |
|
479 Vfp::SetDReg(a[2], 2); |
|
480 Vfp::MscD(); |
|
481 r[0] = Vfp::DReg(0); |
|
482 r[1] = a[1] * a[2] - a[0]; |
|
483 } |
|
484 |
|
485 void TestMulD(const TReal64* a, TReal64* r) |
|
486 { |
|
487 Vfp::SetDReg(a[0], 1); |
|
488 Vfp::SetDReg(a[1], 2); |
|
489 Vfp::MulD(); |
|
490 r[0] = Vfp::DReg(0); |
|
491 TRealX x(a[0]); |
|
492 TRealX y(a[1]); |
|
493 x.MultEq(y); |
|
494 r[1] = (TReal64)x; |
|
495 } |
|
496 |
|
497 void TestNegD(const TReal64* a, TReal64* r) |
|
498 { |
|
499 Vfp::SetDReg(a[0], 1); |
|
500 Vfp::NegD(); |
|
501 r[0] = Vfp::DReg(0); |
|
502 r[1] = -a[0]; |
|
503 } |
|
504 |
|
505 void TestNMacD(const TReal64* a, TReal64* r) |
|
506 { |
|
507 Vfp::SetDReg(a[0], 0); |
|
508 Vfp::SetDReg(a[1], 1); |
|
509 Vfp::SetDReg(a[2], 2); |
|
510 Vfp::NMacD(); |
|
511 r[0] = Vfp::DReg(0); |
|
512 r[1] = a[0] - a[1] * a[2]; |
|
513 } |
|
514 |
|
515 void TestNMscD(const TReal64* a, TReal64* r) |
|
516 { |
|
517 Vfp::SetDReg(a[0], 0); |
|
518 Vfp::SetDReg(a[1], 1); |
|
519 Vfp::SetDReg(a[2], 2); |
|
520 Vfp::NMscD(); |
|
521 r[0] = Vfp::DReg(0); |
|
522 r[1] = -a[1] * a[2] - a[0]; |
|
523 } |
|
524 |
|
525 void TestNMulD(const TReal64* a, TReal64* r) |
|
526 { |
|
527 Vfp::SetDReg(a[0], 1); |
|
528 Vfp::SetDReg(a[1], 2); |
|
529 Vfp::NMulD(); |
|
530 r[0] = Vfp::DReg(0); |
|
531 TRealX x(a[0]); |
|
532 TRealX y(a[1]); |
|
533 x.MultEq(y); |
|
534 r[1] = -(TReal64)x; |
|
535 } |
|
536 |
|
537 void TestSqrtD(const TReal64* a, TReal64* r) |
|
538 { |
|
539 Vfp::SetDReg(a[0], 1); |
|
540 Vfp::SqrtD(); |
|
541 r[0] = Vfp::DReg(0); |
|
542 TReal x = a[0]; |
|
543 TReal y; |
|
544 Math::Sqrt(y, x); |
|
545 r[1] = (TReal64)y; |
|
546 } |
|
547 |
|
548 void TestSubD(const TReal64* a, TReal64* r) |
|
549 { |
|
550 Vfp::SetDReg(a[0], 1); |
|
551 Vfp::SetDReg(a[1], 2); |
|
552 Vfp::SubD(); |
|
553 r[0] = Vfp::DReg(0); |
|
554 r[1] = a[0] - a[1]; |
|
555 } |
|
556 |
|
557 #define DO_SGL_TEST1(name, func, a1) DoSglTest(name, __LINE__, func, a1) |
|
558 #define DO_SGL_TEST2(name, func, a1, a2) DoSglTest(name, __LINE__, func, a1, a2) |
|
559 #define DO_SGL_TEST3(name, func, a1, a2, a3) DoSglTest(name, __LINE__, func, a1, a2, a3) |
|
560 void DoSglTest(const char* aName, TInt aLine, TSglTest aFunc, TReal32 a1, TReal32 a2=0.0f, TReal32 a3=0.0f) |
|
561 { |
|
562 TPtrC8 name8((const TText8*)aName); |
|
563 TBuf<128> name16; |
|
564 name16.Copy(name8); |
|
565 test.Printf(_L("%S(%g,%g,%g)\n"), &name16, a1, a2, a3); |
|
566 TReal32 args[3] = {a1, a2, a3}; |
|
567 TReal32 results[2]; |
|
568 (*aFunc)(args, results); |
|
569 if (IEEEMode) |
|
570 { |
|
571 if (*((TUint32*)&(results[0])) == *((TUint32*)&(results[1]))) |
|
572 return; |
|
573 } |
|
574 else |
|
575 { |
|
576 if (results[0] == results[1]) |
|
577 return; |
|
578 } |
|
579 const TUint32* pa = (const TUint32*)args; |
|
580 const TUint32* pr = (const TUint32*)results; |
|
581 test.Printf(_L("a1=%08x a2=%08x a3=%08x\n"), pa[0], pa[1], pa[2]); |
|
582 test.Printf(_L("actual result = %08x (%g)\nexpected result = %08x (%g)\n"), pr[0], results[0], pr[1], results[1]); |
|
583 test.Printf(_L("Test at line %d failed\n"), aLine); |
|
584 test(0); |
|
585 } |
|
586 |
|
587 void DoSglTests() |
|
588 { |
|
589 // ABS |
|
590 DO_SGL_TEST1("ABS", &TestAbsS, 1.0f); |
|
591 DO_SGL_TEST1("ABS", &TestAbsS, -1.0f); |
|
592 DO_SGL_TEST1("ABS", &TestAbsS, 0.0f); |
|
593 DO_SGL_TEST1("ABS", &TestAbsS, -3.1415926536f); |
|
594 |
|
595 // NEG |
|
596 DO_SGL_TEST1("NEG", &TestNegS, 1.0f); |
|
597 DO_SGL_TEST1("NEG", &TestNegS, -1.0f); |
|
598 DO_SGL_TEST1("NEG", &TestNegS, 0.0f); |
|
599 DO_SGL_TEST1("NEG", &TestNegS, -3.1415926536f); |
|
600 |
|
601 // ADD |
|
602 DO_SGL_TEST2("ADD", &TestAddS, 0.0f, 0.0f); |
|
603 DO_SGL_TEST2("ADD", &TestAddS, 0.0f, 1.0f); |
|
604 DO_SGL_TEST2("ADD", &TestAddS, -1.0f, 1.0f); |
|
605 DO_SGL_TEST2("ADD", &TestAddS, 1.0f, 2.5f); |
|
606 DO_SGL_TEST2("ADD", &TestAddS, 1.0f, 6.022045e23f); |
|
607 DO_SGL_TEST2("ADD", &TestAddS, -7.3890561f, 1.414213562f); |
|
608 DO_SGL_TEST2("ADD", &TestAddS, -7.3890561f, -1.414213562f); |
|
609 |
|
610 // SUB |
|
611 DO_SGL_TEST2("SUB", &TestSubS, 0.0f, 0.0f); |
|
612 DO_SGL_TEST2("SUB", &TestSubS, 0.0f, 1.0f); |
|
613 DO_SGL_TEST2("SUB", &TestSubS, 1.0f, 1.0f); |
|
614 DO_SGL_TEST2("SUB", &TestSubS, 1.0f, 2.5f); |
|
615 DO_SGL_TEST2("SUB", &TestSubS, 91.0f, 2.5f); |
|
616 DO_SGL_TEST2("SUB", &TestSubS, 1.0f, 6.022045e23f); |
|
617 DO_SGL_TEST2("SUB", &TestSubS, -7.3890561f, 1.414213562f); |
|
618 DO_SGL_TEST2("SUB", &TestSubS, -7.3890561f, -1.414213562f); |
|
619 |
|
620 // MUL |
|
621 DO_SGL_TEST2("MUL", &TestMulS, 0.0f, 0.0f); |
|
622 DO_SGL_TEST2("MUL", &TestMulS, 1.0f, 0.0f); |
|
623 DO_SGL_TEST2("MUL", &TestMulS, 0.0f, 1.0f); |
|
624 DO_SGL_TEST2("MUL", &TestMulS, 2.5f, 6.5f); |
|
625 DO_SGL_TEST2("MUL", &TestMulS, -39.6f, 19.72f); |
|
626 DO_SGL_TEST2("MUL", &TestMulS, -10.1f, -20.1f); |
|
627 DO_SGL_TEST2("MUL", &TestMulS, 1e20f, 1e20f); |
|
628 DO_SGL_TEST2("MUL", &TestMulS, 1e-30f, 1e-30f); |
|
629 |
|
630 // DIV |
|
631 DO_SGL_TEST2("DIV", &TestDivS, 0.0f, 1.0f); |
|
632 DO_SGL_TEST2("DIV", &TestDivS, 1.0f, 5.0f); |
|
633 DO_SGL_TEST2("DIV", &TestDivS, 1.0f, -5.0f); |
|
634 DO_SGL_TEST2("DIV", &TestDivS, -1.0f, 5.0f); |
|
635 DO_SGL_TEST2("DIV", &TestDivS, -1.0f, -5.0f); |
|
636 DO_SGL_TEST2("DIV", &TestDivS, 7.3890561f, 2.7182818f); |
|
637 DO_SGL_TEST2("DIV", &TestDivS, 1e20f, 1e-20f); |
|
638 DO_SGL_TEST2("DIV", &TestDivS, 1e-30f, 1e30f); |
|
639 |
|
640 // NMUL |
|
641 DO_SGL_TEST2("NMUL", &TestNMulS, 0.0f, 0.0f); |
|
642 DO_SGL_TEST2("NMUL", &TestNMulS, 1.0f, 0.0f); |
|
643 DO_SGL_TEST2("NMUL", &TestNMulS, 0.0f, 1.0f); |
|
644 DO_SGL_TEST2("NMUL", &TestNMulS, 2.5f, 6.5f); |
|
645 DO_SGL_TEST2("NMUL", &TestNMulS, -39.6f, 19.72f); |
|
646 DO_SGL_TEST2("NMUL", &TestNMulS, -10.1f, -20.1f); |
|
647 DO_SGL_TEST2("NMUL", &TestNMulS, 1e20f, 1e20f); |
|
648 DO_SGL_TEST2("NMUL", &TestNMulS, 1e-30f, 1e-30f); |
|
649 |
|
650 // SQRT |
|
651 DO_SGL_TEST1("SQRT", &TestSqrtS, 0.0f); |
|
652 DO_SGL_TEST1("SQRT", &TestSqrtS, 1.0f); |
|
653 DO_SGL_TEST1("SQRT", &TestSqrtS, 2.0f); |
|
654 DO_SGL_TEST1("SQRT", &TestSqrtS, 3.0f); |
|
655 DO_SGL_TEST1("SQRT", &TestSqrtS, 9096256.0f); |
|
656 DO_SGL_TEST1("SQRT", &TestSqrtS, 1e36f); |
|
657 DO_SGL_TEST1("SQRT", &TestSqrtS, 1e-36f); |
|
658 |
|
659 // MAC |
|
660 DO_SGL_TEST3("MAC", &TestMacS, 0.0f, 0.0f, 0.0f); |
|
661 DO_SGL_TEST3("MAC", &TestMacS, 0.0f, 1.0f, 0.0f); |
|
662 DO_SGL_TEST3("MAC", &TestMacS, 0.0f, 1.0f, 1.0f); |
|
663 DO_SGL_TEST3("MAC", &TestMacS, -1.0f, 1.0f, 1.0f); |
|
664 DO_SGL_TEST3("MAC", &TestMacS, 0.8f, 0.1f, 8.0f); |
|
665 DO_SGL_TEST3("MAC", &TestMacS, 0.8f, -0.1f, 8.0f); |
|
666 DO_SGL_TEST3("MAC", &TestMacS, -0.8f, -0.1f, -8.0f); |
|
667 DO_SGL_TEST3("MAC", &TestMacS, 0.8f, 0.3333333333f, 3.1415926536f); |
|
668 |
|
669 // MSC |
|
670 DO_SGL_TEST3("MSC", &TestMscS, 0.0f, 0.0f, 0.0f); |
|
671 DO_SGL_TEST3("MSC", &TestMscS, 0.0f, 1.0f, 0.0f); |
|
672 DO_SGL_TEST3("MSC", &TestMscS, 0.0f, 1.0f, 1.0f); |
|
673 DO_SGL_TEST3("MSC", &TestMscS, -1.0f, 1.0f, 1.0f); |
|
674 DO_SGL_TEST3("MSC", &TestMscS, 0.8f, 0.1f, 8.0f); |
|
675 DO_SGL_TEST3("MSC", &TestMscS, 0.8f, -0.1f, 8.0f); |
|
676 DO_SGL_TEST3("MSC", &TestMscS, -0.8f, -0.1f, -8.0f); |
|
677 DO_SGL_TEST3("MSC", &TestMscS, 0.8f, 0.3333333333f, 3.1415926536f); |
|
678 |
|
679 // NMAC |
|
680 DO_SGL_TEST3("NMAC", &TestNMacS, 0.0f, 0.0f, 0.0f); |
|
681 DO_SGL_TEST3("NMAC", &TestNMacS, 0.0f, 1.0f, 0.0f); |
|
682 DO_SGL_TEST3("NMAC", &TestNMacS, 0.0f, 1.0f, 1.0f); |
|
683 DO_SGL_TEST3("NMAC", &TestNMacS, -1.0f, 1.0f, 1.0f); |
|
684 DO_SGL_TEST3("NMAC", &TestNMacS, 0.8f, 0.1f, 8.0f); |
|
685 DO_SGL_TEST3("NMAC", &TestNMacS, 0.8f, -0.1f, 8.0f); |
|
686 DO_SGL_TEST3("NMAC", &TestNMacS, -0.8f, -0.1f, -8.0f); |
|
687 DO_SGL_TEST3("NMAC", &TestNMacS, 0.8f, 0.3333333333f, 3.1415926536f); |
|
688 |
|
689 // NMSC |
|
690 DO_SGL_TEST3("NMSC", &TestNMscS, 0.0f, 0.0f, 0.0f); |
|
691 DO_SGL_TEST3("NMSC", &TestNMscS, 0.0f, 1.0f, 0.0f); |
|
692 DO_SGL_TEST3("NMSC", &TestNMscS, 0.0f, 1.0f, 1.0f); |
|
693 DO_SGL_TEST3("NMSC", &TestNMscS, -1.0f, 1.0f, 1.0f); |
|
694 DO_SGL_TEST3("NMSC", &TestNMscS, 0.8f, 0.1f, 8.0f); |
|
695 DO_SGL_TEST3("NMSC", &TestNMscS, 0.8f, -0.1f, 8.0f); |
|
696 DO_SGL_TEST3("NMSC", &TestNMscS, -0.8f, -0.1f, -8.0f); |
|
697 DO_SGL_TEST3("NMSC", &TestNMscS, 0.8f, 0.3333333333f, 3.1415926536f); |
|
698 } |
|
699 |
|
700 #define DO_DBL_TEST1(name, func, a1) DoDblTest(name, __LINE__, func, a1) |
|
701 #define DO_DBL_TEST2(name, func, a1, a2) DoDblTest(name, __LINE__, func, a1, a2) |
|
702 #define DO_DBL_TEST3(name, func, a1, a2, a3) DoDblTest(name, __LINE__, func, a1, a2, a3) |
|
703 void DoDblTest(const char* aName, TInt aLine, TDblTest aFunc, TReal64 a1, TReal64 a2=0.0, TReal64 a3=0.0) |
|
704 { |
|
705 TPtrC8 name8((const TText8*)aName); |
|
706 TBuf<128> name16; |
|
707 name16.Copy(name8); |
|
708 test.Printf(_L("%S(%g,%g,%g)\n"), &name16, a1, a2, a3); |
|
709 TReal64 args[3] = {a1, a2, a3}; |
|
710 TReal64 results[2]; |
|
711 SDouble sargs[3]; |
|
712 sargs[0] = a1; |
|
713 sargs[1] = a2; |
|
714 sargs[2] = a3; |
|
715 (*aFunc)(args, results); |
|
716 if (IEEEMode) |
|
717 { |
|
718 if (*((TUint64*)&(results[0])) == *((TUint64*)&(results[1]))) |
|
719 return; |
|
720 } |
|
721 else |
|
722 { |
|
723 if (results[0] == results[1]) |
|
724 return; |
|
725 } |
|
726 SDouble sres[3]; |
|
727 sres[0] = results[0]; |
|
728 sres[1] = results[1]; |
|
729 test.Printf(_L("a1=%08x %08x\na2=%08x %08x\na3=%08x %08x\n"), sargs[0].iData[1], sargs[0].iData[0], |
|
730 sargs[1].iData[1], sargs[1].iData[0], sargs[2].iData[1], sargs[2].iData[0]); |
|
731 test.Printf(_L("actual result = %08x %08x (%g)\nexpected result = %08x %08x (%g)\n"), |
|
732 sres[0].iData[1], sres[0].iData[0], results[0], sres[1].iData[1], sres[1].iData[0], results[1]); |
|
733 test.Printf(_L("Test at line %d failed\n"), aLine); |
|
734 test(0); |
|
735 } |
|
736 |
|
737 void DoDblTests() |
|
738 { |
|
739 // ABS |
|
740 DO_DBL_TEST1("ABS", &TestAbsD, 1.0); |
|
741 DO_DBL_TEST1("ABS", &TestAbsD, -1.0); |
|
742 DO_DBL_TEST1("ABS", &TestAbsD, 0.0); |
|
743 DO_DBL_TEST1("ABS", &TestAbsD, -3.1415926536); |
|
744 |
|
745 // NEG |
|
746 DO_DBL_TEST1("NEG", &TestNegD, 1.0); |
|
747 DO_DBL_TEST1("NEG", &TestNegD, -1.0); |
|
748 DO_DBL_TEST1("NEG", &TestNegD, 0.0); |
|
749 DO_DBL_TEST1("NEG", &TestNegD, -3.1415926536); |
|
750 |
|
751 // ADD |
|
752 DO_DBL_TEST2("ADD", &TestAddD, 0.0, 0.0); |
|
753 DO_DBL_TEST2("ADD", &TestAddD, 0.0, 1.0); |
|
754 DO_DBL_TEST2("ADD", &TestAddD, -1.0, 1.0); |
|
755 DO_DBL_TEST2("ADD", &TestAddD, 1.0, 2.5); |
|
756 DO_DBL_TEST2("ADD", &TestAddD, 1.0, 6.022045e23); |
|
757 DO_DBL_TEST2("ADD", &TestAddD, -7.3890561, 1.414213562); |
|
758 DO_DBL_TEST2("ADD", &TestAddD, -7.3890561, -1.414213562); |
|
759 |
|
760 // SUB |
|
761 DO_DBL_TEST2("SUB", &TestSubD, 0.0, 0.0); |
|
762 DO_DBL_TEST2("SUB", &TestSubD, 0.0, 1.0); |
|
763 DO_DBL_TEST2("SUB", &TestSubD, 1.0, 1.0); |
|
764 DO_DBL_TEST2("SUB", &TestSubD, 1.0, 2.5); |
|
765 DO_DBL_TEST2("SUB", &TestSubD, 91.0, 2.5); |
|
766 DO_DBL_TEST2("SUB", &TestSubD, 1.0, 6.022045e23); |
|
767 DO_DBL_TEST2("SUB", &TestSubD, -7.3890561, 1.414213562); |
|
768 DO_DBL_TEST2("SUB", &TestSubD, -7.3890561, -1.414213562); |
|
769 |
|
770 // MUL |
|
771 DO_DBL_TEST2("MUL", &TestMulD, 0.0, 0.0); |
|
772 DO_DBL_TEST2("MUL", &TestMulD, 1.0, 0.0); |
|
773 DO_DBL_TEST2("MUL", &TestMulD, 0.0, 1.0); |
|
774 DO_DBL_TEST2("MUL", &TestMulD, 2.5, 6.5); |
|
775 DO_DBL_TEST2("MUL", &TestMulD, -39.6, 19.72); |
|
776 DO_DBL_TEST2("MUL", &TestMulD, -10.1, -20.1); |
|
777 DO_DBL_TEST2("MUL", &TestMulD, 1e20, 1e20); |
|
778 DO_DBL_TEST2("MUL", &TestMulD, 1e100, 1e300); |
|
779 DO_DBL_TEST2("MUL", &TestMulD, 1e-20, 1e-20); |
|
780 DO_DBL_TEST2("MUL", &TestMulD, 1e-200, 1e-300); |
|
781 |
|
782 // DIV |
|
783 DO_DBL_TEST2("DIV", &TestDivD, 0.0, 1.0); |
|
784 DO_DBL_TEST2("DIV", &TestDivD, 1.0, 5.0); |
|
785 DO_DBL_TEST2("DIV", &TestDivD, 1.0, -5.0); |
|
786 DO_DBL_TEST2("DIV", &TestDivD, -1.0, 5.0); |
|
787 DO_DBL_TEST2("DIV", &TestDivD, -1.0, -5.0); |
|
788 DO_DBL_TEST2("DIV", &TestDivD, 7.3890561, 2.7182818); |
|
789 DO_DBL_TEST2("DIV", &TestDivD, 1e20, 1e-20); |
|
790 DO_DBL_TEST2("DIV", &TestDivD, 1e-20, 1e20); |
|
791 DO_DBL_TEST2("DIV", &TestDivD, 1e-50, 1e300); |
|
792 |
|
793 // NMUL |
|
794 DO_DBL_TEST2("NMUL", &TestNMulD, 0.0, 0.0); |
|
795 DO_DBL_TEST2("NMUL", &TestNMulD, 1.0, 0.0); |
|
796 DO_DBL_TEST2("NMUL", &TestNMulD, 0.0, 1.0); |
|
797 DO_DBL_TEST2("NMUL", &TestNMulD, 2.5, 6.5); |
|
798 DO_DBL_TEST2("NMUL", &TestNMulD, -39.6, 19.72); |
|
799 DO_DBL_TEST2("NMUL", &TestNMulD, -10.1, -20.1); |
|
800 DO_DBL_TEST2("NMUL", &TestNMulD, 1e20, 1e20); |
|
801 DO_DBL_TEST2("NMUL", &TestNMulD, 1e100, 1e300); |
|
802 DO_DBL_TEST2("NMUL", &TestNMulD, 1e-20, 1e-20); |
|
803 DO_DBL_TEST2("NMUL", &TestNMulD, 1e-200, 1e-300); |
|
804 |
|
805 // SQRT |
|
806 DO_DBL_TEST1("SQRT", &TestSqrtD, 0.0); |
|
807 DO_DBL_TEST1("SQRT", &TestSqrtD, 1.0); |
|
808 DO_DBL_TEST1("SQRT", &TestSqrtD, 2.0); |
|
809 DO_DBL_TEST1("SQRT", &TestSqrtD, 3.0); |
|
810 DO_DBL_TEST1("SQRT", &TestSqrtD, 9096256.0); |
|
811 DO_DBL_TEST1("SQRT", &TestSqrtD, 1e36); |
|
812 DO_DBL_TEST1("SQRT", &TestSqrtD, 1e-36); |
|
813 |
|
814 // MAC |
|
815 DO_DBL_TEST3("MAC", &TestMacD, 0.0, 0.0, 0.0); |
|
816 DO_DBL_TEST3("MAC", &TestMacD, 0.0, 1.0, 0.0); |
|
817 DO_DBL_TEST3("MAC", &TestMacD, 0.0, 1.0, 1.0); |
|
818 DO_DBL_TEST3("MAC", &TestMacD, -1.0, 1.0, 1.0); |
|
819 DO_DBL_TEST3("MAC", &TestMacD, 0.8, 0.1, 8.0); |
|
820 DO_DBL_TEST3("MAC", &TestMacD, 0.8, -0.1, 8.0); |
|
821 DO_DBL_TEST3("MAC", &TestMacD, -0.8, -0.1, -8.0); |
|
822 DO_DBL_TEST3("MAC", &TestMacD, 0.8, 0.3333333333, 3.1415926536); |
|
823 |
|
824 // MSC |
|
825 DO_DBL_TEST3("MSC", &TestMscD, 0.0, 0.0, 0.0); |
|
826 DO_DBL_TEST3("MSC", &TestMscD, 0.0, 1.0, 0.0); |
|
827 DO_DBL_TEST3("MSC", &TestMscD, 0.0, 1.0, 1.0); |
|
828 DO_DBL_TEST3("MSC", &TestMscD, -1.0, 1.0, 1.0); |
|
829 DO_DBL_TEST3("MSC", &TestMscD, 0.8, 0.1, 8.0); |
|
830 DO_DBL_TEST3("MSC", &TestMscD, 0.8, -0.1, 8.0); |
|
831 DO_DBL_TEST3("MSC", &TestMscD, -0.8, -0.1, -8.0); |
|
832 DO_DBL_TEST3("MSC", &TestMscD, 0.8, 0.3333333333, 3.1415926536); |
|
833 |
|
834 // NMAC |
|
835 DO_DBL_TEST3("NMAC", &TestNMacD, 0.0, 0.0, 0.0); |
|
836 DO_DBL_TEST3("NMAC", &TestNMacD, 0.0, 1.0, 0.0); |
|
837 DO_DBL_TEST3("NMAC", &TestNMacD, 0.0, 1.0, 1.0); |
|
838 DO_DBL_TEST3("NMAC", &TestNMacD, -1.0, 1.0, 1.0); |
|
839 DO_DBL_TEST3("NMAC", &TestNMacD, 0.8, 0.1, 8.0); |
|
840 DO_DBL_TEST3("NMAC", &TestNMacD, 0.8, -0.1, 8.0); |
|
841 DO_DBL_TEST3("NMAC", &TestNMacD, -0.8, -0.1, -8.0); |
|
842 DO_DBL_TEST3("NMAC", &TestNMacD, 0.8, 0.3333333333, 3.1415926536); |
|
843 |
|
844 // NMSC |
|
845 DO_DBL_TEST3("NMSC", &TestNMscD, 0.0, 0.0, 0.0); |
|
846 DO_DBL_TEST3("NMSC", &TestNMscD, 0.0, 1.0, 0.0); |
|
847 DO_DBL_TEST3("NMSC", &TestNMscD, 0.0, 1.0, 1.0); |
|
848 DO_DBL_TEST3("NMSC", &TestNMscD, -1.0, 1.0, 1.0); |
|
849 DO_DBL_TEST3("NMSC", &TestNMscD, 0.8, 0.1, 8.0); |
|
850 DO_DBL_TEST3("NMSC", &TestNMscD, 0.8, -0.1, 8.0); |
|
851 DO_DBL_TEST3("NMSC", &TestNMscD, -0.8, -0.1, -8.0); |
|
852 DO_DBL_TEST3("NMSC", &TestNMscD, 0.8, 0.3333333333, 3.1415926536); |
|
853 } |
|
854 |
|
855 void DoBounceTests() |
|
856 { |
|
857 test.Next(_L("Test denormal handling - single")); |
|
858 DO_SGL_TEST2("ADD", &TestAddS, 1e-39f, 1e-39f); |
|
859 test.Next(_L("Test potential underflow - single")); |
|
860 DO_SGL_TEST2("MUL", &TestMulS, 3.162e-20f, 3.162e-20f); |
|
861 // fails on VFPv2 hardware. ARM's library should be fixed |
|
862 // test.Next(_L("Test NaN input - single")); |
|
863 // TReal32 aSingleNaN; |
|
864 // *((TUint32*)&aSingleNaN) = 0x7F9ABCDE; |
|
865 // Vfp::SetSReg(aSingleNaN, 1); |
|
866 // Vfp::SetSReg(aSingleNaN, 2); |
|
867 // Vfp::AddS(); |
|
868 // TReal32 aSingleResult = Vfp::SReg(0); |
|
869 // test(*((TUint32*)&aSingleResult) == 0x7FDABCDE); |
|
870 |
|
871 if (Double) |
|
872 { |
|
873 test.Next(_L("Test denormal handling - double")); |
|
874 DO_DBL_TEST2("ADD", &TestAddD, 3.1234e-322, 3.1234e-322); |
|
875 test.Next(_L("Test potential underflow - double")); |
|
876 DO_DBL_TEST2("MUL", &TestMulD, 1.767e-161, 1.767e-161); |
|
877 // fails on VFPv2 hardware. ARM's library should be fixed |
|
878 // test.Next(_L("Test NaN input - double")); |
|
879 // TReal64 aDoubleNaN; |
|
880 // *((TUint64*)&aDoubleNaN) = 0x7FF0123456789ABCll; |
|
881 // Vfp::SetDReg(aDoubleNaN, 1); |
|
882 // Vfp::SetDReg(aDoubleNaN, 2); |
|
883 // Vfp::AddD(); |
|
884 // TReal64 aDoubleResult = Vfp::DReg(0); |
|
885 // test(*((TUint64*)&aDoubleResult) == 0x7FF8123456789ABC); |
|
886 } |
|
887 } |
|
888 |
|
889 void DoRunFastTests() |
|
890 { |
|
891 test.Next(_L("Test flushing denormals to zero - single")); |
|
892 Vfp::SetSReg(1e-39f, 1); |
|
893 Vfp::SetSReg(1e-39f, 2); |
|
894 Vfp::AddS(); |
|
895 test(Vfp::SReg(0)==0); |
|
896 |
|
897 test.Next(_L("Test flushing underflow to zero - single")); |
|
898 Vfp::SetSReg(3.162e-20f, 1); |
|
899 Vfp::SetSReg(3.162e-20f, 2); |
|
900 Vfp::MulS(); |
|
901 test(Vfp::SReg(0)==0); |
|
902 |
|
903 test.Next(_L("Test default NaNs - single")); |
|
904 TReal32 aSingleNaN; |
|
905 *((TUint32*)&aSingleNaN) = 0x7F9ABCDE; |
|
906 Vfp::SetSReg(aSingleNaN, 1); |
|
907 Vfp::SetSReg(aSingleNaN, 2); |
|
908 Vfp::AddS(); |
|
909 TReal32 aSingleResult = Vfp::SReg(0); |
|
910 test(*((TUint32*)&aSingleResult) == 0x7FC00000); |
|
911 |
|
912 if (Double) |
|
913 { |
|
914 test.Next(_L("Test flushing denormals to zero - double")); |
|
915 Vfp::SetDReg(3.1234e-322, 1); |
|
916 Vfp::SetDReg(3.1234e-322, 2); |
|
917 Vfp::AddD(); |
|
918 test(Vfp::DReg(0)==0); |
|
919 |
|
920 test.Next(_L("Test flushing underflow to zero - double")); |
|
921 Vfp::SetDReg(1.767e-161, 1); |
|
922 Vfp::SetDReg(1.767e-161, 2); |
|
923 Vfp::MulD(); |
|
924 test(Vfp::DReg(0)==0); |
|
925 |
|
926 test.Next(_L("Test default NaNs - double")); |
|
927 TReal64 aDoubleNaN; |
|
928 *((TUint64*)&aDoubleNaN) = 0x7FF0123456789ABCll; |
|
929 Vfp::SetDReg(aDoubleNaN, 1); |
|
930 Vfp::SetDReg(aDoubleNaN, 2); |
|
931 Vfp::AddD(); |
|
932 TReal64 aDoubleResult = Vfp::DReg(0); |
|
933 test(*((TUint64*)&aDoubleResult) == 0x7FF8000000000000ll); |
|
934 } |
|
935 } |
|
936 |
|
937 void TestAddSResult(const TReal32 a, const TReal32 b, const TReal32 r) |
|
938 { |
|
939 Vfp::SetSReg(a, 1); |
|
940 Vfp::SetSReg(b, 2); |
|
941 Vfp::AddS(); |
|
942 test(Vfp::SReg(0) == r); |
|
943 } |
|
944 |
|
945 void DoRoundingTests() |
|
946 { |
|
947 TFloatingPointMode fpmode = IEEEMode ? EFpModeIEEENoExceptions : EFpModeRunFast; |
|
948 test.Next(_L("Check default rounding to nearest")); |
|
949 test(User::SetFloatingPointMode(fpmode) == KErrNone); |
|
950 test.Next(_L("Check nearest-downward")); |
|
951 TestAddSResult(16777215, 0.49f, 16777215); |
|
952 test.Next(_L("Check nearest-upward")); |
|
953 TestAddSResult(16777215, 0.51f, 16777216); |
|
954 test.Next(_L("Set rounding mode to toward-plus-infinity")); |
|
955 test(User::SetFloatingPointMode(fpmode, EFpRoundToPlusInfinity) == KErrNone); |
|
956 test.Next(_L("Check positive rounding goes upward")); |
|
957 TestAddSResult(16777215, 0.49f, 16777216); |
|
958 test.Next(_L("Check negative rounding goes upward")); |
|
959 TestAddSResult(-16777215, -0.51f, -16777215); |
|
960 test.Next(_L("Set rounding mode to toward-minus-infinity")); |
|
961 test(User::SetFloatingPointMode(fpmode, EFpRoundToMinusInfinity) == KErrNone); |
|
962 test.Next(_L("Check positive rounding goes downward")); |
|
963 TestAddSResult(16777215, 0.51f, 16777215); |
|
964 test.Next(_L("Check negative rounding goes downward")); |
|
965 TestAddSResult(-16777215, -0.49f, -16777216); |
|
966 test.Next(_L("Set rounding mode to toward-zero")); |
|
967 test(User::SetFloatingPointMode(fpmode, EFpRoundToZero) == KErrNone); |
|
968 test.Next(_L("Check positive rounding goes downward")); |
|
969 TestAddSResult(16777215, 0.51f, 16777215); |
|
970 test.Next(_L("Check negative rounding goes upward")); |
|
971 TestAddSResult(-16777215, -0.51f, -16777215); |
|
972 } |
|
973 |
|
974 TInt RunFastThread(TAny* /*unused*/) |
|
975 { |
|
976 Vfp::SetSReg(1e-39f, 1); |
|
977 Vfp::SetSReg(1e-39f, 2); |
|
978 Vfp::AddS(); |
|
979 return (Vfp::SReg(0)==0) ? KErrNone : KErrGeneral; |
|
980 } |
|
981 |
|
982 TInt IEEECompliantThread(TAny* /*unused*/) |
|
983 { |
|
984 Vfp::SetSReg(1e-39f, 1); |
|
985 Vfp::SetSReg(1e-39f, 2); |
|
986 Vfp::AddS(); |
|
987 return (Vfp::SReg(0)==2e-39f) ? KErrNone : KErrGeneral; |
|
988 } |
|
989 |
|
990 void TestVFPModeInheritance() |
|
991 { |
|
992 test.Printf(_L("Set floating point mode to RunFast\n")); |
|
993 test(User::SetFloatingPointMode(EFpModeRunFast)==KErrNone); |
|
994 RThread t; |
|
995 TInt r = t.Create(KNullDesC, &RunFastThread, 0x1000, NULL, NULL); |
|
996 test(r==KErrNone); |
|
997 TRequestStatus s; |
|
998 t.Logon(s); |
|
999 test.Printf(_L("Run RunFast test in another thread...\n")); |
|
1000 t.Resume(); |
|
1001 test.Printf(_L("Wait for other thread to terminate\n")); |
|
1002 User::WaitForRequest(s); |
|
1003 test(t.ExitType() == EExitKill); |
|
1004 test(s == KErrNone); |
|
1005 CLOSE_AND_WAIT(t); |
|
1006 test.Printf(_L("Set floating point mode to IEEE\n")); |
|
1007 test(User::SetFloatingPointMode(EFpModeIEEENoExceptions)==KErrNone); |
|
1008 r = t.Create(KNullDesC, &IEEECompliantThread, 0x1000, NULL, NULL); |
|
1009 test(r==KErrNone); |
|
1010 t.Logon(s); |
|
1011 test.Printf(_L("Run IEEE test in another thread...\n")); |
|
1012 t.Resume(); |
|
1013 test.Printf(_L("Wait for other thread to terminate\n")); |
|
1014 User::WaitForRequest(s); |
|
1015 test(t.ExitType() == EExitKill); |
|
1016 test(s == KErrNone); |
|
1017 CLOSE_AND_WAIT(t); |
|
1018 } |
|
1019 |
|
1020 |
|
1021 void TestVFPv3() |
|
1022 { |
|
1023 test.Next(_L("Transferring to and from fixed point")); |
|
1024 |
|
1025 Vfp::SetSReg(2.5f, 0); |
|
1026 test(Vfp::SReg(0)==2.5f); |
|
1027 Vfp::ToFixedS(3); // Convert to fixed (3) precision |
|
1028 test(Vfp::SRegInt(0)==0x14); // 10.100 in binary fixed(3) format |
|
1029 Vfp::FromFixedS(3); //Convert from fixed (3) precision |
|
1030 test(Vfp::SReg(0)==2.5f); |
|
1031 |
|
1032 |
|
1033 test.Next(_L("Setting immediate value to floating point registers")); |
|
1034 |
|
1035 Vfp::SetSReg(5.0f, 0); |
|
1036 test(Vfp::SReg(0) == 5.0f); |
|
1037 Vfp::TconstS2(); |
|
1038 test(Vfp::SReg(0) == 2.0f); |
|
1039 Vfp::SetSReg(5.0f, 0); |
|
1040 Vfp::TconstS2_8(); |
|
1041 test(Vfp::SReg(0) == 2.875f); |
|
1042 |
|
1043 Vfp::SetDReg(5.0f, 0); |
|
1044 test(Vfp::DReg(0) == 5.0f); |
|
1045 Vfp::TconstD2(); |
|
1046 test(Vfp::DReg(0) == 2.0f); |
|
1047 Vfp::TconstD2_8(); |
|
1048 test(Vfp::DReg(0) == 2.875f); |
|
1049 } |
|
1050 |
|
1051 void TestNEON() |
|
1052 { |
|
1053 RThread t; |
|
1054 TRequestStatus s; |
|
1055 test.Next(_L("Test creating a thread to execute an F2-prefix instruction")); |
|
1056 test_KErrNone(t.Create(KNullDesC, &NeonWithF2, 0x1000, NULL, NULL)); |
|
1057 t.Logon(s); |
|
1058 t.Resume(); |
|
1059 User::WaitForRequest(s); |
|
1060 test(t.ExitType() == EExitKill); |
|
1061 test(s == KErrNone); |
|
1062 t.Close(); |
|
1063 test.Next(_L("Test creating a thread to execute an F3-prefix instruction")); |
|
1064 test_KErrNone(t.Create(KNullDesC, &NeonWithF3, 0x1000, NULL, NULL)); |
|
1065 t.Logon(s); |
|
1066 t.Resume(); |
|
1067 User::WaitForRequest(s); |
|
1068 test(t.ExitType() == EExitKill); |
|
1069 test(s == KErrNone); |
|
1070 t.Close(); |
|
1071 test.Next(_L("Test creating a thread to execute an F4x-prefix instruction")); |
|
1072 test_KErrNone(t.Create(KNullDesC, &NeonWithF4x, 0x1000, NULL, NULL)); |
|
1073 t.Logon(s); |
|
1074 t.Resume(); |
|
1075 User::WaitForRequest(s); |
|
1076 test(t.ExitType() == EExitKill); |
|
1077 test(s == KErrNone); |
|
1078 t.Close(); |
|
1079 } |
|
1080 |
|
1081 void TestThumb() |
|
1082 { |
|
1083 RThread t; |
|
1084 TRequestStatus s; |
|
1085 TInt testStep = 0; |
|
1086 do { |
|
1087 test_KErrNone(t.Create(KNullDesC, &ThumbMode, 0x1000, NULL, (TAny*)testStep++)); |
|
1088 t.Logon(s); |
|
1089 t.Resume(); |
|
1090 User::WaitForRequest(s); |
|
1091 test(s == KErrNone || s == 1); |
|
1092 test(t.ExitType() == EExitKill); |
|
1093 t.Close(); |
|
1094 } |
|
1095 while (s == KErrNone); |
|
1096 |
|
1097 test(s == 1); |
|
1098 test(testStep == 7); |
|
1099 } |
|
1100 |
|
1101 TInt E32Main() |
|
1102 { |
|
1103 test.Title(); |
|
1104 |
|
1105 test.Start(_L("Ask HAL if we have hardware floating point")); |
|
1106 |
|
1107 CPUs = UserSvr::HalFunction(EHalGroupKernel, EKernelHalNumLogicalCpus, 0, 0); |
|
1108 TInt supportedTypes; |
|
1109 TInt HalVfp = HAL::Get(HALData::EHardwareFloatingPoint, supportedTypes); |
|
1110 if (HalVfp == KErrNone) |
|
1111 { |
|
1112 if (supportedTypes == EFpTypeVFPv2) |
|
1113 { |
|
1114 test.Printf(_L("HAL reports VFPv2\n")); |
|
1115 } |
|
1116 else if (supportedTypes == EFpTypeVFPv3) |
|
1117 { |
|
1118 test.Printf(_L("HAL reports VFPv3\n")); |
|
1119 } |
|
1120 else if (supportedTypes == EFpTypeVFPv3D16) |
|
1121 { |
|
1122 test.Printf(_L("HAL reports VFPv3-D16\n")); |
|
1123 } |
|
1124 else |
|
1125 { |
|
1126 test.Printf(_L("HAL reports an unknown floating point type\n")); |
|
1127 test(0); |
|
1128 } |
|
1129 } |
|
1130 else |
|
1131 { |
|
1132 test.Printf(_L("HAL reports no VFP support\n")); |
|
1133 } |
|
1134 |
|
1135 test.Next(_L("Check VFP present")); |
|
1136 TBool present = DetectVFP(); |
|
1137 if (!present) |
|
1138 { |
|
1139 test.Printf(_L("No VFP detected\n")); |
|
1140 test(HalVfp == KErrNotSupported || |
|
1141 ((supportedTypes != EFpTypeVFPv2) && |
|
1142 (supportedTypes != EFpTypeVFPv3) && |
|
1143 (supportedTypes != EFpTypeVFPv3D16)) |
|
1144 ); |
|
1145 test.End(); |
|
1146 return 0; |
|
1147 } |
|
1148 |
|
1149 test.Printf(_L("VFP detected. FPSID = %08x\n"), FPSID); |
|
1150 test(HalVfp == KErrNone); |
|
1151 |
|
1152 // Verify that the HAL architecture ID matches the FPSID values |
|
1153 // ARMv7 redefines some of these bits so the masks are different :( |
|
1154 if (supportedTypes == EFpTypeVFPv2) |
|
1155 { |
|
1156 // assume armv5/6's bit definitions, where 19:16 are the arch version |
|
1157 // and 20 is the single-precision-only bit |
|
1158 ArchVersion = (FPSID >> 16) & 0xf; |
|
1159 test(ArchVersion == ARCH_VERSION_VFPV2); |
|
1160 Double = !(FPSID & VFP_FPSID_SNG); |
|
1161 } |
|
1162 else if (supportedTypes == EFpTypeVFPv3 || supportedTypes == EFpTypeVFPv3D16) |
|
1163 { |
|
1164 // assume armv7's bit definitions, where 22:16 are the arch version |
|
1165 ArchVersion = (FPSID >> 16) & 0x7f; |
|
1166 test(ArchVersion == ARCH_VERSION_VFPV3_SUBARCH_V2 |
|
1167 || ArchVersion == ARCH_VERSION_VFPV3_SUBARCH_NULL |
|
1168 || ArchVersion == ARCH_VERSION_VFPV3_SUBARCH_V3); |
|
1169 // there are bits for this in MVFR0 but ARM implementations should always have it? |
|
1170 Double = ETrue; |
|
1171 } |
|
1172 |
|
1173 if (Double) |
|
1174 test.Printf(_L("Both single and double precision supported\n"), FPSID); |
|
1175 else |
|
1176 test.Printf(_L("Only single precision supported\n"), FPSID); |
|
1177 |
|
1178 test.Next(_L("Test VFP Initial State")); |
|
1179 TestVFPInitialState(); |
|
1180 |
|
1181 test.Next(_L("Test setting VFP to IEEE no exceptions mode")); |
|
1182 IEEEMode = User::SetFloatingPointMode(EFpModeIEEENoExceptions) == KErrNone; |
|
1183 if (!IEEEMode) |
|
1184 test.Printf(_L("IEEE no exceptions mode not supported, continuing in RunFast\n")); |
|
1185 |
|
1186 test.Next(_L("Test VFP calculations - single")); |
|
1187 DoSglTests(); |
|
1188 if (Double) |
|
1189 { |
|
1190 test.Next(_L("Test VFP calculations - double")); |
|
1191 DoDblTests(); |
|
1192 } |
|
1193 |
|
1194 test.Next(_L("Test VFP Context Save")); |
|
1195 TestVFPContextSave(); |
|
1196 |
|
1197 if (IEEEMode) |
|
1198 { |
|
1199 test.Next(_L("Test bounce handling")); |
|
1200 DoBounceTests(); |
|
1201 test.Next(_L("Test bouncing while context switching")); |
|
1202 DoBounceContextSwitchTests(); |
|
1203 test.Next(_L("Test setting VFP to RunFast mode")); |
|
1204 test(User::SetFloatingPointMode(EFpModeRunFast) == KErrNone); |
|
1205 DoRunFastTests(); |
|
1206 } |
|
1207 |
|
1208 test.Next(_L("Test VFP rounding modes")); |
|
1209 DoRoundingTests(); |
|
1210 |
|
1211 if (IEEEMode) |
|
1212 { |
|
1213 test.Next(_L("Test VFP mode inheritance between threads")); |
|
1214 TestVFPModeInheritance(); |
|
1215 } |
|
1216 |
|
1217 if (supportedTypes == EFpTypeVFPv3 || supportedTypes == EFpTypeVFPv3D16) |
|
1218 { |
|
1219 test.Next(_L("Test VFPv3")); |
|
1220 TestVFPv3(); |
|
1221 |
|
1222 if (supportedTypes == EFpTypeVFPv3) |
|
1223 { |
|
1224 test.Next(_L("Test NEON")); |
|
1225 TestNEON(); |
|
1226 |
|
1227 #if defined(__SUPPORT_THUMB_INTERWORKING) |
|
1228 test.Next(_L("Test Thumb Decode")); |
|
1229 TestThumb(); |
|
1230 #endif |
|
1231 } |
|
1232 } |
|
1233 |
|
1234 test.End(); |
|
1235 return 0; |
|
1236 } |