mirror of
https://github.com/xemu-project/xemu.git
synced 2024-11-23 11:39:53 +00:00
ppc patch queue for 2022-09-20:
This queue contains a implementation of PowerISA 3.1B hash insns, ppc TCG insns cleanups and fixes, and miscellaneus fixes in the spapr and pnv_phb models. -----BEGIN PGP SIGNATURE----- iHUEABYKAB0WIQQX6/+ZI9AYAK8oOBk82cqW3gMxZAUCYyoWlAAKCRA82cqW3gMx ZDYhAP0eQMeA4NS3hiw7WMcAVg0pei3ZJL9oEh1UE3+MfK7MhQEA0q8qExWnQJAA a0hfnFH9pLjI+v0f/FbFK6QJBpu/bg8= =qT+H -----END PGP SIGNATURE----- Merge tag 'pull-ppc-20220920' of https://gitlab.com/danielhb/qemu into staging ppc patch queue for 2022-09-20: This queue contains a implementation of PowerISA 3.1B hash insns, ppc TCG insns cleanups and fixes, and miscellaneus fixes in the spapr and pnv_phb models. # -----BEGIN PGP SIGNATURE----- # # iHUEABYKAB0WIQQX6/+ZI9AYAK8oOBk82cqW3gMxZAUCYyoWlAAKCRA82cqW3gMx # ZDYhAP0eQMeA4NS3hiw7WMcAVg0pei3ZJL9oEh1UE3+MfK7MhQEA0q8qExWnQJAA # a0hfnFH9pLjI+v0f/FbFK6QJBpu/bg8= # =qT+H # -----END PGP SIGNATURE----- # gpg: Signature made Tue 20 Sep 2022 15:37:56 EDT # gpg: using EDDSA key 17EBFF9923D01800AF2838193CD9CA96DE033164 # gpg: Good signature from "Daniel Henrique Barboza <danielhb413@gmail.com>" [unknown] # gpg: WARNING: This key is not certified with a trusted signature! # gpg: There is no indication that the signature belongs to the owner. # Primary key fingerprint: 17EB FF99 23D0 1800 AF28 3819 3CD9 CA96 DE03 3164 * tag 'pull-ppc-20220920' of https://gitlab.com/danielhb/qemu: hw/ppc/spapr: Fix code style problems reported by checkpatch hw/pci-host: pnv_phb{3, 4}: Fix heap out-of-bound access failure hw/ppc: spapr: Use qemu_vfree() to free spapr->htab target/ppc: Clear fpstatus flags on helpers missing it target/ppc: Zero second doubleword of VSR registers for FPR insns target/ppc: Set OV32 when OV is set target/ppc: Zero second doubleword for VSX madd instructions target/ppc: Set result to QNaN for DENBCD when VXCVI occurs target/ppc: Zero second doubleword in DFP instructions target/ppc: Remove unused xer_* macros target/ppc: Remove extra space from s128 field in ppc_vsr_t target/ppc: Merge fsqrt and fsqrts helpers target/ppc: Move fsqrts to decodetree target/ppc: Move fsqrt to decodetree target/ppc: Implement hashstp and hashchkp target/ppc: Implement hashst and hashchk target/ppc: Add HASHKEYR and HASHPKEYR SPRs Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
This commit is contained in:
commit
6514f1a522
@ -1169,6 +1169,7 @@ static void pnv_phb3_root_bus_class_init(ObjectClass *klass, void *data)
|
||||
static const TypeInfo pnv_phb3_root_bus_info = {
|
||||
.name = TYPE_PNV_PHB3_ROOT_BUS,
|
||||
.parent = TYPE_PCIE_BUS,
|
||||
.instance_size = sizeof(PnvPHB3RootBus),
|
||||
.class_init = pnv_phb3_root_bus_class_init,
|
||||
};
|
||||
|
||||
|
@ -1773,6 +1773,7 @@ static void pnv_phb4_root_bus_class_init(ObjectClass *klass, void *data)
|
||||
static const TypeInfo pnv_phb4_root_bus_info = {
|
||||
.name = TYPE_PNV_PHB4_ROOT_BUS,
|
||||
.parent = TYPE_PCIE_BUS,
|
||||
.instance_size = sizeof(PnvPHB4RootBus),
|
||||
.class_init = pnv_phb4_root_bus_class_init,
|
||||
};
|
||||
|
||||
|
@ -1522,7 +1522,7 @@ int spapr_hpt_shift_for_ramsize(uint64_t ramsize)
|
||||
|
||||
void spapr_free_hpt(SpaprMachineState *spapr)
|
||||
{
|
||||
g_free(spapr->htab);
|
||||
qemu_vfree(spapr->htab);
|
||||
spapr->htab = NULL;
|
||||
spapr->htab_shift = 0;
|
||||
close_htab_fd(spapr);
|
||||
|
@ -848,7 +848,8 @@ static inline uint64_t ppc64_phys_to_real(uint64_t addr)
|
||||
|
||||
static inline uint32_t rtas_ld(target_ulong phys, int n)
|
||||
{
|
||||
return ldl_be_phys(&address_space_memory, ppc64_phys_to_real(phys + 4*n));
|
||||
return ldl_be_phys(&address_space_memory,
|
||||
ppc64_phys_to_real(phys + 4 * n));
|
||||
}
|
||||
|
||||
static inline uint64_t rtas_ldq(target_ulong phys, int n)
|
||||
@ -858,7 +859,7 @@ static inline uint64_t rtas_ldq(target_ulong phys, int n)
|
||||
|
||||
static inline void rtas_st(target_ulong phys, int n, uint32_t val)
|
||||
{
|
||||
stl_be_phys(&address_space_memory, ppc64_phys_to_real(phys + 4*n), val);
|
||||
stl_be_phys(&address_space_memory, ppc64_phys_to_real(phys + 4 * n), val);
|
||||
}
|
||||
|
||||
typedef void (*spapr_rtas_fn)(PowerPCCPU *cpu, SpaprMachineState *sm,
|
||||
|
@ -246,7 +246,7 @@ typedef union _ppc_vsr_t {
|
||||
#ifdef CONFIG_INT128
|
||||
__uint128_t u128;
|
||||
#endif
|
||||
Int128 s128;
|
||||
Int128 s128;
|
||||
} ppc_vsr_t;
|
||||
|
||||
typedef ppc_vsr_t ppc_avr_t;
|
||||
@ -1506,10 +1506,6 @@ void ppc_compat_add_property(Object *obj, const char *name,
|
||||
#define XER_CMP 8
|
||||
#define XER_BC 0
|
||||
#define xer_so (env->so)
|
||||
#define xer_ov (env->ov)
|
||||
#define xer_ca (env->ca)
|
||||
#define xer_ov32 (env->ov)
|
||||
#define xer_ca32 (env->ca)
|
||||
#define xer_cmp ((env->xer >> XER_CMP) & 0xFF)
|
||||
#define xer_bc ((env->xer >> XER_BC) & 0x7F)
|
||||
|
||||
@ -1676,6 +1672,8 @@ void ppc_compat_add_property(Object *obj, const char *name,
|
||||
#define SPR_BOOKE_GIVOR14 (0x1BD)
|
||||
#define SPR_TIR (0x1BE)
|
||||
#define SPR_PTCR (0x1D0)
|
||||
#define SPR_HASHKEYR (0x1D4)
|
||||
#define SPR_HASHPKEYR (0x1D5)
|
||||
#define SPR_BOOKE_SPEFSCR (0x200)
|
||||
#define SPR_Exxx_BBEAR (0x201)
|
||||
#define SPR_Exxx_BBTAR (0x202)
|
||||
|
@ -5700,6 +5700,33 @@ static void register_power9_mmu_sprs(CPUPPCState *env)
|
||||
#endif
|
||||
}
|
||||
|
||||
static void register_power10_hash_sprs(CPUPPCState *env)
|
||||
{
|
||||
/*
|
||||
* it's the OS responsability to generate a random value for the registers
|
||||
* in each process' context. So, initialize it with 0 here.
|
||||
*/
|
||||
uint64_t hashkeyr_initial_value = 0, hashpkeyr_initial_value = 0;
|
||||
#if defined(CONFIG_USER_ONLY)
|
||||
/* in linux-user, setup the hash register with a random value */
|
||||
GRand *rand = g_rand_new();
|
||||
hashkeyr_initial_value =
|
||||
((uint64_t)g_rand_int(rand) << 32) | (uint64_t)g_rand_int(rand);
|
||||
hashpkeyr_initial_value =
|
||||
((uint64_t)g_rand_int(rand) << 32) | (uint64_t)g_rand_int(rand);
|
||||
g_rand_free(rand);
|
||||
#endif
|
||||
spr_register(env, SPR_HASHKEYR, "HASHKEYR",
|
||||
SPR_NOACCESS, SPR_NOACCESS,
|
||||
&spr_read_generic, &spr_write_generic,
|
||||
hashkeyr_initial_value);
|
||||
spr_register_hv(env, SPR_HASHPKEYR, "HASHPKEYR",
|
||||
SPR_NOACCESS, SPR_NOACCESS,
|
||||
SPR_NOACCESS, SPR_NOACCESS,
|
||||
&spr_read_generic, &spr_write_generic,
|
||||
hashpkeyr_initial_value);
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize PMU counter overflow timers for Power8 and
|
||||
* newer Power chips when using TCG.
|
||||
@ -6518,6 +6545,7 @@ static void init_proc_POWER10(CPUPPCState *env)
|
||||
register_power8_book4_sprs(env);
|
||||
register_power8_rpr_sprs(env);
|
||||
register_power9_mmu_sprs(env);
|
||||
register_power10_hash_sprs(env);
|
||||
|
||||
/* FIXME: Filter fields properly based on privilege level */
|
||||
spr_register_kvm_hv(env, SPR_PSSCR, "PSSCR", NULL, NULL, NULL, NULL,
|
||||
|
@ -42,13 +42,16 @@ static void get_dfp128(ppc_vsr_t *dst, ppc_fprp_t *dfp)
|
||||
|
||||
static void set_dfp64(ppc_fprp_t *dfp, ppc_vsr_t *src)
|
||||
{
|
||||
dfp->VsrD(0) = src->VsrD(1);
|
||||
dfp[0].VsrD(0) = src->VsrD(1);
|
||||
dfp[0].VsrD(1) = 0ULL;
|
||||
}
|
||||
|
||||
static void set_dfp128(ppc_fprp_t *dfp, ppc_vsr_t *src)
|
||||
{
|
||||
dfp[0].VsrD(0) = src->VsrD(0);
|
||||
dfp[1].VsrD(0) = src->VsrD(1);
|
||||
dfp[0].VsrD(1) = 0ULL;
|
||||
dfp[1].VsrD(1) = 0ULL;
|
||||
}
|
||||
|
||||
static void set_dfp128_to_avr(ppc_avr_t *dst, ppc_vsr_t *src)
|
||||
@ -1144,6 +1147,26 @@ static inline uint8_t dfp_get_bcd_digit_128(ppc_vsr_t *t, unsigned n)
|
||||
return t->VsrD((n & 0x10) ? 0 : 1) >> ((n << 2) & 63) & 15;
|
||||
}
|
||||
|
||||
static inline void dfp_invalid_op_vxcvi_64(struct PPC_DFP *dfp)
|
||||
{
|
||||
/* TODO: fpscr is incorrectly not being saved to env */
|
||||
dfp_set_FPSCR_flag(dfp, FP_VX | FP_VXCVI, FPSCR_VE);
|
||||
if ((dfp->env->fpscr & FP_VE) == 0) {
|
||||
dfp->vt.VsrD(1) = 0x7c00000000000000; /* QNaN */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static inline void dfp_invalid_op_vxcvi_128(struct PPC_DFP *dfp)
|
||||
{
|
||||
/* TODO: fpscr is incorrectly not being saved to env */
|
||||
dfp_set_FPSCR_flag(dfp, FP_VX | FP_VXCVI, FPSCR_VE);
|
||||
if ((dfp->env->fpscr & FP_VE) == 0) {
|
||||
dfp->vt.VsrD(0) = 0x7c00000000000000; /* QNaN */
|
||||
dfp->vt.VsrD(1) = 0x0;
|
||||
}
|
||||
}
|
||||
|
||||
#define DFP_HELPER_ENBCD(op, size) \
|
||||
void helper_##op(CPUPPCState *env, ppc_fprp_t *t, ppc_fprp_t *b, \
|
||||
uint32_t s) \
|
||||
@ -1170,7 +1193,8 @@ void helper_##op(CPUPPCState *env, ppc_fprp_t *t, ppc_fprp_t *b, \
|
||||
sgn = 0; \
|
||||
break; \
|
||||
default: \
|
||||
dfp_set_FPSCR_flag(&dfp, FP_VX | FP_VXCVI, FPSCR_VE); \
|
||||
dfp_invalid_op_vxcvi_##size(&dfp); \
|
||||
set_dfp##size(t, &dfp.vt); \
|
||||
return; \
|
||||
} \
|
||||
} \
|
||||
@ -1180,7 +1204,8 @@ void helper_##op(CPUPPCState *env, ppc_fprp_t *t, ppc_fprp_t *b, \
|
||||
digits[(size) / 4 - n] = dfp_get_bcd_digit_##size(&dfp.vb, \
|
||||
offset++); \
|
||||
if (digits[(size) / 4 - n] > 10) { \
|
||||
dfp_set_FPSCR_flag(&dfp, FP_VX | FP_VXCVI, FPSCR_VE); \
|
||||
dfp_invalid_op_vxcvi_##size(&dfp); \
|
||||
set_dfp##size(t, &dfp.vt); \
|
||||
return; \
|
||||
} else { \
|
||||
nonzero |= (digits[(size) / 4 - n] > 0); \
|
||||
|
@ -2173,6 +2173,89 @@ void helper_td(CPUPPCState *env, target_ulong arg1, target_ulong arg2,
|
||||
#endif
|
||||
#endif
|
||||
|
||||
static uint32_t helper_SIMON_LIKE_32_64(uint32_t x, uint64_t key, uint32_t lane)
|
||||
{
|
||||
const uint16_t c = 0xfffc;
|
||||
const uint64_t z0 = 0xfa2561cdf44ac398ULL;
|
||||
uint16_t z = 0, temp;
|
||||
uint16_t k[32], eff_k[32], xleft[33], xright[33], fxleft[32];
|
||||
|
||||
for (int i = 3; i >= 0; i--) {
|
||||
k[i] = key & 0xffff;
|
||||
key >>= 16;
|
||||
}
|
||||
xleft[0] = x & 0xffff;
|
||||
xright[0] = (x >> 16) & 0xffff;
|
||||
|
||||
for (int i = 0; i < 28; i++) {
|
||||
z = (z0 >> (63 - i)) & 1;
|
||||
temp = ror16(k[i + 3], 3) ^ k[i + 1];
|
||||
k[i + 4] = c ^ z ^ k[i] ^ temp ^ ror16(temp, 1);
|
||||
}
|
||||
|
||||
for (int i = 0; i < 8; i++) {
|
||||
eff_k[4 * i + 0] = k[4 * i + ((0 + lane) % 4)];
|
||||
eff_k[4 * i + 1] = k[4 * i + ((1 + lane) % 4)];
|
||||
eff_k[4 * i + 2] = k[4 * i + ((2 + lane) % 4)];
|
||||
eff_k[4 * i + 3] = k[4 * i + ((3 + lane) % 4)];
|
||||
}
|
||||
|
||||
for (int i = 0; i < 32; i++) {
|
||||
fxleft[i] = (rol16(xleft[i], 1) &
|
||||
rol16(xleft[i], 8)) ^ rol16(xleft[i], 2);
|
||||
xleft[i + 1] = xright[i] ^ fxleft[i] ^ eff_k[i];
|
||||
xright[i + 1] = xleft[i];
|
||||
}
|
||||
|
||||
return (((uint32_t)xright[32]) << 16) | xleft[32];
|
||||
}
|
||||
|
||||
static uint64_t hash_digest(uint64_t ra, uint64_t rb, uint64_t key)
|
||||
{
|
||||
uint64_t stage0_h = 0ULL, stage0_l = 0ULL;
|
||||
uint64_t stage1_h, stage1_l;
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
stage0_h |= ror64(rb & 0xff, 8 * (2 * i + 1));
|
||||
stage0_h |= ((ra >> 32) & 0xff) << (8 * 2 * i);
|
||||
stage0_l |= ror64((rb >> 32) & 0xff, 8 * (2 * i + 1));
|
||||
stage0_l |= (ra & 0xff) << (8 * 2 * i);
|
||||
rb >>= 8;
|
||||
ra >>= 8;
|
||||
}
|
||||
|
||||
stage1_h = (uint64_t)helper_SIMON_LIKE_32_64(stage0_h >> 32, key, 0) << 32;
|
||||
stage1_h |= helper_SIMON_LIKE_32_64(stage0_h, key, 1);
|
||||
stage1_l = (uint64_t)helper_SIMON_LIKE_32_64(stage0_l >> 32, key, 2) << 32;
|
||||
stage1_l |= helper_SIMON_LIKE_32_64(stage0_l, key, 3);
|
||||
|
||||
return stage1_h ^ stage1_l;
|
||||
}
|
||||
|
||||
#include "qemu/guest-random.h"
|
||||
|
||||
#define HELPER_HASH(op, key, store) \
|
||||
void helper_##op(CPUPPCState *env, target_ulong ea, target_ulong ra, \
|
||||
target_ulong rb) \
|
||||
{ \
|
||||
uint64_t calculated_hash = hash_digest(ra, rb, key), loaded_hash; \
|
||||
\
|
||||
if (store) { \
|
||||
cpu_stq_data_ra(env, ea, calculated_hash, GETPC()); \
|
||||
} else { \
|
||||
loaded_hash = cpu_ldq_data_ra(env, ea, GETPC()); \
|
||||
if (loaded_hash != calculated_hash) { \
|
||||
raise_exception_err_ra(env, POWERPC_EXCP_PROGRAM, \
|
||||
POWERPC_EXCP_TRAP, GETPC()); \
|
||||
} \
|
||||
} \
|
||||
}
|
||||
|
||||
HELPER_HASH(HASHST, env->spr[SPR_HASHKEYR], true)
|
||||
HELPER_HASH(HASHCHK, env->spr[SPR_HASHKEYR], false)
|
||||
HELPER_HASH(HASHSTP, env->spr[SPR_HASHPKEYR], true)
|
||||
HELPER_HASH(HASHCHKP, env->spr[SPR_HASHPKEYR], false)
|
||||
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
|
||||
#ifdef CONFIG_TCG
|
||||
|
@ -830,30 +830,21 @@ static void float_invalid_op_sqrt(CPUPPCState *env, int flags,
|
||||
}
|
||||
}
|
||||
|
||||
/* fsqrt - fsqrt. */
|
||||
float64 helper_fsqrt(CPUPPCState *env, float64 arg)
|
||||
{
|
||||
float64 ret = float64_sqrt(arg, &env->fp_status);
|
||||
int flags = get_float_exception_flags(&env->fp_status);
|
||||
|
||||
if (unlikely(flags & float_flag_invalid)) {
|
||||
float_invalid_op_sqrt(env, flags, 1, GETPC());
|
||||
}
|
||||
|
||||
return ret;
|
||||
#define FPU_FSQRT(name, op) \
|
||||
float64 helper_##name(CPUPPCState *env, float64 arg) \
|
||||
{ \
|
||||
float64 ret = op(arg, &env->fp_status); \
|
||||
int flags = get_float_exception_flags(&env->fp_status); \
|
||||
\
|
||||
if (unlikely(flags & float_flag_invalid)) { \
|
||||
float_invalid_op_sqrt(env, flags, 1, GETPC()); \
|
||||
} \
|
||||
\
|
||||
return ret; \
|
||||
}
|
||||
|
||||
/* fsqrts - fsqrts. */
|
||||
float64 helper_fsqrts(CPUPPCState *env, float64 arg)
|
||||
{
|
||||
float64 ret = float64r32_sqrt(arg, &env->fp_status);
|
||||
int flags = get_float_exception_flags(&env->fp_status);
|
||||
|
||||
if (unlikely(flags & float_flag_invalid)) {
|
||||
float_invalid_op_sqrt(env, flags, 1, GETPC());
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
FPU_FSQRT(FSQRT, float64_sqrt)
|
||||
FPU_FSQRT(FSQRTS, float64r32_sqrt)
|
||||
|
||||
/* fre - fre. */
|
||||
float64 helper_fre(CPUPPCState *env, float64 arg)
|
||||
@ -2176,7 +2167,7 @@ VSX_TSQRT(xvtsqrtsp, 4, float32, VsrW(i), -126, 23)
|
||||
void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, \
|
||||
ppc_vsr_t *s1, ppc_vsr_t *s2, ppc_vsr_t *s3) \
|
||||
{ \
|
||||
ppc_vsr_t t = *xt; \
|
||||
ppc_vsr_t t = { }; \
|
||||
int i; \
|
||||
\
|
||||
helper_reset_fpstatus(env); \
|
||||
@ -2637,6 +2628,8 @@ uint32_t helper_##op(CPUPPCState *env, ppc_vsr_t *xt, \
|
||||
int all_true = 1; \
|
||||
int all_false = 1; \
|
||||
\
|
||||
helper_reset_fpstatus(env); \
|
||||
\
|
||||
for (i = 0; i < nels; i++) { \
|
||||
if (unlikely(tp##_is_any_nan(xa->fld) || \
|
||||
tp##_is_any_nan(xb->fld))) { \
|
||||
@ -2690,6 +2683,8 @@ void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb) \
|
||||
ppc_vsr_t t = { }; \
|
||||
int i; \
|
||||
\
|
||||
helper_reset_fpstatus(env); \
|
||||
\
|
||||
for (i = 0; i < nels; i++) { \
|
||||
t.tfld = stp##_to_##ttp(xb->sfld, &env->fp_status); \
|
||||
if (unlikely(stp##_is_signaling_nan(xb->sfld, \
|
||||
@ -2715,6 +2710,8 @@ void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb) \
|
||||
ppc_vsr_t t = { }; \
|
||||
int i; \
|
||||
\
|
||||
helper_reset_fpstatus(env); \
|
||||
\
|
||||
for (i = 0; i < nels; i++) { \
|
||||
t.VsrW(2 * i) = stp##_to_##ttp(xb->VsrD(i), &env->fp_status); \
|
||||
if (unlikely(stp##_is_signaling_nan(xb->VsrD(i), \
|
||||
@ -2752,6 +2749,8 @@ void helper_##op(CPUPPCState *env, uint32_t opcode, \
|
||||
ppc_vsr_t t = *xt; \
|
||||
int i; \
|
||||
\
|
||||
helper_reset_fpstatus(env); \
|
||||
\
|
||||
for (i = 0; i < nels; i++) { \
|
||||
t.tfld = stp##_to_##ttp(xb->sfld, &env->fp_status); \
|
||||
if (unlikely(stp##_is_signaling_nan(xb->sfld, \
|
||||
@ -2787,6 +2786,8 @@ void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb) \
|
||||
ppc_vsr_t t = { }; \
|
||||
int i; \
|
||||
\
|
||||
helper_reset_fpstatus(env); \
|
||||
\
|
||||
for (i = 0; i < nels; i++) { \
|
||||
t.tfld = stp##_to_##ttp(xb->sfld, 1, &env->fp_status); \
|
||||
if (unlikely(stp##_is_signaling_nan(xb->sfld, \
|
||||
@ -2834,6 +2835,8 @@ void helper_XSCVQPDP(CPUPPCState *env, uint32_t ro, ppc_vsr_t *xt,
|
||||
ppc_vsr_t t = { };
|
||||
float_status tstat;
|
||||
|
||||
helper_reset_fpstatus(env);
|
||||
|
||||
tstat = env->fp_status;
|
||||
if (ro != 0) {
|
||||
tstat.float_rounding_mode = float_round_to_odd;
|
||||
@ -2855,6 +2858,7 @@ uint64_t helper_xscvdpspn(CPUPPCState *env, uint64_t xb)
|
||||
{
|
||||
uint64_t result, sign, exp, frac;
|
||||
|
||||
helper_reset_fpstatus(env);
|
||||
float_status tstat = env->fp_status;
|
||||
set_float_exception_flags(0, &tstat);
|
||||
|
||||
@ -2910,22 +2914,20 @@ uint64_t helper_XSCVSPDPN(uint64_t xb)
|
||||
#define VSX_CVT_FP_TO_INT(op, nels, stp, ttp, sfld, tfld, sfi, rnan) \
|
||||
void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb) \
|
||||
{ \
|
||||
int all_flags = env->fp_status.float_exception_flags, flags; \
|
||||
ppc_vsr_t t = { }; \
|
||||
int i; \
|
||||
int i, flags; \
|
||||
\
|
||||
helper_reset_fpstatus(env); \
|
||||
\
|
||||
for (i = 0; i < nels; i++) { \
|
||||
env->fp_status.float_exception_flags = 0; \
|
||||
t.tfld = stp##_to_##ttp##_round_to_zero(xb->sfld, &env->fp_status); \
|
||||
flags = env->fp_status.float_exception_flags; \
|
||||
if (unlikely(flags & float_flag_invalid)) { \
|
||||
t.tfld = float_invalid_cvt(env, flags, t.tfld, rnan, 0, GETPC());\
|
||||
} \
|
||||
all_flags |= flags; \
|
||||
} \
|
||||
\
|
||||
*xt = t; \
|
||||
env->fp_status.float_exception_flags = all_flags; \
|
||||
do_float_check_status(env, sfi, GETPC()); \
|
||||
}
|
||||
|
||||
@ -2977,12 +2979,12 @@ VSX_CVT_FP_TO_INT128(XSCVQPSQZ, int128, 0x8000000000000000ULL);
|
||||
#define VSX_CVT_FP_TO_INT2(op, nels, stp, ttp, sfi, rnan) \
|
||||
void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb) \
|
||||
{ \
|
||||
int all_flags = env->fp_status.float_exception_flags, flags; \
|
||||
ppc_vsr_t t = { }; \
|
||||
int i; \
|
||||
int i, flags; \
|
||||
\
|
||||
helper_reset_fpstatus(env); \
|
||||
\
|
||||
for (i = 0; i < nels; i++) { \
|
||||
env->fp_status.float_exception_flags = 0; \
|
||||
t.VsrW(2 * i) = stp##_to_##ttp##_round_to_zero(xb->VsrD(i), \
|
||||
&env->fp_status); \
|
||||
flags = env->fp_status.float_exception_flags; \
|
||||
@ -2991,11 +2993,9 @@ void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb) \
|
||||
rnan, 0, GETPC()); \
|
||||
} \
|
||||
t.VsrW(2 * i + 1) = t.VsrW(2 * i); \
|
||||
all_flags |= flags; \
|
||||
} \
|
||||
\
|
||||
*xt = t; \
|
||||
env->fp_status.float_exception_flags = all_flags; \
|
||||
do_float_check_status(env, sfi, GETPC()); \
|
||||
}
|
||||
|
||||
@ -3020,6 +3020,8 @@ void helper_##op(CPUPPCState *env, uint32_t opcode, \
|
||||
ppc_vsr_t t = { }; \
|
||||
int flags; \
|
||||
\
|
||||
helper_reset_fpstatus(env); \
|
||||
\
|
||||
t.tfld = stp##_to_##ttp##_round_to_zero(xb->sfld, &env->fp_status); \
|
||||
flags = get_float_exception_flags(&env->fp_status); \
|
||||
if (flags & float_flag_invalid) { \
|
||||
@ -3032,7 +3034,6 @@ void helper_##op(CPUPPCState *env, uint32_t opcode, \
|
||||
|
||||
VSX_CVT_FP_TO_INT_VECTOR(xscvqpsdz, float128, int64, f128, VsrD(0), \
|
||||
0x8000000000000000ULL)
|
||||
|
||||
VSX_CVT_FP_TO_INT_VECTOR(xscvqpswz, float128, int32, f128, VsrD(0), \
|
||||
0xffffffff80000000ULL)
|
||||
VSX_CVT_FP_TO_INT_VECTOR(xscvqpudz, float128, uint64, f128, VsrD(0), 0x0ULL)
|
||||
@ -3055,6 +3056,8 @@ void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb) \
|
||||
ppc_vsr_t t = { }; \
|
||||
int i; \
|
||||
\
|
||||
helper_reset_fpstatus(env); \
|
||||
\
|
||||
for (i = 0; i < nels; i++) { \
|
||||
t.tfld = stp##_to_##ttp(xb->sfld, &env->fp_status); \
|
||||
if (r2sp) { \
|
||||
@ -3124,6 +3127,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode, \
|
||||
{ \
|
||||
ppc_vsr_t t = *xt; \
|
||||
\
|
||||
helper_reset_fpstatus(env); \
|
||||
t.tfld = stp##_to_##ttp(xb->sfld, &env->fp_status); \
|
||||
helper_compute_fprf_##ttp(env, t.tfld); \
|
||||
\
|
||||
@ -3157,6 +3161,8 @@ void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb) \
|
||||
int i; \
|
||||
FloatRoundMode curr_rounding_mode; \
|
||||
\
|
||||
helper_reset_fpstatus(env); \
|
||||
\
|
||||
if (rmode != FLOAT_ROUND_CURRENT) { \
|
||||
curr_rounding_mode = get_float_rounding_mode(&env->fp_status); \
|
||||
set_float_rounding_mode(rmode, &env->fp_status); \
|
||||
|
@ -4,6 +4,10 @@ DEF_HELPER_FLAGS_4(tw, TCG_CALL_NO_WG, void, env, tl, tl, i32)
|
||||
#if defined(TARGET_PPC64)
|
||||
DEF_HELPER_FLAGS_4(td, TCG_CALL_NO_WG, void, env, tl, tl, i32)
|
||||
#endif
|
||||
DEF_HELPER_4(HASHST, void, env, tl, tl, tl)
|
||||
DEF_HELPER_4(HASHCHK, void, env, tl, tl, tl)
|
||||
DEF_HELPER_4(HASHSTP, void, env, tl, tl, tl)
|
||||
DEF_HELPER_4(HASHCHKP, void, env, tl, tl, tl)
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
DEF_HELPER_2(store_msr, void, env, tl)
|
||||
DEF_HELPER_1(rfi, void, env)
|
||||
@ -116,8 +120,8 @@ DEF_HELPER_4(fmadds, i64, env, i64, i64, i64)
|
||||
DEF_HELPER_4(fmsubs, i64, env, i64, i64, i64)
|
||||
DEF_HELPER_4(fnmadds, i64, env, i64, i64, i64)
|
||||
DEF_HELPER_4(fnmsubs, i64, env, i64, i64, i64)
|
||||
DEF_HELPER_2(fsqrt, f64, env, f64)
|
||||
DEF_HELPER_2(fsqrts, f64, env, f64)
|
||||
DEF_HELPER_2(FSQRT, f64, env, f64)
|
||||
DEF_HELPER_2(FSQRTS, f64, env, f64)
|
||||
DEF_HELPER_2(fre, i64, env, i64)
|
||||
DEF_HELPER_2(fres, i64, env, i64)
|
||||
DEF_HELPER_2(frsqrte, i64, env, i64)
|
||||
|
@ -20,6 +20,9 @@
|
||||
&A frt fra frb frc rc:bool
|
||||
@A ...... frt:5 fra:5 frb:5 frc:5 ..... rc:1 &A
|
||||
|
||||
&A_tb frt frb rc:bool
|
||||
@A_tb ...... frt:5 ..... frb:5 ..... ..... rc:1 &A_tb
|
||||
|
||||
&D rt ra si:int64_t
|
||||
@D ...... rt:5 ra:5 si:s16 &D
|
||||
|
||||
@ -172,6 +175,9 @@
|
||||
@X_TSX ...... ..... ra:5 rb:5 .......... . &X rt=%x_rt_tsx
|
||||
@X_TSXP ...... ..... ra:5 rb:5 .......... . &X rt=%rt_tsxp
|
||||
|
||||
%x_dw 0:1 21:5 !function=dw_compose_ea
|
||||
@X_DW ...... ..... ra:5 rb:5 .......... . &X rt=%x_dw
|
||||
|
||||
&X_frtp_vrb frtp vrb
|
||||
@X_frtp_vrb ...... ....0 ..... vrb:5 .......... . &X_frtp_vrb frtp=%x_frtp
|
||||
|
||||
@ -323,6 +329,13 @@ CNTTZDM 011111 ..... ..... ..... 1000111011 - @X
|
||||
PDEPD 011111 ..... ..... ..... 0010011100 - @X
|
||||
PEXTD 011111 ..... ..... ..... 0010111100 - @X
|
||||
|
||||
# Fixed-Point Hash Instructions
|
||||
|
||||
HASHST 011111 ..... ..... ..... 1011010010 . @X_DW
|
||||
HASHCHK 011111 ..... ..... ..... 1011110010 . @X_DW
|
||||
HASHSTP 011111 ..... ..... ..... 1010010010 . @X_DW
|
||||
HASHCHKP 011111 ..... ..... ..... 1010110010 . @X_DW
|
||||
|
||||
## BCD Assist
|
||||
|
||||
ADDG6S 011111 ..... ..... ..... - 001001010 - @X
|
||||
@ -353,6 +366,11 @@ STFDU 110111 ..... ...... ............... @D
|
||||
STFDX 011111 ..... ...... .... 1011010111 - @X
|
||||
STFDUX 011111 ..... ...... .... 1011110111 - @X
|
||||
|
||||
### Floating-Point Arithmetic Instructions
|
||||
|
||||
FSQRT 111111 ..... ----- ..... ----- 10110 . @A_tb
|
||||
FSQRTS 111011 ..... ----- ..... ----- 10110 . @A_tb
|
||||
|
||||
### Floating-Point Select Instruction
|
||||
|
||||
FSEL 111111 ..... ..... ..... ..... 10111 . @A
|
||||
|
@ -37,9 +37,9 @@
|
||||
static inline void helper_update_ov_legacy(CPUPPCState *env, int ov)
|
||||
{
|
||||
if (unlikely(ov)) {
|
||||
env->so = env->ov = 1;
|
||||
env->so = env->ov = env->ov32 = 1;
|
||||
} else {
|
||||
env->ov = 0;
|
||||
env->ov = env->ov32 = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -6443,6 +6443,14 @@ static inline void get_fpr(TCGv_i64 dst, int regno)
|
||||
static inline void set_fpr(int regno, TCGv_i64 src)
|
||||
{
|
||||
tcg_gen_st_i64(src, cpu_env, fpr_offset(regno));
|
||||
/*
|
||||
* Before PowerISA v3.1 the result of doubleword 1 of the VSR
|
||||
* corresponding to the target FPR was undefined. However,
|
||||
* most (if not all) real hardware were setting the result to 0.
|
||||
* Starting at ISA v3.1, the result for doubleword 1 is now defined
|
||||
* to be 0.
|
||||
*/
|
||||
tcg_gen_st_i64(tcg_constant_i64(0), cpu_env, vsr64_offset(regno, false));
|
||||
}
|
||||
|
||||
static inline void get_avr64(TCGv_i64 dst, int regno, bool high)
|
||||
@ -6473,6 +6481,11 @@ static int times_16(DisasContext *ctx, int x)
|
||||
return x * 16;
|
||||
}
|
||||
|
||||
static int64_t dw_compose_ea(DisasContext *ctx, int x)
|
||||
{
|
||||
return deposit64(0xfffffffffffffe00, 3, 6, x);
|
||||
}
|
||||
|
||||
/*
|
||||
* Helpers for trans_* functions to check for specific insns flags.
|
||||
* Use token pasting to ensure that we use the proper flag with the
|
||||
|
@ -540,3 +540,37 @@ static bool trans_CBCDTD(DisasContext *ctx, arg_X_sa *a)
|
||||
gen_helper_CBCDTD(cpu_gpr[a->ra], cpu_gpr[a->rs]);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool do_hash(DisasContext *ctx, arg_X *a, bool priv,
|
||||
void (*helper)(TCGv_ptr, TCGv, TCGv, TCGv))
|
||||
{
|
||||
TCGv ea;
|
||||
|
||||
if (!(ctx->insns_flags2 & PPC2_ISA310)) {
|
||||
/* if version is before v3.1, this operation is a nop */
|
||||
return true;
|
||||
}
|
||||
|
||||
if (priv) {
|
||||
/* if instruction is privileged but the context is in user space */
|
||||
REQUIRE_SV(ctx);
|
||||
}
|
||||
|
||||
if (unlikely(a->ra == 0)) {
|
||||
/* if RA=0, the instruction form is invalid */
|
||||
gen_invalid(ctx);
|
||||
return true;
|
||||
}
|
||||
|
||||
ea = do_ea_calc(ctx, a->ra, tcg_constant_tl(a->rt));
|
||||
helper(cpu_env, ea, cpu_gpr[a->ra], cpu_gpr[a->rb]);
|
||||
|
||||
tcg_temp_free(ea);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
TRANS(HASHST, do_hash, false, gen_helper_HASHST)
|
||||
TRANS(HASHCHK, do_hash, false, gen_helper_HASHCHK)
|
||||
TRANS(HASHSTP, do_hash, true, gen_helper_HASHSTP)
|
||||
TRANS(HASHCHKP, do_hash, true, gen_helper_HASHCHKP)
|
||||
|
@ -254,50 +254,34 @@ static bool trans_FSEL(DisasContext *ctx, arg_A *a)
|
||||
GEN_FLOAT_AB(sub, 0x14, 0x000007C0, 1, PPC_FLOAT);
|
||||
/* Optional: */
|
||||
|
||||
/* fsqrt */
|
||||
static void gen_fsqrt(DisasContext *ctx)
|
||||
static bool do_helper_fsqrt(DisasContext *ctx, arg_A_tb *a,
|
||||
void (*helper)(TCGv_i64, TCGv_ptr, TCGv_i64))
|
||||
{
|
||||
TCGv_i64 t0;
|
||||
TCGv_i64 t1;
|
||||
if (unlikely(!ctx->fpu_enabled)) {
|
||||
gen_exception(ctx, POWERPC_EXCP_FPU);
|
||||
return;
|
||||
}
|
||||
TCGv_i64 t0, t1;
|
||||
|
||||
REQUIRE_INSNS_FLAGS(ctx, FLOAT_FSQRT);
|
||||
REQUIRE_FPU(ctx);
|
||||
|
||||
t0 = tcg_temp_new_i64();
|
||||
t1 = tcg_temp_new_i64();
|
||||
|
||||
gen_reset_fpstatus();
|
||||
get_fpr(t0, rB(ctx->opcode));
|
||||
gen_helper_fsqrt(t1, cpu_env, t0);
|
||||
set_fpr(rD(ctx->opcode), t1);
|
||||
get_fpr(t0, a->frb);
|
||||
helper(t1, cpu_env, t0);
|
||||
set_fpr(a->frt, t1);
|
||||
gen_compute_fprf_float64(t1);
|
||||
if (unlikely(Rc(ctx->opcode) != 0)) {
|
||||
if (unlikely(a->rc != 0)) {
|
||||
gen_set_cr1_from_fpscr(ctx);
|
||||
}
|
||||
|
||||
tcg_temp_free_i64(t0);
|
||||
tcg_temp_free_i64(t1);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void gen_fsqrts(DisasContext *ctx)
|
||||
{
|
||||
TCGv_i64 t0;
|
||||
TCGv_i64 t1;
|
||||
if (unlikely(!ctx->fpu_enabled)) {
|
||||
gen_exception(ctx, POWERPC_EXCP_FPU);
|
||||
return;
|
||||
}
|
||||
t0 = tcg_temp_new_i64();
|
||||
t1 = tcg_temp_new_i64();
|
||||
gen_reset_fpstatus();
|
||||
get_fpr(t0, rB(ctx->opcode));
|
||||
gen_helper_fsqrts(t1, cpu_env, t0);
|
||||
set_fpr(rD(ctx->opcode), t1);
|
||||
gen_compute_fprf_float64(t1);
|
||||
if (unlikely(Rc(ctx->opcode) != 0)) {
|
||||
gen_set_cr1_from_fpscr(ctx);
|
||||
}
|
||||
tcg_temp_free_i64(t0);
|
||||
tcg_temp_free_i64(t1);
|
||||
}
|
||||
TRANS(FSQRT, do_helper_fsqrt, gen_helper_FSQRT);
|
||||
TRANS(FSQRTS, do_helper_fsqrt, gen_helper_FSQRTS);
|
||||
|
||||
/*** Floating-Point multiply-and-add ***/
|
||||
/* fmadd - fmadds */
|
||||
|
@ -62,8 +62,6 @@ GEN_HANDLER_E(stfdepx, 0x1F, 0x1F, 0x16, 0x00000001, PPC_NONE, PPC2_BOOKE206),
|
||||
GEN_HANDLER_E(stfdpx, 0x1F, 0x17, 0x1C, 0x00200001, PPC_NONE, PPC2_ISA205),
|
||||
|
||||
GEN_HANDLER(frsqrtes, 0x3B, 0x1A, 0xFF, 0x001F07C0, PPC_FLOAT_FRSQRTES),
|
||||
GEN_HANDLER(fsqrt, 0x3F, 0x16, 0xFF, 0x001F07C0, PPC_FLOAT_FSQRT),
|
||||
GEN_HANDLER(fsqrts, 0x3B, 0x16, 0xFF, 0x001F07C0, PPC_FLOAT_FSQRT),
|
||||
GEN_HANDLER(fcmpo, 0x3F, 0x00, 0x01, 0x00600001, PPC_FLOAT),
|
||||
GEN_HANDLER(fcmpu, 0x3F, 0x00, 0x00, 0x00600001, PPC_FLOAT),
|
||||
GEN_HANDLER(fabs, 0x3F, 0x08, 0x08, 0x001F0000, PPC_FLOAT),
|
||||
|
Loading…
Reference in New Issue
Block a user