mirror of
https://github.com/kanjitalk755/macemu.git
synced 2024-11-27 02:49:42 +00:00
Add AltiVec regression testsuite
This commit is contained in:
parent
8d4108dd3a
commit
d92989dc53
@ -19,10 +19,15 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <limits>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <netinet/in.h> // ntohl(), htonl()
|
#include <netinet/in.h> // ntohl(), htonl()
|
||||||
|
#include <setjmp.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
#if EMU_KHEPERIX
|
#if EMU_KHEPERIX
|
||||||
#include "sysdeps.h"
|
#include "sysdeps.h"
|
||||||
@ -85,6 +90,8 @@ typedef uintptr_t uintptr;
|
|||||||
#define TEST_LOGICAL 1
|
#define TEST_LOGICAL 1
|
||||||
#define TEST_COMPARE 1
|
#define TEST_COMPARE 1
|
||||||
#define TEST_CR_LOGICAL 1
|
#define TEST_CR_LOGICAL 1
|
||||||
|
#define TEST_VMX_LOAD 1
|
||||||
|
#define TEST_VMX_ARITH 1
|
||||||
|
|
||||||
// Partial PowerPC runtime assembler from GNU lightning
|
// Partial PowerPC runtime assembler from GNU lightning
|
||||||
#define _I(X) ((uint32)(X))
|
#define _I(X) ((uint32)(X))
|
||||||
@ -98,16 +105,24 @@ typedef uintptr_t uintptr;
|
|||||||
#define _u6(I) _ck_u( 6,I)
|
#define _u6(I) _ck_u( 6,I)
|
||||||
#define _u9(I) _ck_u( 9,I)
|
#define _u9(I) _ck_u( 9,I)
|
||||||
#define _u10(I) _ck_u(10,I)
|
#define _u10(I) _ck_u(10,I)
|
||||||
|
#define _u11(I) _ck_u(11,I)
|
||||||
#define _s16(I) _ck_s(16,I)
|
#define _s16(I) _ck_s(16,I)
|
||||||
|
|
||||||
#define _D( OP,RD,RA, DD ) _I((_u6(OP)<<26)|(_u5(RD)<<21)|(_u5(RA)<<16)| _s16(DD) )
|
#define _D( OP,RD,RA, DD ) _I((_u6(OP)<<26)|(_u5(RD)<<21)|(_u5(RA)<<16)| _s16(DD) )
|
||||||
#define _X( OP,RD,RA,RB, XO,RC ) _I((_u6(OP)<<26)|(_u5(RD)<<21)|(_u5(RA)<<16)|( _u5(RB)<<11)| (_u10(XO)<<1)|_u1(RC))
|
#define _X( OP,RD,RA,RB, XO,RC ) _I((_u6(OP)<<26)|(_u5(RD)<<21)|(_u5(RA)<<16)|( _u5(RB)<<11)| (_u10(XO)<<1)|_u1(RC))
|
||||||
#define _XO( OP,RD,RA,RB,OE,XO,RC ) _I((_u6(OP)<<26)|(_u5(RD)<<21)|(_u5(RA)<<16)|( _u5(RB)<<11)|(_u1(OE)<<10)|( _u9(XO)<<1)|_u1(RC))
|
#define _XO( OP,RD,RA,RB,OE,XO,RC ) _I((_u6(OP)<<26)|(_u5(RD)<<21)|(_u5(RA)<<16)|( _u5(RB)<<11)|(_u1(OE)<<10)|( _u9(XO)<<1)|_u1(RC))
|
||||||
#define _M( OP,RS,RA,SH,MB,ME,RC ) _I((_u6(OP)<<26)|(_u5(RS)<<21)|(_u5(RA)<<16)|( _u5(SH)<<11)|(_u5(MB)<< 6)|( _u5(ME)<<1)|_u1(RC))
|
#define _M( OP,RS,RA,SH,MB,ME,RC ) _I((_u6(OP)<<26)|(_u5(RS)<<21)|(_u5(RA)<<16)|( _u5(SH)<<11)|(_u5(MB)<< 6)|( _u5(ME)<<1)|_u1(RC))
|
||||||
|
#define _VX( OP,VD,VA,VB, XO ) _I((_u6(OP)<<26)|(_u5(VD)<<21)|(_u5(VA)<<16)|( _u5(VB)<<11)| _u11(XO) )
|
||||||
|
#define _VXR( OP,VD,VA,VB, XO,RC ) _I((_u6(OP)<<26)|(_u5(VD)<<21)|(_u5(VA)<<16)|( _u5(VB)<<11)| (_u1(RC)<<10)|_u10(XO))
|
||||||
|
#define _VA( OP,VD,VA,VB,VC,XO ) _I((_u6(OP)<<26)|(_u5(VD)<<21)|(_u5(VA)<<16)|( _u5(VB)<<11)|(_u5(VC)<< 6)| _u6(XO) )
|
||||||
|
|
||||||
// PowerPC opcodes
|
// PowerPC opcodes
|
||||||
static inline uint32 POWERPC_MR(int RD, int RA) { return _X(31,RA,RD,RA,444,0); }
|
static inline uint32 POWERPC_MR(int RD, int RA) { return _X(31,RA,RD,RA,444,0); }
|
||||||
static inline uint32 POWERPC_MFCR(int RD) { return _X(31,RD,00,00,19,0); }
|
static inline uint32 POWERPC_MFCR(int RD) { return _X(31,RD,00,00,19,0); }
|
||||||
|
static inline uint32 POWERPC_LVX(int vD, int rA, int rB) { return _X(31,vD,rA,rB,103,0); }
|
||||||
|
static inline uint32 POWERPC_STVX(int vS, int rA, int rB) { return _X(31,vS,rA,rB,231,0); }
|
||||||
|
static inline uint32 POWERPC_MFSPR(int rD, int SPR) { return _X(31,rD,(SPR&0x1f),((SPR>>5)&0x1f),339,0); }
|
||||||
|
static inline uint32 POWERPC_MTSPR(int rS, int SPR) { return _X(31,rS,(SPR&0x1f),((SPR>>5)&0x1f),467,0); }
|
||||||
const uint32 POWERPC_NOP = 0x60000000;
|
const uint32 POWERPC_NOP = 0x60000000;
|
||||||
const uint32 POWERPC_BLR = 0x4e800020;
|
const uint32 POWERPC_BLR = 0x4e800020;
|
||||||
const uint32 POWERPC_BLRL = 0x4e800021;
|
const uint32 POWERPC_BLRL = 0x4e800021;
|
||||||
@ -174,13 +189,6 @@ void powerpc_cpu_base::execute_return(uint32 opcode)
|
|||||||
|
|
||||||
void powerpc_cpu_base::init_decoder()
|
void powerpc_cpu_base::init_decoder()
|
||||||
{
|
{
|
||||||
#ifndef PPC_NO_STATIC_II_INDEX_TABLE
|
|
||||||
static bool initialized = false;
|
|
||||||
if (initialized)
|
|
||||||
return;
|
|
||||||
initialized = true;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static const instr_info_t return_ii_table[] = {
|
static const instr_info_t return_ii_table[] = {
|
||||||
{ "return",
|
{ "return",
|
||||||
(execute_pmf)&powerpc_cpu_base::execute_return,
|
(execute_pmf)&powerpc_cpu_base::execute_return,
|
||||||
@ -400,6 +408,14 @@ typedef bit_field< 16, 20 > rB_field;
|
|||||||
typedef bit_field< 6, 10 > rD_field;
|
typedef bit_field< 6, 10 > rD_field;
|
||||||
typedef bit_field< 6, 10 > rS_field;
|
typedef bit_field< 6, 10 > rS_field;
|
||||||
|
|
||||||
|
// Vector registers
|
||||||
|
typedef bit_field< 11, 15 > vA_field;
|
||||||
|
typedef bit_field< 16, 20 > vB_field;
|
||||||
|
typedef bit_field< 21, 25 > vC_field;
|
||||||
|
typedef bit_field< 6, 10 > vD_field;
|
||||||
|
typedef bit_field< 6, 10 > vS_field;
|
||||||
|
typedef bit_field< 22, 25 > vSH_field;
|
||||||
|
|
||||||
// Condition registers
|
// Condition registers
|
||||||
typedef bit_field< 11, 15 > crbA_field;
|
typedef bit_field< 11, 15 > crbA_field;
|
||||||
typedef bit_field< 16, 20 > crbB_field;
|
typedef bit_field< 16, 20 > crbB_field;
|
||||||
@ -433,6 +449,144 @@ typedef bit_field< 2, 2 > XER_CA_field;
|
|||||||
#undef SO
|
#undef SO
|
||||||
#define SO XER_SO_field::mask()
|
#define SO XER_SO_field::mask()
|
||||||
|
|
||||||
|
// Flag: does the host support AltiVec instructions?
|
||||||
|
static bool has_altivec = true;
|
||||||
|
|
||||||
|
// A 128-bit AltiVec register
|
||||||
|
typedef uint8 vector_t[16] __attribute__((aligned(16)));
|
||||||
|
|
||||||
|
union vector_helper_t {
|
||||||
|
vector_t v;
|
||||||
|
uint8 b[16];
|
||||||
|
uint16 h[8];
|
||||||
|
uint32 w[4];
|
||||||
|
float f[4];
|
||||||
|
};
|
||||||
|
|
||||||
|
static void print_vector(vector_t const & v, char type = 'b')
|
||||||
|
{
|
||||||
|
vector_helper_t x;
|
||||||
|
memcpy(&x.b, &v, sizeof(vector_t));
|
||||||
|
|
||||||
|
printf("{");
|
||||||
|
switch (type) {
|
||||||
|
case 'b':
|
||||||
|
default:
|
||||||
|
for (int i = 0; i < 16; i++) {
|
||||||
|
if (i != 0)
|
||||||
|
printf(",");
|
||||||
|
printf(" %02x", x.b[i]);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'h':
|
||||||
|
for (int i = 0; i < 8; i++) {
|
||||||
|
if (i != 0)
|
||||||
|
printf(",");
|
||||||
|
printf(" %04x", x.h[i]);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'w':
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
if (i != 0)
|
||||||
|
printf(",");
|
||||||
|
printf(" %08x", x.w[i]);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'f':
|
||||||
|
case 'e': // estimate result
|
||||||
|
case 'l': // estimate log2 result
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
x.w[i] = ntohl(x.w[i]);
|
||||||
|
if (i != 0)
|
||||||
|
printf(",");
|
||||||
|
printf(" %g", x.f[i]);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
printf(" }");
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool do_float_equals(float a, float b, float tolerance)
|
||||||
|
{
|
||||||
|
if (a == b)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (isnan(a) && isnan(b))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (isinf(a) && isinf(b) && signbit(a) == signbit(b))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if ((b < (a + tolerance)) && (b > (a - tolerance)))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool float_equals(float a, float b)
|
||||||
|
{
|
||||||
|
return do_float_equals(a, b, 3 * std::numeric_limits<float>::epsilon());
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool vector_equals(char type, vector_t const & a, vector_t const & b)
|
||||||
|
{
|
||||||
|
// the vector is in ppc big endian format
|
||||||
|
float tolerance;
|
||||||
|
switch (type) {
|
||||||
|
case 'f':
|
||||||
|
tolerance = 3 * std::numeric_limits<float>::epsilon();
|
||||||
|
goto do_compare;
|
||||||
|
case 'l': // FIXME: this does not handle |x-1|<=1/8 case
|
||||||
|
tolerance = 1. / 32.;
|
||||||
|
goto do_compare;
|
||||||
|
case 'e':
|
||||||
|
tolerance = 1. / 4096.;
|
||||||
|
do_compare:
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
union { float f; uint32 i; } u, v;
|
||||||
|
u.i = ntohl(((uint32 *)&a)[i]);
|
||||||
|
v.i = ntohl(((uint32 *)&b)[i]);
|
||||||
|
if (!do_float_equals(u.f, v.f, tolerance))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return memcmp(&a, &b, sizeof(vector_t)) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool vector_all_eq(char type, vector_t const & b)
|
||||||
|
{
|
||||||
|
uint32 v;
|
||||||
|
vector_helper_t x;
|
||||||
|
memcpy(&x.v, &b, sizeof(vector_t));
|
||||||
|
|
||||||
|
bool all_eq = true;
|
||||||
|
switch (type) {
|
||||||
|
case 'b':
|
||||||
|
default:
|
||||||
|
v = x.b[0];
|
||||||
|
for (int i = 1; all_eq && i < 16; i++)
|
||||||
|
if (x.b[i] != v)
|
||||||
|
all_eq = false;
|
||||||
|
break;
|
||||||
|
case 'h':
|
||||||
|
v = x.h[0];
|
||||||
|
for (int i = 1; all_eq && i < 8; i++)
|
||||||
|
if (x.h[i] != v)
|
||||||
|
all_eq = false;
|
||||||
|
break;
|
||||||
|
case 'w':
|
||||||
|
case 'f':
|
||||||
|
v = x.w[0];
|
||||||
|
for (int i = 1; all_eq && i < 4; i++)
|
||||||
|
if (x.w[i] != v)
|
||||||
|
all_eq = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return all_eq;
|
||||||
|
}
|
||||||
|
|
||||||
// Define PowerPC tester
|
// Define PowerPC tester
|
||||||
class powerpc_test_cpu
|
class powerpc_test_cpu
|
||||||
: public powerpc_cpu_base
|
: public powerpc_cpu_base
|
||||||
@ -477,8 +631,10 @@ private:
|
|||||||
FILE *results_file;
|
FILE *results_file;
|
||||||
uint32 get32();
|
uint32 get32();
|
||||||
void put32(uint32 v);
|
void put32(uint32 v);
|
||||||
|
void get_vector(vector_t & v);
|
||||||
|
void put_vector(vector_t const & v);
|
||||||
|
|
||||||
// Initial CR0, XER state
|
// Initial CR0, XER states
|
||||||
uint32 init_cr;
|
uint32 init_cr;
|
||||||
uint32 init_xer;
|
uint32 init_xer;
|
||||||
|
|
||||||
@ -490,12 +646,36 @@ private:
|
|||||||
enum {
|
enum {
|
||||||
RD = 3,
|
RD = 3,
|
||||||
RA = 4,
|
RA = 4,
|
||||||
RB = 5
|
RB = 5,
|
||||||
|
RC = 6,
|
||||||
|
VSCR = 7,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Operands
|
||||||
|
enum {
|
||||||
|
__,
|
||||||
|
vD, vS, vA, vB, vC, vI, vN,
|
||||||
|
rD, rS, rA, rB, rC,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct vector_test_t {
|
||||||
|
uint8 name[14];
|
||||||
|
char type;
|
||||||
|
char op_type;
|
||||||
|
uint32 opcode;
|
||||||
|
uint8 operands[4];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct vector_value_t {
|
||||||
|
char type;
|
||||||
|
vector_t v;
|
||||||
};
|
};
|
||||||
|
|
||||||
static const uint32 reg_values[];
|
static const uint32 reg_values[];
|
||||||
static const uint32 imm_values[];
|
static const uint32 imm_values[];
|
||||||
static const uint32 msk_values[];
|
static const uint32 msk_values[];
|
||||||
|
static const vector_value_t vector_values[];
|
||||||
|
static const vector_value_t vector_fp_values[];
|
||||||
|
|
||||||
void test_one_1(uint32 *code, const char *insn, uint32 a1, uint32 a2, uint32 a3, uint32 a0 = 0);
|
void test_one_1(uint32 *code, const char *insn, uint32 a1, uint32 a2, uint32 a3, uint32 a0 = 0);
|
||||||
void test_one(uint32 *code, const char *insn, uint32 a1, uint32 a2, uint32 a3, uint32 a0 = 0);
|
void test_one(uint32 *code, const char *insn, uint32 a1, uint32 a2, uint32 a3, uint32 a0 = 0);
|
||||||
@ -522,6 +702,12 @@ private:
|
|||||||
void test_logical(void);
|
void test_logical(void);
|
||||||
void test_compare(void);
|
void test_compare(void);
|
||||||
void test_cr_logical(void);
|
void test_cr_logical(void);
|
||||||
|
|
||||||
|
void test_one_vector(uint32 *code, vector_test_t const & vt, uint8 *rA, uint8 *rB = 0, uint8 *rC = 0);
|
||||||
|
void test_one_vector(uint32 *code, vector_test_t const & vt, vector_t const *vA = 0, vector_t const *vB = 0, vector_t const *vC = 0)
|
||||||
|
{ test_one_vector(code, vt, (uint8 *)vA, (uint8 *)vB, (uint8 *)vC); }
|
||||||
|
void test_vector_load(void);
|
||||||
|
void test_vector_arith(void);
|
||||||
};
|
};
|
||||||
|
|
||||||
powerpc_test_cpu::powerpc_test_cpu()
|
powerpc_test_cpu::powerpc_test_cpu()
|
||||||
@ -558,6 +744,22 @@ void powerpc_test_cpu::put32(uint32 v)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void powerpc_test_cpu::get_vector(vector_t & v)
|
||||||
|
{
|
||||||
|
if (fread(&v, sizeof(v), 1, results_file) != 1) {
|
||||||
|
fprintf(stderr, "ERROR: unexpected end of results file\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void powerpc_test_cpu::put_vector(vector_t const & v)
|
||||||
|
{
|
||||||
|
if (fwrite(&v, sizeof(v), 1, results_file) != 1) {
|
||||||
|
fprintf(stderr, "could not write vector to results file\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void powerpc_test_cpu::execute(uint32 *code_p)
|
void powerpc_test_cpu::execute(uint32 *code_p)
|
||||||
{
|
{
|
||||||
static uint32 code[2];
|
static uint32 code[2];
|
||||||
@ -1265,13 +1467,520 @@ void powerpc_test_cpu::test_cr_logical(void)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Template-generated vector values
|
||||||
|
const powerpc_test_cpu::vector_value_t powerpc_test_cpu::vector_values[] = {
|
||||||
|
{'w',{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
|
||||||
|
{'w',{0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01}},
|
||||||
|
{'w',{0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02}},
|
||||||
|
{'w',{0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03}},
|
||||||
|
{'w',{0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04}},
|
||||||
|
{'w',{0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05}},
|
||||||
|
{'w',{0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06}},
|
||||||
|
{'w',{0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07}},
|
||||||
|
{'w',{0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08}},
|
||||||
|
{'w',{0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10}},
|
||||||
|
{'w',{0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18}},
|
||||||
|
{'w',{0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20}},
|
||||||
|
{'w',{0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28,0x28}},
|
||||||
|
{'w',{0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30}},
|
||||||
|
{'w',{0x38,0x38,0x38,0x38,0x38,0x38,0x38,0x38,0x38,0x38,0x38,0x38,0x38,0x38,0x38,0x38}},
|
||||||
|
{'w',{0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40}},
|
||||||
|
{'w',{0x48,0x48,0x48,0x48,0x48,0x48,0x48,0x48,0x48,0x48,0x48,0x48,0x48,0x48,0x48,0x48}},
|
||||||
|
{'w',{0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50,0x50}},
|
||||||
|
{'w',{0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58}},
|
||||||
|
{'w',{0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60}},
|
||||||
|
{'w',{0x68,0x68,0x68,0x68,0x68,0x68,0x68,0x68,0x68,0x68,0x68,0x68,0x68,0x68,0x68,0x68}},
|
||||||
|
{'w',{0x70,0x70,0x70,0x70,0x70,0x70,0x70,0x70,0x70,0x70,0x70,0x70,0x70,0x70,0x70,0x70}},
|
||||||
|
{'w',{0x78,0x78,0x78,0x78,0x78,0x78,0x78,0x78,0x78,0x78,0x78,0x78,0x78,0x78,0x78,0x78}},
|
||||||
|
{'w',{0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00}},
|
||||||
|
{'w',{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04}},
|
||||||
|
{'w',{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10}},
|
||||||
|
{'w',{0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff}},
|
||||||
|
{'w',{0x11,0x11,0x11,0x11,0x22,0x22,0x22,0x22,0x33,0x33,0x33,0x33,0x44,0x44,0x44,0x44}},
|
||||||
|
{'w',{0x88,0x88,0x88,0x88,0x77,0x77,0x77,0x77,0x66,0x66,0x66,0x66,0x55,0x55,0x55,0x55}},
|
||||||
|
{'w',{0x99,0x99,0x99,0x99,0xaa,0xaa,0xaa,0xaa,0xbb,0xbb,0xbb,0xbb,0xcc,0xcc,0xcc,0xcc}},
|
||||||
|
{'w',{0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xee,0xee,0xee,0xee,0xdd,0xdd,0xdd,0xdd}},
|
||||||
|
{'h',{0x00,0x00,0x11,0x11,0x22,0x22,0x33,0x33,0x44,0x44,0x55,0x55,0x66,0x66,0x77,0x77}},
|
||||||
|
{'h',{0x00,0x01,0x00,0x02,0x00,0x03,0x00,0x04,0x00,0x05,0x00,0x06,0x00,0x07,0x00,0x08}},
|
||||||
|
{'h',{0x00,0x16,0x00,0x15,0x00,0x14,0x00,0x13,0x00,0x12,0x00,0x10,0x00,0x10,0x00,0x09}},
|
||||||
|
{'b',{0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88,0x99,0xaa,0xbb,0xcc,0xdd,0xee,0xff}},
|
||||||
|
{'b',{0xff,0xee,0xdd,0xcc,0xbb,0xaa,0x99,0x88,0x77,0x66,0x55,0x44,0x33,0x22,0x11,0x00}},
|
||||||
|
{'b',{0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f}},
|
||||||
|
{'b',{0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f}},
|
||||||
|
{'b',{0x2f,0x2e,0x2d,0x2c,0x2b,0x2a,0x29,0x28,0x27,0x26,0x25,0x24,0x23,0x22,0x21,0x20}}
|
||||||
|
};
|
||||||
|
|
||||||
|
const powerpc_test_cpu::vector_value_t powerpc_test_cpu::vector_fp_values[] = {
|
||||||
|
{'f',{0x80,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x80,0x00,0x00,0x00}}, // -0, -0, -0, -0
|
||||||
|
{'f',{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}}, // 0, 0, 0, 0
|
||||||
|
{'f',{0xbf,0x80,0x00,0x00,0xbf,0x80,0x00,0x00,0xbf,0x80,0x00,0x00,0xbf,0x80,0x00,0x00}}, // -1, -1, -1, -1
|
||||||
|
{'f',{0x3f,0x80,0x00,0x00,0x3f,0x80,0x00,0x00,0x3f,0x80,0x00,0x00,0x3f,0x80,0x00,0x00}}, // 1, 1, 1, 1
|
||||||
|
{'f',{0xc0,0x00,0x00,0x00,0xc0,0x00,0x00,0x00,0xc0,0x00,0x00,0x00,0xc0,0x00,0x00,0x00}}, // -2, -2, -2, -2
|
||||||
|
{'f',{0x40,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x40,0x00,0x00,0x00}}, // 2, 2, 2, 2
|
||||||
|
{'f',{0xc0,0x00,0x00,0x00,0xbf,0x80,0x00,0x00,0x3f,0x80,0x00,0x00,0x40,0x00,0x00,0x00}}, // -2, -1, 1, 2
|
||||||
|
{'f',{0xc0,0x40,0x00,0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x40,0x00,0x00}}, // -3, -0, 0, 3
|
||||||
|
{'f',{0x40,0x00,0x00,0x00,0x3f,0x80,0x00,0x00,0xbf,0x80,0x00,0x00,0xc0,0x00,0x00,0x00}} // 2, 1, -1, -2
|
||||||
|
};
|
||||||
|
|
||||||
|
void powerpc_test_cpu::test_one_vector(uint32 *code, vector_test_t const & vt, uint8 *rAp, uint8 *rBp, uint8 *rCp)
|
||||||
|
{
|
||||||
|
#if TEST_VMX_OPS
|
||||||
|
static vector_t native_vD;
|
||||||
|
memset(&native_vD, 0, sizeof(native_vD));
|
||||||
|
static vector_helper_t native_vSCR;
|
||||||
|
memset(&native_vSCR, 0, sizeof(native_vSCR));
|
||||||
|
static vector_t dummy_vector;
|
||||||
|
if (!rAp) rAp = dummy_vector;
|
||||||
|
if (!rBp) rBp = dummy_vector;
|
||||||
|
if (!rCp) rCp = dummy_vector;
|
||||||
|
#if defined(__powerpc__)
|
||||||
|
// Invoke native code
|
||||||
|
const uint32 save_cr = native_get_cr();
|
||||||
|
native_set_cr(init_cr);
|
||||||
|
native_vSCR.w[3] = 0;
|
||||||
|
typedef void (*func_t)(uint8 *, uint8 *, uint8 *, uint8 *, uint8 *);
|
||||||
|
func_t func = (func_t)code;
|
||||||
|
func((uint8 *)&native_vD, rAp, rBp, rCp, native_vSCR.b);
|
||||||
|
const uint32 native_cr = native_get_cr();
|
||||||
|
const uint32 native_vscr = native_vSCR.w[3];
|
||||||
|
native_set_cr(save_cr);
|
||||||
|
if (results_file) {
|
||||||
|
put_vector(native_vD);
|
||||||
|
put32(native_cr);
|
||||||
|
put32(native_vscr);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
get_vector(native_vD);
|
||||||
|
const uint32 native_cr = get32();
|
||||||
|
const uint32 native_vscr = get32();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Invoke emulated code
|
||||||
|
static vector_t emul_vD;
|
||||||
|
memset(&emul_vD, 0, sizeof(emul_vD));
|
||||||
|
static vector_helper_t emul_vSCR;
|
||||||
|
memset(&emul_vSCR, 0, sizeof(emul_vSCR));
|
||||||
|
emul_vSCR.w[3] = 0;
|
||||||
|
emul_set_cr(init_cr);
|
||||||
|
set_gpr(RD, (uintptr)&emul_vD);
|
||||||
|
set_gpr(RA, (uintptr)rAp);
|
||||||
|
set_gpr(RB, (uintptr)rBp);
|
||||||
|
set_gpr(RC, (uintptr)rCp);
|
||||||
|
set_gpr(VSCR, (uintptr)emul_vSCR.b);
|
||||||
|
execute(code);
|
||||||
|
const uint32 emul_cr = emul_get_cr();
|
||||||
|
const uint32 emul_vscr = ntohl(emul_vSCR.w[3]);
|
||||||
|
|
||||||
|
++tests;
|
||||||
|
|
||||||
|
bool ok = vector_equals(vt.type, native_vD, emul_vD)
|
||||||
|
&& native_cr == emul_cr
|
||||||
|
&& native_vscr == emul_vscr;
|
||||||
|
|
||||||
|
if (!ok) {
|
||||||
|
printf("FAIL: %s [%08x]\n", vt.name, vt.opcode);
|
||||||
|
errors++;
|
||||||
|
}
|
||||||
|
else if (verbose) {
|
||||||
|
printf("PASS: %s [%08x]\n", vt.name, vt.opcode);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ok || verbose) {
|
||||||
|
#if ENABLE_MON
|
||||||
|
disass_ppc(stdout, (uintptr)code, vt.opcode);
|
||||||
|
#endif
|
||||||
|
char op_type = tolower(vt.op_type);
|
||||||
|
if (!op_type)
|
||||||
|
op_type = vt.type;
|
||||||
|
#define PRINT_OPERAND(N, vX, rX) \
|
||||||
|
switch (vt.operands[N]) { \
|
||||||
|
case vX: \
|
||||||
|
printf(#vX " = "); \
|
||||||
|
print_vector(*((vector_t *)rX##p)); \
|
||||||
|
printf("\n"); \
|
||||||
|
break; \
|
||||||
|
case vI: \
|
||||||
|
case vN: \
|
||||||
|
printf(#vX " = %d\n", vX##_field::extract(vt.opcode)); \
|
||||||
|
break; \
|
||||||
|
case rX: \
|
||||||
|
printf(#rX " = %08x", rX##p); \
|
||||||
|
if (rX##p) switch (op_type) { \
|
||||||
|
case 'b': printf(" [%02x]", *rX##p); break; \
|
||||||
|
case 'h': printf(" [%04x]", *((uint16 *)rX##p)); break; \
|
||||||
|
case 'w': printf(" [%08x]", *((uint32 *)rX##p)); break; \
|
||||||
|
} \
|
||||||
|
printf("\n"); \
|
||||||
|
break; \
|
||||||
|
}
|
||||||
|
PRINT_OPERAND(1, vA, rA);
|
||||||
|
PRINT_OPERAND(2, vB, rB);
|
||||||
|
PRINT_OPERAND(3, vC, rC);
|
||||||
|
#undef PRINT_OPERAND
|
||||||
|
printf("vD.N = ");
|
||||||
|
print_vector(native_vD, vt.type);
|
||||||
|
printf("\n");
|
||||||
|
printf("vD.E = ");
|
||||||
|
print_vector(emul_vD, vt.type);
|
||||||
|
printf("\n");
|
||||||
|
printf("CR.N = %08x ; VSCR.N = %08x\n", native_cr, native_vscr);
|
||||||
|
printf("CR.E = %08x ; VSCR.E = %08x\n", emul_cr, emul_vscr);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void powerpc_test_cpu::test_vector_load(void)
|
||||||
|
{
|
||||||
|
#if TEST_VMX_LOAD
|
||||||
|
// Tested instructions
|
||||||
|
static const vector_test_t tests[] = {
|
||||||
|
{ "lvebx", 'b', 0, _X (31,00,00,00, 7,0), { vD, rA, rB } },
|
||||||
|
{ "lvehx", 'h', 0, _X (31,00,00,00, 39,0), { vD, rA, rB } },
|
||||||
|
{ "lvewx", 'w', 0, _X (31,00,00,00, 71,0), { vD, rA, rB } }
|
||||||
|
};
|
||||||
|
|
||||||
|
// Code template
|
||||||
|
static uint32 code[] = {
|
||||||
|
POWERPC_MFSPR(12, 256), // mfvrsave r12
|
||||||
|
_D(15,0,0,0x1000), // lis r0,0x1000 ([v3])
|
||||||
|
POWERPC_MTSPR(0, 256), // mtvrsave r0
|
||||||
|
POWERPC_LVX(RD, 0, RD), // lvx v3,r3(0)
|
||||||
|
0, // <insn>
|
||||||
|
POWERPC_STVX(RD, 0, RD), // stvx v3,r3(0)
|
||||||
|
POWERPC_MTSPR(12, 256), // mtvrsave r12
|
||||||
|
POWERPC_BLR // blr
|
||||||
|
};
|
||||||
|
|
||||||
|
int i_opcode = -1;
|
||||||
|
const int n_instructions = sizeof(code) / sizeof(code[0]);
|
||||||
|
for (int i = 0; i < n_instructions; i++) {
|
||||||
|
if (code[i] == 0) {
|
||||||
|
i_opcode = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert(i_opcode != -1);
|
||||||
|
|
||||||
|
const int n_elements = sizeof(tests) / sizeof(tests[0]);
|
||||||
|
for (int i = 0; i < n_elements; i++) {
|
||||||
|
vector_test_t const & vt = tests[i];
|
||||||
|
code[i_opcode] = vt.opcode;
|
||||||
|
vD_field::insert(code[i_opcode], RD);
|
||||||
|
rA_field::insert(code[i_opcode], 00);
|
||||||
|
rB_field::insert(code[i_opcode], RA);
|
||||||
|
flush_icache_range(code, sizeof(code));
|
||||||
|
|
||||||
|
printf("Testing %s\n", vt.name);
|
||||||
|
const int n_vector_values = sizeof(vector_values)/sizeof(vector_values[0]);
|
||||||
|
for (int j = 0; j < n_vector_values; j++) {
|
||||||
|
switch (vt.type) {
|
||||||
|
case 'b':
|
||||||
|
for (int k = 0; k < 16; k++)
|
||||||
|
test_one_vector(code, vt, ((uint8 *)&vector_values[j].v) + 1 * k);
|
||||||
|
break;
|
||||||
|
case 'h':
|
||||||
|
for (int k = 0; k < 8; k++)
|
||||||
|
test_one_vector(code, vt, ((uint8 *)&vector_values[j].v) + 2 * k);
|
||||||
|
break;
|
||||||
|
case 'w':
|
||||||
|
for (int k = 0; k < 4; k++)
|
||||||
|
test_one_vector(code, vt, ((uint8 *)&vector_values[j].v) + 4 * k);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void powerpc_test_cpu::test_vector_arith(void)
|
||||||
|
{
|
||||||
|
#if TEST_VMX_ARITH
|
||||||
|
// Tested instructions
|
||||||
|
static const vector_test_t tests[] = {
|
||||||
|
{ "vaddcuw", 'w', 0 , _VX(04,RD,RA,RB, 384), { vD, vA, vB } },
|
||||||
|
{ "vaddfp", 'f', 0 , _VX(04,RD,RA,RB, 10), { vD, vA, vB } },
|
||||||
|
{ "vaddsbs", 'b', 0 , _VX(04,RD,RA,RB, 768), { vD, vA, vB } },
|
||||||
|
{ "vaddshs", 'h', 0 , _VX(04,RD,RA,RB, 832), { vD, vA, vB } },
|
||||||
|
{ "vaddsws", 'w', 0 , _VX(04,RD,RA,RB, 896), { vD, vA, vB } },
|
||||||
|
{ "vaddubm", 'b', 0 , _VX(04,RD,RA,RB, 0), { vD, vA, vB } },
|
||||||
|
{ "vaddubs", 'b', 0 , _VX(04,RD,RA,RB, 512), { vD, vA, vB } },
|
||||||
|
{ "vadduhm", 'h', 0 , _VX(04,RD,RA,RB, 64), { vD, vA, vB } },
|
||||||
|
{ "vadduhs", 'h', 0 , _VX(04,RD,RA,RB, 576), { vD, vA, vB } },
|
||||||
|
{ "vadduwm", 'w', 0 , _VX(04,RD,RA,RB, 128), { vD, vA, vB } },
|
||||||
|
{ "vadduws", 'w', 0 , _VX(04,RD,RA,RB, 640), { vD, vA, vB } },
|
||||||
|
{ "vand", 'w', 0 , _VX(04,RD,RA,RB,1028), { vD, vA, vB } },
|
||||||
|
{ "vandc", 'w', 0 , _VX(04,RD,RA,RB,1092), { vD, vA, vB } },
|
||||||
|
{ "vavgsb", 'b', 0 , _VX(04,RD,RA,RB,1282), { vD, vA, vB } },
|
||||||
|
{ "vavgsh", 'h', 0 , _VX(04,RD,RA,RB,1346), { vD, vA, vB } },
|
||||||
|
{ "vavgsw", 'w', 0 , _VX(04,RD,RA,RB,1410), { vD, vA, vB } },
|
||||||
|
{ "vavgub", 'b', 0 , _VX(04,RD,RA,RB,1026), { vD, vA, vB } },
|
||||||
|
{ "vavguh", 'h', 0 , _VX(04,RD,RA,RB,1090), { vD, vA, vB } },
|
||||||
|
{ "vavguw", 'w', 0 , _VX(04,RD,RA,RB,1154), { vD, vA, vB } },
|
||||||
|
{ "vcfsx", 'f', 'w', _VX(04,RD,00,RB, 842), { vD, vI, vB } },
|
||||||
|
{ "vcfux", 'f', 'w', _VX(04,RD,00,RB, 778), { vD, vI, vB } },
|
||||||
|
{ "vcmpbfp", 'w', 'f', _VXR(04,RD,RA,RB,966,0), { vD, vA, vB } },
|
||||||
|
{ "vcmpbfp.", 'w', 'f', _VXR(04,RD,RA,RB,966,1), { vD, vA, vB } },
|
||||||
|
{ "vcmpeqfp", 'w', 'f', _VXR(04,RD,RA,RB,198,0), { vD, vA, vB } },
|
||||||
|
{ "vcmpeqfp.", 'w', 'f', _VXR(04,RD,RA,RB,198,1), { vD, vA, vB } },
|
||||||
|
{ "vcmpequb", 'b', 0 , _VXR(04,RD,RA,RB, 6,0), { vD, vA, vB } },
|
||||||
|
{ "vcmpequb.", 'b', 0 , _VXR(04,RD,RA,RB, 6,1), { vD, vA, vB } },
|
||||||
|
{ "vcmpequh", 'h', 0 , _VXR(04,RD,RA,RB, 70,0), { vD, vA, vB } },
|
||||||
|
{ "vcmpequh.", 'h', 0 , _VXR(04,RD,RA,RB, 70,1), { vD, vA, vB } },
|
||||||
|
{ "vcmpequw", 'w', 0 , _VXR(04,RD,RA,RB,134,0), { vD, vA, vB } },
|
||||||
|
{ "vcmpequw.", 'w', 0 , _VXR(04,RD,RA,RB,134,1), { vD, vA, vB } },
|
||||||
|
{ "vcmpgefp", 'w', 'f', _VXR(04,RD,RA,RB,454,0), { vD, vA, vB } },
|
||||||
|
{ "vcmpgefp.", 'w', 'f', _VXR(04,RD,RA,RB,454,1), { vD, vA, vB } },
|
||||||
|
{ "vcmpgtfp", 'w', 'f', _VXR(04,RD,RA,RB,710,0), { vD, vA, vB } },
|
||||||
|
{ "vcmpgtfp.", 'w', 'f', _VXR(04,RD,RA,RB,710,1), { vD, vA, vB } },
|
||||||
|
{ "vcmpgtsb", 'b', 0 , _VXR(04,RD,RA,RB,774,0), { vD, vA, vB } },
|
||||||
|
{ "vcmpgtsb.", 'b', 0 , _VXR(04,RD,RA,RB,774,1), { vD, vA, vB } },
|
||||||
|
{ "vcmpgtsh", 'h', 0 , _VXR(04,RD,RA,RB,838,0), { vD, vA, vB } },
|
||||||
|
{ "vcmpgtsh.", 'h', 0 , _VXR(04,RD,RA,RB,838,1), { vD, vA, vB } },
|
||||||
|
{ "vcmpgtsw", 'w', 0 , _VXR(04,RD,RA,RB,902,0), { vD, vA, vB } },
|
||||||
|
{ "vcmpgtsw.", 'w', 0 , _VXR(04,RD,RA,RB,902,1), { vD, vA, vB } },
|
||||||
|
{ "vcmpgtub", 'b', 0 , _VXR(04,RD,RA,RB,518,0), { vD, vA, vB } },
|
||||||
|
{ "vcmpgtub.", 'b', 0 , _VXR(04,RD,RA,RB,518,1), { vD, vA, vB } },
|
||||||
|
{ "vcmpgtuh", 'h', 0 , _VXR(04,RD,RA,RB,582,0), { vD, vA, vB } },
|
||||||
|
{ "vcmpgtuh.", 'h', 0 , _VXR(04,RD,RA,RB,582,1), { vD, vA, vB } },
|
||||||
|
{ "vcmpgtuw", 'w', 0 , _VXR(04,RD,RA,RB,646,0), { vD, vA, vB } },
|
||||||
|
{ "vcmpgtuw.", 'w', 0 , _VXR(04,RD,RA,RB,646,1), { vD, vA, vB } },
|
||||||
|
{ "vctsxs", 'w', 'f', _VX(04,RD,00,RB, 970), { vD, vI, vB } },
|
||||||
|
{ "vctuxs", 'w', 'f', _VX(04,RD,00,RB, 906), { vD, vI, vB } },
|
||||||
|
{ "vexptefp", 'f', 0 , _VX(04,RD,00,RB, 394), { vD, __, vB } },
|
||||||
|
{ "vlogefp", 'l', 'f', _VX(04,RD,00,RB, 458), { vD, __, vB } },
|
||||||
|
{ "vmaddfp", 'f', 0 , _VA(04,RD,RA,RB,RC,46),{ vD, vA, vB, vC } },
|
||||||
|
{ "vmaxfp", 'f', 0 , _VX(04,RD,RA,RB,1034), { vD, vA, vB } },
|
||||||
|
{ "vmaxsb", 'b', 0 , _VX(04,RD,RA,RB, 258), { vD, vA, vB } },
|
||||||
|
{ "vmaxsh", 'h', 0 , _VX(04,RD,RA,RB, 322), { vD, vA, vB } },
|
||||||
|
{ "vmaxsw", 'w', 0 , _VX(04,RD,RA,RB, 386), { vD, vA, vB } },
|
||||||
|
{ "vmaxub", 'b', 0 , _VX(04,RD,RA,RB, 2), { vD, vA, vB } },
|
||||||
|
{ "vmaxuh", 'h', 0 , _VX(04,RD,RA,RB, 66), { vD, vA, vB } },
|
||||||
|
{ "vmaxuw", 'w', 0 , _VX(04,RD,RA,RB, 130), { vD, vA, vB } },
|
||||||
|
{ "vmhaddshs", 'h', 0 , _VA(04,RD,RA,RB,RC,32),{ vD, vA, vB, vC } },
|
||||||
|
{ "vmhraddshs", 'h', 0 , _VA(04,RD,RA,RB,RC,33),{ vD, vA, vB, vC } },
|
||||||
|
{ "vminfp", 'f', 0 , _VX(04,RD,RA,RB,1098), { vD, vA, vB } },
|
||||||
|
{ "vminsb", 'b', 0 , _VX(04,RD,RA,RB, 770), { vD, vA, vB } },
|
||||||
|
{ "vminsh", 'h', 0 , _VX(04,RD,RA,RB, 834), { vD, vA, vB } },
|
||||||
|
{ "vminsw", 'w', 0 , _VX(04,RD,RA,RB, 898), { vD, vA, vB } },
|
||||||
|
{ "vminub", 'b', 0 , _VX(04,RD,RA,RB, 514), { vD, vA, vB } },
|
||||||
|
{ "vminuh", 'h', 0 , _VX(04,RD,RA,RB, 578), { vD, vA, vB } },
|
||||||
|
{ "vminuw", 'w', 0 , _VX(04,RD,RA,RB, 642), { vD, vA, vB } },
|
||||||
|
{ "vmladduhm", 'h', 0 , _VA(04,RD,RA,RB,RC,34),{ vD, vA, vB, vC } },
|
||||||
|
{ "vmrghb", 'b', 0 , _VX(04,RD,RA,RB, 12), { vD, vA, vB } },
|
||||||
|
{ "vmrghh", 'h', 0 , _VX(04,RD,RA,RB, 76), { vD, vA, vB } },
|
||||||
|
{ "vmrghw", 'w', 0 , _VX(04,RD,RA,RB, 140), { vD, vA, vB } },
|
||||||
|
{ "vmrglb", 'b', 0 , _VX(04,RD,RA,RB, 268), { vD, vA, vB } },
|
||||||
|
{ "vmrglh", 'h', 0 , _VX(04,RD,RA,RB, 332), { vD, vA, vB } },
|
||||||
|
{ "vmrglw", 'w', 0 , _VX(04,RD,RA,RB, 396), { vD, vA, vB } },
|
||||||
|
{ "vmsummbm", 'b', 0 , _VA(04,RD,RA,RB,RC,37),{ vD, vA, vB, vC } },
|
||||||
|
{ "vmsumshm", 'h', 0 , _VA(04,RD,RA,RB,RC,40),{ vD, vA, vB, vC } },
|
||||||
|
{ "vmsumshs", 'h', 0 , _VA(04,RD,RA,RB,RC,41),{ vD, vA, vB, vC } },
|
||||||
|
{ "vmsumubm", 'b', 0 , _VA(04,RD,RA,RB,RC,36),{ vD, vA, vB, vC } },
|
||||||
|
{ "vmsumuhm", 'h', 0 , _VA(04,RD,RA,RB,RC,38),{ vD, vA, vB, vC } },
|
||||||
|
{ "vmsumuhs", 'h', 0 , _VA(04,RD,RA,RB,RC,39),{ vD, vA, vB, vC } },
|
||||||
|
{ "vmulesb", 'b', 0 , _VX(04,RD,RA,RB, 776), { vD, vA, vB } },
|
||||||
|
{ "vmulesh", 'h', 0 , _VX(04,RD,RA,RB, 840), { vD, vA, vB } },
|
||||||
|
{ "vmuleub", 'b', 0 , _VX(04,RD,RA,RB, 520), { vD, vA, vB } },
|
||||||
|
{ "vmuleuh", 'h', 0 , _VX(04,RD,RA,RB, 584), { vD, vA, vB } },
|
||||||
|
{ "vmulosb", 'b', 0 , _VX(04,RD,RA,RB, 264), { vD, vA, vB } },
|
||||||
|
{ "vmulosh", 'h', 0 , _VX(04,RD,RA,RB, 328), { vD, vA, vB } },
|
||||||
|
{ "vmuloub", 'b', 0 , _VX(04,RD,RA,RB, 8), { vD, vA, vB } },
|
||||||
|
{ "vmulouh", 'h', 0 , _VX(04,RD,RA,RB, 72), { vD, vA, vB } },
|
||||||
|
{ "vnmsubfp", 'f', 0 , _VA(04,RD,RA,RB,RC,47),{ vD, vA, vB, vC } },
|
||||||
|
{ "vnor", 'w', 0 , _VX(04,RD,RA,RB,1284), { vD, vA, vB } },
|
||||||
|
{ "vor", 'w', 0 , _VX(04,RD,RA,RB,1156), { vD, vA, vB } },
|
||||||
|
{ "vperm", 'b', 0 , _VA(04,RD,RA,RB,RC,43),{ vD, vA, vB, vC } },
|
||||||
|
{ "vpkpx", 'h', 0 , _VX(04,RD,RA,RB, 782), { vD, vA, vB } },
|
||||||
|
{ "vpkshss", 'b', 0 , _VX(04,RD,RA,RB, 398), { vD, vA, vB } },
|
||||||
|
{ "vpkshus", 'b', 0 , _VX(04,RD,RA,RB, 270), { vD, vA, vB } },
|
||||||
|
{ "vpkswss", 'h', 0 , _VX(04,RD,RA,RB, 462), { vD, vA, vB } },
|
||||||
|
{ "vpkswus", 'h', 0 , _VX(04,RD,RA,RB, 334), { vD, vA, vB } },
|
||||||
|
{ "vpkuhum", 'b', 0 , _VX(04,RD,RA,RB, 14), { vD, vA, vB } },
|
||||||
|
{ "vpkuhus", 'b', 0 , _VX(04,RD,RA,RB, 142), { vD, vA, vB } },
|
||||||
|
{ "vpkuwum", 'h', 0 , _VX(04,RD,RA,RB, 78), { vD, vA, vB } },
|
||||||
|
{ "vpkuwus", 'h', 0 , _VX(04,RD,RA,RB, 206), { vD, vA, vB } },
|
||||||
|
{ "vrefp", 'e', 'f', _VX(04,RD,00,RB, 266), { vD, __, vB } },
|
||||||
|
{ "vrfim", 'f', 0 , _VX(04,RD,00,RB, 714), { vD, __, vB } },
|
||||||
|
{ "vrfin", 'f', 0 , _VX(04,RD,00,RB, 522), { vD, __, vB } },
|
||||||
|
{ "vrfip", 'f', 0 , _VX(04,RD,00,RB, 650), { vD, __, vB } },
|
||||||
|
{ "vrfiz", 'f', 0 , _VX(04,RD,00,RB, 586), { vD, __, vB } },
|
||||||
|
{ "vrlb", 'b', 0 , _VX(04,RD,RA,RB, 4), { vD, vA, vB } },
|
||||||
|
{ "vrlh", 'h', 0 , _VX(04,RD,RA,RB, 68), { vD, vA, vB } },
|
||||||
|
{ "vrlw", 'w', 0 , _VX(04,RD,RA,RB, 132), { vD, vA, vB } },
|
||||||
|
{ "vrsqrtefp", 'e', 'f', _VX(04,RD,00,RB, 330), { vD, __, vB } },
|
||||||
|
{ "vsel", 'b', 0 , _VA(04,RD,RA,RB,RC,42),{ vD, vA, vB, vC } },
|
||||||
|
{ "vsl", 'b', 'B', _VX(04,RD,RA,RB, 452), { vD, vA, vB } },
|
||||||
|
{ "vslb", 'b', 0 , _VX(04,RD,RA,RB, 260), { vD, vA, vB } },
|
||||||
|
{ "vsldoi", 'b', 0 , _VA(04,RD,RA,RB,00,44),{ vD, vA, vB, vI } },
|
||||||
|
{ "vslh", 'h', 0 , _VX(04,RD,RA,RB, 324), { vD, vA, vB } },
|
||||||
|
{ "vslo", 'b', 0 , _VX(04,RD,RA,RB,1036), { vD, vA, vB } },
|
||||||
|
{ "vslw", 'w', 0 , _VX(04,RD,RA,RB, 388), { vD, vA, vB } },
|
||||||
|
{ "vspltb", 'b', 0 , _VX(04,RD,00,RB, 524), { vD, vI, vB } },
|
||||||
|
{ "vsplth", 'h', 0 , _VX(04,RD,00,RB, 588), { vD, vI, vB } },
|
||||||
|
{ "vspltisb", 'b', 0 , _VX(04,RD,00,00, 780), { vD, vI } },
|
||||||
|
{ "vspltish", 'h', 0 , _VX(04,RD,00,00, 844), { vD, vI } },
|
||||||
|
{ "vspltisw", 'w', 0 , _VX(04,RD,00,00, 908), { vD, vI } },
|
||||||
|
{ "vspltw", 'w', 0 , _VX(04,RD,00,RB, 652), { vD, vI, vB } },
|
||||||
|
{ "vsr", 'b', 'B', _VX(04,RD,RA,RB, 708), { vD, vA, vB } },
|
||||||
|
{ "vsrab", 'b', 0 , _VX(04,RD,RA,RB, 772), { vD, vA, vB } },
|
||||||
|
{ "vsrah", 'h', 0 , _VX(04,RD,RA,RB, 836), { vD, vA, vB } },
|
||||||
|
{ "vsraw", 'w', 0 , _VX(04,RD,RA,RB, 900), { vD, vA, vB } },
|
||||||
|
{ "vsrb", 'b', 0 , _VX(04,RD,RA,RB, 516), { vD, vA, vB } },
|
||||||
|
{ "vsrh", 'h', 0 , _VX(04,RD,RA,RB, 580), { vD, vA, vB } },
|
||||||
|
{ "vsro", 'b', 0 , _VX(04,RD,RA,RB,1100), { vD, vA, vB } },
|
||||||
|
{ "vsrw", 'w', 0 , _VX(04,RD,RA,RB, 644), { vD, vA, vB } },
|
||||||
|
{ "vsubcuw", 'w', 0 , _VX(04,RD,RA,RB,1408), { vD, vA, vB } },
|
||||||
|
{ "vsubfp", 'f', 0 , _VX(04,RD,RA,RB, 74), { vD, vA, vB } },
|
||||||
|
{ "vsubsbs", 'b', 0 , _VX(04,RD,RA,RB,1792), { vD, vA, vB } },
|
||||||
|
{ "vsubshs", 'h', 0 , _VX(04,RD,RA,RB,1856), { vD, vA, vB } },
|
||||||
|
{ "vsubsws", 'w', 0 , _VX(04,RD,RA,RB,1920), { vD, vA, vB } },
|
||||||
|
{ "vsububm", 'b', 0 , _VX(04,RD,RA,RB,1024), { vD, vA, vB } },
|
||||||
|
{ "vsububs", 'b', 0 , _VX(04,RD,RA,RB,1536), { vD, vA, vB } },
|
||||||
|
{ "vsubuhm", 'h', 0 , _VX(04,RD,RA,RB,1088), { vD, vA, vB } },
|
||||||
|
{ "vsubuhs", 'h', 0 , _VX(04,RD,RA,RB,1600), { vD, vA, vB } },
|
||||||
|
{ "vsubuwm", 'w', 0 , _VX(04,RD,RA,RB,1152), { vD, vA, vB } },
|
||||||
|
{ "vsubuws", 'w', 0 , _VX(04,RD,RA,RB,1664), { vD, vA, vB } },
|
||||||
|
{ "vsum2sws", 'w', 0 , _VX(04,RD,RA,RB,1672), { vD, vA, vB } },
|
||||||
|
{ "vsum4sbs", 'w', 0 , _VX(04,RD,RA,RB,1800), { vD, vA, vB } },
|
||||||
|
{ "vsum4shs", 'w', 0 , _VX(04,RD,RA,RB,1608), { vD, vA, vB } },
|
||||||
|
{ "vsum4ubs", 'w', 0 , _VX(04,RD,RA,RB,1544), { vD, vA, vB } },
|
||||||
|
{ "vsumsws", 'w', 0 , _VX(04,RD,RA,RB,1928), { vD, vA, vB } },
|
||||||
|
{ "vupkhpx", 'w', 0 , _VX(04,RD,00,RB, 846), { vD, __, vB } },
|
||||||
|
{ "vupkhsb", 'h', 0 , _VX(04,RD,00,RB, 526), { vD, __, vB } },
|
||||||
|
{ "vupkhsh", 'w', 0 , _VX(04,RD,00,RB, 590), { vD, __, vB } },
|
||||||
|
{ "vupklpx", 'w', 0 , _VX(04,RD,00,RB, 974), { vD, __, vB } },
|
||||||
|
{ "vupklsb", 'h', 0 , _VX(04,RD,00,RB, 654), { vD, __, vB } },
|
||||||
|
{ "vupklsh", 'w', 0 , _VX(04,RD,00,RB, 718), { vD, __, vB } },
|
||||||
|
{ "vxor", 'w', 0 , _VX(04,RD,RA,RB,1220), { vD, vA, vB } },
|
||||||
|
};
|
||||||
|
|
||||||
|
// Code template
|
||||||
|
static uint32 code[] = {
|
||||||
|
POWERPC_MFSPR(12, 256), // mfvrsave r12
|
||||||
|
_D(15,0,0,0x1e00), // lis r0,0x9e00 ([v0;v3-v6])
|
||||||
|
POWERPC_MTSPR(0, 256), // mtvrsave r0
|
||||||
|
POWERPC_LVX(RA, 0, RA), // lvx v4,r4(0)
|
||||||
|
POWERPC_LVX(RB, 0, RB), // lvx v5,r5(0)
|
||||||
|
POWERPC_LVX(RC, 0, RC), // lvx v6,r6(0)
|
||||||
|
POWERPC_LVX(0, 0, VSCR), // lvx v0,r7(0)
|
||||||
|
_VX(04,00,00,00,1604), // mtvscr v0
|
||||||
|
0, // <op> v3,v4,v5
|
||||||
|
_VX(04,00,00,00,1540), // mfvscr v0
|
||||||
|
POWERPC_STVX(0, 0, VSCR), // stvx v0,r7(0)
|
||||||
|
POWERPC_STVX(RD, 0, RD), // stvx v3,r3(0)
|
||||||
|
POWERPC_MTSPR(12, 256), // mtvrsave r12
|
||||||
|
POWERPC_BLR // blr
|
||||||
|
};
|
||||||
|
|
||||||
|
int i_opcode = -1;
|
||||||
|
const int n_instructions = sizeof(code) / sizeof(code[0]);
|
||||||
|
for (int i = 0; i < n_instructions; i++) {
|
||||||
|
if (code[i] == 0) {
|
||||||
|
i_opcode = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert(i_opcode != -1);
|
||||||
|
|
||||||
|
const int n_elements = sizeof(tests) / sizeof(tests[0]);
|
||||||
|
for (int n = 0; n < n_elements; n++) {
|
||||||
|
vector_test_t vt = tests[n];
|
||||||
|
code[i_opcode] = vt.opcode;
|
||||||
|
flush_icache_range(code, sizeof(code));
|
||||||
|
|
||||||
|
// Operand type
|
||||||
|
char op_type = vt.op_type;
|
||||||
|
if (!op_type)
|
||||||
|
op_type = vt.type;
|
||||||
|
|
||||||
|
// Operand values
|
||||||
|
int n_vector_values;
|
||||||
|
const vector_value_t *vvp;
|
||||||
|
if (op_type == 'f') {
|
||||||
|
n_vector_values = sizeof(vector_fp_values)/sizeof(vector_fp_values[0]);
|
||||||
|
vvp = vector_fp_values;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
n_vector_values = sizeof(vector_values)/sizeof(vector_values[0]);
|
||||||
|
vvp = vector_values;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("Testing %s\n", vt.name);
|
||||||
|
if (vt.operands[1] == vA && vt.operands[2] == vB && vt.operands[3] == vC) {
|
||||||
|
for (int i = 0; i < n_vector_values; i++)
|
||||||
|
for (int j = 0; j < n_vector_values; j++)
|
||||||
|
for (int k = 0; k < n_vector_values; k++)
|
||||||
|
test_one_vector(code, vt, &vvp[i].v, &vvp[j].v, &vvp[k].v);
|
||||||
|
}
|
||||||
|
else if (vt.operands[1] == vA && vt.operands[2] == vB && vt.operands[3] == vN) {
|
||||||
|
for (int i = 0; i < 16; i++) {
|
||||||
|
vSH_field::insert(vt.opcode, i);
|
||||||
|
code[i_opcode] = vt.opcode;
|
||||||
|
flush_icache_range(code, sizeof(code));
|
||||||
|
for (int j = 0; j < n_vector_values; j++)
|
||||||
|
for (int k = 0; k < n_vector_values; k++)
|
||||||
|
test_one_vector(code, vt, &vvp[i].v, &vvp[j].v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (vt.operands[1] == vA && vt.operands[2] == vB) {
|
||||||
|
for (int i = 0; i < n_vector_values; i++) {
|
||||||
|
for (int j = 0; j < n_vector_values; j++) {
|
||||||
|
if (op_type == 'B') {
|
||||||
|
if (!vector_all_eq('b', vvp[j].v))
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
test_one_vector(code, vt, &vvp[i].v, &vvp[j].v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (vt.operands[1] == vI && vt.operands[2] == vB) {
|
||||||
|
for (int i = 0; i < 32; i++) {
|
||||||
|
rA_field::insert(vt.opcode, i);
|
||||||
|
code[i_opcode] = vt.opcode;
|
||||||
|
flush_icache_range(code, sizeof(code));
|
||||||
|
for (int j = 0; j < n_vector_values; j++)
|
||||||
|
test_one_vector(code, vt, NULL, &vvp[j].v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (vt.operands[1] == vI) {
|
||||||
|
for (int i = 0; i < 32; i++) {
|
||||||
|
rA_field::insert(vt.opcode, i);
|
||||||
|
code[i_opcode] = vt.opcode;
|
||||||
|
flush_icache_range(code, sizeof(code));
|
||||||
|
test_one_vector(code, vt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (vt.operands[1] == __ && vt.operands[2] == vB) {
|
||||||
|
for (int i = 0; i < n_vector_values; i++)
|
||||||
|
test_one_vector(code, vt, NULL, &vvp[i].v);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
printf("ERROR: unhandled test case\n");
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
// Illegal handler to catch out AltiVec instruction
|
||||||
|
#if defined(__powerpc__)
|
||||||
|
static sigjmp_buf env;
|
||||||
|
|
||||||
|
static void sigill_handler(int sig)
|
||||||
|
{
|
||||||
|
has_altivec = false;
|
||||||
|
siglongjmp(env, 1);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
bool powerpc_test_cpu::test(void)
|
bool powerpc_test_cpu::test(void)
|
||||||
{
|
{
|
||||||
// Tests initialization
|
// Tests initialization
|
||||||
tests = errors = 0;
|
tests = errors = 0;
|
||||||
init_cr = init_xer = 0;
|
init_cr = init_xer = 0;
|
||||||
|
|
||||||
// Execution tests
|
// Execution ALU tests
|
||||||
|
#if TEST_ALU_OPS
|
||||||
test_add();
|
test_add();
|
||||||
test_sub();
|
test_sub();
|
||||||
test_mul();
|
test_mul();
|
||||||
@ -1281,6 +1990,15 @@ bool powerpc_test_cpu::test(void)
|
|||||||
test_logical();
|
test_logical();
|
||||||
test_compare();
|
test_compare();
|
||||||
test_cr_logical();
|
test_cr_logical();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Execute VMX tests
|
||||||
|
#if TEST_VMX_OPS
|
||||||
|
if (has_altivec) {
|
||||||
|
test_vector_load();
|
||||||
|
test_vector_arith();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
printf("%u errors out of %u tests\n", errors, tests);
|
printf("%u errors out of %u tests\n", errors, tests);
|
||||||
return errors != 0;
|
return errors != 0;
|
||||||
@ -1319,6 +2037,15 @@ int main(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Check if host CPU supports AltiVec instructions
|
||||||
|
has_altivec = true;
|
||||||
|
#if defined(__powerpc__)
|
||||||
|
signal(SIGILL, sigill_handler);
|
||||||
|
if (!sigsetjmp(env, 1))
|
||||||
|
asm volatile(".long 0x10000484"); // vor v0,v0,v0
|
||||||
|
signal(SIGILL, SIG_DFL);
|
||||||
|
#endif
|
||||||
|
|
||||||
int ret = ppc.test();
|
int ret = ppc.test();
|
||||||
if (fp) fclose(fp);
|
if (fp) fclose(fp);
|
||||||
return !ret;
|
return !ret;
|
||||||
|
Loading…
Reference in New Issue
Block a user