mirror of
https://github.com/kanjitalk755/macemu.git
synced 2025-02-19 19:30:42 +00:00
Align PowerPC registers struct manually, i.e. don't depend on non-portable
compiler extensions (e.g. GCC __attribute__((aligned(N)))).
This commit is contained in:
parent
d8aa8a7459
commit
dd2b9a95d5
@ -177,50 +177,8 @@ public:
|
|||||||
|
|
||||||
// Make sure the SIGSEGV handler can access CPU registers
|
// Make sure the SIGSEGV handler can access CPU registers
|
||||||
friend sigsegv_return_t sigsegv_handler(sigsegv_address_t, sigsegv_address_t);
|
friend sigsegv_return_t sigsegv_handler(sigsegv_address_t, sigsegv_address_t);
|
||||||
|
|
||||||
// Memory allocator returning areas aligned on 16-byte boundaries
|
|
||||||
void *operator new(size_t size);
|
|
||||||
void operator delete(void *p);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Memory allocator returning sheepshaver_cpu objects aligned on 16-byte boundaries
|
|
||||||
// FORMAT: [ alignment ] magic identifier, offset to malloc'ed data, sheepshaver_cpu data
|
|
||||||
void *sheepshaver_cpu::operator new(size_t size)
|
|
||||||
{
|
|
||||||
const int ALIGN = 16;
|
|
||||||
|
|
||||||
// Allocate enough space for sheepshaver_cpu data + signature + align pad
|
|
||||||
uint8 *ptr = (uint8 *)malloc(size + ALIGN * 2);
|
|
||||||
if (ptr == NULL)
|
|
||||||
throw std::bad_alloc();
|
|
||||||
|
|
||||||
// Align memory
|
|
||||||
int ofs = 0;
|
|
||||||
while ((((uintptr)ptr) % ALIGN) != 0)
|
|
||||||
ofs++, ptr++;
|
|
||||||
|
|
||||||
// Insert signature and offset
|
|
||||||
struct aligned_block_t {
|
|
||||||
uint32 pad[(ALIGN - 8) / 4];
|
|
||||||
uint32 signature;
|
|
||||||
uint32 offset;
|
|
||||||
uint8 data[sizeof(sheepshaver_cpu)];
|
|
||||||
};
|
|
||||||
aligned_block_t *blk = (aligned_block_t *)ptr;
|
|
||||||
blk->signature = FOURCC('S','C','P','U');
|
|
||||||
blk->offset = ofs + (&blk->data[0] - (uint8 *)blk);
|
|
||||||
assert((((uintptr)&blk->data) % ALIGN) == 0);
|
|
||||||
return &blk->data[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
void sheepshaver_cpu::operator delete(void *p)
|
|
||||||
{
|
|
||||||
uint32 *blk = (uint32 *)p;
|
|
||||||
assert(blk[-2] == FOURCC('S','C','P','U'));
|
|
||||||
void *ptr = (void *)(((uintptr)p) - blk[-1]);
|
|
||||||
free(ptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
sheepshaver_cpu::sheepshaver_cpu()
|
sheepshaver_cpu::sheepshaver_cpu()
|
||||||
: powerpc_cpu(enable_jit_p())
|
: powerpc_cpu(enable_jit_p())
|
||||||
{
|
{
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
|
|
||||||
#include "sysdeps.h"
|
#include "sysdeps.h"
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <assert.h>
|
||||||
#include "vm_alloc.h"
|
#include "vm_alloc.h"
|
||||||
#include "cpu/vm.hpp"
|
#include "cpu/vm.hpp"
|
||||||
#include "cpu/ppc/ppc-cpu.hpp"
|
#include "cpu/ppc/ppc-cpu.hpp"
|
||||||
@ -119,6 +120,7 @@ uint32 powerpc_registers::reserve_data = 0;
|
|||||||
|
|
||||||
void powerpc_cpu::init_registers()
|
void powerpc_cpu::init_registers()
|
||||||
{
|
{
|
||||||
|
assert((((uintptr)&vr(0)) % 16) == 0);
|
||||||
for (int i = 0; i < 32; i++) {
|
for (int i = 0; i < 32; i++) {
|
||||||
gpr(i) = 0;
|
gpr(i) = 0;
|
||||||
fpr(i) = 0;
|
fpr(i) = 0;
|
||||||
@ -299,6 +301,44 @@ void powerpc_cpu::initialize()
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Memory allocator returning powerpc_cpu objects aligned on 16-byte boundaries
|
||||||
|
// FORMAT: [ alignment ] magic identifier, offset to malloc'ed data, powerpc_cpu data
|
||||||
|
void *powerpc_cpu::operator new(size_t size)
|
||||||
|
{
|
||||||
|
const int ALIGN = 16;
|
||||||
|
|
||||||
|
// Allocate enough space for powerpc_cpu data + signature + align pad
|
||||||
|
uint8 *ptr = (uint8 *)malloc(size + ALIGN * 2);
|
||||||
|
if (ptr == NULL)
|
||||||
|
throw std::bad_alloc();
|
||||||
|
|
||||||
|
// Align memory
|
||||||
|
int ofs = 0;
|
||||||
|
while ((((uintptr)ptr) % ALIGN) != 0)
|
||||||
|
ofs++, ptr++;
|
||||||
|
|
||||||
|
// Insert signature and offset
|
||||||
|
struct aligned_block_t {
|
||||||
|
uint32 pad[(ALIGN - 8) / 4];
|
||||||
|
uint32 signature;
|
||||||
|
uint32 offset;
|
||||||
|
uint8 data[sizeof(powerpc_cpu)];
|
||||||
|
};
|
||||||
|
aligned_block_t *blk = (aligned_block_t *)ptr;
|
||||||
|
blk->signature = 0x53435055; /* 'SCPU' */
|
||||||
|
blk->offset = ofs + (&blk->data[0] - (uint8 *)blk);
|
||||||
|
assert((((uintptr)&blk->data) % ALIGN) == 0);
|
||||||
|
return &blk->data[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
void powerpc_cpu::operator delete(void *p)
|
||||||
|
{
|
||||||
|
uint32 *blk = (uint32 *)p;
|
||||||
|
assert(blk[-2] == 0x53435055); /* 'SCPU' */
|
||||||
|
void *ptr = (void *)(((uintptr)p) - blk[-1]);
|
||||||
|
free(ptr);
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef SHEEPSHAVER
|
#ifdef SHEEPSHAVER
|
||||||
powerpc_cpu::powerpc_cpu(bool do_use_jit)
|
powerpc_cpu::powerpc_cpu(bool do_use_jit)
|
||||||
: use_jit(do_use_jit)
|
: use_jit(do_use_jit)
|
||||||
@ -468,9 +508,9 @@ bool powerpc_cpu::check_spcflags()
|
|||||||
if (!processing_interrupt) {
|
if (!processing_interrupt) {
|
||||||
processing_interrupt = true;
|
processing_interrupt = true;
|
||||||
powerpc_registers r;
|
powerpc_registers r;
|
||||||
powerpc_registers::interrupt_copy(r, regs);
|
powerpc_registers::interrupt_copy(r, regs());
|
||||||
HandleInterrupt(&r);
|
HandleInterrupt(&r);
|
||||||
powerpc_registers::interrupt_copy(regs, r);
|
powerpc_registers::interrupt_copy(regs(), r);
|
||||||
processing_interrupt = false;
|
processing_interrupt = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -38,7 +38,22 @@ class powerpc_cpu
|
|||||||
: public basic_cpu
|
: public basic_cpu
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
powerpc_registers regs;
|
// NOTE: PowerPC registers structure shall be aligned on 16-byte
|
||||||
|
// boundaries for the AltiVec registers to be used in native code
|
||||||
|
// with aligned load/stores.
|
||||||
|
//
|
||||||
|
// We can't assume (offsetof(powerpc_cpu, regs) % 16) == 0 since
|
||||||
|
// extra data could be inserted prior regs, e.g. pointer to vtable
|
||||||
|
struct {
|
||||||
|
powerpc_registers regs;
|
||||||
|
uint8 pad[16];
|
||||||
|
} _regs;
|
||||||
|
|
||||||
|
// Make sure the calculation of the current offset makes use of
|
||||||
|
// 'this' as this could make it simplified at compile-time
|
||||||
|
powerpc_registers *regs_ptr() const { return (powerpc_registers *)((char *)&_regs.regs + (16 - (((char *)&_regs.regs - (char *)this) % 16))); }
|
||||||
|
powerpc_registers const & regs() const { return *regs_ptr(); }
|
||||||
|
powerpc_registers & regs() { return *regs_ptr(); }
|
||||||
|
|
||||||
#if PPC_PROFILE_REGS_USE
|
#if PPC_PROFILE_REGS_USE
|
||||||
// Registers use statistics
|
// Registers use statistics
|
||||||
@ -59,30 +74,30 @@ private:
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
powerpc_spcflags & spcflags() { return regs.spcflags; }
|
powerpc_spcflags & spcflags() { return regs().spcflags; }
|
||||||
powerpc_spcflags const & spcflags() const { return regs.spcflags; }
|
powerpc_spcflags const & spcflags() const { return regs().spcflags; }
|
||||||
powerpc_cr_register & cr() { return regs.cr; }
|
powerpc_cr_register & cr() { return regs().cr; }
|
||||||
powerpc_cr_register const & cr() const { return regs.cr; }
|
powerpc_cr_register const & cr() const { return regs().cr; }
|
||||||
powerpc_xer_register & xer() { return regs.xer; }
|
powerpc_xer_register & xer() { return regs().xer; }
|
||||||
powerpc_xer_register const & xer() const { return regs.xer; }
|
powerpc_xer_register const & xer() const { return regs().xer; }
|
||||||
powerpc_vscr & vscr() { return regs.vscr; }
|
powerpc_vscr & vscr() { return regs().vscr; }
|
||||||
powerpc_vscr const & vscr() const { return regs.vscr; }
|
powerpc_vscr const & vscr() const { return regs().vscr; }
|
||||||
|
|
||||||
uint32 vrsave() const { return regs.vrsave; }
|
uint32 vrsave() const { return regs().vrsave; }
|
||||||
uint32 & vrsave() { return regs.vrsave; }
|
uint32 & vrsave() { return regs().vrsave; }
|
||||||
double fp_result() const { return regs.fp_result.d; }
|
double fp_result() const { return regs().fp_result.d; }
|
||||||
double & fp_result() { return regs.fp_result.d; }
|
double & fp_result() { return regs().fp_result.d; }
|
||||||
uint64 fp_result_dw() const { return regs.fp_result.j; }
|
uint64 fp_result_dw() const { return regs().fp_result.j; }
|
||||||
uint64 & fp_result_dw() { return regs.fp_result.j; }
|
uint64 & fp_result_dw() { return regs().fp_result.j; }
|
||||||
|
|
||||||
uint32 & fpscr() { return regs.fpscr; }
|
uint32 & fpscr() { return regs().fpscr; }
|
||||||
uint32 fpscr() const { return regs.fpscr; }
|
uint32 fpscr() const { return regs().fpscr; }
|
||||||
uint32 & lr() { return regs.lr; }
|
uint32 & lr() { return regs().lr; }
|
||||||
uint32 lr() const { return regs.lr; }
|
uint32 lr() const { return regs().lr; }
|
||||||
uint32 & ctr() { return regs.ctr; }
|
uint32 & ctr() { return regs().ctr; }
|
||||||
uint32 ctr() const { return regs.ctr; }
|
uint32 ctr() const { return regs().ctr; }
|
||||||
uint32 & pc() { return regs.pc; }
|
uint32 & pc() { return regs().pc; }
|
||||||
uint32 pc() const { return regs.pc; }
|
uint32 pc() const { return regs().pc; }
|
||||||
void increment_pc(int o) { pc() += o; }
|
void increment_pc(int o) { pc() += o; }
|
||||||
|
|
||||||
friend class pc_operand;
|
friend class pc_operand;
|
||||||
@ -94,14 +109,14 @@ protected:
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
uint32 & gpr(int i) { log_reg(i); return regs.gpr[i]; }
|
uint32 & gpr(int i) { log_reg(i); return regs().gpr[i]; }
|
||||||
uint32 gpr(int i) const { log_reg(i); return regs.gpr[i]; }
|
uint32 gpr(int i) const { log_reg(i); return regs().gpr[i]; }
|
||||||
double & fpr(int i) { return regs.fpr[i].d; }
|
double & fpr(int i) { return regs().fpr[i].d; }
|
||||||
double fpr(int i) const { return regs.fpr[i].d; }
|
double fpr(int i) const { return regs().fpr[i].d; }
|
||||||
uint64 & fpr_dw(int i) { return regs.fpr[i].j; }
|
uint64 & fpr_dw(int i) { return regs().fpr[i].j; }
|
||||||
uint64 fpr_dw(int i) const { return regs.fpr[i].j; }
|
uint64 fpr_dw(int i) const { return regs().fpr[i].j; }
|
||||||
powerpc_vr & vr(int i) { return regs.vr[i]; }
|
powerpc_vr & vr(int i) { return regs().vr[i]; }
|
||||||
powerpc_vr const & vr(int i) const { return regs.vr[i]; }
|
powerpc_vr const & vr(int i) const { return regs().vr[i]; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
@ -258,6 +273,10 @@ public:
|
|||||||
#endif
|
#endif
|
||||||
~powerpc_cpu();
|
~powerpc_cpu();
|
||||||
|
|
||||||
|
// Specialised memory allocation (needs to be 16-byte aligned)
|
||||||
|
void *operator new(size_t size);
|
||||||
|
void operator delete(void *p);
|
||||||
|
|
||||||
// Handle flight recorder
|
// Handle flight recorder
|
||||||
#if PPC_FLIGHT_RECORDER
|
#if PPC_FLIGHT_RECORDER
|
||||||
bool is_logging() const { return logging; }
|
bool is_logging() const { return logging; }
|
||||||
|
@ -735,10 +735,10 @@ template< class RA >
|
|||||||
void powerpc_cpu::execute_lwarx(uint32 opcode)
|
void powerpc_cpu::execute_lwarx(uint32 opcode)
|
||||||
{
|
{
|
||||||
const uint32 ea = RA::get(this, opcode) + operand_RB::get(this, opcode);
|
const uint32 ea = RA::get(this, opcode) + operand_RB::get(this, opcode);
|
||||||
regs.reserve_valid = 1;
|
regs().reserve_valid = 1;
|
||||||
regs.reserve_addr = ea;
|
regs().reserve_addr = ea;
|
||||||
regs.reserve_data = vm_read_memory_4(ea);
|
regs().reserve_data = vm_read_memory_4(ea);
|
||||||
operand_RD::set(this, opcode, regs.reserve_data);
|
operand_RD::set(this, opcode, regs().reserve_data);
|
||||||
increment_pc(4);
|
increment_pc(4);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -747,13 +747,13 @@ void powerpc_cpu::execute_stwcx(uint32 opcode)
|
|||||||
{
|
{
|
||||||
const uint32 ea = RA::get(this, opcode) + operand_RB::get(this, opcode);
|
const uint32 ea = RA::get(this, opcode) + operand_RB::get(this, opcode);
|
||||||
cr().clear(0);
|
cr().clear(0);
|
||||||
if (regs.reserve_valid) {
|
if (regs().reserve_valid) {
|
||||||
if (regs.reserve_addr == ea /* physical_addr(EA) */
|
if (regs().reserve_addr == ea /* physical_addr(EA) */
|
||||||
&& /* HACK */ regs.reserve_data == vm_read_memory_4(ea)) {
|
&& /* HACK */ regs().reserve_data == vm_read_memory_4(ea)) {
|
||||||
vm_write_memory_4(ea, operand_RS::get(this, opcode));
|
vm_write_memory_4(ea, operand_RS::get(this, opcode));
|
||||||
cr().set(0, standalone_CR_EQ_field::mask());
|
cr().set(0, standalone_CR_EQ_field::mask());
|
||||||
}
|
}
|
||||||
regs.reserve_valid = 0;
|
regs().reserve_valid = 0;
|
||||||
}
|
}
|
||||||
cr().set_so(0, xer().get_so());
|
cr().set_so(0, xer().get_so());
|
||||||
increment_pc(4);
|
increment_pc(4);
|
||||||
|
@ -210,13 +210,7 @@ union powerpc_vr
|
|||||||
uint32 w[4];
|
uint32 w[4];
|
||||||
uint64 j[2];
|
uint64 j[2];
|
||||||
float f[4];
|
float f[4];
|
||||||
}
|
};
|
||||||
#if defined(__GNUC__)
|
|
||||||
// 16-byte alignment is required for SIMD optimizations operating on
|
|
||||||
// 128-bit aligned registers (e.g. SSE).
|
|
||||||
__attribute__((aligned(16)))
|
|
||||||
#endif
|
|
||||||
;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -253,8 +247,8 @@ struct powerpc_registers
|
|||||||
powerpc_fpr fpr[32]; // Floating-Point Registers
|
powerpc_fpr fpr[32]; // Floating-Point Registers
|
||||||
powerpc_fpr fp_result; // Floating-Point result
|
powerpc_fpr fp_result; // Floating-Point result
|
||||||
powerpc_cr_register cr; // Condition Register
|
powerpc_cr_register cr; // Condition Register
|
||||||
uint32 fpscr; // Floating-Point Status and Control Register
|
|
||||||
powerpc_xer_register xer; // XER Register (SPR 1)
|
powerpc_xer_register xer; // XER Register (SPR 1)
|
||||||
|
uint32 fpscr; // Floating-Point Status and Control Register
|
||||||
uint32 lr; // Link Register (SPR 8)
|
uint32 lr; // Link Register (SPR 8)
|
||||||
uint32 ctr; // Count Register (SPR 9)
|
uint32 ctr; // Count Register (SPR 9)
|
||||||
uint32 pc; // Program Counter
|
uint32 pc; // Program Counter
|
||||||
@ -262,6 +256,9 @@ struct powerpc_registers
|
|||||||
static uint32 reserve_valid;
|
static uint32 reserve_valid;
|
||||||
static uint32 reserve_addr;
|
static uint32 reserve_addr;
|
||||||
static uint32 reserve_data;
|
static uint32 reserve_data;
|
||||||
|
#define PPC_SZ(T) sizeof(powerpc_##T)
|
||||||
|
uint8 _pad[16 - ((PPC_SZ(fpr) + PPC_SZ(cr_register) + PPC_SZ(xer_register) + PPC_SZ(spcflags)) % 16)];
|
||||||
|
#undef PPC_SZ
|
||||||
powerpc_vr vr[32]; // Vector Registers
|
powerpc_vr vr[32]; // Vector Registers
|
||||||
powerpc_vscr vscr; // Vector Status and Control Register
|
powerpc_vscr vscr; // Vector Status and Control Register
|
||||||
uint32 vrsave; // AltiVec Save Register
|
uint32 vrsave; // AltiVec Save Register
|
||||||
|
@ -104,14 +104,6 @@ typedef uintptr_t uintptr;
|
|||||||
#define TEST_VMX_ARITH 1
|
#define TEST_VMX_ARITH 1
|
||||||
|
|
||||||
|
|
||||||
#if defined __GNUC__
|
|
||||||
#define ALIGNED(N) __attribute__((aligned(N)))
|
|
||||||
#else
|
|
||||||
#if TEST_VMX_OPS
|
|
||||||
#error "AltiVec testing requires the align attribute"
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Partial PowerPC runtime assembler from GNU lightning
|
// Partial PowerPC runtime assembler from GNU lightning
|
||||||
#undef _I
|
#undef _I
|
||||||
#define _I(X) ((uint32)(X))
|
#define _I(X) ((uint32)(X))
|
||||||
@ -506,7 +498,25 @@ typedef bit_field< 2, 2 > XER_CA_field;
|
|||||||
static bool has_altivec = true;
|
static bool has_altivec = true;
|
||||||
|
|
||||||
// A 128-bit AltiVec register
|
// A 128-bit AltiVec register
|
||||||
typedef uint8 vector_t[16] ALIGNED(16);
|
typedef uint8 vector_t[16];
|
||||||
|
|
||||||
|
class aligned_vector_t {
|
||||||
|
struct {
|
||||||
|
vector_t v;
|
||||||
|
uint8 pad[16];
|
||||||
|
} vs;
|
||||||
|
public:
|
||||||
|
aligned_vector_t()
|
||||||
|
{ memset(addr(), 0, sizeof(vector_t)); }
|
||||||
|
aligned_vector_t(vector_t const & vi)
|
||||||
|
{ memcpy(addr(), &vi, sizeof(vector_t)); }
|
||||||
|
vector_t *addr() const
|
||||||
|
{ return (vector_t *)((char *)&vs.v + (16 - (((char *)&vs.v - (char *)this) % 16))); }
|
||||||
|
vector_t const & value() const
|
||||||
|
{ return *addr(); }
|
||||||
|
vector_t & value()
|
||||||
|
{ return *addr(); }
|
||||||
|
};
|
||||||
|
|
||||||
union vector_helper_t {
|
union vector_helper_t {
|
||||||
vector_t v;
|
vector_t v;
|
||||||
@ -721,7 +731,7 @@ private:
|
|||||||
|
|
||||||
struct vector_value_t {
|
struct vector_value_t {
|
||||||
char type;
|
char type;
|
||||||
vector_t v ALIGNED(16);
|
vector_t v;
|
||||||
};
|
};
|
||||||
|
|
||||||
static const uint32 reg_values[];
|
static const uint32 reg_values[];
|
||||||
@ -1611,24 +1621,25 @@ void powerpc_test_cpu::test_one_vector(uint32 *code, vector_test_t const & vt, u
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Invoke emulated code
|
// Invoke emulated code
|
||||||
static vector_t emul_vD;
|
static aligned_vector_t emul_vD;
|
||||||
memset(&emul_vD, 0, sizeof(emul_vD));
|
memset(emul_vD.addr(), 0, sizeof(vector_t));
|
||||||
static vector_helper_t emul_vSCR;
|
static aligned_vector_t emul_vSCR;
|
||||||
memset(&emul_vSCR, 0, sizeof(emul_vSCR));
|
memset(emul_vSCR.addr(), 0, sizeof(vector_t));
|
||||||
emul_vSCR.w[3] = 0;
|
|
||||||
emul_set_cr(init_cr);
|
emul_set_cr(init_cr);
|
||||||
set_gpr(RD, (uintptr)&emul_vD);
|
set_gpr(RD, (uintptr)emul_vD.addr());
|
||||||
set_gpr(RA, (uintptr)rAp);
|
set_gpr(RA, (uintptr)rAp);
|
||||||
set_gpr(RB, (uintptr)rBp);
|
set_gpr(RB, (uintptr)rBp);
|
||||||
set_gpr(RC, (uintptr)rCp);
|
set_gpr(RC, (uintptr)rCp);
|
||||||
set_gpr(VSCR, (uintptr)emul_vSCR.b);
|
set_gpr(VSCR, (uintptr)emul_vSCR.addr());
|
||||||
execute(code);
|
execute(code);
|
||||||
|
vector_helper_t emul_vSCR_helper;
|
||||||
|
memcpy(&emul_vSCR_helper, emul_vSCR.addr(), sizeof(vector_t));
|
||||||
const uint32 emul_cr = emul_get_cr();
|
const uint32 emul_cr = emul_get_cr();
|
||||||
const uint32 emul_vscr = ntohl(emul_vSCR.w[3]);
|
const uint32 emul_vscr = ntohl(emul_vSCR_helper.w[3]);
|
||||||
|
|
||||||
++tests;
|
++tests;
|
||||||
|
|
||||||
bool ok = vector_equals(vt.type, native_vD, emul_vD)
|
bool ok = vector_equals(vt.type, native_vD, emul_vD.value())
|
||||||
&& native_cr == emul_cr
|
&& native_cr == emul_cr
|
||||||
&& native_vscr == emul_vscr;
|
&& native_vscr == emul_vscr;
|
||||||
|
|
||||||
@ -1676,7 +1687,7 @@ void powerpc_test_cpu::test_one_vector(uint32 *code, vector_test_t const & vt, u
|
|||||||
print_vector(native_vD, vt.type);
|
print_vector(native_vD, vt.type);
|
||||||
printf("\n");
|
printf("\n");
|
||||||
printf("vD.E = ");
|
printf("vD.E = ");
|
||||||
print_vector(emul_vD, vt.type);
|
print_vector(emul_vD.value(), vt.type);
|
||||||
printf("\n");
|
printf("\n");
|
||||||
printf("CR.N = %08x ; VSCR.N = %08x\n", native_cr, native_vscr);
|
printf("CR.N = %08x ; VSCR.N = %08x\n", native_cr, native_vscr);
|
||||||
printf("CR.E = %08x ; VSCR.E = %08x\n", emul_cr, emul_vscr);
|
printf("CR.E = %08x ; VSCR.E = %08x\n", emul_cr, emul_vscr);
|
||||||
@ -1764,7 +1775,6 @@ void powerpc_test_cpu::test_vector_load(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
assert(i_opcode != -1);
|
assert(i_opcode != -1);
|
||||||
assert(((uintptr)&vector_values[0].v) % 16 == 0);
|
|
||||||
|
|
||||||
const int n_elements = sizeof(tests) / sizeof(tests[0]);
|
const int n_elements = sizeof(tests) / sizeof(tests[0]);
|
||||||
for (int i = 0; i < n_elements; i++) {
|
for (int i = 0; i < n_elements; i++) {
|
||||||
@ -1778,18 +1788,19 @@ void powerpc_test_cpu::test_vector_load(void)
|
|||||||
printf("Testing %s\n", vt.name);
|
printf("Testing %s\n", vt.name);
|
||||||
const int n_vector_values = sizeof(vector_values)/sizeof(vector_values[0]);
|
const int n_vector_values = sizeof(vector_values)/sizeof(vector_values[0]);
|
||||||
for (int j = 0; j < n_vector_values; j++) {
|
for (int j = 0; j < n_vector_values; j++) {
|
||||||
|
aligned_vector_t av(vector_values[j].v);
|
||||||
switch (vt.type) {
|
switch (vt.type) {
|
||||||
case 'b':
|
case 'b':
|
||||||
for (int k = 0; k < 16; k++)
|
for (int k = 0; k < 16; k++)
|
||||||
test_one_vector(code, vt, ((uint8 *)&vector_values[j].v) + 1 * k);
|
test_one_vector(code, vt, ((uint8 *)av.addr()) + 1 * k);
|
||||||
break;
|
break;
|
||||||
case 'h':
|
case 'h':
|
||||||
for (int k = 0; k < 8; k++)
|
for (int k = 0; k < 8; k++)
|
||||||
test_one_vector(code, vt, ((uint8 *)&vector_values[j].v) + 2 * k);
|
test_one_vector(code, vt, ((uint8 *)av.addr()) + 2 * k);
|
||||||
break;
|
break;
|
||||||
case 'w':
|
case 'w':
|
||||||
for (int k = 0; k < 4; k++)
|
for (int k = 0; k < 4; k++)
|
||||||
test_one_vector(code, vt, ((uint8 *)&vector_values[j].v) + 4 * k);
|
test_one_vector(code, vt, ((uint8 *)av.addr()) + 4 * k);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2012,29 +2023,40 @@ void powerpc_test_cpu::test_vector_arith(void)
|
|||||||
|
|
||||||
printf("Testing %s\n", vt.name);
|
printf("Testing %s\n", vt.name);
|
||||||
if (vt.operands[1] == vA && vt.operands[2] == vB && vt.operands[3] == vC) {
|
if (vt.operands[1] == vA && vt.operands[2] == vB && vt.operands[3] == vC) {
|
||||||
for (int i = 0; i < n_vector_values; i++)
|
for (int i = 0; i < n_vector_values; i++) {
|
||||||
for (int j = 0; j < n_vector_values; j++)
|
aligned_vector_t avi(vvp[i].v);
|
||||||
for (int k = 0; k < n_vector_values; k++)
|
for (int j = 0; j < n_vector_values; j++) {
|
||||||
test_one_vector(code, vt, &vvp[i].v, &vvp[j].v, &vvp[k].v);
|
aligned_vector_t avj(vvp[j].v);
|
||||||
|
for (int k = 0; k < n_vector_values; k++) {
|
||||||
|
aligned_vector_t avk(vvp[k].v);
|
||||||
|
test_one_vector(code, vt, avi.addr(), avj.addr(), avk.addr());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (vt.operands[1] == vA && vt.operands[2] == vB && vt.operands[3] == vN) {
|
else if (vt.operands[1] == vA && vt.operands[2] == vB && vt.operands[3] == vN) {
|
||||||
for (int i = 0; i < 16; i++) {
|
for (int i = 0; i < 16; i++) {
|
||||||
vSH_field::insert(vt.opcode, i);
|
vSH_field::insert(vt.opcode, i);
|
||||||
code[i_opcode] = vt.opcode;
|
code[i_opcode] = vt.opcode;
|
||||||
flush_icache_range(code, sizeof(code));
|
flush_icache_range(code, sizeof(code));
|
||||||
for (int j = 0; j < n_vector_values; j++)
|
aligned_vector_t avi(vvp[i].v);
|
||||||
|
for (int j = 0; j < n_vector_values; j++) {
|
||||||
|
aligned_vector_t avj(vvp[j].v);
|
||||||
for (int k = 0; k < n_vector_values; k++)
|
for (int k = 0; k < n_vector_values; k++)
|
||||||
test_one_vector(code, vt, &vvp[i].v, &vvp[j].v);
|
test_one_vector(code, vt, avi.addr(), avj.addr());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (vt.operands[1] == vA && vt.operands[2] == vB) {
|
else if (vt.operands[1] == vA && vt.operands[2] == vB) {
|
||||||
for (int i = 0; i < n_vector_values; i++) {
|
for (int i = 0; i < n_vector_values; i++) {
|
||||||
|
aligned_vector_t avi(vvp[i].v);
|
||||||
for (int j = 0; j < n_vector_values; j++) {
|
for (int j = 0; j < n_vector_values; j++) {
|
||||||
if (op_type == 'B') {
|
if (op_type == 'B') {
|
||||||
if (!vector_all_eq('b', vvp[j].v))
|
if (!vector_all_eq('b', vvp[j].v))
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
test_one_vector(code, vt, &vvp[i].v, &vvp[j].v);
|
aligned_vector_t avj(vvp[j].v);
|
||||||
|
test_one_vector(code, vt, avi.addr(), avj.addr());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2043,8 +2065,10 @@ void powerpc_test_cpu::test_vector_arith(void)
|
|||||||
rA_field::insert(vt.opcode, i);
|
rA_field::insert(vt.opcode, i);
|
||||||
code[i_opcode] = vt.opcode;
|
code[i_opcode] = vt.opcode;
|
||||||
flush_icache_range(code, sizeof(code));
|
flush_icache_range(code, sizeof(code));
|
||||||
for (int j = 0; j < n_vector_values; j++)
|
for (int j = 0; j < n_vector_values; j++) {
|
||||||
test_one_vector(code, vt, NULL, &vvp[j].v);
|
aligned_vector_t avj(vvp[j].v);
|
||||||
|
test_one_vector(code, vt, NULL, avj.addr());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (vt.operands[1] == vI) {
|
else if (vt.operands[1] == vI) {
|
||||||
@ -2056,8 +2080,10 @@ void powerpc_test_cpu::test_vector_arith(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (vt.operands[1] == __ && vt.operands[2] == vB) {
|
else if (vt.operands[1] == __ && vt.operands[2] == vB) {
|
||||||
for (int i = 0; i < n_vector_values; i++)
|
for (int i = 0; i < n_vector_values; i++) {
|
||||||
test_one_vector(code, vt, NULL, &vvp[i].v);
|
aligned_vector_t avi(vvp[i].v);
|
||||||
|
test_one_vector(code, vt, NULL, avi.addr());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
printf("ERROR: unhandled test case\n");
|
printf("ERROR: unhandled test case\n");
|
||||||
|
Loading…
x
Reference in New Issue
Block a user