1 /* Copyright (C) 2012 IBM
2
3 Author: Maynard Johnson <maynardj@us.ibm.com>
4
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License as
7 published by the Free Software Foundation; either version 2 of the
8 License, or (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
18 02111-1307, USA.
19
20 The GNU General Public License is contained in the file COPYING.
21 */
22
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <stdint.h>
26
27 #if defined(HAS_DFP)
28
29 typedef union stuff {
30 _Decimal64 dec_val;
31 _Decimal128 dec_val128;
32 unsigned long long u64_val;
33 struct {
34 #if defined(VGP_ppc64le_linux)
35 unsigned long long vall;
36 unsigned long long valu;
37 #else
38 unsigned long long valu;
39 unsigned long long vall;
40 #endif
41 } u128;
42 } dfp_val_t;
43
44
45 typedef unsigned char Bool;
46 #define True 1
47 #define False 0
48
49
50 #define ALLCR "cr0","cr1","cr2","cr3","cr4","cr5","cr6","cr7"
51
52 #define SET_CR(_arg) \
53 __asm__ __volatile__ ("mtcr %0" : : "b"(_arg) : ALLCR );
54
55 #define SET_XER(_arg) \
56 __asm__ __volatile__ ("mtxer %0" : : "b"(_arg) : "xer" );
57
58 #define GET_CR(_lval) \
59 __asm__ __volatile__ ("mfcr %0" : "=b"(_lval) )
60
61 #define GET_XER(_lval) \
62 __asm__ __volatile__ ("mfxer %0" : "=b"(_lval) )
63
64 #define GET_CR_XER(_lval_cr,_lval_xer) \
65 do { GET_CR(_lval_cr); GET_XER(_lval_xer); } while (0)
66
67 #define SET_CR_ZERO \
68 SET_CR(0)
69
70 #define SET_XER_ZERO \
71 SET_XER(0)
72
73 #define SET_CR_XER_ZERO \
74 do { SET_CR_ZERO; SET_XER_ZERO; } while (0)
75
76 #define SET_FPSCR_ZERO \
77 do { double _d = 0.0; \
78 __asm__ __volatile__ ("mtfsf 0xFF, %0" : : "f"(_d) ); \
79 } while (0)
80
81 #define GET_FPSCR(_arg) \
82 __asm__ __volatile__ ("mffs %0" : "=f"(_arg) )
83
84 #define SET_FPSCR_DRN \
85 __asm__ __volatile__ ("mtfsf 1, %0, 0, 1" : : "f"(f14) )
86
87 #ifndef __powerpc64__
88 typedef uint32_t HWord_t;
89 #else
90 typedef uint64_t HWord_t;
91 #endif /* __powerpc64__ */
92
93 enum BF_vals { BF_val1 = 0, BF_val2 = 1, BF_val3 =6};
94
95 // The assembly-level instructions being tested
_test_dtstsf(unsigned int BF,unsigned int ref_sig,dfp_val_t * valB)96 static void _test_dtstsf(unsigned int BF, unsigned int ref_sig, dfp_val_t *valB)
97 {
98 _Decimal64 f16 = valB->dec_val;
99 register HWord_t r14 __asm__ ("r14");
100 double f14;
101 r14 = (HWord_t)&ref_sig;
102
103 __asm __volatile__ ("lfiwax %0, 0, %1" : "=f" (f14): "r" (r14));
104 switch (BF) {
105 case BF_val1:
106 __asm__ __volatile__ ("dtstsf %0, %1, %2" : : "i" (BF_val1), "f" (f14), "f" (f16));
107 break;
108 case BF_val2:
109 __asm__ __volatile__ ("dtstsf %0, %1, %2" : : "i" (BF_val2), "f" (f14), "f" (f16));
110 break;
111 case BF_val3:
112 __asm__ __volatile__ ("dtstsf %0, %1, %2" : : "i" (BF_val3), "f" (f14), "f" (f16));
113 break;
114 default:
115 fprintf(stderr, "Invalid value %d for BF\n", BF);
116 break;
117 }
118 }
119
_test_dtstsfq(unsigned int BF,unsigned int ref_sig,dfp_val_t * valB)120 static void _test_dtstsfq(unsigned int BF, unsigned int ref_sig, dfp_val_t *valB)
121 {
122 _Decimal128 f16 = valB->dec_val128;
123 register HWord_t r14 __asm__ ("r14");
124 double f14;
125 r14 = (HWord_t)&ref_sig;
126
127 __asm __volatile__ ("lfiwax %0, 0, %1" : "=f" (f14): "r" (r14));
128 switch (BF) {
129 case BF_val1:
130 __asm__ __volatile__ ("dtstsfq %0, %1, %2" : : "i" (BF_val1), "f" (f14), "f" (f16));
131 break;
132 case BF_val2:
133 __asm__ __volatile__ ("dtstsfq %0, %1, %2" : : "i" (BF_val2), "f" (f14), "f" (f16));
134 break;
135 case BF_val3:
136 __asm__ __volatile__ ("dtstsfq %0, %1, %2" : : "i" (BF_val3), "f" (f14), "f" (f16));
137 break;
138 default:
139 fprintf(stderr, "Invalid value %d for BF\n", BF);
140 break;
141 }
142 }
143
_test_ddedpd(unsigned int SP,dfp_val_t * valB)144 static dfp_val_t _test_ddedpd(unsigned int SP, dfp_val_t *valB)
145 {
146 _Decimal64 ret = 0;
147 dfp_val_t result;
148 _Decimal64 f16 = valB->dec_val;
149 switch (SP) {
150 case 0:
151 __asm__ __volatile__ ("ddedpd. 0, %0, %1" : "=f" (ret) : "f" (f16));
152 break;
153 case 1:
154 __asm__ __volatile__ ("ddedpd. 1, %0, %1" : "=f" (ret) : "f" (f16));
155 break;
156 case 2:
157 __asm__ __volatile__ ("ddedpd. 2, %0, %1" : "=f" (ret) : "f" (f16));
158 break;
159 case 3:
160 __asm__ __volatile__ ("ddedpd. 3, %0, %1" : "=f" (ret) : "f" (f16));
161 break;
162 default:
163 fprintf(stderr, "Invalid value %d for SP\n", SP);
164 break;
165 }
166 result.dec_val = ret;
167 return result;
168 }
169
170
_test_ddedpdq(unsigned int SP,dfp_val_t * valB)171 static dfp_val_t _test_ddedpdq(unsigned int SP, dfp_val_t *valB)
172 {
173 _Decimal128 ret = 0;
174 dfp_val_t result;
175 _Decimal128 f16 = valB->dec_val128;
176 switch (SP) {
177 case 0:
178 __asm__ __volatile__ ("ddedpdq 0, %0, %1" : "=f" (ret) : "f" (f16));
179 break;
180 case 1:
181 __asm__ __volatile__ ("ddedpdq 1, %0, %1" : "=f" (ret) : "f" (f16));
182 break;
183 case 2:
184 __asm__ __volatile__ ("ddedpdq 2, %0, %1" : "=f" (ret) : "f" (f16));
185 break;
186 case 3:
187 __asm__ __volatile__ ("ddedpdq 3, %0, %1" : "=f" (ret) : "f" (f16));
188 break;
189 default:
190 fprintf(stderr, "Invalid value %d for SP\n", SP);
191 break;
192 }
193 result.dec_val128 = ret;
194 return result;
195 }
196
_test_denbcd(unsigned int S,dfp_val_t * valB)197 static dfp_val_t _test_denbcd(unsigned int S, dfp_val_t *valB)
198 {
199 _Decimal64 ret = 0;
200 dfp_val_t result;
201 _Decimal64 f16 = valB->dec_val;
202 switch (S) {
203 case 0:
204 __asm__ __volatile__ ("denbcd. 0, %0, %1" : "=f" (ret) : "f" (f16));
205 break;
206 case 1:
207 __asm__ __volatile__ ("denbcd. 1, %0, %1" : "=f" (ret) : "f" (f16));
208 break;
209 default:
210 fprintf(stderr, "Invalid value %d for S\n", S);
211 break;
212 }
213 result.dec_val = ret;
214 return result;
215 }
216
217
_test_denbcdq(unsigned int S,dfp_val_t * valB)218 static dfp_val_t _test_denbcdq(unsigned int S, dfp_val_t *valB)
219 {
220 _Decimal128 ret = 0;
221 dfp_val_t result;
222 _Decimal128 f16 = valB->dec_val128;
223 switch (S) {
224 case 0:
225 __asm__ __volatile__ ("denbcdq 0, %0, %1" : "=f" (ret) : "f" (f16));
226 break;
227 case 1:
228 __asm__ __volatile__ ("denbcdq 1, %0, %1" : "=f" (ret) : "f" (f16));
229 break;
230 default:
231 fprintf(stderr, "Invalid value %d for S\n", S);
232 break;
233 }
234 result.dec_val128 = ret;
235 return result;
236 }
237
238
239 typedef void (*test_funcp_t)(unsigned int imm, unsigned int imm2, dfp_val_t *valB);
240 typedef dfp_val_t (*test_func_bcdp_t)(unsigned int imm, dfp_val_t *valB);
241 typedef void (*test_driver_func_t)(void);
242 typedef struct test_table
243 {
244 test_driver_func_t test_category;
245 char * name;
246 } test_table_t;
247
248 /*
249 * 345.0DD (0x2207c00000000000 0xe50)
250 * 1.2300e+5DD (0x2207c00000000000 0x14c000)
251 * -16.0DD (0xa207c00000000000 0xe0)
252 * 0.00189DD (0x2206c00000000000 0xcf)
253 * -4.1235DD (0xa205c00000000000 0x10a395bcf)
254 * 9.8399e+20DD (0x2209400000000000 0x253f1f534acdd4)
255 * 0DD (0x2208000000000000 0x0)
256 * 0DD (0x2208000000000000 0x0)
257 * infDD (0x7800000000000000 0x0)
258 * nanDD (0x7c00000000000000 0x0
259 */
260 static unsigned long long dfp128_vals[] = {
261 // Some finite numbers
262 0x2207c00000000000ULL, 0x0000000000000e50ULL,
263 0x2207c00000000000ULL, 0x000000000014c000ULL,
264 0xa207c00000000000ULL, 0x00000000000000e0ULL,
265 0x2206c00000000000ULL, 0x00000000000000cfULL,
266 0xa205c00000000000ULL, 0x000000010a395bcfULL,
267 0x6209400000fd0000ULL, 0x00253f1f534acdd4ULL, // huge number
268 0x000400000089b000ULL, 0x0a6000d000000049ULL, // very small number
269 // flavors of zero
270 0x2208000000000000ULL, 0x0000000000000000ULL,
271 0xa208000000000000ULL, 0x0000000000000000ULL, // negative
272 0xa248000000000000ULL, 0x0000000000000000ULL,
273 // flavors of NAN
274 0x7c00000000000000ULL, 0x0000000000000000ULL, // quiet
275 0xfc00000000000000ULL, 0xc00100035b007700ULL,
276 0x7e00000000000000ULL, 0xfe000000d0e0a0d0ULL, // signaling
277 // flavors of Infinity
278 0x7800000000000000ULL, 0x0000000000000000ULL,
279 0xf800000000000000ULL, 0x0000000000000000ULL, // negative
280 0xf900000000000000ULL, 0x0000000000000000ULL
281 };
282
283 static unsigned long long dfp64_vals[] = {
284 // various finite numbers
285 0x2234000000000e50ULL,
286 0x223400000014c000ULL,
287 0xa2340000000000e0ULL,// negative
288 0x22240000000000cfULL,
289 0xa21400010a395bcfULL,// negative
290 0x6e4d3f1f534acdd4ULL,// huge number
291 0x000400000089b000ULL,// very small number
292 // flavors of zero
293 0x2238000000000000ULL,
294 0xa238000000000000ULL,
295 0x4248000000000000ULL,
296 // flavors of NAN
297 0x7e34000000000111ULL,
298 0xfe000000d0e0a0d0ULL,//signaling
299 0xfc00000000000000ULL,//quiet
300 // flavors of Infinity
301 0x7800000000000000ULL,
302 0xf800000000000000ULL,//negative
303 0x7a34000000000000ULL,
304 };
305
306 /* The bcd64_vals and bdc128_vals hold the unique results of executing
307 * the ddedpd instruction on the basic dfp64 and dfp128 array values.
308 * Executing the inverse operation (denbcd) on these values with the
309 * appropriate S (signed) value should yield values approximating the
310 * original dfp values (except being 2^4 in magnitude since the decoding
311 * operation shifted the value one hex digit to the left to make room
312 * for signedness info).
313 */
314 static unsigned long long bcd64_vals[] = {
315 0x0000000000003450ULL,
316 0x000000000003450cULL,
317 0x000000000003450fULL,
318 0x0000000001230000ULL,
319 0x000000001230000cULL,
320 0x000000001230000fULL,
321 0x0000000000000160ULL,
322 0x000000000000160dULL,
323 0x0000000000000189ULL,
324 0x000000000000189cULL,
325 0x000000000000189fULL,
326 0x0000004123456789ULL,
327 0x000004123456789dULL,
328 0x9839871234533354ULL,
329 0x839871234533354cULL,
330 0x839871234533354fULL,
331 0x0000000008864000ULL,
332 0x000000008864000cULL,
333 0x000000008864000fULL,
334 0x0000000000000000ULL,
335 0x000000000000000cULL,
336 0x000000000000000fULL,
337 0x000000000000000dULL,
338 0x0000000000000211ULL,
339 0x000000000000211cULL,
340 0x000000000000211fULL,
341 0x0000003882028150ULL,
342 0x000003882028150dULL
343 };
344
345 static unsigned long long bcd128_vals[] = {
346 0x0000000000000000ULL, 0x0000000000003450ULL,
347 0x0000000000000000ULL, 0x000000000003450cULL,
348 0x0000000000000000ULL, 0x000000000003450fULL,
349 0x0000000000000000ULL, 0x0000000001230000ULL,
350 0x0000000000000000ULL, 0x000000001230000cULL,
351 0x0000000000000000ULL, 0x000000001230000fULL,
352 0x0000000000000000ULL, 0x0000000000000160ULL,
353 0x0000000000000000ULL, 0x000000000000160dULL,
354 0x0000000000000000ULL, 0x0000000000000189ULL,
355 0x0000000000000000ULL, 0x000000000000189cULL,
356 0x0000000000000000ULL, 0x000000000000189fULL,
357 0x0000000000000000ULL, 0x0000004123456789ULL,
358 0x0000000000000000ULL, 0x000004123456789dULL,
359 0x0000097100000000ULL, 0x9839871234533354ULL,
360 0x0000971000000009ULL, 0x839871234533354cULL,
361 0x0000971000000009ULL, 0x839871234533354fULL,
362 0x0000010954000051ULL, 0x8000640000000049ULL,
363 0x0000109540000518ULL, 0x000640000000049cULL,
364 0x0000109540000518ULL, 0x000640000000049fULL,
365 0x0000000000000000ULL, 0x0000000000000000ULL,
366 0x0000000000000000ULL, 0x000000000000000cULL,
367 0x0000000000000000ULL, 0x000000000000000fULL,
368 0x0000000000000000ULL, 0x000000000000000dULL,
369 0x0000000000080000ULL, 0x0200801330811600ULL,
370 0x0000000000800000ULL, 0x200801330811600dULL,
371 0x0000000000088170ULL, 0x0000003882028150ULL,
372 0x0000000000881700ULL, 0x000003882028150cULL,
373 0x0000000000881700ULL, 0x000003882028150fULL
374 };
375
376 // Both Long and Quad arrays of DFP values should have the same length, so it
377 // doesn't matter which array I use for calculating the following #define.
378 #define NUM_DFP_VALS (sizeof(dfp64_vals)/8)
379
380 typedef enum {
381 LONG_TEST,
382 QUAD_TEST
383 } precision_type_t;
384
385 typedef struct dfp_one_arg_test
386 {
387 test_funcp_t test_func;
388 const char * name;
389 precision_type_t precision;
390 const char * op;
391 } dfp_one_arg_test_t;
392
393 typedef struct dfp_one_arg_bcd_test
394 {
395 test_func_bcdp_t test_func;
396 const char * name;
397 precision_type_t precision;
398 const char * op;
399 } dfp_one_arg_bcd_test_t;
400
401 static dfp_one_arg_bcd_test_t
402 dfp_test_dfp_ddedpd_tests[] = {
403 { &_test_ddedpd, "ddedpd", LONG_TEST, "[D->B]"},
404 { &_test_ddedpdq, "ddedpdq", QUAD_TEST, "[D->B]"},
405 { NULL, NULL, 0, NULL}
406 };
407
test_dfp_ddedpd_ops(void)408 static void test_dfp_ddedpd_ops(void)
409 {
410 test_func_bcdp_t func;
411 dfp_val_t test_val;
412
413 int k = 0;
414
415 while ((func = dfp_test_dfp_ddedpd_tests[k].test_func)) {
416 int i;
417 dfp_one_arg_bcd_test_t test_def = dfp_test_dfp_ddedpd_tests[k];
418
419 for (i = 0; i < NUM_DFP_VALS; i++) {
420 unsigned int SP;
421
422 if (test_def.precision == LONG_TEST) {
423 test_val.u64_val = dfp64_vals[i];
424 } else {
425 test_val.u128.valu = dfp128_vals[i * 2];
426 test_val.u128.vall = dfp128_vals[(i * 2) + 1];
427 }
428
429 for (SP = 0; SP < 4; SP++) {
430 dfp_val_t result;
431
432 /* There is an ABI change in how 128 bit arguments are aligned
433 * with GCC 5.0. The compiler generates a "note" about this
434 * starting with GCC 4.8. To avoid generating the "note", pass
435 * the address of the 128-bit arguments rather then the value.
436 */
437 result = (*func)(SP, &test_val);
438 printf("%s (SP=%d) %s", test_def.name, SP, test_def.op);
439 if (test_def.precision == LONG_TEST) {
440 printf("%016llx ==> %016llx\n", test_val.u64_val, result.u64_val);
441 } else {
442 printf("%016llx %016llx ==> %016llx %016llx\n",
443 test_val.u128.valu, test_val.u128.vall,
444 result.u128.valu, result.u128.vall);
445 }
446 }
447 }
448 k++;
449 printf( "\n" );
450 }
451 }
452
453 static dfp_one_arg_bcd_test_t
454 dfp_test_dfp_denbcd_tests[] = {
455 { &_test_denbcd, "denbcd", LONG_TEST, "[B->D]"},
456 { &_test_denbcdq, "denbcdq", QUAD_TEST, "[B->D]"},
457 { NULL, NULL, 0, NULL}
458 };
459
test_dfp_denbcd_ops(void)460 static void test_dfp_denbcd_ops(void)
461 {
462 test_func_bcdp_t func;
463 dfp_val_t test_val;
464 int num_test_vals;
465
466 int k = 0;
467
468 while ((func = dfp_test_dfp_denbcd_tests[k].test_func)) {
469 int i;
470 dfp_one_arg_bcd_test_t test_def = dfp_test_dfp_denbcd_tests[k];
471 if (test_def.precision == LONG_TEST)
472 num_test_vals = sizeof(bcd64_vals)/sizeof(unsigned long long);
473 else
474 num_test_vals = sizeof(bcd128_vals)/(2 * sizeof(unsigned long long));
475
476 for (i = 0; i < num_test_vals; i++) {
477 unsigned int S;
478 dfp_val_t result;
479 /* The DPD-to-BCD decodings may contain up to 3 decodings for each normal DFP
480 * value: the first is an unsigned decoding, and the other two are
481 * signed decodings, with SP[1] set to '0' and '1' respectively at decode
482 * time. But some of the results of decodings were duplicates, so they were
483 * not included in the bcd64_vals and bcd128_vals arrays.
484 *
485 * When doing the encoding operation (denbcd), we'll attempt both S=0 and
486 * S=1; one or the other should encode the BCD value to something close to
487 * its original DFP value (except being 2^4 in magnitude since the decoding
488 * operation shifted the value one hex digit to the left to make room
489 * for signedness info).
490 */
491 for (S = 0; S < 2; S++) {
492 if (test_def.precision == LONG_TEST) {
493 test_val.u64_val = bcd64_vals[i];
494 } else {
495 test_val.u128.valu = bcd128_vals[i * 2];
496 test_val.u128.vall = bcd128_vals[(i * 2) + 1];
497 }
498
499 /* There is an API change in how 128 bit arguments are aligned
500 * with GCC 5.0. The compiler generates a "note" about this
501 * starting with GCC 4.8. To avoid generating the "note", pass
502 * the address of the 128-bit arguments rather then the value.
503 */
504 result = (*func)(S, &test_val);
505 printf("%s (S=%d) %s", test_def.name, S, test_def.op);
506 if (test_def.precision == LONG_TEST) {
507 printf("%016llx ==> %016llx\n", test_val.u64_val, result.u64_val);
508 } else {
509 printf("%016llx %016llx ==> %016llx %016llx\n",
510 test_val.u128.valu, test_val.u128.vall,
511 result.u128.valu, result.u128.vall);
512 }
513 }
514 }
515 k++;
516 printf( "\n" );
517 }
518 }
519
520
521 static dfp_one_arg_test_t
522 dfp_test_significance_tests[] = {
523 { &_test_dtstsf, "dtstsf", LONG_TEST, "[tSig]"},
524 { &_test_dtstsfq, "dtstsfq", QUAD_TEST, "[tSig]"},
525 { NULL, NULL, 0, NULL}
526 };
527
test_dfp_test_significance_ops(void)528 static void test_dfp_test_significance_ops(void)
529 {
530 test_funcp_t func;
531 dfp_val_t test_valB;
532 int k = 0;
533 unsigned int BF_vals[] = {BF_val1, BF_val2, BF_val3};
534 unsigned int reference_sig, reference_sig_vals[] = {0U, 1U, 2U, 4U, 6U, 63U};
535 int num_reference_sig_vals = sizeof(reference_sig_vals)/sizeof(unsigned int);
536
537 while ((func = dfp_test_significance_tests[k].test_func)) {
538 int i;
539 dfp_one_arg_test_t test_def = dfp_test_significance_tests[k];
540
541 for (i = 0; i < NUM_DFP_VALS; i++) {
542 int j;
543 if (test_def.precision == LONG_TEST) {
544 test_valB.u64_val = dfp64_vals[i];
545 } else {
546 test_valB.u128.valu = dfp128_vals[i * 2];
547 test_valB.u128.vall = dfp128_vals[(i * 2) + 1];
548 }
549
550 for (j = 0; j < num_reference_sig_vals; j++) {
551 int bf_idx, BF;
552 reference_sig = reference_sig_vals[j];
553 for (bf_idx = 0; bf_idx < sizeof(BF_vals)/sizeof(unsigned int); bf_idx++) {
554 unsigned int condreg;
555 unsigned int flags;
556 BF = BF_vals[bf_idx];
557 SET_FPSCR_ZERO;
558 SET_CR_XER_ZERO;
559 /* There is an ABI change in how 128 bit arguments are aligned
560 * with GCC 5.0. The compiler generates a "note" about this
561 * starting with GCC 4.9. To avoid generating the "note", pass
562 * the address of the 128-bit arguments rather then the value.
563 */
564 (*func)(BF, reference_sig, &test_valB);
565 GET_CR(flags);
566
567 condreg = ((flags >> (4 * (7-BF)))) & 0xf;
568 printf("%s (ref_sig=%d) %s", test_def.name, reference_sig, test_def.op);
569 if (test_def.precision == LONG_TEST) {
570 printf("%016llx", test_valB.u64_val);
571 } else {
572 printf("%016llx %016llx", test_valB.u128.valu, test_valB.u128.vall);
573 }
574 printf(" => %x (BF=%d)\n", condreg, BF);
575 }
576 }
577 printf( "\n" );
578 }
579 k++;
580 }
581 }
582
583 static test_table_t
584 all_tests[] =
585 {
586 { &test_dfp_test_significance_ops,
587 "Test DFP test significance instructions"},
588 { &test_dfp_ddedpd_ops,
589 "Test DFP DPD-to-BCD instructions"},
590 { &test_dfp_denbcd_ops,
591 "Test DFP BCD-to-DPD instructions"},
592 { NULL, NULL }
593 };
594 #endif // HAS_DFP
595
main()596 int main() {
597 #if defined(HAS_DFP)
598
599 test_table_t aTest;
600 test_driver_func_t func;
601 int i = 0;
602
603 while ((func = all_tests[i].test_category)) {
604 aTest = all_tests[i];
605 printf( "%s\n", aTest.name );
606 (*func)();
607 i++;
608 }
609
610 #endif // HAS_DFP
611 return 0;
612 }
613