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