/* Copyright (C) 2011 IBM
Author: Maynard Johnson <maynardj@us.ibm.com>
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, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307, USA.
The GNU General Public License is contained in the file COPYING.
*/
#ifdef HAS_VSX
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <malloc.h>
#include <altivec.h>
#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 xs<ZZZ>mdp cases, VSX[XT] holds
* src3 and VSX[XB] holds src2; for the xs<ZZZ>adp 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 xs<ZZZ>adp 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;
int res32 = strcmp(fp_tests[k].name, "fcfidu");
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;
}