/* Copyright (C) 2011 IBM Author: Maynard Johnson This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see . The GNU General Public License is contained in the file COPYING. */ #include #include #include #include #include #ifdef HAS_VSX #include #ifndef __powerpc64__ typedef uint32_t HWord_t; #else typedef uint64_t HWord_t; #endif /* __powerpc64__ */ #ifdef VGP_ppc64le_linux #define isLE 1 #else #define isLE 0 #endif register HWord_t r14 __asm__ ("r14"); register HWord_t r15 __asm__ ("r15"); register HWord_t r16 __asm__ ("r16"); register HWord_t r17 __asm__ ("r17"); register double f14 __asm__ ("fr14"); register double f15 __asm__ ("fr15"); register double f16 __asm__ ("fr16"); register double f17 __asm__ ("fr17"); static volatile unsigned int cond_reg; #define ALLCR "cr0","cr1","cr2","cr3","cr4","cr5","cr6","cr7" #define SET_CR(_arg) \ __asm__ __volatile__ ("mtcr %0" : : "b"(_arg) : ALLCR ); #define SET_XER(_arg) \ __asm__ __volatile__ ("mtxer %0" : : "b"(_arg) : "xer" ); #define GET_CR(_lval) \ __asm__ __volatile__ ("mfcr %0" : "=b"(_lval) ) #define GET_XER(_lval) \ __asm__ __volatile__ ("mfxer %0" : "=b"(_lval) ) #define GET_CR_XER(_lval_cr,_lval_xer) \ do { GET_CR(_lval_cr); GET_XER(_lval_xer); } while (0) #define SET_CR_ZERO \ SET_CR(0) #define SET_XER_ZERO \ SET_XER(0) #define SET_CR_XER_ZERO \ do { SET_CR_ZERO; SET_XER_ZERO; } while (0) #define SET_FPSCR_ZERO \ do { double _d = 0.0; \ __asm__ __volatile__ ("mtfsf 0xFF, %0" : : "f"(_d) ); \ } while (0) typedef void (*test_func_t)(void); typedef struct ldst_test ldst_test_t; typedef struct vsx_logic_test logic_test_t; typedef struct xs_conv_test xs_conv_test_t; typedef struct p7_fp_test fp_test_t; typedef struct vx_fp_test vx_fp_test_t; typedef struct vsx_move_test move_test_t; typedef struct vsx_permute_test permute_test_t; typedef struct test_table test_table_t; static double *fargs = NULL; static int nb_fargs; /* These functions below that construct a table of floating point * values were lifted from none/tests/ppc32/jm-insns.c. */ #if defined (DEBUG_ARGS_BUILD) #define AB_DPRINTF(fmt, args...) do { fprintf(stderr, fmt , ##args); } while (0) #else #define AB_DPRINTF(fmt, args...) do { } while (0) #endif static inline void register_farg (void *farg, int s, uint16_t _exp, uint64_t mant) { uint64_t tmp; tmp = ((uint64_t)s << 63) | ((uint64_t)_exp << 52) | mant; *(uint64_t *)farg = tmp; AB_DPRINTF("%d %03x %013llx => %016llx %0e\n", s, _exp, mant, *(uint64_t *)farg, *(double *)farg); } static void build_fargs_table(void) /* * Double precision: * Sign goes from zero to one (1 bit) * Exponent goes from 0 to ((1 << 12) - 1) (11 bits) * Mantissa goes from 1 to ((1 << 52) - 1) (52 bits) * + special values: * +0.0 : 0 0x000 0x0000000000000 => 0x0000000000000000 * -0.0 : 1 0x000 0x0000000000000 => 0x8000000000000000 * +infinity : 0 0x7FF 0x0000000000000 => 0x7FF0000000000000 * -infinity : 1 0x7FF 0x0000000000000 => 0xFFF0000000000000 * +QNaN : 0 0x7FF 0x8000000000000 => 0x7FF8000000000000 * -QNaN : 1 0x7FF 0x8000000000000 => 0xFFF8000000000000 * +SNaN : 0 0x7FF 0x7FFFFFFFFFFFF => 0x7FF7FFFFFFFFFFFF * -SNaN : 1 0x7FF 0x7FFFFFFFFFFFF => 0xFFF7FFFFFFFFFFFF * (8 values) * * Single precision * Sign: 1 bit * Exponent: 8 bits * Mantissa: 23 bits * +0.0 : 0 0x00 0x000000 => 0x00000000 * -0.0 : 1 0x00 0x000000 => 0x80000000 * +infinity : 0 0xFF 0x000000 => 0x7F800000 * -infinity : 1 0xFF 0x000000 => 0xFF800000 * +QNaN : 0 0xFF 0x400000 => 0x7FC00000 * -QNaN : 1 0xFF 0x400000 => 0xFFC00000 * +SNaN : 0 0xFF 0x3FFFFF => 0x7FBFFFFF * -SNaN : 1 0xFF 0x3FFFFF => 0xFFBFFFFF */ { uint64_t mant; uint16_t _exp, e1; int s; int i=0; if (nb_fargs) return; fargs = malloc( 16 * sizeof(double) ); for (s = 0; s < 2; s++) { for (e1 = 0x001;; e1 = ((e1 + 1) << 13) + 7) { if (e1 >= 0x400) e1 = 0x3fe; _exp = e1; for (mant = 0x0000000000001ULL; mant < (1ULL << 52); /* Add 'random' bits */ mant = ((mant + 0x4A6) << 29) + 0x359) { register_farg( &fargs[i++], s, _exp, mant ); } if (e1 == 0x3fe) break; } } // add a few smaller values to fargs . . . s = 0; _exp = 0x002; mant = 0x0000000000b01ULL; register_farg(&fargs[i++], s, _exp, mant); _exp = 0x000; mant = 0x00000203f0b3dULL; register_farg(&fargs[i++], s, _exp, mant); mant = 0x00000005a203dULL; register_farg(&fargs[i++], s, _exp, mant); s = 1; _exp = 0x002; mant = 0x0000000000b01ULL; register_farg(&fargs[i++], s, _exp, mant); _exp = 0x000; mant = 0x00000203f0b3dULL; register_farg(&fargs[i++], s, _exp, mant); nb_fargs = i; } typedef struct fp_test_args { int fra_idx; int frb_idx; int cr_flags; } fp_test_args_t; fp_test_args_t ftdiv_tests[] = { {0, 1, 0x8}, {9, 1, 0xa}, {1, 12, 0xa}, {0, 2, 0xa}, {1, 3, 0xa}, {3, 0, 0xa}, {0, 3, 0xa}, {4, 0, 0xa}, {7, 1, 0xe}, {8, 1, 0xe}, {1, 7, 0xe}, {0, 13, 0xe}, {5, 5, 0xe}, {5, 6, 0xe}, }; fp_test_args_t xscmpX_tests[] = { {8, 8, 0x2}, {8, 14, 0x8}, {8, 6, 0x8}, {8, 5, 0x8}, {8, 4, 0x8}, {8, 7, 0x8}, {8, 9, 0x1}, {8, 11, 0x1}, {14, 8, 0x4}, {14, 14, 0x2}, {14, 6, 0x8}, {14, 5, 0x8}, {14, 4, 0x8}, {14, 7, 0x8}, {14, 9, 0x1}, {14, 11, 0x1}, {6, 8, 0x4}, {6, 14, 0x4}, {6, 6, 0x2}, {6, 5, 0x2}, {6, 4, 0x8}, {6, 7, 0x8}, {6, 9, 0x1}, {6, 11, 0x1}, {5, 8, 0x4}, {5, 14, 0x4}, {5, 6, 0x2}, {5, 5, 0x2}, {5, 4, 0x8}, {5, 7, 0x8}, {5, 9, 0x1}, {5, 11, 0x1}, {4, 8, 0x4}, {4, 14, 0x4}, {4, 6, 0x4}, {4, 5, 0x4}, {4, 1, 0x8}, {4, 7, 0x8}, {4, 9, 0x1}, {4, 11, 0x1}, {7, 8, 0x4}, {7, 14, 0x4}, {7, 6, 0x4}, {7, 5, 0x4}, {7, 4, 0x4}, {7, 7, 0x2}, {7, 9, 0x1}, {7, 11, 0x1}, {10, 8, 0x1}, {10, 14, 0x1}, {10, 6, 0x1}, {10, 5, 0x1}, {10, 4, 0x1}, {10, 7, 0x1}, {10, 9, 0x1}, {10, 11, 0x1}, {12, 8, 0x1}, {12, 14, 0x1}, {12, 6, 0x1}, {12, 5, 0x1}, {12, 4, 0x1}, {12, 7, 0x1}, {12, 9, 0x1}, {12, 11, 0x1}, }; fp_test_args_t xsadddp_tests[] = { {8, 8, 0x0}, {8, 14, 0x0}, {8, 6, 0x0}, {8, 5, 0x0}, {8, 4, 0x0}, {8, 7, 0x0}, {8, 9, 0x0}, {8, 11, 0x0}, {14, 8, 0x0}, {14, 14, 0x0}, {14, 6, 0x0}, {14, 5, 0x0}, {14, 4, 0x0}, {14, 7, 0x0}, {14, 9, 0x0}, {14, 11, 0x0}, {6, 8, 0x0}, {6, 14, 0x0}, {6, 6, 0x0}, {6, 5, 0x0}, {6, 4, 0x0}, {6, 7, 0x0}, {6, 9, 0x0}, {6, 11, 0x0}, {5, 8, 0x0}, {5, 14, 0x0}, {5, 6, 0x0}, {5, 5, 0x0}, {5, 4, 0x0}, {5, 7, 0x0}, {5, 9, 0x0}, {5, 11, 0x0}, {4, 8, 0x0}, {4, 14, 0x0}, {4, 6, 0x0}, {4, 5, 0x0}, {4, 1, 0x0}, {4, 7, 0x0}, {4, 9, 0x0}, {4, 11, 0x0}, {7, 8, 0x0}, {7, 14, 0x0}, {7, 6, 0x0}, {7, 5, 0x0}, {7, 4, 0x0}, {7, 7, 0x0}, {7, 9, 0x0}, {7, 11, 0x0}, {10, 8, 0x0}, {10, 14, 0x0}, {10, 6, 0x0}, {10, 5, 0x0}, {10, 4, 0x0}, {10, 7, 0x0}, {10, 9, 0x0}, {10, 11, 0x0}, {12, 8, 0x0}, {12, 14, 0x0}, {12, 6, 0x0}, {12, 5, 0x0}, {12, 4, 0x0}, {12, 7, 0x0}, {12, 9, 0x0}, {12, 11, 0x0}, }; fp_test_args_t xsdivdp_tests[] = { {8, 8, 0x0}, {8, 14, 0x0}, {8, 6, 0x0}, {8, 5, 0x0}, {8, 4, 0x0}, {8, 7, 0x0}, {8, 9, 0x0}, {8, 11, 0x0}, {14, 8, 0x0}, {14, 14, 0x0}, {14, 6, 0x0}, {14, 5, 0x0}, {14, 4, 0x0}, {14, 7, 0x0}, {14, 9, 0x0}, {14, 11, 0x0}, {6, 8, 0x0}, {6, 14, 0x0}, {6, 6, 0x0}, {6, 5, 0x0}, {6, 4, 0x0}, {6, 7, 0x0}, {6, 9, 0x0}, {6, 11, 0x0}, {5, 8, 0x0}, {5, 14, 0x0}, {5, 6, 0x0}, {5, 5, 0x0}, {5, 4, 0x0}, {5, 7, 0x0}, {5, 9, 0x0}, {5, 11, 0x0}, {4, 8, 0x0}, {4, 14, 0x0}, {4, 6, 0x0}, {4, 5, 0x0}, {4, 1, 0x0}, {4, 7, 0x0}, {4, 9, 0x0}, {4, 11, 0x0}, {7, 8, 0x0}, {7, 14, 0x0}, {7, 6, 0x0}, {7, 5, 0x0}, {7, 4, 0x0}, {7, 7, 0x0}, {7, 9, 0x0}, {7, 11, 0x0}, {10, 8, 0x0}, {10, 14, 0x0}, {10, 6, 0x0}, {10, 5, 0x0}, {10, 4, 0x0}, {10, 7, 0x0}, {10, 9, 0x0}, {10, 11, 0x0}, {12, 8, 0x0}, {12, 14, 0x0}, {12, 6, 0x0}, {12, 5, 0x0}, {12, 4, 0x0}, {12, 7, 0x0}, {12, 9, 0x0}, {12, 11, 0x0}, }; fp_test_args_t xsmaddXdp_tests[] = { {8, 8, 0x0}, {8, 14, 0x0}, {8, 6, 0x0}, {8, 5, 0x0}, {8, 4, 0x0}, {8, 7, 0x0}, {8, 9, 0x0}, {8, 11, 0x0}, {14, 8, 0x0}, {14, 14, 0x0}, {14, 6, 0x0}, {14, 5, 0x0}, {14, 4, 0x0}, {14, 7, 0x0}, {14, 9, 0x0}, {14, 11, 0x0}, {6, 8, 0x0}, {6, 14, 0x0}, {6, 6, 0x0}, {6, 5, 0x0}, {6, 4, 0x0}, {6, 7, 0x0}, {6, 9, 0x0}, {6, 11, 0x0}, {5, 8, 0x0}, {5, 14, 0x0}, {5, 6, 0x0}, {5, 5, 0x0}, {5, 4, 0x0}, {5, 7, 0x0}, {5, 9, 0x0}, {5, 11, 0x0}, {4, 8, 0x0}, {4, 14, 0x0}, {4, 6, 0x0}, {4, 5, 0x0}, {4, 1, 0x0}, {4, 7, 0x0}, {4, 9, 0x0}, {4, 11, 0x0}, {7, 8, 0x0}, {7, 14, 0x0}, {7, 6, 0x0}, {7, 5, 0x0}, {7, 4, 0x0}, {7, 7, 0x0}, {7, 9, 0x0}, {7, 11, 0x0}, {10, 8, 0x0}, {10, 14, 0x0}, {10, 6, 0x0}, {10, 5, 0x0}, {10, 4, 0x0}, {10, 7, 0x0}, {10, 9, 0x0}, {10, 11, 0x0}, {12, 8, 0x0}, {12, 14, 0x0}, {12, 6, 0x0}, {12, 5, 0x0}, {12, 4, 0x0}, {12, 7, 0x0}, {12, 9, 0x0}, {12, 11, 0x0}, }; fp_test_args_t xsmsubXdp_tests[] = { {8, 8, 0x0}, {8, 14, 0x0}, {8, 6, 0x0}, {8, 5, 0x0}, {8, 4, 0x0}, {8, 7, 0x0}, {8, 9, 0x0}, {8, 11, 0x0}, {14, 8, 0x0}, {14, 14, 0x0}, {14, 6, 0x0}, {14, 5, 0x0}, {14, 4, 0x0}, {14, 7, 0x0}, {14, 9, 0x0}, {14, 11, 0x0}, {6, 8, 0x0}, {6, 14, 0x0}, {6, 6, 0x0}, {6, 5, 0x0}, {6, 4, 0x0}, {6, 7, 0x0}, {6, 9, 0x0}, {6, 11, 0x0}, {5, 8, 0x0}, {5, 14, 0x0}, {5, 6, 0x0}, {5, 5, 0x0}, {5, 4, 0x0}, {5, 7, 0x0}, {5, 9, 0x0}, {5, 11, 0x0}, {4, 8, 0x0}, {4, 14, 0x0}, {4, 6, 0x0}, {4, 5, 0x0}, {4, 1, 0x0}, {4, 7, 0x0}, {4, 9, 0x0}, {4, 11, 0x0}, {7, 8, 0x0}, {7, 14, 0x0}, {7, 6, 0x0}, {7, 5, 0x0}, {7, 4, 0x0}, {7, 7, 0x0}, {7, 9, 0x0}, {7, 11, 0x0}, {10, 8, 0x0}, {10, 14, 0x0}, {10, 6, 0x0}, {10, 5, 0x0}, {10, 4, 0x0}, {10, 7, 0x0}, {10, 9, 0x0}, {10, 11, 0x0}, {12, 8, 0x0}, {12, 14, 0x0}, {12, 6, 0x0}, {12, 5, 0x0}, {12, 4, 0x0}, {12, 7, 0x0}, {12, 9, 0x0}, {12, 11, 0x0}, }; fp_test_args_t xsnmaddXdp_tests[] = { {8, 8, 0x0}, {8, 14, 0x0}, {8, 6, 0x0}, {8, 5, 0x0}, {8, 4, 0x0}, {8, 7, 0x0}, {8, 9, 0x0}, {8, 11, 0x0}, {14, 8, 0x0}, {14, 14, 0x0}, {14, 6, 0x0}, {14, 5, 0x0}, {14, 4, 0x0}, {14, 7, 0x0}, {14, 9, 0x0}, {14, 11, 0x0}, {6, 8, 0x0}, {6, 14, 0x0}, {6, 6, 0x0}, {6, 5, 0x0}, {6, 4, 0x0}, {6, 7, 0x0}, {6, 9, 0x0}, {6, 11, 0x0}, {5, 8, 0x0}, {5, 14, 0x0}, {5, 6, 0x0}, {5, 5, 0x0}, {5, 4, 0x0}, {5, 7, 0x0}, {5, 9, 0x0}, {5, 11, 0x0}, {4, 8, 0x0}, {4, 14, 0x0}, {4, 6, 0x0}, {4, 5, 0x0}, {4, 1, 0x0}, {4, 7, 0x0}, {4, 9, 0x0}, {4, 11, 0x0}, {7, 8, 0x0}, {7, 14, 0x0}, {7, 6, 0x0}, {7, 5, 0x0}, {7, 4, 0x0}, {7, 7, 0x0}, {7, 9, 0x0}, {7, 11, 0x0}, {10, 8, 0x0}, {10, 14, 0x0}, {10, 6, 0x0}, {10, 5, 0x0}, {10, 4, 0x0}, {10, 7, 0x0}, {10, 9, 0x0}, {10, 11, 0x0}, {12, 8, 0x0}, {12, 14, 0x0}, {12, 6, 0x0}, {12, 5, 0x0}, {12, 4, 0x0}, {12, 7, 0x0}, {12, 9, 0x0}, {12, 11, 0x0}, }; fp_test_args_t xsmuldp_tests[] = { {8, 8, 0x0}, {8, 14, 0x0}, {8, 6, 0x0}, {8, 5, 0x0}, {8, 4, 0x0}, {8, 7, 0x0}, {8, 9, 0x0}, {8, 11, 0x0}, {14, 8, 0x0}, {14, 14, 0x0}, {14, 6, 0x0}, {14, 5, 0x0}, {14, 4, 0x0}, {14, 7, 0x0}, {14, 9, 0x0}, {14, 11, 0x0}, {6, 8, 0x0}, {6, 14, 0x0}, {6, 6, 0x0}, {6, 5, 0x0}, {6, 4, 0x0}, {6, 7, 0x0}, {6, 9, 0x0}, {6, 11, 0x0}, {5, 8, 0x0}, {5, 14, 0x0}, {5, 6, 0x0}, {5, 5, 0x0}, {5, 4, 0x0}, {5, 7, 0x0}, {5, 9, 0x0}, {5, 11, 0x0}, {4, 8, 0x0}, {4, 14, 0x0}, {4, 6, 0x0}, {4, 5, 0x0}, {4, 1, 0x0}, {4, 7, 0x0}, {4, 9, 0x0}, {4, 11, 0x0}, {7, 8, 0x0}, {7, 14, 0x0}, {7, 6, 0x0}, {7, 5, 0x0}, {7, 4, 0x0}, {7, 7, 0x0}, {7, 9, 0x0}, {7, 11, 0x0}, {10, 8, 0x0}, {10, 14, 0x0}, {10, 6, 0x0}, {10, 5, 0x0}, {10, 4, 0x0}, {10, 7, 0x0}, {10, 9, 0x0}, {10, 11, 0x0}, {12, 8, 0x0}, {12, 14, 0x0}, {12, 6, 0x0}, {12, 5, 0x0}, {12, 4, 0x0}, {12, 7, 0x0}, {12, 9, 0x0}, {12, 11, 0x0}, }; fp_test_args_t xssubdp_tests[] = { {8, 8, 0x0}, {8, 14, 0x0}, {8, 6, 0x0}, {8, 5, 0x0}, {8, 4, 0x0}, {8, 7, 0x0}, {8, 9, 0x0}, {8, 11, 0x0}, {14, 8, 0x0}, {14, 14, 0x0}, {14, 6, 0x0}, {14, 5, 0x0}, {14, 4, 0x0}, {14, 7, 0x0}, {14, 9, 0x0}, {14, 11, 0x0}, {6, 8, 0x0}, {6, 14, 0x0}, {6, 6, 0x0}, {6, 5, 0x0}, {6, 4, 0x0}, {6, 7, 0x0}, {6, 9, 0x0}, {6, 11, 0x0}, {5, 8, 0x0}, {5, 14, 0x0}, {5, 6, 0x0}, {5, 5, 0x0}, {5, 4, 0x0}, {5, 7, 0x0}, {5, 9, 0x0}, {5, 11, 0x0}, {4, 8, 0x0}, {4, 14, 0x0}, {4, 6, 0x0}, {4, 5, 0x0}, {4, 1, 0x0}, {4, 7, 0x0}, {4, 9, 0x0}, {4, 11, 0x0}, {7, 8, 0x0}, {7, 14, 0x0}, {7, 6, 0x0}, {7, 5, 0x0}, {7, 4, 0x0}, {7, 7, 0x0}, {7, 9, 0x0}, {7, 11, 0x0}, {10, 8, 0x0}, {10, 14, 0x0}, {10, 6, 0x0}, {10, 5, 0x0}, {10, 4, 0x0}, {10, 7, 0x0}, {10, 9, 0x0}, {10, 11, 0x0}, {12, 8, 0x0}, {12, 14, 0x0}, {12, 6, 0x0}, {12, 5, 0x0}, {12, 4, 0x0}, {12, 7, 0x0}, {12, 9, 0x0}, {12, 11, 0x0}, }; static int nb_special_fargs; static double * spec_fargs; static void build_special_fargs_table(void) { /* The special floating point values created below are for * use in the ftdiv tests for setting the fe_flag and fg_flag, * but they can also be used for other tests (e.g., xscmpudp). * * Note that fl_flag is 'always '1' on ppc64 Linux. * Entry Sign Exp fraction Special value 0 0 3fd 0x8000000000000ULL Positive finite number 1 0 404 0xf000000000000ULL ... 2 0 001 0x8000000b77501ULL ... 3 0 7fe 0x800000000051bULL ... 4 0 012 0x3214569900000ULL ... 5 0 000 0x0000000000000ULL +0.0 (+zero) 6 1 000 0x0000000000000ULL -0.0 (-zero) 7 0 7ff 0x0000000000000ULL +infinity 8 1 7ff 0x0000000000000ULL -infinity 9 0 7ff 0x7FFFFFFFFFFFFULL +SNaN 10 1 7ff 0x7FFFFFFFFFFFFULL -SNaN 11 0 7ff 0x8000000000000ULL +QNaN 12 1 7ff 0x8000000000000ULL -QNaN 13 1 000 0x8340000078000ULL Denormalized val (zero exp and non-zero fraction) 14 1 40d 0x0650f5a07b353ULL Negative finite number */ uint64_t mant; uint16_t _exp; int s; int i = 0; if (spec_fargs) return; spec_fargs = malloc( 16 * sizeof(double) ); // #0 s = 0; _exp = 0x3fd; mant = 0x8000000000000ULL; register_farg(&spec_fargs[i++], s, _exp, mant); // #1 s = 0; _exp = 0x404; mant = 0xf000000000000ULL; register_farg(&spec_fargs[i++], s, _exp, mant); /* None of the ftdiv tests succeed. * FRA = value #0; FRB = value #1 * ea_ = -2; e_b = 5 * fl_flag || fg_flag || fe_flag = 100 */ /************************************************* * fe_flag tests * *************************************************/ /* fe_flag <- 1 if FRA is a NaN * FRA = value #9; FRB = value #1 * e_a = 1024; e_b = 5 * fl_flag || fg_flag || fe_flag = 101 */ /* fe_flag <- 1 if FRB is a NaN * FRA = value #1; FRB = value #12 * e_a = 5; e_b = 1024 * fl_flag || fg_flag || fe_flag = 101 */ /* fe_flag <- 1 if e_b <= -1022 * FRA = value #0; FRB = value #2 * e_a = -2; e_b = -1022 * fl_flag || fg_flag || fe_flag = 101 * */ // #2 s = 0; _exp = 0x001; mant = 0x8000000b77501ULL; register_farg(&spec_fargs[i++], s, _exp, mant); /* fe_flag <- 1 if e_b >= 1021 * FRA = value #1; FRB = value #3 * e_a = 5; e_b = 1023 * fl_flag || fg_flag || fe_flag = 101 */ // #3 s = 0; _exp = 0x7fe; mant = 0x800000000051bULL; register_farg(&spec_fargs[i++], s, _exp, mant); /* fe_flag <- 1 if FRA != 0 && e_a - e_b >= 1023 * Let FRA = value #3 and FRB be value #0. * e_a = 1023; e_b = -2 * fl_flag || fg_flag || fe_flag = 101 */ /* fe_flag <- 1 if FRA != 0 && e_a - e_b <= -1023 * Let FRA = value #0 above and FRB be value #3 above * e_a = -2; e_b = 1023 * fl_flag || fg_flag || fe_flag = 101 */ /* fe_flag <- 1 if FRA != 0 && e_a <= -970 * Let FRA = value #4 and FRB be value #0 * e_a = -1005; e_b = -2 * fl_flag || fg_flag || fe_flag = 101 */ // #4 s = 0; _exp = 0x012; mant = 0x3214569900000ULL; register_farg(&spec_fargs[i++], s, _exp, mant); /************************************************* * fg_flag tests * *************************************************/ /* fg_flag <- 1 if FRA is an Infinity * NOTE: FRA = Inf also sets fe_flag * Do two tests, using values #7 and #8 (+/- Inf) for FRA. * Test 1: * Let FRA be value #7 and FRB be value #1 * e_a = 1024; e_b = 5 * fl_flag || fg_flag || fe_flag = 111 * * Test 2: * Let FRA be value #8 and FRB be value #1 * e_a = 1024; e_b = 5 * fl_flag || fg_flag || fe_flag = 111 * */ /* fg_flag <- 1 if FRB is an Infinity * NOTE: FRB = Inf also sets fe_flag * Let FRA be value #1 and FRB be value #7 * e_a = 5; e_b = 1024 * fl_flag || fg_flag || fe_flag = 111 */ /* fg_flag <- 1 if FRB is denormalized * NOTE: e_b < -1022 ==> fe_flag <- 1 * Let FRA be value #0 and FRB be value #13 * e_a = -2; e_b = -1023 * fl_flag || fg_flag || fe_flag = 111 */ /* fg_flag <- 1 if FRB is +zero * NOTE: FRA = Inf also sets fe_flag * Let FRA = val #5; FRB = val #5 * ea_ = -1023; e_b = -1023 * fl_flag || fg_flag || fe_flag = 111 */ /* fg_flag <- 1 if FRB is -zero * NOTE: FRA = Inf also sets fe_flag * Let FRA = val #5; FRB = val #6 * ea_ = -1023; e_b = -1023 * fl_flag || fg_flag || fe_flag = 111 */ /* Special values */ /* +0.0 : 0 0x000 0x0000000000000 */ // #5 s = 0; _exp = 0x000; mant = 0x0000000000000ULL; register_farg(&spec_fargs[i++], s, _exp, mant); /* -0.0 : 1 0x000 0x0000000000000 */ // #6 s = 1; _exp = 0x000; mant = 0x0000000000000ULL; register_farg(&spec_fargs[i++], s, _exp, mant); /* +infinity : 0 0x7FF 0x0000000000000 */ // #7 s = 0; _exp = 0x7FF; mant = 0x0000000000000ULL; register_farg(&spec_fargs[i++], s, _exp, mant); /* -infinity : 1 0x7FF 0x0000000000000 */ // #8 s = 1; _exp = 0x7FF; mant = 0x0000000000000ULL; register_farg(&spec_fargs[i++], s, _exp, mant); /* +SNaN : 0 0x7FF 0x7FFFFFFFFFFFF */ // #9 s = 0; _exp = 0x7FF; mant = 0x7FFFFFFFFFFFFULL; register_farg(&spec_fargs[i++], s, _exp, mant); /* -SNaN : 1 0x7FF 0x7FFFFFFFFFFFF */ // #10 s = 1; _exp = 0x7FF; mant = 0x7FFFFFFFFFFFFULL; register_farg(&spec_fargs[i++], s, _exp, mant); /* +QNaN : 0 0x7FF 0x8000000000000 */ // #11 s = 0; _exp = 0x7FF; mant = 0x8000000000000ULL; register_farg(&spec_fargs[i++], s, _exp, mant); /* -QNaN : 1 0x7FF 0x8000000000000 */ // #12 s = 1; _exp = 0x7FF; mant = 0x8000000000000ULL; register_farg(&spec_fargs[i++], s, _exp, mant); /* denormalized value */ // #13 s = 1; _exp = 0x000; mant = 0x8340000078000ULL; register_farg(&spec_fargs[i++], s, _exp, mant); /* Negative finite number */ // #14 s = 1; _exp = 0x40d; mant = 0x0650f5a07b353ULL; register_farg(&spec_fargs[i++], s, _exp, mant); nb_special_fargs = i; } struct test_table { test_func_t test_category; char * name; }; struct p7_fp_test { test_func_t test_func; const char *name; int single; // 1=single precision result; 0=double precision result }; typedef enum { VX_FP_CMP, VX_FP_SMA, VX_FP_SMS, VX_FP_SNMA, VX_FP_OTHER } vx_fp_test_type; struct vx_fp_test { test_func_t test_func; const char *name; fp_test_args_t * targs; int num_tests; vx_fp_test_type test_type; }; struct xs_conv_test { test_func_t test_func; const char *name; int num_tests; }; typedef enum { VSX_LOAD =1, VSX_LOAD_SPLAT, VSX_STORE } vsx_ldst_type; struct ldst_test { test_func_t test_func; const char *name; void * base_addr; uint32_t offset; int num_words_to_process; vsx_ldst_type type; }; typedef enum { VSX_AND = 1, VSX_XOR, VSX_ANDC, VSX_OR, VSX_NOR } vsx_log_op; struct vsx_logic_test { test_func_t test_func; const char *name; vsx_log_op op; }; struct vsx_move_test { test_func_t test_func; const char *name; }; struct vsx_permute_test { test_func_t test_func; const char *name; unsigned int xa[4]; unsigned int xb[4]; }; static vector unsigned int vec_out, vec_inA, vec_inB; static void test_lxsdx(void) { __asm__ __volatile__ ("lxsdx %x0, %1, %2" : "=wa" (vec_out): "b" (r14),"r" (r15)); } static void test_lxvd2x(void) { __asm__ __volatile__ ("lxvd2x %x0, %1, %2" : "=wa" (vec_out): "b" (r14),"r" (r15)); } static void test_lxvdsx(void) { __asm__ __volatile__ ("lxvdsx %x0, %1, %2" : "=wa" (vec_out): "b" (r14),"r" (r15)); } static void test_lxvw4x(void) { __asm__ __volatile__ ("lxvw4x %x0, %1, %2" : "=wa" (vec_out): "b" (r14),"r" (r15)); } static void test_stxsdx(void) { __asm__ __volatile__ ("stxsdx %x0, %1, %2" : : "wa" (vec_inA), "b" (r14),"r" (r15)); } static void test_stxvd2x(void) { __asm__ __volatile__ ("stxvd2x %x0, %1, %2" : : "wa" (vec_inA), "b" (r14),"r" (r15)); } static void test_stxvw4x(void) { __asm__ __volatile__ ("stxvw4x %x0, %1, %2" : : "wa" (vec_inA), "b" (r14),"r" (r15)); } static void test_xxlxor(void) { __asm__ __volatile__ ("xxlxor %x0, %x1, %x2" : "=wa" (vec_out): "wa" (vec_inA),"wa" (vec_inB)); } static void test_xxlor(void) { __asm__ __volatile__ ("xxlor %x0, %x1, %x2" : "=wa" (vec_out): "wa" (vec_inA),"wa" (vec_inB)); } static void test_xxlnor(void) { __asm__ __volatile__ ("xxlnor %x0, %x1, %x2" : "=wa" (vec_out): "wa" (vec_inA),"wa" (vec_inB)); } static void test_xxland(void) { __asm__ __volatile__ ("xxland %x0, %x1, %x2" : "=wa" (vec_out): "wa" (vec_inA),"wa" (vec_inB)); } static void test_xxlandc(void) { __asm__ __volatile__ ("xxlandc %x0, %x1, %x2" : "=wa" (vec_out): "wa" (vec_inA),"wa" (vec_inB)); } static void test_xxmrghw(void) { __asm__ __volatile__ ("xxmrghw %x0, %x1, %x2" : "=wa" (vec_out): "wa" (vec_inA),"wa" (vec_inB)); } static void test_xxmrglw(void) { __asm__ __volatile__ ("xxmrglw %x0, %x1, %x2" : "=wa" (vec_out): "wa" (vec_inA),"wa" (vec_inB)); } static void test_xxpermdi_00(void) { __asm__ __volatile__ ("xxpermdi %x0, %x1, %x2, 0x0" : "=wa" (vec_out): "wa" (vec_inA),"wa" (vec_inB)); } static void test_xxpermdi_01(void) { __asm__ __volatile__ ("xxpermdi %x0, %x1, %x2, 0x1" : "=wa" (vec_out): "wa" (vec_inA),"wa" (vec_inB)); } static void test_xxpermdi_10(void) { __asm__ __volatile__ ("xxpermdi %x0, %x1, %x2, 0x2" : "=wa" (vec_out): "wa" (vec_inA),"wa" (vec_inB)); } static void test_xxpermdi_11(void) { __asm__ __volatile__ ("xxpermdi %x0, %x1, %x2, 0x3" : "=wa" (vec_out): "wa" (vec_inA),"wa" (vec_inB)); } static void test_xxsldwi_0(void) { __asm__ __volatile__ ("xxsldwi %x0, %x1, %x2, 0" : "=wa" (vec_out): "wa" (vec_inA),"wa" (vec_inB)); } static void test_xxsldwi_1(void) { __asm__ __volatile__ ("xxsldwi %x0, %x1, %x2, 1" : "=wa" (vec_out): "wa" (vec_inA),"wa" (vec_inB)); } static void test_xxsldwi_2(void) { __asm__ __volatile__ ("xxsldwi %x0, %x1, %x2, 2" : "=wa" (vec_out): "wa" (vec_inA),"wa" (vec_inB)); } static void test_xxsldwi_3(void) { __asm__ __volatile__ ("xxsldwi %x0, %x1, %x2, 3" : "=wa" (vec_out): "wa" (vec_inA),"wa" (vec_inB)); } static void test_fcfids (void) { __asm__ __volatile__ ("fcfids %0, %1" : "=f" (f17): "d" (f14)); } static void test_fcfidus (void) { __asm__ __volatile__ ("fcfidus %0, %1" : "=f" (f17): "d" (f14)); } static void test_fcfidu (void) { __asm__ __volatile__ ("fcfidu %0, %1" : "=f" (f17): "d" (f14)); } static void test_xsabsdp (void) { __asm__ __volatile__ ("xsabsdp %x0, %x1" : "=wa" (vec_out): "wa" (vec_inB)); } static void test_xscpsgndp (void) { __asm__ __volatile__ ("xscpsgndp %x0, %x1, %x2" : "=wa" (vec_out): "wa" (vec_inA),"wa" (vec_inB)); } static void test_xsnabsdp (void) { __asm__ __volatile__ ("xsnabsdp %x0, %x1" : "=wa" (vec_out): "wa" (vec_inB)); } static void test_xsnegdp (void) { __asm__ __volatile__ ("xsnegdp %x0, %x1" : "=wa" (vec_out): "wa" (vec_inB)); } static int do_cmpudp; static void test_xscmp (void) { if (do_cmpudp) __asm__ __volatile__ ("xscmpudp cr1, %x0, %x1" : : "wa" (vec_inA),"wa" (vec_inB)); else __asm__ __volatile__ ("xscmpodp cr1, %x0, %x1" : : "wa" (vec_inA),"wa" (vec_inB)); } static void test_xsadddp(void) { __asm__ __volatile__ ("xsadddp %x0, %x1, %x2" : "=wa" (vec_out): "wa" (vec_inA),"wa" (vec_inB)); } static void test_xsdivdp(void) { __asm__ __volatile__ ("xsdivdp %x0, %x1, %x2" : "=wa" (vec_out): "wa" (vec_inA),"wa" (vec_inB)); } static int do_adp; static void test_xsmadd(void) { if (do_adp) __asm__ __volatile__ ("xsmaddadp %x0, %x1, %x2" : "+wa" (vec_out): "wa" (vec_inA),"wa" (vec_inB)); else __asm__ __volatile__ ("xsmaddmdp %x0, %x1, %x2" : "+wa" (vec_out): "wa" (vec_inA),"wa" (vec_inB)); } static void test_xsmsub(void) { if (do_adp) __asm__ __volatile__ ("xsmsubadp %x0, %x1, %x2" : "+wa" (vec_out): "wa" (vec_inA),"wa" (vec_inB)); else __asm__ __volatile__ ("xsmsubmdp %x0, %x1, %x2" : "+wa" (vec_out): "wa" (vec_inA),"wa" (vec_inB)); } static void test_xsnmadd(void) { if (do_adp) __asm__ __volatile__ ("xsnmaddadp %x0, %x1, %x2" : "+wa" (vec_out): "wa" (vec_inA),"wa" (vec_inB)); else __asm__ __volatile__ ("xsnmaddmdp %x0, %x1, %x2" : "+wa" (vec_out): "wa" (vec_inA),"wa" (vec_inB)); } static void test_xsmuldp(void) { __asm__ __volatile__ ("xsmuldp %x0, %x1, %x2" : "=wa" (vec_out): "wa" (vec_inA),"wa" (vec_inB)); } static void test_xssubdp(void) { __asm__ __volatile__ ("xssubdp %x0, %x1, %x2" : "=wa" (vec_out): "wa" (vec_inA),"wa" (vec_inB)); } static void test_xscvdpsxds (void) { __asm__ __volatile__ ("xscvdpsxds %x0, %x1" : "=wa" (vec_out): "wa" (vec_inB)); } static void test_xscvsxddp (void) { __asm__ __volatile__ ("xscvsxddp %x0, %x1" : "=wa" (vec_out): "wa" (vec_inB)); } static void test_xscvuxddp (void) { __asm__ __volatile__ ("xscvuxddp %x0, %x1" : "=wa" (vec_out): "wa" (vec_inB)); } static unsigned int vstg[] __attribute__ ((aligned (16))) = { 0, 0, 0,0, 0, 0, 0, 0 }; #define NUM_VSTG_INTS (sizeof vstg/sizeof vstg[0]) #define NUM_VSTG_VECS (NUM_VSTG_INTS/4) static unsigned int viargs[] __attribute__ ((aligned (16))) = { 0x01234567, 0x89abcdef, 0x00112233, 0x44556677, 0x8899aabb, 0x91929394, 0xa1a2a3a4, 0xb1b2b3b4, 0xc1c2c3c4, 0xd1d2d3d4, 0x7a6b5d3e }; #define NUM_VIARGS_INTS (sizeof viargs/sizeof viargs[0]) #define NUM_VIARGS_VECS (NUM_VIARGS_INTS/4) static ldst_test_t ldst_tests[] = { { &test_lxsdx, "lxsdx", viargs, 0, 2, VSX_LOAD }, { &test_lxsdx, "lxsdx", viargs, 4, 2, VSX_LOAD }, { &test_lxvd2x, "lxvd2x", viargs, 0, 4, VSX_LOAD }, { &test_lxvd2x, "lxvd2x", viargs, 4, 4, VSX_LOAD }, { &test_lxvdsx, "lxvdsx", viargs, 0, 4, VSX_LOAD_SPLAT }, { &test_lxvdsx, "lxvdsx", viargs, 4, 4, VSX_LOAD_SPLAT }, { &test_lxvw4x, "lxvw4x", viargs, 0, 4, VSX_LOAD }, { &test_lxvw4x, "lxvw4x", viargs, 4, 4, VSX_LOAD }, { &test_stxsdx, "stxsdx", vstg, 0, 2, VSX_STORE }, { &test_stxsdx, "stxsdx", vstg, 4, 2, VSX_STORE }, { &test_stxvd2x, "stxvd2x", vstg, 0, 4, VSX_STORE }, { &test_stxvd2x, "stxvd2x", vstg, 4, 4, VSX_STORE }, { &test_stxvw4x, "stxvw4x", vstg, 0, 4, VSX_STORE }, { &test_stxvw4x, "stxvw4x", vstg, 4, 4, VSX_STORE }, { NULL, NULL, NULL, 0, 0, 0 } }; static logic_test_t logic_tests[] = { { &test_xxlxor, "xxlxor", VSX_XOR }, { &test_xxlor, "xxlor", VSX_OR } , { &test_xxlnor, "xxlnor", VSX_NOR }, { &test_xxland, "xxland", VSX_AND }, { &test_xxlandc, "xxlandc", VSX_ANDC }, { NULL, NULL, 0}}; static move_test_t move_tests[] = { { &test_xsabsdp, "xsabsdp" }, { &test_xscpsgndp, "xscpsgndp" }, { &test_xsnabsdp, "xsnabsdp" }, { &test_xsnegdp, "xsnegdp" }, { NULL, NULL } }; static permute_test_t permute_tests[] = { { &test_xxmrghw, "xxmrghw", { 0x11111111, 0x22222222, 0x33333333, 0x44444444 }, /* XA input */ { 0x55555555, 0x66666666, 0x77777777, 0x88888888 }, /* XB input */ }, { &test_xxmrghw, "xxmrghw", { 0x00112233, 0x44556677, 0x8899aabb, 0xccddeeff }, /* XA input */ { 0x11111111, 0x22222222, 0x33333333, 0x44444444 }, /* XB input */ }, { &test_xxmrglw, "xxmrglw", { 0x11111111, 0x22222222, 0x33333333, 0x44444444 }, /* XA input */ { 0x55555555, 0x66666666, 0x77777777, 0x88888888 }, /* XB input */ }, { &test_xxmrglw, "xxmrglw", { 0x00112233, 0x44556677, 0x8899aabb, 0xccddeeff}, /* XA input */ { 0x11111111, 0x22222222, 0x33333333, 0x44444444}, /* XB input */ }, { &test_xxpermdi_00, "xxpermdi DM=00", { 0x11111111, 0x22222222, 0x33333333, 0x44444444 }, /* XA input */ { 0x55555555, 0x66666666, 0x77777777, 0x88888888 }, /* XB input */ }, { &test_xxpermdi_01, "xxpermdi DM=01", { 0x11111111, 0x22222222, 0x33333333, 0x44444444 }, /* XA input */ { 0x55555555, 0x66666666, 0x77777777, 0x88888888 }, /* XB input */ }, { &test_xxpermdi_10, "xxpermdi DM=10", { 0x11111111, 0x22222222, 0x33333333, 0x44444444 }, /* XA input */ { 0x55555555, 0x66666666, 0x77777777, 0x88888888 }, /* XB input */ }, { &test_xxpermdi_11, "xxpermdi DM=11", { 0x11111111, 0x22222222, 0x33333333, 0x44444444 }, /* XA input */ { 0x55555555, 0x66666666, 0x77777777, 0x88888888 }, /* XB input */ }, { &test_xxsldwi_0, "xxsldwi SHW=0", { 0x11111111, 0x22222222, 0x33333333, 0x44444444 }, /* XA input */ { 0x55555555, 0x66666666, 0x77777777, 0x88888888 }, /* XB input */ }, { &test_xxsldwi_1, "xxsldwi SHW=1", { 0x11111111, 0x22222222, 0x33333333, 0x44444444 }, /* XA input */ { 0x55555555, 0x66666666, 0x77777777, 0x88888888 }, /* XB input */ }, { &test_xxsldwi_2, "xxsldwi SHW=2", { 0x11111111, 0x22222222, 0x33333333, 0x44444444 }, /* XA input */ { 0x55555555, 0x66666666, 0x77777777, 0x88888888 }, /* XB input */ }, { &test_xxsldwi_3, "xxsldwi SHW=3", { 0x11111111, 0x22222222, 0x33333333, 0x44444444 }, /* XA input */ { 0x55555555, 0x66666666, 0x77777777, 0x88888888 }, /* XB input */ }, { NULL, NULL } }; static fp_test_t fp_tests[] = { { &test_fcfids, "fcfids", 1 }, { &test_fcfidus, "fcfidus", 1 }, { &test_fcfidu, "fcfidu", 1 }, { NULL, NULL, 0 }, }; static vx_fp_test_t vx_fp_tests[] = { { &test_xscmp, "xscmp", xscmpX_tests, 64, VX_FP_CMP}, { &test_xsadddp, "xsadddp", xsadddp_tests, 64, VX_FP_OTHER}, { &test_xsdivdp, "xsdivdp", xsdivdp_tests, 64, VX_FP_OTHER}, { &test_xsmadd, "xsmadd", xsmaddXdp_tests, 64, VX_FP_SMA}, { &test_xsmsub, "xsmsub", xsmsubXdp_tests, 64, VX_FP_SMS}, { &test_xsnmadd, "xsnmadd", xsnmaddXdp_tests, 64, VX_FP_SNMA}, { & test_xsmuldp, "xsmuldp", xsmuldp_tests, 64, VX_FP_OTHER}, { & test_xssubdp, "xssubdp", xssubdp_tests, 64, VX_FP_OTHER}, { NULL, NULL, NULL, 0, 0 } }; static xs_conv_test_t xs_conv_tests[] = { { &test_xscvdpsxds, "xscvdpsxds", 15}, { &test_xscvsxddp, "xscvsxddp", 15}, { &test_xscvuxddp, "xscvuxddp", 15}, { NULL, NULL, 0} }; #ifdef __powerpc64__ static void test_ldbrx(void) { int i; HWord_t reg_out; unsigned char * byteIn, * byteOut; r14 = (HWord_t)viargs; // Just try the instruction an arbitrary number of times at different r15 offsets. for (i = 0; i < 3; i++) { int j, k; reg_out = 0; r15 = i * 4; __asm__ __volatile__ ("ldbrx %0, %1, %2" : "=r" (reg_out): "b" (r14),"r" (r15)); byteIn = ((unsigned char *)(r14 + r15)); byteOut = (unsigned char *)®_out; printf("ldbrx:"); for (k = 0; k < 8; k++) { printf( " %02x", (byteIn[k])); } printf(" (reverse) =>"); for (j = 0; j < 8; j++) { printf( " %02x", (byteOut[j])); } printf("\n"); } printf( "\n" ); } static void test_popcntd(void) { uint64_t res; unsigned long long src = 0x9182736405504536ULL; r14 = src; __asm__ __volatile__ ("popcntd %0, %1" : "=r" (res): "r" (r14)); printf("popcntd: 0x%llx => %d\n", src, (int)res); printf( "\n" ); } #endif static void test_lfiwzx(void) { unsigned int i; unsigned int * src; uint64_t reg_out; r14 = (HWord_t)viargs; // Just try the instruction an arbitrary number of times at different r15 offsets. for (i = 0; i < 3; i++) { reg_out = 0; r15 = i * 4; __asm__ __volatile__ ("lfiwzx %0, %1, %2" : "=d" (reg_out): "b" (r14),"r" (r15)); src = ((unsigned int *)(r14 + r15)); printf("lfiwzx: %u => %llu.00\n", *src, (unsigned long long)reg_out); } printf( "\n" ); } static void test_vx_fp_ops(void) { test_func_t func; int k; char * test_name = (char *)malloc(20); k = 0; build_special_fargs_table(); while ((func = vx_fp_tests[k].test_func)) { int i, condreg, repeat = 0; unsigned int flags; unsigned long long * frap, * frbp, * dst; vx_fp_test_t test_group = vx_fp_tests[k]; vx_fp_test_type test_type = test_group.test_type; switch (test_type) { case VX_FP_CMP: strcpy(test_name, "xscmp"); if (!repeat) { repeat = 1; strcat(test_name, "udp"); do_cmpudp = 1; } break; case VX_FP_SMA: case VX_FP_SMS: case VX_FP_SNMA: if (test_type == VX_FP_SMA) strcpy(test_name, "xsmadd"); else if (test_type == VX_FP_SMS) strcpy(test_name, "xsmsub"); else strcpy(test_name, "xsnmadd"); if (!repeat) { repeat = 1; strcat(test_name, "adp"); do_adp = 1; } break; case VX_FP_OTHER: strcpy(test_name, test_group.name); break; default: printf("ERROR: Invalid VX FP test type %d\n", test_type); exit(1); } again: for (i = 0; i < test_group.num_tests; i++) { unsigned int * inA, * inB, * pv; double * dpA = (double *)&vec_inA; double * dpB = (double *)&vec_inB; double * dpT = (double *)&vec_out; fp_test_args_t aTest = test_group.targs[i]; inA = (unsigned int *)&spec_fargs[aTest.fra_idx]; inB = (unsigned int *)&spec_fargs[aTest.frb_idx]; frap = (unsigned long long *)&spec_fargs[aTest.fra_idx]; frbp = (unsigned long long *)&spec_fargs[aTest.frb_idx]; // Only need to copy one doubleword into each vector's element 0 if (isLE) { // With LE, vector element 0 is the second doubleword from the left memset(dpA, 0, 8); memset(dpB, 0, 8); dpA++; dpB++; } memcpy(dpA, inA, 8); memcpy(dpB, inB, 8); switch (test_type) { case VX_FP_CMP: SET_FPSCR_ZERO; SET_CR_XER_ZERO; (*func)(); GET_CR(flags); condreg = (flags & 0x0f000000) >> 24; printf("#%d: %s %016llx <=> %016llx ? %x (CRx)\n", i, test_name, *frap, *frbp, condreg); // printf("\tFRA: %e; FRB: %e\n", spec_fargs[aTest.fra_idx], spec_fargs[aTest.frb_idx]); if ( condreg != aTest.cr_flags) { printf("Error: Expected CR flags 0x%x; actual flags: 0x%x\n", aTest.cr_flags, condreg); } break; case VX_FP_SMA: case VX_FP_SMS: case VX_FP_SNMA: case VX_FP_OTHER: { int idx; unsigned long long vsr_XT; pv = (unsigned int *)&vec_out; // clear vec_out for (idx = 0; idx < 4; idx++, pv++) *pv = 0; if (test_type != VX_FP_OTHER) { /* Then we need a third src argument, which is stored in element 0 of * VSX[XT] -- i.e., vec_out. For the xsmdp cases, VSX[XT] holds * src3 and VSX[XB] holds src2; for the xsadp cases, VSX[XT] holds * src2 and VSX[XB] holds src3. The fp_test_args_t that holds the test * data (input args) contain only two inputs, so I arbitrarily * use spec_fargs elements 4 and 14 (alternating) for the third source * argument. We can use the same input data for a given pair of * adp/mdp-type instructions by swapping the src2 and src3 arguments; thus * the expected result should be the same. */ int extra_arg_idx; if (i % 2) extra_arg_idx = 4; else extra_arg_idx = 14; if (repeat) { /* We're on the first time through of one of the VX_FP_SMx * test types, meaning we're testing a xsadp case, thus we * have to swap inputs as described above: * src2 <= VSX[XT] * src3 <= VSX[XB] */ if (isLE) dpT++; memcpy(dpT, inB, 8); // src2 memcpy(dpB, &spec_fargs[extra_arg_idx], 8); //src3 frbp = (unsigned long long *)&spec_fargs[extra_arg_idx]; } else { // Don't need to init src2, as it's done before the switch() if (isLE) dpT++; memcpy(dpT, &spec_fargs[extra_arg_idx], 8); //src3 } memcpy(&vsr_XT, dpT, 8); } (*func)(); dst = (unsigned long long *) &vec_out; if (isLE) dst++; if (test_type == VX_FP_OTHER) printf("#%d: %s %016llx %016llx = %016llx\n", i, test_name, *frap, *frbp, *dst); else printf( "#%d: %s %016llx %016llx %016llx = %016llx\n", i, test_name, vsr_XT, *frap, *frbp, *dst ); /* { // Debug code. Keep this block commented out except when debugging. double result, expected; memcpy(&result, dst, 8); memcpy(&expected, &aTest.dp_bin_result, 8); printf( "\tFRA + FRB: %e + %e: Expected = %e; Actual = %e\n", spec_fargs[aTest.fra_idx], spec_fargs[aTest.frb_idx], expected, result ); } */ break; } } } printf( "\n" ); if (repeat) { repeat = 0; switch (test_type) { case VX_FP_CMP: strcpy(test_name, "xscmp"); strcat(test_name, "odp"); do_cmpudp = 0; break; case VX_FP_SMA: case VX_FP_SMS: case VX_FP_SNMA: if (test_type == VX_FP_SMA) strcpy(test_name, "xsmadd"); else if (test_type == VX_FP_SMS) strcpy(test_name, "xsmsub"); else strcpy(test_name, "xsnmadd"); strcat(test_name, "mdp"); do_adp = 0; break; case VX_FP_OTHER: break; } goto again; } k++; } printf( "\n" ); free(test_name); } static void test_xs_conv_ops(void) { test_func_t func; int k = 0; double * dpB = (double *)&vec_inB; if (isLE) { memset(dpB, 0, 8); dpB++; } build_special_fargs_table(); while ((func = xs_conv_tests[k].test_func)) { int i; unsigned long long * frbp, * dst; xs_conv_test_t test_group = xs_conv_tests[k]; for (i = 0; i < test_group.num_tests; i++) { unsigned int * inB, * pv; int idx; inB = (unsigned int *)&spec_fargs[i]; frbp = (unsigned long long *)&spec_fargs[i]; memcpy(dpB, inB, 8); pv = (unsigned int *)&vec_out; // clear vec_out for (idx = 0; idx < 4; idx++, pv++) *pv = 0; (*func)(); dst = (unsigned long long *) &vec_out; if (isLE) dst++; printf("#%d: %s %016llx => %016llx\n", i, test_group.name, *frbp, *dst); } k++; printf("\n"); } printf( "\n" ); } static void do_load_test(ldst_test_t loadTest) { test_func_t func; unsigned int *src, *dst; int splat = loadTest.type == VSX_LOAD_SPLAT ? 1: 0; int i, j, m, k; i = j = 0; func = loadTest.test_func; for (i = 0, r14 = (HWord_t) loadTest.base_addr; i < NUM_VIARGS_VECS; i++) { int again; j = 0; r14 += i * 16; do { unsigned int * pv = (unsigned int *)&vec_out; int idx; // clear vec_out for (idx = 0; idx < 4; idx++, pv+=idx) *pv = 0; again = 0; r15 = j; // execute test insn (*func)(); src = (unsigned int*) (((unsigned char *)r14) + j); dst = (unsigned int*) &vec_out; printf( "%s:", loadTest.name); for (m = 0; m < loadTest.num_words_to_process; m++) { printf( " %08x", src[splat ? m % 2 : m]); } printf( " =>"); m = 0; k = loadTest.num_words_to_process; if (isLE) { if (loadTest.num_words_to_process == 2) { m = 2; k += 2; } } for (; m < k; m++) { printf( " %08x", dst[m]); } printf("\n"); if (j == 0 && loadTest.offset) { again = 1; j += loadTest.offset; } } while (again); } } static void do_store_test ( ldst_test_t storeTest ) { test_func_t func; unsigned int *src, *dst; int m; func = storeTest.test_func; r14 = (HWord_t) storeTest.base_addr; r15 = (HWord_t) storeTest.offset; unsigned int * pv = (unsigned int *) storeTest.base_addr; int idx; // clear out storage destination for (idx = 0; idx < 4; idx++, pv += idx) *pv = 0; memcpy(&vec_inA, &viargs[0], sizeof(vector unsigned char)); // execute test insn (*func)(); src = &viargs[0]; dst = (unsigned int*) (((unsigned char *) r14) + storeTest.offset); printf( "%s:", storeTest.name ); for (m = 0; m < storeTest.num_words_to_process; m++) { printf( " %08x", src[m] ); } printf( " =>" ); for (m = 0; m < storeTest.num_words_to_process; m++) { printf( " %08x", dst[m] ); } printf( "\n" ); } static void test_ldst(void) { int k = 0; while (ldst_tests[k].test_func) { if (ldst_tests[k].type == VSX_STORE) do_store_test(ldst_tests[k]); else do_load_test(ldst_tests[k]); k++; printf("\n"); } } static void test_ftdiv(void) { int i, num_tests, crx; unsigned int flags; unsigned long long * frap, * frbp; build_special_fargs_table(); num_tests = sizeof ftdiv_tests/sizeof ftdiv_tests[0]; for (i = 0; i < num_tests; i++) { fp_test_args_t aTest = ftdiv_tests[i]; f14 = spec_fargs[aTest.fra_idx]; f15 = spec_fargs[aTest.frb_idx]; frap = (unsigned long long *)&spec_fargs[aTest.fra_idx]; frbp = (unsigned long long *)&spec_fargs[aTest.frb_idx]; SET_FPSCR_ZERO; SET_CR_XER_ZERO; __asm__ __volatile__ ("ftdiv cr1, %0, %1" : : "d" (f14), "d" (f15)); GET_CR(flags); crx = (flags & 0x0f000000) >> 24; printf( "ftdiv: %016llx <=> %016llx ? %x (CRx)\n", *frap, *frbp, crx); // printf("\tFRA: %e; FRB: %e\n", f14, f15); if ( crx != aTest.cr_flags) { printf("Error: Expected CR flags 0x%x; actual flags: 0x%x\n", aTest.cr_flags, crx); } } printf( "\n" ); } static void test_p7_fpops ( void ) { int k = 0; test_func_t func; build_fargs_table(); while ((func = fp_tests[k].test_func)) { float res; double resd; unsigned long long u0; int i; // fcfids - 64-bit fp converted to inf precise fp integer, rounded to SP. (32) // fcfidus - 64-bit fp converted to inf precise fp integer, rounded to SP. (32) // fcfidu - 64-bit fp converted to inf precise fp integer, rounded to DP. (64) int res32 = ( (strcmp(fp_tests[k].name, "fcfids")==0) || (strcmp(fp_tests[k].name, "fcfidus")==0) ); for (i = 0; i < nb_fargs; i++) { u0 = *(unsigned long long *) (&fargs[i]); f14 = fargs[i]; (*func)(); if (res32) { res = f17; printf( "%s %016llx => (raw sp) %08x)", fp_tests[k].name, u0, *((unsigned int *)&res)); } else { resd = f17; printf( "%s %016llx => (raw sp) %016llx)", fp_tests[k].name, u0, *(unsigned long long *)(&resd)); } printf( "\n" ); } k++; printf( "\n" ); } } static void test_vsx_logic(void) { logic_test_t aTest; test_func_t func; int k; k = 0; while ((func = logic_tests[k].test_func)) { unsigned int * pv; int startA, startB; unsigned int * inA, * inB, * dst; int idx, i; startA = 0; aTest = logic_tests[k]; for (i = 0; i <= (NUM_VIARGS_INTS - (NUM_VIARGS_VECS * sizeof(int))); i++, startA++) { startB = startA + 4; pv = (unsigned int *)&vec_out; inA = &viargs[startA]; inB = &viargs[startB]; memcpy(&vec_inA, inA, sizeof(vector unsigned char)); memcpy(&vec_inB, inB, sizeof(vector unsigned char)); // clear vec_out for (idx = 0; idx < 4; idx++, pv++) *pv = 0; // execute test insn (*func)(); dst = (unsigned int*) &vec_out; printf( "%s:", aTest.name); printf( " %08x %08x %08x %08x %s", inA[0], inA[1], inA[2], inA[3], aTest.name); printf( " %08x %08x %08x %08x", inB[0], inB[1], inB[2], inB[3]); printf(" => %08x %08x %08x %08x\n", dst[0], dst[1], dst[2], dst[3]); } k++; } printf( "\n" ); } static vector unsigned long long vec_args[] __attribute__ ((aligned (16))) = { { 0x0123456789abcdefULL, 0x0011223344556677ULL}, { 0x8899aabb19293942ULL, 0xa1a2a3a4b1b2b3b4ULL}, { 0xc1c2c3c4d1d2d3d4ULL, 0x7a6b5d3efc032778ULL} }; #define NUM_VEC_ARGS_LONGS (sizeof vec_args/sizeof vec_args[0]) static void test_move_ops (void) { move_test_t aTest; test_func_t func; int k; k = 0; while ((func = move_tests[k].test_func)) { unsigned int * pv; int startA, startB; unsigned long long * inA, * inB, * dst; int use_vecA = (strcmp(move_tests[k].name, "xscpsgndp") == 0); int idx; inA = NULL; aTest = move_tests[k]; for (startB = 0; startB < NUM_VEC_ARGS_LONGS; startB++) { inB = (unsigned long long *)&vec_args[startB]; memcpy(&vec_inB, inB, sizeof(vector unsigned char)); if (isLE) inB++; startA = 0; repeat: if (use_vecA) { inA = (unsigned long long *)&vec_args[startA]; memcpy(&vec_inA, inA, sizeof(vector unsigned char)); startA++; } pv = (unsigned int *)&vec_out; // clear vec_out for (idx = 0; idx < 4; idx++, pv++) *pv = 0; // execute test insn (*func)(); dst = (unsigned long long *) &vec_out; if (isLE) { dst++; inA++; } printf( "%s:", aTest.name); if (use_vecA) printf( " X[A]: %016llx ", *inA); printf( " X[B]: %016llx", *inB); printf(" => %016llx\n", *dst); if (use_vecA && startA < NUM_VEC_ARGS_LONGS) goto repeat; } k++; printf( "\n" ); } } static void test_permute_ops (void) { permute_test_t *aTest; unsigned int *dst = (unsigned int *) &vec_out; for (aTest = &(permute_tests[0]); aTest->test_func != NULL; aTest++) { /* Grab test input and clear output vector. */ memcpy(&vec_inA, aTest->xa, sizeof(vec_inA)); memcpy(&vec_inB, aTest->xb, sizeof(vec_inB)); memset(dst, 0, sizeof(vec_out)); /* execute test insn */ aTest->test_func(); printf( "%s:\n", aTest->name); printf( " XA[%08x,%08x,%08x,%08x]\n", aTest->xa[0], aTest->xa[1], aTest->xa[2], aTest->xa[3]); printf( " XB[%08x,%08x,%08x,%08x]\n", aTest->xb[0], aTest->xb[1], aTest->xb[2], aTest->xb[3]); printf( " => XT[%08x,%08x,%08x,%08x]\n", dst[0], dst[1], dst[2], dst[3]); } printf( "\n" ); } static test_table_t all_tests[] = { { &test_ldst, "Test VSX load/store instructions" }, { &test_vsx_logic, "Test VSX logic instructions" }, #ifdef __powerpc64__ { &test_ldbrx, "Test ldbrx instruction" }, { &test_popcntd, "Test popcntd instruction" }, #endif { &test_lfiwzx, "Test lfiwzx instruction" }, { &test_p7_fpops, "Test P7 floating point convert instructions"}, { &test_ftdiv, "Test ftdiv instruction" }, { &test_move_ops, "Test VSX move instructions"}, { &test_permute_ops, "Test VSX permute instructions"}, { &test_vx_fp_ops, "Test VSX floating point instructions"}, { &test_xs_conv_ops, "Test VSX scalar integer conversion instructions" }, { NULL, NULL } }; #endif // HAS_VSX int main(int argc, char *argv[]) { #ifdef HAS_VSX test_table_t aTest; test_func_t func; int i = 0; while ((func = all_tests[i].test_category)) { aTest = all_tests[i]; printf( "%s\n", aTest.name ); (*func)(); i++; } #endif // HAS _VSX return 0; }