1 /*  Copyright (C) 2012 IBM
2 
3  Author: Maynard Johnson <maynardj@us.ibm.com>
4          Carl Love <carll@us.ibm.com>
5 
6  This program is free software; you can redistribute it and/or
7  modify it under the terms of the GNU General Public License as
8  published by the Free Software Foundation; either version 2 of the
9  License, or (at your option) any later version.
10 
11  This program is distributed in the hope that it will be useful, but
12  WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  General Public License for more details.
15 
16  You should have received a copy of the GNU General Public License
17  along with this program; if not, write to the Free Software
18  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19  02111-1307, USA.
20 
21  The GNU General Public License is contained in the file COPYING.
22  */
23 
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <stdint.h>
27 #include <string.h>
28 #include <elf.h>
29 #include <link.h>
30 
31 #define PPC_FEATURE_HAS_VSX  0x00000080 /* Vector Scalar Extension. */
32 
33 #if defined(HAS_DFP)
34 
35 register double f14 __asm__ ("fr14");
36 register double f15 __asm__ ("fr15");
37 register double f16 __asm__ ("fr16");
38 register double f17 __asm__ ("fr17");
39 register double f18 __asm__ ("fr18");
40 register double f19 __asm__ ("fr19");
41 
42 typedef unsigned char Bool;
43 #define True 1
44 #define False 0
45 
46 #define SET_FPSCR_ZERO \
47 		do { double _d = 0.0;		                           \
48 		__asm__ __volatile__ ("mtfsf 0xFF, %0" : : "f"(_d) ); \
49 		} while (0)
50 
51 #define GET_FPSCR(_arg) \
52   __asm__ __volatile__ ("mffs %0"  : "=f"(_arg) )
53 
54 #define SET_FPSCR_DRN \
55   __asm__ __volatile__ ("mtfsf  1, %0, 0, 1" :  : "f"(f14) )
56 
57 #define SH_0  0
58 #define SH_1  1
59 #define SH_2  15
60 #define SH_3  63
61 
62 #define NUM_RND_MODES  8
63 #define CONDREG_MASK  0x0f000000
64 #define CONDREG_SHIFT 24
65 
66 static char ** my_envp;
__auxv_find(void)67 static inline char** __auxv_find(void)
68 {
69    char **result = my_envp;
70    /* Scan over the env vector looking for the ending NULL */
71    for (; *result != NULL; ++result) {
72    }
73    /* Bump the pointer one more step, which should be the auxv. */
74    return ++result;
75 }
76 
fetch_at_hwcap(void)77 static unsigned long fetch_at_hwcap(void)
78 {
79    static unsigned long auxv_hwcap = 0;
80    int i;
81    ElfW(auxv_t) * auxv_buf = NULL;
82 
83    if (auxv_hwcap)
84       return auxv_hwcap;
85 
86    auxv_buf = (ElfW(auxv_t)*) __auxv_find();
87    for (i = 0; auxv_buf[i].a_type != AT_NULL; i++)
88       if (auxv_buf[i].a_type == AT_HWCAP) {
89          auxv_hwcap = auxv_buf[i].a_un.a_val;
90          break;
91       }
92 
93    return auxv_hwcap;
94 }
95 
get_vsx(void)96 int get_vsx(void)
97 {
98    /* Check to see if the AUX vector has the bit set indicating the HW
99     * supports the vsx instructions.  This implies the processor is
100     * at least a POWER 7.
101     */
102    unsigned long hwcap;
103 
104    hwcap = fetch_at_hwcap();
105    if ((hwcap & PPC_FEATURE_HAS_VSX) == PPC_FEATURE_HAS_VSX)
106       return 1;
107 
108    return 0;
109 }
110 
111 /* The assembly-level instructions being tested */
_test_dscri(int shift)112 static void _test_dscri (int shift)
113 {
114    switch(shift) {
115    case SH_0:
116       __asm__ __volatile__ ("dscri  %0, %1, %2" : "=f" (f18) : "f" (f14), "i" (SH_0));
117       break;
118 
119    case SH_1:
120       __asm__ __volatile__ ("dscri  %0, %1, %2" : "=f" (f18) : "f" (f14), "i" (SH_1));
121       break;
122 
123    case SH_2:
124       __asm__ __volatile__ ("dscri  %0, %1, %2" : "=f" (f18) : "f" (f14), "i" (SH_2));
125       break;
126 
127    case SH_3:
128       __asm__ __volatile__ ("dscri  %0, %1, %2" : "=f" (f18) : "f" (f14), "i" (SH_3));
129       break;
130    default:
131       printf(" dscri, unsupported shift case %d\n", shift);
132    }
133 }
134 
_test_dscli(int shift)135 static void _test_dscli (int shift)
136 {
137    switch(shift) {
138    case SH_0:
139       __asm__ __volatile__ ("dscli  %0, %1, %2" : "=f" (f18) : "f" (f14), "i" (SH_0));
140       break;
141 
142    case SH_1:
143       __asm__ __volatile__ ("dscli  %0, %1, %2" : "=f" (f18) : "f" (f14), "i" (SH_1));
144       break;
145 
146    case SH_2:
147       __asm__ __volatile__ ("dscli  %0, %1, %2" : "=f" (f18) : "f" (f14), "i" (SH_2));
148       break;
149 
150    case SH_3:
151       __asm__ __volatile__ ("dscli  %0, %1, %2" : "=f" (f18) : "f" (f14), "i" (SH_3));
152       break;
153    default:
154       printf(" dscli, unsupported shift case %d\n", shift);
155    }
156 }
157 
_test_dctdp(void)158 static void _test_dctdp (void)
159 {
160    __asm__ __volatile__ ("dctdp  %0, %1" : "=f" (f18) : "f" (f14));
161 }
162 
_test_drsp(void)163 static void _test_drsp (void)
164 {
165    __asm__ __volatile__ ("drsp  %0, %1" : "=f" (f18) : "f" (f14));
166 }
167 
_test_dctfix(void)168 static void _test_dctfix (void)
169 {
170    __asm__ __volatile__ ("dctfix  %0, %1" : "=f" (f18) : "f" (f14));
171 }
172 
173 /* Power 7 and newer processors support this instruction */
_test_dcffix(void)174 static void _test_dcffix (void)
175 {
176    __asm__ __volatile__ ("dcffix  %0, %1" : "=f" (f18) : "f" (f14));
177 }
178 
_test_dscriq(int shift)179 static void _test_dscriq (int shift)
180 {
181    switch(shift) {
182    case SH_0:
183       __asm__ __volatile__ ("dscriq  %0, %1, %2" : "=f" (f18) : "f" (f14), "i" (SH_0));
184       break;
185    case SH_1:
186       __asm__ __volatile__ ("dscriq  %0, %1, %2" : "=f" (f18) : "f" (f14), "i" (SH_1));
187       break;
188    case SH_2:
189       __asm__ __volatile__ ("dscriq  %0, %1, %2" : "=f" (f18) : "f" (f14), "i" (SH_2));
190       break;
191    case SH_3:
192       __asm__ __volatile__ ("dscriq  %0, %1, %2" : "=f" (f18) : "f" (f14), "i" (SH_3));
193       break;
194    default:
195       printf(" dscriq, unsupported shift case %d\n", shift);
196    }
197 }
198 
_test_dscliq(int shift)199 static void _test_dscliq (int shift)
200 {
201    switch(shift) {
202    case SH_0:
203       __asm__ __volatile__ ("dscliq  %0, %1, %2" : "=f" (f18) : "f" (f14), "i" (SH_0));
204       break;
205    case SH_1:
206       __asm__ __volatile__ ("dscliq  %0, %1, %2" : "=f" (f18) : "f" (f14), "i" (SH_1));
207       break;
208    case SH_2:
209       __asm__ __volatile__ ("dscliq  %0, %1, %2" : "=f" (f18) : "f" (f14), "i" (SH_2));
210       break;
211    case SH_3:
212       __asm__ __volatile__ ("dscliq  %0, %1, %2" : "=f" (f18) : "f" (f14), "i" (SH_3));
213       break;
214    default:
215       printf(" dscliq, unsupported shift case %d\n", shift);
216    }
217 }
218 
_test_dctqpq(void)219 static void _test_dctqpq (void)
220 {
221    __asm__ __volatile__ ("dctqpq  %0, %1" : "=f" (f18) : "f" (f14));
222 }
223 
_test_dctfixq(void)224 static void _test_dctfixq (void)
225 {
226    __asm__ __volatile__ ("dctfixq  %0, %1" : "=f" (f18) : "f" (f14));
227 }
228 
_test_drdpq(void)229 static void _test_drdpq (void)
230 {
231    __asm__ __volatile__ ("drdpq  %0, %1" : "=f" (f18) : "f" (f14));
232 }
233 
_test_dcffixq(void)234 static void _test_dcffixq (void)
235 {
236    __asm__ __volatile__ ("dcffixq  %0, %1" : "=f" (f18) : "f" (f14));
237 }
238 
239 typedef void (*test_func_t)();
240 typedef void (*test_func_main_t)(int);
241 typedef void (*test_func_shift_t)(int);
242 typedef struct test_table
243 {
244    test_func_main_t test_category;
245    char * name;
246 } test_table_t;
247 
248 static unsigned long long dfp128_vals[] = {
249                                            // Some finite numbers
250                                            0x2207c00000000000ULL, 0x0000000000000e50ULL,
251                                            0x2f07c00000000000ULL, 0x000000000014c000ULL,  //large number
252                                            0xa207c00000000000ULL, 0x00000000000000e0ULL,
253                                            0x2206c00000000000ULL, 0x00000000000000cfULL,
254                                            0xa205c00000000000ULL, 0x000000010a395bcfULL,
255                                            0x6209400000fd0000ULL, 0x00253f1f534acdd4ULL, // a small number
256                                            0x000400000089b000ULL, 0x0a6000d000000049ULL, // very small number
257                                            // flavors of zero
258                                            0x2208000000000000ULL, 0x0000000000000000ULL,
259                                            0xa208000000000000ULL, 0x0000000000000000ULL, // negative
260                                            0xa248000000000000ULL, 0x0000000000000000ULL,
261                                            // flavors of NAN
262                                            0x7c00000000000000ULL, 0x0000000000000000ULL, // quiet
263                                            0xfc00000000000000ULL, 0xc00100035b007700ULL,
264                                            0x7e00000000000000ULL, 0xfe000000d0e0a0d0ULL, // signaling
265                                            // flavors of Infinity
266                                            0x7800000000000000ULL, 0x0000000000000000ULL,
267                                            0xf800000000000000ULL, 0x0000000000000000ULL, // negative
268                                            0xf900000000000000ULL, 0x0000000000000000ULL
269 };
270 
271 static unsigned long long int64_vals[] = {
272                                           // I64 values
273                                           0x0ULL,                // zero
274                                           0x1ULL,                // one
275                                           0xffffffffffffffffULL, // minus one
276                                           0x2386f26fc0ffffULL,   // 9999999999999999
277                                           0xffdc790d903f0001ULL, // -9999999999999999
278                                           0x462d53c8abac0ULL,    // 1234567890124567
279                                           0xfffb9d2ac3754540ULL, // -1234567890124567
280 };
281 
282 static unsigned long long dfp64_vals[] = {
283                                           // various finite numbers
284                                           0x2234000000000e50ULL,
285                                           0x223400000014c000ULL,
286                                           0xa2340000000000e0ULL,// negative
287                                           0x22240000000000cfULL,
288                                           0xa21400010a395bcfULL,// negative
289                                           0x6e4d3f1f534acdd4ULL,// large number
290                                           0x000400000089b000ULL,// very small number
291                                           // flavors of zero
292                                           0x2238000000000000ULL,
293                                           0xa238000000000000ULL,
294                                           0x4248000000000000ULL,
295                                           // flavors of NAN
296                                           0x7e34000000000111ULL,
297                                           0xfe000000d0e0a0d0ULL,//signaling
298                                           0xfc00000000000000ULL,//quiet
299                                           // flavors of Infinity
300                                           0x7800000000000000ULL,
301                                           0xf800000000000000ULL,//negative
302                                           0x7a34000000000000ULL,
303 };
304 
305 
306 typedef struct dfp_test_args {
307    int fra_idx;
308    int frb_idx;
309 } dfp_test_args_t;
310 
311 
312 /* Index pairs from dfp64_vals or dfp128_vals array to be used with
313  * dfp_two_arg_tests */
314 static dfp_test_args_t int64_args_x1[] = {
315   /*                        {int64 input val, unused } */
316                                           {0, 0},
317                                           {1, 0},
318                                           {2, 0},
319                                           {3, 0},
320                                           {4, 0},
321                                           {5, 0},
322                                           {6, 0},
323 };
324 
325 static dfp_test_args_t dfp_2args_x1[] = {
326   /*                               {dfp_arg, shift_arg} */
327                                          {0, SH_0},
328                                          {0, SH_1},
329                                          {0, SH_2},
330                                          {0, SH_3},
331                                          {5, SH_0},
332                                          {5, SH_1},
333                                          {5, SH_2},
334                                          {5, SH_3},
335                                          {6, SH_0},
336                                          {6, SH_1},
337                                          {6, SH_2},
338                                          {6, SH_3},
339                                          {7, SH_0},
340                                          {7, SH_1},
341                                          {7, SH_2},
342                                          {7, SH_3},
343                                          {10, SH_0},
344                                          {10, SH_1},
345                                          {10, SH_2},
346                                          {10, SH_3},
347                                          {13, SH_0},
348                                          {13, SH_1},
349                                          {13, SH_2},
350                                          {13, SH_3},
351 };
352 
353 /* Index pairs from dfp64_vals array to be used with dfp_one_arg_tests */
354 static dfp_test_args_t dfp_1args_x1[] = {
355   /*                               {dfp_arg, unused} */
356                                          {0, 0},
357                                          {1, 0},
358                                          {2, 0},
359                                          {3, 0},
360                                          {4, 0},
361                                          {5, 0},
362                                          {6, 0},
363                                          {7, 0},
364                                          {8, 0},
365                                          {9, 0},
366                                          {10, 0},
367                                          {11, 0},
368                                          {12, 0},
369                                          {13, 0},
370                                          {14, 0},
371 };
372 
373 typedef enum {
374    LONG_TEST,
375    QUAD_TEST
376 } precision_type_t;
377 
378 typedef struct dfp_test
379 {
380    test_func_t test_func;
381    const char * name;
382    dfp_test_args_t * targs;
383    int num_tests;
384    precision_type_t precision;
385    const char * op;
386    Bool cr_supported;
387 } dfp_test_t;
388 
389 /* The dcffix and dcffixq tests are a little different in that they both take
390  * an I64 input.
391  */
392 static dfp_test_t
393 dfp_dcffix_dcffixq_tests[] = {
394                               { &_test_dcffixq,"dcffixq", int64_args_x1, 7, QUAD_TEST, "I64S->D128", True},
395                               /* Power 7 instruction */
396                               { &_test_dcffix, "dcffix",  int64_args_x1, 7, LONG_TEST, "I64S->D64", True},
397                               { NULL, NULL, NULL, 0, 0, NULL}
398 };
399 
400 static dfp_test_t
401 dfp_one_arg_tests[] = {
402                        { &_test_dctdp,  "dctdp",   dfp_1args_x1, 15, LONG_TEST, "D32->D64", True},
403                        { &_test_drsp,   "drsp",    dfp_1args_x1, 15, LONG_TEST, "D64->D32", True},
404                        { &_test_dctfix, "dctfix",  dfp_1args_x1, 15, LONG_TEST, "D64->I64S", True},
405                        { &_test_dctqpq, "dctqpq",  dfp_1args_x1, 15, QUAD_TEST, "D64->D128", True},
406                        { &_test_dctfixq,"dctfixq", dfp_1args_x1, 15, QUAD_TEST, "D128->I64S", True},
407                        { &_test_drdpq,  "drdpq",   dfp_1args_x1, 15, QUAD_TEST, "D128->D64", True},
408                        { NULL, NULL, NULL, 0, 0, NULL}
409 };
410 
411 
412 static dfp_test_t
413 dfp_two_arg_tests[] = {
414                        { &_test_dscri,  "dscri",   dfp_2args_x1, 20, LONG_TEST, ">>", True},
415                        { &_test_dscli,  "dscli",   dfp_2args_x1, 20, LONG_TEST, "<<", True},
416                        { &_test_dscriq, "dscriq",  dfp_2args_x1, 20, QUAD_TEST, ">>", True},
417                        { &_test_dscliq, "dscliq",  dfp_2args_x1, 20, QUAD_TEST, "<<", True},
418                        { NULL, NULL, NULL, 0, 0, NULL}
419 };
420 
set_rounding_mode(unsigned long long rnd_mode)421 void set_rounding_mode(unsigned long long rnd_mode)
422 {
423    double fpscr;
424    unsigned long long * hex_fpscr = (unsigned long long *)&fpscr;
425 
426    *hex_fpscr = 0ULL;
427    __asm__ __volatile__ ("mffs %0"  : "=f"(f14));
428    fpscr = f14;
429    *hex_fpscr &= 0xFFFFFFF0FFFFFFFFULL;
430    *hex_fpscr |= (rnd_mode << 32);
431    f14 = fpscr;
432    SET_FPSCR_DRN;
433 }
434 
test_dfp_one_arg_ops(int unused)435 static void test_dfp_one_arg_ops(int unused)
436 {
437    test_func_t func;
438    unsigned long long u0, u0x;
439    double res, d0, *d0p;
440    double d0x, *d0xp;
441    unsigned long round_mode;
442    int k = 0;
443 
444    u0x = 0;
445    d0p = &d0;
446    d0xp = &d0x;
447 
448    while ((func = dfp_one_arg_tests[k].test_func)) {
449       int i;
450 
451       for (round_mode = 0; round_mode < NUM_RND_MODES; round_mode++) {
452          /* Do each test with each of the possible rounding modes */
453          dfp_test_t test_group = dfp_one_arg_tests[k];
454 
455          printf("\ntest with rounding mode %lu \n", round_mode);
456          /* The set_rounding_mode() uses the global value f14. Call the
457           * function before setting up the test for the specific instruction
458           * to avoid avoid conflicts using f14.
459           */
460          set_rounding_mode(round_mode);
461 
462          for (i = 0; i < test_group.num_tests; i++) {
463 
464             if (test_group.precision == LONG_TEST) {
465                u0 = dfp64_vals[test_group.targs[i].fra_idx];
466             } else {
467                u0 = dfp128_vals[test_group.targs[i].fra_idx * 2];
468                u0x = dfp128_vals[(test_group.targs[i].fra_idx * 2) + 1];
469             }
470 
471             *(unsigned long long *)d0p = u0;
472             f14 = d0;
473             if (test_group.precision == QUAD_TEST) {
474 	       *(unsigned long long *)d0xp = u0x;
475                 f15 = d0x;
476             }
477 
478             (*func)();
479             res = f18;
480 
481             printf("%s %016llx", test_group.name, u0);
482 
483             if (test_group.precision == LONG_TEST) {
484                printf(" %s  => %016llx",
485                       test_group.op, *((unsigned long long *)(&res)));
486             } else {
487                double resx = f19;
488                printf(" %016llx %s ==> %016llx %016llx",
489                       u0x, test_group.op,
490                       *((unsigned long long *)(&res)),
491                       *((unsigned long long *)(&resx)));
492             }
493             printf("\n");
494          }
495       }
496 
497       k++;
498       printf( "\n" );
499    }
500 }
501 
test_dfp_two_arg_ops(int unused)502 static void test_dfp_two_arg_ops(int unused)
503 /* Shift instructions: first argument is the DFP source, second argument
504  * is 6 bit shift amount.
505  */
506 {
507    test_func_shift_t func;
508    unsigned long long u0, u0x;
509    unsigned int shift_by;
510    double res, d0, *d0p;
511    double d0x, *d0xp;
512    unsigned long round_mode;
513    int k = 0;
514 
515    u0x = 0;
516    d0p = &d0;
517    d0xp = &d0x;
518 
519    while ((func = dfp_two_arg_tests[k].test_func)) {
520       int i;
521 
522       for (round_mode = 0; round_mode < NUM_RND_MODES; round_mode++) {
523          /* Do each test with each of the possible rounding modes */
524          dfp_test_t test_group = dfp_two_arg_tests[k];
525 
526          printf("\ntest with rounding mode %lu \n", round_mode);
527 
528          /* The set_rounding_mode() uses the global value f14. Call the
529           * function before setting up the test for the specific instruction
530           * to avoid avoid conflicts using f14.
531           */
532          set_rounding_mode(round_mode);
533 
534          for (i = 0; i < test_group.num_tests; i++) {
535 
536             shift_by = test_group.targs[i].frb_idx;
537 
538             if (test_group.precision == LONG_TEST) {
539                u0 = dfp64_vals[test_group.targs[i].fra_idx];
540             } else {
541                u0 = dfp128_vals[test_group.targs[i].fra_idx * 2];
542                u0x = dfp128_vals[(test_group.targs[i].fra_idx * 2) + 1];
543             }
544 
545             *(unsigned long long *)d0p = u0;
546             f14 = d0;
547             if (test_group.precision == QUAD_TEST) {
548                *(unsigned long long *)d0xp = u0x;
549                f15 = d0x;
550             }
551 
552             (*func)(shift_by);
553             res = f18;
554 
555             printf("%s %016llx", test_group.name, u0);
556 
557             if (test_group.precision) {
558                printf(" %s %-3d => %016llx",
559                       test_group.op, shift_by, *((unsigned long long *)(&res)));
560             } else {
561                double resx = f19;
562                printf(" %016llx %s %-3d  ==> %016llx %016llx",
563                       u0x, test_group.op, shift_by,
564                       *((unsigned long long *)(&res)),
565                       *((unsigned long long *)(&resx)));
566             }
567             printf("\n" );
568          }
569       }
570 
571       k++;
572       printf( "\n" );
573    }
574 }
575 
test_dcffix_dcffixq(int has_vsx)576 static void test_dcffix_dcffixq(int has_vsx)
577 {
578    test_func_t func;
579    unsigned long long u0;
580    double res, d0, *d0p;
581    int k = 0, round_mode;
582 
583    d0p = &d0;
584 
585 
586    while ((func = dfp_dcffix_dcffixq_tests[k].test_func)) {
587       int i;
588 
589       if ((!has_vsx) && (!strcmp("dcffix", dfp_dcffix_dcffixq_tests[k].name))) {
590          k++;
591          /* The test instruction is dcffix it is supported on POWER 7
592           * and newer processors.  Skip if not POWER 7 or newer.
593           */
594          continue;
595       }
596 
597       for (round_mode = 0; round_mode < NUM_RND_MODES; round_mode++) {
598          /* Do each test with each of the possible rounding modes */
599          dfp_test_t test_group = dfp_dcffix_dcffixq_tests[k];
600 
601          printf("\ntest with rounding mode %u \n", round_mode);
602 
603          /* The set_rounding_mode() uses the global value f14. Call the
604           * function before setting up the test for the specific instruction
605           * to avoid avoid conflicts using f14.
606           */
607          set_rounding_mode(round_mode);
608 
609          for (i = 0; i < test_group.num_tests; i++) {
610 
611             /* The instructions take I64 inputs */
612             u0 = int64_vals[test_group.targs[i].fra_idx];
613 
614             *(unsigned long long *)d0p = u0;
615             f14 = d0;
616 
617             (*func)();
618             res = f18;
619 
620             printf("%s %016llx", test_group.name, u0);
621 
622             if (test_group.precision) {
623                printf(" %s  => %016llx",
624                       test_group.op, *((unsigned long long *)(&res)));
625             } else {
626                double resx = f19;
627                printf(" %s ==> %016llx %016llx",
628                       test_group.op,
629                       *((unsigned long long *)(&res)),
630                       *((unsigned long long *)(&resx)));
631             }
632             printf("\n" );
633          }
634       }
635 
636       k++;
637       printf( "\n" );
638    }
639 }
640 
641 static test_table_t
642 all_tests[] =
643 {
644    { &test_dfp_one_arg_ops,
645    "Test DFP fomat conversion instructions" },
646    { &test_dfp_two_arg_ops,
647    "Test DFP shift instructions" },
648    { test_dcffix_dcffixq,
649    "Test DCFFIX and DCFFIXQ instructions" },
650    { NULL, NULL }
651 };
652 #endif // HAS_DFP
653 
main(int argc,char ** argv,char ** envp)654 int main(int argc, char ** argv, char ** envp) {
655 #if defined(HAS_DFP)
656    test_table_t aTest;
657    test_func_t func;
658    int i = 0, has_vsx;
659 
660    /* If the processor has the VSX functionality then it is POWER 7
661     * or newer.
662     */
663    my_envp = envp;
664    has_vsx = get_vsx();
665 
666    while ((func = all_tests[i].test_category)) {
667       aTest = all_tests[i];
668       printf( "%s\n", aTest.name );
669       (*func)(has_vsx);
670       i++;
671    }
672 
673 #endif // HAS_DFP
674    return 0;
675 }
676