Home | History | Annotate | Download | only in ppc32
      1 /*  Copyright (C) 2012 IBM
      2 
      3  Author: Maynard Johnson <maynardj (at) 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 register double f14 __asm__ ("fr14");
     30 register double f15 __asm__ ("fr15");
     31 register double f16 __asm__ ("fr16");
     32 register double f17 __asm__ ("fr17");
     33 register double f18 __asm__ ("fr18");
     34 register double f19 __asm__ ("fr19");
     35 
     36 
     37 typedef unsigned char Bool;
     38 #define True 1
     39 #define False 0
     40 
     41 
     42 #define ALLCR "cr0","cr1","cr2","cr3","cr4","cr5","cr6","cr7"
     43 
     44 #define SET_CR(_arg) \
     45       __asm__ __volatile__ ("mtcr  %0" : : "b"(_arg) : ALLCR );
     46 
     47 #define SET_XER(_arg) \
     48       __asm__ __volatile__ ("mtxer %0" : : "b"(_arg) : "xer" );
     49 
     50 #define GET_CR(_lval) \
     51       __asm__ __volatile__ ("mfcr %0"  : "=b"(_lval) )
     52 
     53 #define GET_XER(_lval) \
     54       __asm__ __volatile__ ("mfxer %0" : "=b"(_lval) )
     55 
     56 #define GET_CR_XER(_lval_cr,_lval_xer) \
     57    do { GET_CR(_lval_cr); GET_XER(_lval_xer); } while (0)
     58 
     59 #define SET_CR_ZERO \
     60       SET_CR(0)
     61 
     62 #define SET_XER_ZERO \
     63       SET_XER(0)
     64 
     65 #define SET_CR_XER_ZERO \
     66    do { SET_CR_ZERO; SET_XER_ZERO; } while (0)
     67 
     68 #define SET_FPSCR_ZERO \
     69    do { double _d = 0.0; \
     70         __asm__ __volatile__ ("mtfsf 0xFF, %0" : : "f"(_d) ); \
     71    } while (0)
     72 
     73 #define GET_FPSCR(_arg) \
     74     __asm__ __volatile__ ("mffs %0"  : "=f"(_arg) )
     75 
     76 #define SET_FPSCR_DRN \
     77     __asm__ __volatile__ ("mtfsf  1, %0, 0, 1" :  : "f"(f14) )
     78 
     79 
     80 // The assembly-level instructions being tested
     81 static Bool do_dot;
     82 static void _test_dadd (void)
     83 {
     84    if (do_dot)
     85       __asm__ __volatile__ ("dadd. %0, %1, %2" : "=f" (f18) : "f" (f14),"f" (f16));
     86    else
     87       __asm__ __volatile__ ("dadd %0, %1, %2" : "=f" (f18) : "f" (f14),"f" (f16));
     88 }
     89 
     90 static void _test_dsub (void)
     91 {
     92    if (do_dot)
     93       __asm__ __volatile__ ("dsub. %0, %1, %2" : "=f" (f18) : "f" (f14),"f" (f16));
     94    else
     95       __asm__ __volatile__ ("dsub %0, %1, %2" : "=f" (f18) : "f" (f14),"f" (f16));
     96 }
     97 
     98 static void _test_dmul (void)
     99 {
    100    if (do_dot)
    101       __asm__ __volatile__ ("dmul. %0, %1, %2" : "=f" (f18) : "f" (f14),"f" (f16));
    102    else
    103       __asm__ __volatile__ ("dmul %0, %1, %2" : "=f" (f18) : "f" (f14),"f" (f16));
    104 }
    105 
    106 static void _test_ddiv (void)
    107 {
    108    if (do_dot)
    109       __asm__ __volatile__ ("ddiv. %0, %1, %2" : "=f" (f18) : "f" (f14),"f" (f16));
    110    else
    111       __asm__ __volatile__ ("ddiv %0, %1, %2" : "=f" (f18) : "f" (f14),"f" (f16));
    112 }
    113 
    114 // Quad DFP arith instructions
    115 static void _test_daddq (void)
    116 {
    117    if (do_dot)
    118       __asm__ __volatile__ ("daddq. %0, %1, %2" : "=f" (f18) : "f" (f14),"f" (f16));
    119    else
    120       __asm__ __volatile__ ("daddq %0, %1, %2" : "=f" (f18) : "f" (f14),"f" (f16));
    121 }
    122 
    123 static void _test_dsubq (void)
    124 {
    125    if (do_dot)
    126       __asm__ __volatile__ ("dsubq. %0, %1, %2" : "=f" (f18) : "f" (f14),"f" (f16));
    127    else
    128       __asm__ __volatile__ ("dsubq %0, %1, %2" : "=f" (f18) : "f" (f14),"f" (f16));
    129 }
    130 
    131 static void _test_dmulq (void)
    132 {
    133    if (do_dot)
    134       __asm__ __volatile__ ("dmulq. %0, %1, %2" : "=f" (f18) : "f" (f14),"f" (f16));
    135    else
    136       __asm__ __volatile__ ("dmulq %0, %1, %2" : "=f" (f18) : "f" (f14),"f" (f16));
    137 }
    138 
    139 static void _test_ddivq (void)
    140 {
    141    if (do_dot)
    142       __asm__ __volatile__ ("ddivq. %0, %1, %2" : "=f" (f18) : "f" (f14),"f" (f16));
    143    else
    144       __asm__ __volatile__ ("ddivq %0, %1, %2" : "=f" (f18) : "f" (f14),"f" (f16));
    145 }
    146 
    147 static void _test_mffs (void)
    148 {
    149    __asm__ __volatile__ ("mffs %0"  : "=f"(f14));
    150 }
    151 
    152 static void _test_mtfsf (int upper)
    153 {
    154    if (upper)
    155       __asm__ __volatile__ ("mtfsf  1, %0, 0, 1" :  : "f"(f14) );
    156    else
    157       __asm__ __volatile__ ("mtfsf  1, %0, 0, 0" :  : "f"(f14) );
    158 }
    159 
    160 typedef void (*test_func_t)(void);
    161 typedef struct test_table
    162 {
    163    test_func_t test_category;
    164    char * name;
    165 } test_table_t;
    166 
    167 /*
    168  *  345.0DD (0x2207c00000000000 0xe50)
    169  *  1.2300e+5DD (0x2207c00000000000 0x14c000)
    170  *  -16.0DD (0xa207c00000000000 0xe0)
    171  *  0.00189DD (0x2206c00000000000 0xcf)
    172  *  -4.1235DD (0xa205c00000000000 0x10a395bcf)
    173  *  9.8399e+20DD (0x2209400000000000 0x253f1f534acdd4)
    174  *  0DD (0x2208000000000000 0x0)
    175  *  0DD (0x2208000000000000 0x0)
    176  *  infDD (0x7800000000000000 0x0)
    177  *  nanDD (0x7c00000000000000 0x0
    178  */
    179 static unsigned long long dfp128_vals[] = {
    180                                     // Some finite numbers
    181                                     0x2207c00000000000ULL, 0x0000000000000e50ULL,
    182                                     0x2207c00000000000ULL, 0x000000000014c000ULL,
    183                                     0xa207c00000000000ULL, 0x00000000000000e0ULL,
    184                                     0x2206c00000000000ULL, 0x00000000000000cfULL,
    185                                     0xa205c00000000000ULL, 0x000000010a395bcfULL,
    186                                     0x6209400000fd0000ULL, 0x00253f1f534acdd4ULL, // huge number
    187                                     0x000400000089b000ULL, 0x0a6000d000000049ULL, // very small number
    188                                     // flavors of zero
    189                                     0x2208000000000000ULL, 0x0000000000000000ULL,
    190                                     0xa208000000000000ULL, 0x0000000000000000ULL, // negative
    191                                     0xa248000000000000ULL, 0x0000000000000000ULL,
    192                                     // flavors of NAN
    193                                     0x7c00000000000000ULL, 0x0000000000000000ULL, // quiet
    194                                     0xfc00000000000000ULL, 0xc00100035b007700ULL,
    195                                     0x7e00000000000000ULL, 0xfe000000d0e0a0d0ULL, // signaling
    196                                     // flavors of Infinity
    197                                     0x7800000000000000ULL, 0x0000000000000000ULL,
    198                                     0xf800000000000000ULL, 0x0000000000000000ULL, // negative
    199                                     0xf900000000000000ULL, 0x0000000000000000ULL
    200 };
    201 
    202 static unsigned long long dfp64_vals[] = {
    203                                  // various finite numbers
    204                                  0x2234000000000e50ULL,
    205                                  0x223400000014c000ULL,
    206                                  0xa2340000000000e0ULL,// negative
    207                                  0x22240000000000cfULL,
    208                                  0xa21400010a395bcfULL,// negative
    209                                  0x6e4d3f1f534acdd4ULL,// huge number
    210                                  0x000400000089b000ULL,// very small number
    211                                  // flavors of zero
    212                                  0x2238000000000000ULL,
    213                                  0xa238000000000000ULL,
    214                                  0x4248000000000000ULL,
    215                                  // flavors of NAN
    216                                  0x7e34000000000111ULL,
    217                                  0xfe000000d0e0a0d0ULL,//signaling
    218                                  0xfc00000000000000ULL,//quiet
    219                                  // flavors of Infinity
    220                                  0x7800000000000000ULL,
    221                                  0xf800000000000000ULL,//negative
    222                                  0x7a34000000000000ULL,
    223 };
    224 
    225 
    226 typedef struct dfp_test_args {
    227    int fra_idx;
    228    int frb_idx;
    229 } dfp_test_args_t;
    230 
    231 
    232 // Index pairs from dfp64_vals or dfp128_vals array to be used with dfp_two_arg_tests
    233 static dfp_test_args_t dfp_2args_x2[] = {
    234                                   {0, 1},
    235                                   {2, 1},
    236                                   {3, 4},
    237                                   {0, 6},
    238                                   {2, 4},
    239                                   {5, 1},
    240                                   {5, 2},
    241                                   {7, 8},
    242                                   {7, 1},
    243                                   {9, 15},
    244                                   {8, 12},
    245                                   {7, 11},
    246                                   {13, 2},
    247                                   {13, 14},
    248                                   {15, 12},
    249                                   {14, 11},
    250                                   {12, 12},
    251                                   {12, 11},
    252                                   {11, 11}
    253 };
    254 
    255 // Index pairs from dfp64_vals array to be used with dfp_two_arg_tests
    256 static dfp_test_args_t dfp_2args_x1[] = {
    257                                     {0, 1},
    258                                     {2, 1},
    259                                     {3, 4},
    260                                     {0, 6},
    261                                     {2, 4},
    262                                     {5, 1},
    263                                     {5, 2},
    264                                     {7, 1},
    265                                     {7, 2},
    266                                     {8, 0},
    267                                     {8, 1},
    268                                     {8, 2},
    269                                     {7, 8},
    270                                     {12, 14},
    271                                     {12, 1},
    272                                     {12, 13},
    273                                     {12, 12},
    274                                     {12, 11},
    275                                     {11, 14},
    276                                     {11, 0},
    277                                     {11, 13},
    278                                     {11, 11},
    279                                     {14, 14},
    280                                     {14, 3},
    281                                     {14, 15},
    282 };
    283 
    284 typedef enum {
    285    LONG_TEST,
    286    QUAD_TEST
    287 } precision_type_t;
    288 
    289 typedef struct dfp_test
    290 {
    291    test_func_t test_func;
    292    const char * name;
    293    dfp_test_args_t * targs;
    294    int num_tests;
    295    precision_type_t precision;
    296    const char * op;
    297    Bool cr_supported;
    298 } dfp_test_t;
    299 
    300 
    301 static dfp_test_t
    302 dfp_two_arg_tests[] = {
    303                      { &_test_dadd, "dadd", dfp_2args_x1, 25, LONG_TEST, "+", False},
    304                      { &_test_dsub, "dsub", dfp_2args_x1, 25, LONG_TEST, "-", False},
    305                      { &_test_dmul, "dmul", dfp_2args_x2, 19, LONG_TEST, "*", False},
    306                      { &_test_ddiv, "ddiv", dfp_2args_x2, 19, LONG_TEST, "/", False},
    307                      { &_test_daddq, "daddq", dfp_2args_x1, 25, QUAD_TEST, "+", False},
    308                      { &_test_dsubq, "dsubq", dfp_2args_x1, 25, QUAD_TEST, "-", False},
    309                      { &_test_dmulq, "dmulq", dfp_2args_x2, 19, QUAD_TEST, "*", False},
    310                      { &_test_ddivq, "ddivq", dfp_2args_x2, 19, QUAD_TEST, "/", False},
    311                      { NULL, NULL, NULL, 0, 0, NULL}
    312 };
    313 
    314 static void test_dfp_two_arg_ops(void)
    315 {
    316    test_func_t func;
    317    unsigned long long u0, u0x, u1, u1x;
    318    double res, d0, d1, *d0p, *d1p;
    319    double d0x, d1x, *d0xp, *d1xp;
    320    int k = 0;
    321    u0x = u1x = 0;
    322    d0p = &d0;
    323    d0xp = &d0x;
    324    d1p = &d1;
    325    d1xp = &d1x;
    326 
    327    while ((func = dfp_two_arg_tests[k].test_func)) {
    328       int i, repeat = 1;
    329       dfp_test_t test_group = dfp_two_arg_tests[k];
    330       do_dot = False;
    331 
    332 again:
    333       for (i = 0; i < test_group.num_tests; i++) {
    334          unsigned int condreg;
    335          unsigned int flags;
    336 
    337          if (test_group.precision == LONG_TEST) {
    338             u0 = dfp64_vals[test_group.targs[i].fra_idx];
    339             u1 = dfp64_vals[test_group.targs[i].frb_idx];
    340          } else {
    341             u0 = dfp128_vals[test_group.targs[i].fra_idx * 2];
    342             u0x = dfp128_vals[(test_group.targs[i].fra_idx * 2) + 1];
    343             u1 = dfp128_vals[test_group.targs[i].frb_idx * 2];
    344             u1x = dfp128_vals[(test_group.targs[i].frb_idx * 2) + 1];
    345          }
    346          *(unsigned long long *)d0p = u0;
    347          *(unsigned long long *)d1p = u1;
    348          f14 = d0;
    349          f16 = d1;
    350          if (test_group.precision == QUAD_TEST) {
    351             *(unsigned long long *)d0xp = u0x;
    352             *(unsigned long long *)d1xp = u1x;
    353             f15 = d0x;
    354             f17 = d1x;
    355          }
    356 
    357          SET_FPSCR_ZERO;
    358          SET_CR_XER_ZERO;
    359          (*func)();
    360          GET_CR(flags);
    361          res = f18;
    362 
    363          condreg = (flags & 0x000000f0) >> 4;
    364          printf("%s%s %016llx", test_group.name, do_dot? "." : "", u0);
    365          if (test_group.precision == LONG_TEST) {
    366             printf(" %s %016llx => %016llx",
    367                    test_group.op, u1, *((unsigned long long *)(&res)));
    368          } else {
    369             double resx = f19;
    370             printf(" %016llx %s %016llx %016llx ==> %016llx %016llx",
    371                    u0x, test_group.op, u1, u1x,
    372                    *((unsigned long long *)(&res)), *((unsigned long long *)(&resx)));
    373          }
    374          if (test_group.cr_supported)
    375             printf(" (cr = %08x)\n", condreg);
    376          else
    377             printf("\n");
    378 
    379       }
    380       printf("\n");
    381       if (repeat) {
    382          repeat = 0;
    383          do_dot = True;
    384          goto again;
    385       }
    386       k++;
    387       printf( "\n" );
    388    }
    389 }
    390 
    391 void test_move_toFrom_fpscr(void)
    392 {
    393 #define BFP_MAX_RM 3
    394    int shift = 0;
    395    unsigned long long i, max_rm, expected_val;
    396    double fpscr_in, fpscr_out;
    397    unsigned long long * hex_fpscr_in = (unsigned long long *)&fpscr_in;
    398    unsigned long long * hex_fpscr_out = (unsigned long long *)&fpscr_out;
    399 
    400 
    401    max_rm = 4;
    402 again:
    403    /* NOTE: The first time through this loop is for setting the binary
    404     * floating point rounding mode (bits 62:63 of FPSCR).  The second time
    405     * through is for setting the decimal floating point rounding mode
    406     * (bits 29:31 of FPSCR).  In the second time through this loop, the value
    407     * returned should include the final binary FP rounding mode, along with
    408     * the decimal FP rounding modes.
    409     */
    410    for (i = 0; i < max_rm; i++) {
    411       *hex_fpscr_in = (i << shift);
    412       f14 = fpscr_in;
    413       _test_mtfsf(max_rm/8);
    414       *hex_fpscr_in = 0ULL;
    415       f14= fpscr_in;
    416       _test_mffs();
    417       fpscr_out = f14;
    418       if (max_rm == 4) {
    419          *hex_fpscr_out &= (max_rm - 1) << shift;
    420          expected_val = i << shift;
    421       } else {
    422          *hex_fpscr_out &= BFP_MAX_RM | ((max_rm - 1) << shift);
    423          expected_val = (i << shift) | BFP_MAX_RM;
    424       }
    425 
    426       printf("FPSCR %s floating point rounding mode %016llx == %016llx? %s\n",
    427              (max_rm == 8) ? "decimal" : "binary",
    428              *hex_fpscr_out, expected_val,
    429              (expected_val == *hex_fpscr_out) ? "yes" : "no");
    430    }
    431    if (max_rm == 4) {
    432       max_rm = 8;
    433       shift = 32;
    434       goto again;
    435    }
    436 }
    437 
    438 void test_rounding_modes(void)
    439 {
    440    int j;
    441    unsigned long long u0, u1, rm_idx;
    442    double res, d0, d1, *d0p, *d1p, fpscr;
    443    unsigned long long * hex_fpscr = (unsigned long long *)&fpscr;
    444    u0 = 0x26cc3f1f534acdd4ULL;
    445    u1 = 0x27feff197a42ba06ULL;
    446    d0p = &d0;
    447    d1p = &d1;
    448 
    449    for (j = 0; j < 12; j++) {
    450       for (rm_idx = 0; rm_idx < 8; rm_idx++) {
    451          *hex_fpscr = 0ULL;
    452          __asm__ __volatile__ ("mffs %0"  : "=f"(f14));
    453          fpscr = f14;
    454          *hex_fpscr &= 0xFFFFFFF0FFFFFFFFULL;
    455          *hex_fpscr |= (rm_idx << 32);
    456          f14 = fpscr;
    457          SET_FPSCR_DRN;
    458          *(unsigned long long *)d0p = u0;
    459          *(unsigned long long *)d1p = u1;
    460          f14 = d0;
    461          f16 = d1;
    462          _test_dmul();
    463          res = f18;
    464          printf("test #%d: dmul with rounding mode %d: %016llx * %016llx => %016llx\n",
    465                 j, (int)rm_idx, u0, u1, *((unsigned long long *)(&res)));
    466          printf("\n");
    467       }
    468       // Changing the least significant bit of one of the dmul arguments give us more
    469       // opportunities for different rounding modes to yield different results which
    470       // can then be validated.
    471       u0++;
    472    }
    473 }
    474 
    475 static test_table_t
    476          all_tests[] =
    477 {
    478                     { &test_dfp_two_arg_ops,
    479                       "Test DFP arithmetic instructions"},
    480                     { &test_rounding_modes,
    481                       "Test DFP rounding modes"},
    482                     { &test_move_toFrom_fpscr,
    483                     "Test move to/from FPSCR"},
    484                     { NULL, NULL }
    485 };
    486 #endif // HAS_DFP
    487 
    488 int main() {
    489 #if defined(HAS_DFP)
    490 
    491    test_table_t aTest;
    492    test_func_t func;
    493    int i = 0;
    494 
    495    while ((func = all_tests[i].test_category)) {
    496       aTest = all_tests[i];
    497       printf( "%s\n", aTest.name );
    498       (*func)();
    499       i++;
    500    }
    501 
    502 #endif // HAS_DFP
    503    return 0;
    504 }
    505