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
88 // The assembly-level instructions being tested
89
90 /* In _test_dtstdc[q], DCM can be one of 6 possible data classes, numbered 0-5.
91 * In reality, DCM is a 6-bit mask field. We just test the individual values
92 * and assume that masking multiple values would work OK.
93 * BF is the condition register bit field which can range from 0-7. But for
94 * testing purposes, we only use BF values of '0' and '5'.
95 */
_test_dtstdc(int BF,int DCM,dfp_val_t * val1,dfp_val_t * x1)96 static void _test_dtstdc(int BF, int DCM, dfp_val_t *val1, dfp_val_t *x1 __attribute__((unused)))
97 {
98 _Decimal64 f14 = val1->dec_val;
99 if (DCM < 0 || DCM > 5 || !(BF == 0 || BF == 5)) {
100 fprintf(stderr, "Invalid inputs to asm test: a=%d, b=%d\n", BF, DCM);
101 return;
102 }
103 switch (DCM) {
104 case 0:
105 if (BF)
106 __asm__ __volatile__ ("dtstdc 5, %0, 1" : : "f" (f14));
107 else
108 __asm__ __volatile__ ("dtstdc 0, %0, 1" : : "f" (f14));
109 break;
110 case 1:
111 if (BF)
112 __asm__ __volatile__ ("dtstdc 5, %0, 2" : : "f" (f14));
113 else
114 __asm__ __volatile__ ("dtstdc 0, %0, 2" : : "f" (f14));
115 break;
116 case 2:
117 if (BF)
118 __asm__ __volatile__ ("dtstdc 5, %0, 4" : : "f" (f14));
119 else
120 __asm__ __volatile__ ("dtstdc 0, %0, 4" : : "f" (f14));
121 break;
122 case 3:
123 if (BF)
124 __asm__ __volatile__ ("dtstdc 5, %0, 8" : : "f" (f14));
125 else
126 __asm__ __volatile__ ("dtstdc 0, %0, 8" : : "f" (f14));
127 break;
128 case 4:
129 if (BF)
130 __asm__ __volatile__ ("dtstdc 5, %0, 16" : : "f" (f14));
131 else
132 __asm__ __volatile__ ("dtstdc 0, %0, 16" : : "f" (f14));
133 break;
134 case 5:
135 if (BF)
136 __asm__ __volatile__ ("dtstdc 5, %0, 32" : : "f" (f14));
137 else
138 __asm__ __volatile__ ("dtstdc 0, %0, 32" : : "f" (f14));
139 break;
140 default:
141 break;
142 }
143 }
144
_test_dtstdcq(int BF,int DCM,dfp_val_t * val1,dfp_val_t * x1)145 static void _test_dtstdcq(int BF, int DCM, dfp_val_t *val1, dfp_val_t *x1 __attribute__((unused)))
146 {
147 _Decimal128 f14 = val1->dec_val128;
148 if (DCM < 0 || DCM > 5 || !(BF == 0 || BF == 5)) {
149 fprintf(stderr, "Invalid inputs to asm test: a=%d, b=%d\n", BF, DCM);
150 return;
151 }
152 switch (DCM) {
153 case 0:
154 if (BF)
155 __asm__ __volatile__ ("dtstdcq 5, %0, 1" : : "f" (f14));
156 else
157 __asm__ __volatile__ ("dtstdcq 0, %0, 1" : : "f" (f14));
158 break;
159 case 1:
160 if (BF)
161 __asm__ __volatile__ ("dtstdcq 5, %0, 2" : : "f" (f14));
162 else
163 __asm__ __volatile__ ("dtstdcq 0, %0, 2" : : "f" (f14));
164 break;
165 case 2:
166 if (BF)
167 __asm__ __volatile__ ("dtstdcq 5, %0, 4" : : "f" (f14));
168 else
169 __asm__ __volatile__ ("dtstdcq 0, %0, 4" : : "f" (f14));
170 break;
171 case 3:
172 if (BF)
173 __asm__ __volatile__ ("dtstdcq 5, %0, 8" : : "f" (f14));
174 else
175 __asm__ __volatile__ ("dtstdcq 0, %0, 8" : : "f" (f14));
176 break;
177 case 4:
178 if (BF)
179 __asm__ __volatile__ ("dtstdcq 5, %0, 16" : : "f" (f14));
180 else
181 __asm__ __volatile__ ("dtstdcq 0, %0, 16" : : "f" (f14));
182 break;
183 case 5:
184 if (BF)
185 __asm__ __volatile__ ("dtstdcq 5, %0, 32" : : "f" (f14));
186 else
187 __asm__ __volatile__ ("dtstdcq 0, %0, 32" : : "f" (f14));
188 break;
189 default:
190 break;
191 }
192 }
193
194 /* In _test_dtstdg[q], DGM can be one of 6 possible data groups, numbered 0-5.
195 * In reality, DGM is a 6-bit mask field. We just test the individual values
196 * and assume that masking multiple values would work OK.
197 * BF is the condition register bit field which can range from 0-7. But for
198 * testing purposes, we only use BF values of '0' and '5'.
199 */
_test_dtstdg(int BF,int DGM,dfp_val_t * val1,dfp_val_t * x1)200 static void _test_dtstdg(int BF, int DGM, dfp_val_t *val1, dfp_val_t *x1 __attribute__((unused)))
201 {
202 _Decimal64 f14 = val1->dec_val;
203 if (DGM < 0 || DGM > 5 || !(BF == 0 || BF == 5)) {
204 fprintf(stderr, "Invalid inputs to asm test: a=%d, b=%d\n", BF, DGM);
205 return;
206 }
207 switch (DGM) {
208 case 0:
209 if (BF)
210 __asm__ __volatile__ ("dtstdg 5, %0, 1" : : "f" (f14));
211 else
212 __asm__ __volatile__ ("dtstdg 0, %0, 1" : : "f" (f14));
213 break;
214 case 1:
215 if (BF)
216 __asm__ __volatile__ ("dtstdg 5, %0, 2" : : "f" (f14));
217 else
218 __asm__ __volatile__ ("dtstdg 0, %0, 2" : : "f" (f14));
219 break;
220 case 2:
221 if (BF)
222 __asm__ __volatile__ ("dtstdg 5, %0, 4" : : "f" (f14));
223 else
224 __asm__ __volatile__ ("dtstdg 0, %0, 4" : : "f" (f14));
225 break;
226 case 3:
227 if (BF)
228 __asm__ __volatile__ ("dtstdg 5, %0, 8" : : "f" (f14));
229 else
230 __asm__ __volatile__ ("dtstdg 0, %0, 8" : : "f" (f14));
231 break;
232 case 4:
233 if (BF)
234 __asm__ __volatile__ ("dtstdg 5, %0, 16" : : "f" (f14));
235 else
236 __asm__ __volatile__ ("dtstdg 0, %0, 16" : : "f" (f14));
237 break;
238 case 5:
239 if (BF)
240 __asm__ __volatile__ ("dtstdg 5, %0, 32" : : "f" (f14));
241 else
242 __asm__ __volatile__ ("dtstdg 0, %0, 32" : : "f" (f14));
243 break;
244 default:
245 break;
246 }
247 }
248
_test_dtstdgq(int BF,int DGM,dfp_val_t * val1,dfp_val_t * x1)249 static void _test_dtstdgq(int BF, int DGM, dfp_val_t *val1, dfp_val_t *x1 __attribute__((unused)))
250 {
251 _Decimal128 f14 = val1->dec_val128;
252 if (DGM < 0 || DGM > 5 || !(BF == 0 || BF == 5)) {
253 fprintf(stderr, "Invalid inputs to asm test: a=%d, b=%d\n", BF, DGM);
254 return;
255 }
256 switch (DGM) {
257 case 0:
258 if (BF)
259 __asm__ __volatile__ ("dtstdgq 5, %0, 1" : : "f" (f14));
260 else
261 __asm__ __volatile__ ("dtstdgq 0, %0, 1" : : "f" (f14));
262 break;
263 case 1:
264 if (BF)
265 __asm__ __volatile__ ("dtstdgq 5, %0, 2" : : "f" (f14));
266 else
267 __asm__ __volatile__ ("dtstdgq 0, %0, 2" : : "f" (f14));
268 break;
269 case 2:
270 if (BF)
271 __asm__ __volatile__ ("dtstdgq 5, %0, 4" : : "f" (f14));
272 else
273 __asm__ __volatile__ ("dtstdgq 0, %0, 4" : : "f" (f14));
274 break;
275 case 3:
276 if (BF)
277 __asm__ __volatile__ ("dtstdgq 5, %0, 8" : : "f" (f14));
278 else
279 __asm__ __volatile__ ("dtstdgq 0, %0, 8" : : "f" (f14));
280 break;
281 case 4:
282 if (BF)
283 __asm__ __volatile__ ("dtstdgq 5, %0, 16" : : "f" (f14));
284 else
285 __asm__ __volatile__ ("dtstdgq 0, %0, 16" : : "f" (f14));
286 break;
287 case 5:
288 if (BF)
289 __asm__ __volatile__ ("dtstdgq 5, %0, 32" : : "f" (f14));
290 else
291 __asm__ __volatile__ ("dtstdgq 0, %0, 32" : : "f" (f14));
292 break;
293 default:
294 break;
295 }
296 }
297
298 /* In _test_dtstex[q], BF is the condition register bit field indicating the
299 * CR field in which the result of the test should be placed. BF can range
300 * from 0-7, but for testing purposes, we only use BF values of '4' and '7'.
301 */
302 static void
_test_dtstex(int BF,int x,dfp_val_t * val1,dfp_val_t * val2)303 _test_dtstex(int BF, int x __attribute__((unused)), dfp_val_t *val1, dfp_val_t *val2)
304 {
305 _Decimal64 f14 = val1->dec_val;
306 _Decimal64 f16 = val2->dec_val;
307 if (!(BF == 4 || BF == 7)) {
308 fprintf(stderr, "Invalid input to asm test: a=%d\n", BF);
309 return;
310 }
311 switch (BF) {
312 case 4:
313 __asm__ __volatile__ ("dtstex 4, %0, %1" : : "f" (f14),"f" (f16));
314 break;
315 case 7:
316 __asm__ __volatile__ ("dtstex 7, %0, %1" : : "f" (f14),"f" (f16));
317 break;
318 default:
319 break;
320 }
321 }
322
_test_dtstexq(int BF,int x,dfp_val_t * val1,dfp_val_t * val2)323 static void _test_dtstexq(int BF, int x __attribute__((unused)), dfp_val_t *val1, dfp_val_t *val2)
324 {
325 _Decimal128 f14 = val1->dec_val128;
326 _Decimal128 f16 = val2->dec_val128;
327 if (!(BF == 4 || BF == 7)) {
328 fprintf(stderr, "Invalid input to asm test: a=%d\n", BF);
329 return;
330 }
331 switch (BF) {
332 case 4:
333 __asm__ __volatile__ ("dtstexq 4, %0, %1" : : "f" (f14),"f" (f16));
334 break;
335 case 7:
336 __asm__ __volatile__ ("dtstexq 7, %0, %1" : : "f" (f14),"f" (f16));
337 break;
338 default:
339 break;
340 }
341 }
342
343
344
345 typedef void (*test_funcp_t)(int a, int b, dfp_val_t *val1, dfp_val_t *val2);
346 typedef void (*test_driver_func_t)(void);
347 typedef struct test_table
348 {
349 test_driver_func_t test_category;
350 char * name;
351 } test_table_t;
352
353 /*
354 * 345.0DD (0x2207c00000000000 0xe50)
355 * 1.2300e+5DD (0x2207c00000000000 0x14c000)
356 * -16.0DD (0xa207c00000000000 0xe0)
357 * 0.00189DD (0x2206c00000000000 0xcf)
358 * -4.1235DD (0xa205c00000000000 0x10a395bcf)
359 * 9.8399e+20DD (0x2209400000000000 0x253f1f534acdd4)
360 * 0DD (0x2208000000000000 0x0)
361 * 0DD (0x2208000000000000 0x0)
362 * infDD (0x7800000000000000 0x0)
363 * nanDD (0x7c00000000000000 0x0
364 */
365 static unsigned long long dfp128_vals[] = {
366 // Some finite numbers
367 0x2207c00000000000ULL, 0x0000000000000e50ULL,
368 0x2207c00000000000ULL, 0x000000000014c000ULL,
369 0xa207c00000000000ULL, 0x00000000000000e0ULL,
370 0x2206c00000000000ULL, 0x00000000000000cfULL,
371 0xa205c00000000000ULL, 0x000000010a395bcfULL,
372 0x6209400000fd0000ULL, 0x00253f1f534acdd4ULL, // huge number
373 0x000400000089b000ULL, 0x0a6000d000000049ULL, // very small number
374 // flavors of zero
375 0x2208000000000000ULL, 0x0000000000000000ULL,
376 0xa208000000000000ULL, 0x0000000000000000ULL, // negative
377 0xa248000000000000ULL, 0x0000000000000000ULL,
378 // flavors of NAN
379 0x7c00000000000000ULL, 0x0000000000000000ULL, // quiet
380 0xfc00000000000000ULL, 0xc00100035b007700ULL,
381 0x7e00000000000000ULL, 0xfe000000d0e0a0d0ULL, // signaling
382 // flavors of Infinity
383 0x7800000000000000ULL, 0x0000000000000000ULL,
384 0xf800000000000000ULL, 0x0000000000000000ULL, // negative
385 0xf900000000000000ULL, 0x0000000000000000ULL
386 };
387
388 static unsigned long long dfp64_vals[] = {
389 // various finite numbers
390 0x2234000000000e50ULL,
391 0x223400000014c000ULL,
392 0xa2340000000000e0ULL,// negative
393 0x22240000000000cfULL,
394 0xa21400010a395bcfULL,// negative
395 0x6e4d3f1f534acdd4ULL,// huge number
396 0x000400000089b000ULL,// very small number
397 // flavors of zero
398 0x2238000000000000ULL,
399 0xa238000000000000ULL,
400 0x4248000000000000ULL,
401 // flavors of NAN
402 0x7e34000000000111ULL,
403 0xfe000000d0e0a0d0ULL,//signaling
404 0xfc00000000000000ULL,//quiet
405 // flavors of Infinity
406 0x7800000000000000ULL,
407 0xf800000000000000ULL,//negative
408 0x7a34000000000000ULL,
409 };
410
411 // Both Long and Quad arrays of DFP values should have the same length, so it
412 // doesn't matter which array I use for calculating the following #define.
413 #define NUM_DFP_VALS (sizeof(dfp64_vals)/8)
414
415 typedef struct dfp_test_args {
416 int fra_idx;
417 int frb_idx;
418 } dfp_test_args_t;
419
420
421 // Index pairs from dfp64_vals array to be used with dfp_two_arg_tests
422 static dfp_test_args_t dfp_2args_x1[] = {
423 {0, 1},
424 {2, 1},
425 {4, 3},
426 {6, 0},
427 {2, 4},
428 {5, 1},
429 {5, 2},
430 {7, 1},
431 {7, 2},
432 {8, 0},
433 {8, 1},
434 {8, 2},
435 {7, 8},
436 {12, 14},
437 {12, 1},
438 {12, 13},
439 {12, 12},
440 {12, 11},
441 {11, 14},
442 {11, 0},
443 {11, 13},
444 {11, 11},
445 {14, 14},
446 {14, 3},
447 {14, 15},
448 };
449
450 typedef enum {
451 LONG_TEST,
452 QUAD_TEST
453 } precision_type_t;
454
455 typedef struct dfp_test
456 {
457 test_funcp_t test_func;
458 const char * name;
459 dfp_test_args_t * targs;
460 int num_tests;
461 precision_type_t precision;
462 const char * op;
463 } dfp_test_t;
464
465 typedef struct dfp_one_arg_test
466 {
467 test_funcp_t test_func;
468 const char * name;
469 precision_type_t precision;
470 const char * op;
471 } dfp_one_arg_test_t;
472
473
474
475 static dfp_one_arg_test_t
476 dfp_ClassAndGroupTest_tests[] = {
477 { &_test_dtstdc, "dtstdc", LONG_TEST, "[tCls]"},
478 { &_test_dtstdcq, "dtstdcq", QUAD_TEST, "[tCls]"},
479 { &_test_dtstdg, "dtstdg", LONG_TEST, "[tGrp]"},
480 { &_test_dtstdgq, "dtstdgq", QUAD_TEST, "[tGrp]"},
481 { NULL, NULL, 0, NULL}
482 };
483
test_dfp_ClassAndGroupTest_ops(void)484 static void test_dfp_ClassAndGroupTest_ops(void)
485 {
486 test_funcp_t func;
487 dfp_val_t test_val, dummy;
488
489 int k = 0;
490
491 while ((func = dfp_ClassAndGroupTest_tests[k].test_func)) {
492 int i;
493 dfp_one_arg_test_t test_def = dfp_ClassAndGroupTest_tests[k];
494
495 for (i = 0; i < NUM_DFP_VALS; i++) {
496 int data_class_OR_group, BF = 0;
497 Bool repeat = True;
498
499 if (test_def.precision == LONG_TEST) {
500 test_val.u64_val = dfp64_vals[i];
501 } else {
502 test_val.u128.valu = dfp128_vals[i * 2];
503 test_val.u128.vall = dfp128_vals[(i * 2) + 1];
504 }
505
506 again:
507 for (data_class_OR_group = 0; data_class_OR_group < 6; data_class_OR_group++) {
508 unsigned int condreg;
509 unsigned int flags;
510 SET_FPSCR_ZERO;
511 SET_CR_XER_ZERO;
512
513 /* There is an ABI change in how 128 bit arguments are aligned
514 * with GCC 5.0. The compiler generates a "note" about this
515 * starting with GCC 4.8. To avoid generating the "note", pass
516 * the address of the 128-bit arguments rather then the value.
517 */
518 (*func)(BF, data_class_OR_group, &test_val, &dummy);
519 GET_CR(flags);
520
521 condreg = ((flags >> (4 * (7-BF)))) & 0xf;
522 printf("%s (DC/DG=%d) %s", test_def.name, data_class_OR_group,
523 test_def.op);
524 if (test_def.precision == QUAD_TEST) {
525 printf("%016llx %016llx", test_val.u128.valu, test_val.u128.vall);
526 } else {
527 printf("%016llx", test_val.u64_val);
528 }
529
530 //%016llx
531 printf(" => %x (BF=%d)\n", condreg, BF);
532 }
533 if (repeat) {
534 repeat = False;
535 BF = 5;
536 goto again;
537 }
538 }
539 k++;
540 printf( "\n" );
541 }
542 }
543
544
545 static dfp_test_t
546 dfp_ExpTest_tests[] = {
547 { &_test_dtstex, "dtstex", dfp_2args_x1, 25, LONG_TEST, "[tExp]"},
548 { &_test_dtstexq, "dtstexq", dfp_2args_x1, 25, QUAD_TEST, "[tExp]"},
549 { NULL, NULL, NULL, 0, 0, NULL}
550 };
551
552
test_dfp_ExpTest_ops(void)553 static void test_dfp_ExpTest_ops(void)
554 {
555 dfp_val_t test_val1, test_val2;
556 test_funcp_t func;
557 int k = 0;
558
559 while ((func = dfp_ExpTest_tests[k].test_func)) {
560 /* BF is a 3-bit instruction field that indicates the CR field in which the
561 * result of the test should be placed. We won't iterate through all
562 * 8 possible BF values since storing compare results to a given field is
563 * a well-tested mechanism in VEX. But we will test two BF values, just as
564 * a sniff-test.
565 */
566 int i, repeat = 1, BF = 4;
567 dfp_test_t test_def = dfp_ExpTest_tests[k];
568
569 again:
570 for (i = 0; i < test_def.num_tests; i++) {
571 unsigned int condreg;
572 unsigned int flags;
573
574 if (test_def.precision == LONG_TEST) {
575 test_val1.u64_val = dfp64_vals[test_def.targs[i].fra_idx];
576 test_val2.u64_val = dfp64_vals[test_def.targs[i].frb_idx];
577 } else {
578 test_val1.u128.valu = dfp128_vals[test_def.targs[i].fra_idx * 2];
579 test_val1.u128.vall = dfp128_vals[(test_def.targs[i].fra_idx * 2) + 1];
580 test_val2.u128.valu = dfp128_vals[test_def.targs[i].frb_idx * 2];
581 test_val2.u128.vall = dfp128_vals[(test_def.targs[i].frb_idx * 2) + 1];
582 }
583
584 SET_FPSCR_ZERO;
585 SET_CR_XER_ZERO;
586 /* There is an ABI change in how 128 bit arguments are aligned
587 * with GCC 5.0. The compiler generates a "note" about this
588 * starting with GCC 4.8. To avoid generating the "note", pass
589 * the address of the 128-bit arguments rather then the value.
590 */
591 (*func)(BF, 0, &test_val1, &test_val2);
592 GET_CR(flags);
593
594 condreg = ((flags >> (4 * (7-BF)))) & 0xf;
595 printf("%s ", test_def.name);
596 if (test_def.precision == LONG_TEST) {
597 printf("%016llx %s %016llx ",
598 test_val1.u64_val, test_def.op, test_val2.u64_val);
599 } else {
600 printf("%016llx %016llx %s %016llx %016llx ",
601 test_val1.u128.valu, test_val1.u128.vall, test_def.op, test_val2.u128.valu, test_val2.u128.vall);
602 }
603 printf(" => %x (BF=%d)\n", condreg, BF);
604 }
605 if (repeat) {
606 repeat = 0;
607 BF = 7;
608 goto again;
609 }
610 k++;
611 printf( "\n" );
612 }
613 }
614
615
616 static test_table_t
617 all_tests[] =
618 {
619 { &test_dfp_ExpTest_ops,
620 "Test DFP exponent test instructions"},
621 { &test_dfp_ClassAndGroupTest_ops,
622 "Test DFP class and group test instructions"},
623 { NULL, NULL }
624 };
625 #endif // HAS_DFP
626
main()627 int main() {
628 #if defined(HAS_DFP)
629
630 test_table_t aTest;
631 test_driver_func_t func;
632 int i = 0;
633
634 while ((func = all_tests[i].test_category)) {
635 aTest = all_tests[i];
636 printf( "%s\n", aTest.name );
637 (*func)();
638 i++;
639 }
640
641 #endif // HAS_DFP
642 return 0;
643 }
644