aboutsummaryrefslogtreecommitdiff
path: root/target/ppc
diff options
context:
space:
mode:
Diffstat (limited to 'target/ppc')
-rw-r--r--target/ppc/Makefile.objs2
-rw-r--r--target/ppc/compat.c185
-rw-r--r--target/ppc/cpu-models.c22
-rw-r--r--target/ppc/cpu-models.h2
-rw-r--r--target/ppc/cpu-qom.h3
-rw-r--r--target/ppc/cpu.h67
-rw-r--r--target/ppc/excp_helper.c11
-rw-r--r--target/ppc/fpu_helper.c756
-rw-r--r--target/ppc/helper.h50
-rw-r--r--target/ppc/int_helper.c473
-rw-r--r--target/ppc/internal.h202
-rw-r--r--target/ppc/kvm.c40
-rw-r--r--target/ppc/kvm_ppc.h4
-rw-r--r--target/ppc/mem_helper.c66
-rw-r--r--target/ppc/mmu-hash64.c4
-rw-r--r--target/ppc/mmu-hash64.h2
-rw-r--r--target/ppc/translate.c244
-rw-r--r--target/ppc/translate/fp-impl.inc.c20
-rw-r--r--target/ppc/translate/fp-ops.inc.c2
-rw-r--r--target/ppc/translate/vmx-impl.inc.c64
-rw-r--r--target/ppc/translate/vmx-ops.inc.c23
-rw-r--r--target/ppc/translate/vsx-impl.inc.c484
-rw-r--r--target/ppc/translate/vsx-ops.inc.c74
-rw-r--r--target/ppc/translate_init.c97
24 files changed, 2421 insertions, 476 deletions
diff --git a/target/ppc/Makefile.objs b/target/ppc/Makefile.objs
index e667e69701..a8c7a30cde 100644
--- a/target/ppc/Makefile.objs
+++ b/target/ppc/Makefile.objs
@@ -2,7 +2,7 @@ obj-y += cpu-models.o
obj-y += translate.o
ifeq ($(CONFIG_SOFTMMU),y)
obj-y += machine.o mmu_helper.o mmu-hash32.o monitor.o
-obj-$(TARGET_PPC64) += mmu-hash64.o arch_dump.o
+obj-$(TARGET_PPC64) += mmu-hash64.o arch_dump.o compat.o
endif
obj-$(CONFIG_KVM) += kvm.o
obj-$(call lnot,$(CONFIG_KVM)) += kvm-stub.o
diff --git a/target/ppc/compat.c b/target/ppc/compat.c
new file mode 100644
index 0000000000..458da262be
--- /dev/null
+++ b/target/ppc/compat.c
@@ -0,0 +1,185 @@
+/*
+ * PowerPC CPU initialization for qemu.
+ *
+ * Copyright 2016, David Gibson, Red Hat Inc. <dgibson@redhat.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu/osdep.h"
+#include "sysemu/hw_accel.h"
+#include "sysemu/kvm.h"
+#include "kvm_ppc.h"
+#include "sysemu/cpus.h"
+#include "qemu/error-report.h"
+#include "qapi/error.h"
+#include "cpu-models.h"
+
+typedef struct {
+ uint32_t pvr;
+ uint64_t pcr;
+ uint64_t pcr_level;
+ int max_threads;
+} CompatInfo;
+
+static const CompatInfo compat_table[] = {
+ /*
+ * Ordered from oldest to newest - the code relies on this
+ */
+ { /* POWER6, ISA2.05 */
+ .pvr = CPU_POWERPC_LOGICAL_2_05,
+ .pcr = PCR_COMPAT_2_07 | PCR_COMPAT_2_06 | PCR_COMPAT_2_05
+ | PCR_TM_DIS | PCR_VSX_DIS,
+ .pcr_level = PCR_COMPAT_2_05,
+ .max_threads = 2,
+ },
+ { /* POWER7, ISA2.06 */
+ .pvr = CPU_POWERPC_LOGICAL_2_06,
+ .pcr = PCR_COMPAT_2_07 | PCR_COMPAT_2_06 | PCR_TM_DIS,
+ .pcr_level = PCR_COMPAT_2_06,
+ .max_threads = 4,
+ },
+ {
+ .pvr = CPU_POWERPC_LOGICAL_2_06_PLUS,
+ .pcr = PCR_COMPAT_2_07 | PCR_COMPAT_2_06 | PCR_TM_DIS,
+ .pcr_level = PCR_COMPAT_2_06,
+ .max_threads = 4,
+ },
+ { /* POWER8, ISA2.07 */
+ .pvr = CPU_POWERPC_LOGICAL_2_07,
+ .pcr = PCR_COMPAT_2_07,
+ .pcr_level = PCR_COMPAT_2_07,
+ .max_threads = 8,
+ },
+};
+
+static const CompatInfo *compat_by_pvr(uint32_t pvr)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(compat_table); i++) {
+ if (compat_table[i].pvr == pvr) {
+ return &compat_table[i];
+ }
+ }
+ return NULL;
+}
+
+bool ppc_check_compat(PowerPCCPU *cpu, uint32_t compat_pvr,
+ uint32_t min_compat_pvr, uint32_t max_compat_pvr)
+{
+ PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu);
+ const CompatInfo *compat = compat_by_pvr(compat_pvr);
+ const CompatInfo *min = compat_by_pvr(min_compat_pvr);
+ const CompatInfo *max = compat_by_pvr(max_compat_pvr);
+
+#if !defined(CONFIG_USER_ONLY)
+ g_assert(cpu->vhyp);
+#endif
+ g_assert(!min_compat_pvr || min);
+ g_assert(!max_compat_pvr || max);
+
+ if (!compat) {
+ /* Not a recognized logical PVR */
+ return false;
+ }
+ if ((min && (compat < min)) || (max && (compat > max))) {
+ /* Outside specified range */
+ return false;
+ }
+ if (!(pcc->pcr_supported & compat->pcr_level)) {
+ /* Not supported by this CPU */
+ return false;
+ }
+ return true;
+}
+
+void ppc_set_compat(PowerPCCPU *cpu, uint32_t compat_pvr, Error **errp)
+{
+ const CompatInfo *compat = compat_by_pvr(compat_pvr);
+ CPUPPCState *env = &cpu->env;
+ PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu);
+ uint64_t pcr;
+
+ if (!compat_pvr) {
+ pcr = 0;
+ } else if (!compat) {
+ error_setg(errp, "Unknown compatibility PVR 0x%08"PRIx32, compat_pvr);
+ return;
+ } else if (!ppc_check_compat(cpu, compat_pvr, 0, 0)) {
+ error_setg(errp, "Compatibility PVR 0x%08"PRIx32" not valid for CPU",
+ compat_pvr);
+ return;
+ } else {
+ pcr = compat->pcr;
+ }
+
+ cpu_synchronize_state(CPU(cpu));
+
+ cpu->compat_pvr = compat_pvr;
+ env->spr[SPR_PCR] = pcr & pcc->pcr_mask;
+
+ if (kvm_enabled()) {
+ int ret = kvmppc_set_compat(cpu, cpu->compat_pvr);
+ if (ret < 0) {
+ error_setg_errno(errp, -ret,
+ "Unable to set CPU compatibility mode in KVM");
+ }
+ }
+}
+
+typedef struct {
+ uint32_t compat_pvr;
+ Error *err;
+} SetCompatState;
+
+static void do_set_compat(CPUState *cs, run_on_cpu_data arg)
+{
+ PowerPCCPU *cpu = POWERPC_CPU(cs);
+ SetCompatState *s = arg.host_ptr;
+
+ ppc_set_compat(cpu, s->compat_pvr, &s->err);
+}
+
+void ppc_set_compat_all(uint32_t compat_pvr, Error **errp)
+{
+ CPUState *cs;
+
+ CPU_FOREACH(cs) {
+ SetCompatState s = {
+ .compat_pvr = compat_pvr,
+ .err = NULL,
+ };
+
+ run_on_cpu(cs, do_set_compat, RUN_ON_CPU_HOST_PTR(&s));
+
+ if (s.err) {
+ error_propagate(errp, s.err);
+ return;
+ }
+ }
+}
+
+int ppc_compat_max_threads(PowerPCCPU *cpu)
+{
+ const CompatInfo *compat = compat_by_pvr(cpu->compat_pvr);
+ int n_threads = CPU(cpu)->nr_threads;
+
+ if (cpu->compat_pvr) {
+ g_assert(compat);
+ n_threads = MIN(n_threads, compat->max_threads);
+ }
+
+ return n_threads;
+}
diff --git a/target/ppc/cpu-models.c b/target/ppc/cpu-models.c
index 506dee1ee8..4d3e6354cf 100644
--- a/target/ppc/cpu-models.c
+++ b/target/ppc/cpu-models.c
@@ -1375,19 +1375,15 @@ PowerPCCPUAlias ppc_cpu_aliases[] = {
{ "7445", "7445_v3.2" },
{ "7455", "7455_v3.2" },
{ "Apollo6", "7455" },
- { "7447", "7447_v1.2" },
+ { "7447", "7447_v1.1" },
{ "7457", "7457_v1.2" },
{ "Apollo7", "7457" },
{ "7447A", "7447A_v1.2" },
{ "7457A", "7457A_v1.2" },
{ "Apollo7PM", "7457A_v1.0" },
#if defined(TARGET_PPC64)
- { "Trident", "620" },
{ "POWER3", "630" },
- { "Boxer", "POWER3" },
- { "Dino", "POWER3" },
{ "POWER3+", "631" },
- { "POWER5gr", "POWER5" },
{ "POWER5+", "POWER5+_v2.1" },
{ "POWER5gs", "POWER5+_v2.1" },
{ "POWER7", "POWER7_v2.3" },
@@ -1399,21 +1395,7 @@ PowerPCCPUAlias ppc_cpu_aliases[] = {
{ "970", "970_v2.2" },
{ "970fx", "970fx_v3.1" },
{ "970mp", "970mp_v1.1" },
- { "Apache", "RS64" },
- { "A35", "RS64" },
- { "NorthStar", "RS64-II" },
- { "A50", "RS64-II" },
- { "Pulsar", "RS64-III" },
- { "IceStar", "RS64-IV" },
- { "IStar", "RS64-IV" },
- { "SStar", "RS64-IV" },
-#endif
- { "RIOS", "POWER" },
- { "RSC", "POWER" },
- { "RSC3308", "POWER" },
- { "RSC4608", "POWER" },
- { "RSC2", "POWER2" },
- { "P2SC", "POWER2" },
+#endif
/* Generic PowerPCs */
#if defined(TARGET_PPC64)
diff --git a/target/ppc/cpu-models.h b/target/ppc/cpu-models.h
index aafbbd7d5d..d587e69bbc 100644
--- a/target/ppc/cpu-models.h
+++ b/target/ppc/cpu-models.h
@@ -601,7 +601,7 @@ enum {
CPU_POWERPC_LOGICAL_2_06 = 0x0F000003,
CPU_POWERPC_LOGICAL_2_06_PLUS = 0x0F100003,
CPU_POWERPC_LOGICAL_2_07 = 0x0F000004,
- CPU_POWERPC_LOGICAL_2_08 = 0x0F000005,
+ CPU_POWERPC_LOGICAL_3_00 = 0x0F000005,
};
/* System version register (used on MPC 8xxx) */
diff --git a/target/ppc/cpu-qom.h b/target/ppc/cpu-qom.h
index d46c31a15d..b7977bad18 100644
--- a/target/ppc/cpu-qom.h
+++ b/target/ppc/cpu-qom.h
@@ -214,6 +214,9 @@ extern const struct VMStateDescription vmstate_ppc_timebase;
.flags = VMS_STRUCT, \
.offset = vmstate_offset_value(_state, _field, PPCTimebase), \
}
+
+void cpu_ppc_clock_vm_state_change(void *opaque, int running,
+ RunState state);
#endif
#endif
diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
index 2a50c43689..bc2a2ce431 100644
--- a/target/ppc/cpu.h
+++ b/target/ppc/cpu.h
@@ -21,6 +21,7 @@
#define PPC_CPU_H
#include "qemu-common.h"
+#include "qemu/int128.h"
//#define PPC_EMULATE_32BITS_HYPV
@@ -262,6 +263,7 @@ union ppc_avr_t {
#ifdef CONFIG_INT128
__uint128_t u128;
#endif
+ Int128 s128;
};
#if !defined(CONFIG_USER_ONLY)
@@ -1148,12 +1150,15 @@ do { \
env->wdt_period[3] = (d_); \
} while (0)
+typedef struct PPCVirtualHypervisor PPCVirtualHypervisor;
+typedef struct PPCVirtualHypervisorClass PPCVirtualHypervisorClass;
+
/**
* PowerPCCPU:
* @env: #CPUPPCState
* @cpu_dt_id: CPU index used in the device tree. KVM uses this index too
* @max_compat: Maximal supported logical PVR from the command line
- * @cpu_version: Current logical PVR, zero if in "raw" mode
+ * @compat_pvr: Current logical PVR, zero if in "raw" mode
*
* A PowerPC CPU.
*/
@@ -1165,7 +1170,8 @@ struct PowerPCCPU {
CPUPPCState env;
int cpu_dt_id;
uint32_t max_compat;
- uint32_t cpu_version;
+ uint32_t compat_pvr;
+ PPCVirtualHypervisor *vhyp;
/* Fields related to migration compatibility hacks */
bool pre_2_8_migration;
@@ -1187,6 +1193,25 @@ static inline PowerPCCPU *ppc_env_get_cpu(CPUPPCState *env)
PowerPCCPUClass *ppc_cpu_class_by_pvr(uint32_t pvr);
PowerPCCPUClass *ppc_cpu_class_by_pvr_mask(uint32_t pvr);
+struct PPCVirtualHypervisor {
+ Object parent;
+};
+
+struct PPCVirtualHypervisorClass {
+ InterfaceClass parent;
+ void (*hypercall)(PPCVirtualHypervisor *vhyp, PowerPCCPU *cpu);
+};
+
+#define TYPE_PPC_VIRTUAL_HYPERVISOR "ppc-virtual-hypervisor"
+#define PPC_VIRTUAL_HYPERVISOR(obj) \
+ OBJECT_CHECK(PPCVirtualHypervisor, (obj), TYPE_PPC_VIRTUAL_HYPERVISOR)
+#define PPC_VIRTUAL_HYPERVISOR_CLASS(klass) \
+ OBJECT_CLASS_CHECK(PPCVirtualHypervisorClass, (klass), \
+ TYPE_PPC_VIRTUAL_HYPERVISOR)
+#define PPC_VIRTUAL_HYPERVISOR_GET_CLASS(obj) \
+ OBJECT_GET_CLASS(PPCVirtualHypervisorClass, (obj), \
+ TYPE_PPC_VIRTUAL_HYPERVISOR)
+
void ppc_cpu_do_interrupt(CPUState *cpu);
bool ppc_cpu_exec_interrupt(CPUState *cpu, int int_req);
void ppc_cpu_dump_state(CPUState *cpu, FILE *f, fprintf_function cpu_fprintf,
@@ -1225,9 +1250,7 @@ void ppc_store_sdr1 (CPUPPCState *env, target_ulong value);
void ppc_store_msr (CPUPPCState *env, target_ulong value);
void ppc_cpu_list (FILE *f, fprintf_function cpu_fprintf);
-int ppc_get_compat_smt_threads(PowerPCCPU *cpu);
#if defined(TARGET_PPC64)
-void ppc_set_compat(PowerPCCPU *cpu, uint32_t cpu_version, Error **errp);
#endif
/* Time-base and decrementer management */
@@ -1259,6 +1282,7 @@ void store_booke_tcr (CPUPPCState *env, target_ulong val);
void store_booke_tsr (CPUPPCState *env, target_ulong val);
void ppc_tlb_invalidate_all (CPUPPCState *env);
void ppc_tlb_invalidate_one (CPUPPCState *env, target_ulong addr);
+void cpu_ppc_set_vhyp(PowerPCCPU *cpu, PPCVirtualHypervisor *vhyp);
void cpu_ppc_set_papr(PowerPCCPU *cpu);
#endif
#endif
@@ -1297,18 +1321,34 @@ static inline int cpu_mmu_index (CPUPPCState *env, bool ifetch)
return ifetch ? env->immu_idx : env->dmmu_idx;
}
+/* Compatibility modes */
+#if defined(TARGET_PPC64)
+bool ppc_check_compat(PowerPCCPU *cpu, uint32_t compat_pvr,
+ uint32_t min_compat_pvr, uint32_t max_compat_pvr);
+void ppc_set_compat(PowerPCCPU *cpu, uint32_t compat_pvr, Error **errp);
+#if !defined(CONFIG_USER_ONLY)
+void ppc_set_compat_all(uint32_t compat_pvr, Error **errp);
+#endif
+int ppc_compat_max_threads(PowerPCCPU *cpu);
+#endif /* defined(TARGET_PPC64) */
+
#include "exec/cpu-all.h"
/*****************************************************************************/
/* CRF definitions */
-#define CRF_LT 3
-#define CRF_GT 2
-#define CRF_EQ 1
-#define CRF_SO 0
-#define CRF_CH (1 << CRF_LT)
-#define CRF_CL (1 << CRF_GT)
-#define CRF_CH_OR_CL (1 << CRF_EQ)
-#define CRF_CH_AND_CL (1 << CRF_SO)
+#define CRF_LT_BIT 3
+#define CRF_GT_BIT 2
+#define CRF_EQ_BIT 1
+#define CRF_SO_BIT 0
+#define CRF_LT (1 << CRF_LT_BIT)
+#define CRF_GT (1 << CRF_GT_BIT)
+#define CRF_EQ (1 << CRF_EQ_BIT)
+#define CRF_SO (1 << CRF_SO_BIT)
+/* For SPE extensions */
+#define CRF_CH (1 << CRF_LT_BIT)
+#define CRF_CL (1 << CRF_GT_BIT)
+#define CRF_CH_OR_CL (1 << CRF_EQ_BIT)
+#define CRF_CH_AND_CL (1 << CRF_SO_BIT)
/* XER definitions */
#define XER_SO 31
@@ -2250,6 +2290,7 @@ enum {
PCR_COMPAT_2_05 = 1ull << (63-62),
PCR_COMPAT_2_06 = 1ull << (63-61),
PCR_COMPAT_2_07 = 1ull << (63-60),
+ PCR_COMPAT_3_00 = 1ull << (63-59),
PCR_VEC_DIS = 1ull << (63-0), /* Vec. disable (bit NA since POWER8) */
PCR_VSX_DIS = 1ull << (63-1), /* VSX disable (bit NA since POWER8) */
PCR_TM_DIS = 1ull << (63-2), /* Trans. memory disable (POWER8) */
@@ -2428,8 +2469,6 @@ static inline bool lsw_reg_in_range(int start, int nregs, int rx)
(start + nregs > 32 && (rx >= start || rx < start + nregs - 32));
}
-extern void (*cpu_ppc_hypercall)(PowerPCCPU *);
-
void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUPPCState *env);
/**
diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
index 93369d4fe5..f4ee7aacd2 100644
--- a/target/ppc/excp_helper.c
+++ b/target/ppc/excp_helper.c
@@ -35,11 +35,6 @@
#endif
/*****************************************************************************/
-/* PowerPC Hypercall emulation */
-
-void (*cpu_ppc_hypercall)(PowerPCCPU *);
-
-/*****************************************************************************/
/* Exception processing */
#if defined(CONFIG_USER_ONLY)
void ppc_cpu_do_interrupt(CPUState *cs)
@@ -318,8 +313,10 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
env->nip += 4;
/* "PAPR mode" built-in hypercall emulation */
- if ((lev == 1) && cpu_ppc_hypercall) {
- cpu_ppc_hypercall(cpu);
+ if ((lev == 1) && cpu->vhyp) {
+ PPCVirtualHypervisorClass *vhc =
+ PPC_VIRTUAL_HYPERVISOR_GET_CLASS(cpu->vhyp);
+ vhc->hypercall(cpu->vhyp, cpu);
return;
}
if (lev == 1) {
diff --git a/target/ppc/fpu_helper.c b/target/ppc/fpu_helper.c
index 8a389e19af..9f5cafd5ba 100644
--- a/target/ppc/fpu_helper.c
+++ b/target/ppc/fpu_helper.c
@@ -20,9 +20,20 @@
#include "cpu.h"
#include "exec/helper-proto.h"
#include "exec/exec-all.h"
+#include "internal.h"
+
+static inline float128 float128_snan_to_qnan(float128 x)
+{
+ float128 r;
+
+ r.high = x.high | 0x0000800000000000;
+ r.low = x.low;
+ return r;
+}
#define float64_snan_to_qnan(x) ((x) | 0x0008000000000000ULL)
#define float32_snan_to_qnan(x) ((x) | 0x00400000)
+#define float16_snan_to_qnan(x) ((x) | 0x0200)
/*****************************************************************************/
/* Floating point operations helpers */
@@ -46,15 +57,6 @@ uint32_t helper_float64_to_float32(CPUPPCState *env, uint64_t arg)
return f.l;
}
-static inline int isden(float64 d)
-{
- CPU_DoubleU u;
-
- u.d = d;
-
- return ((u.ll >> 52) & 0x7FF) == 0;
-}
-
static inline int ppc_float32_get_unbiased_exp(float32 f)
{
return ((f >> 23) & 0xFF) - 127;
@@ -65,56 +67,60 @@ static inline int ppc_float64_get_unbiased_exp(float64 f)
return ((f >> 52) & 0x7FF) - 1023;
}
-void helper_compute_fprf(CPUPPCState *env, uint64_t arg)
-{
- CPU_DoubleU farg;
- int isneg;
- int fprf;
-
- farg.ll = arg;
- isneg = float64_is_neg(farg.d);
- if (unlikely(float64_is_any_nan(farg.d))) {
- if (float64_is_signaling_nan(farg.d, &env->fp_status)) {
- /* Signaling NaN: flags are undefined */
- fprf = 0x00;
- } else {
- /* Quiet NaN */
- fprf = 0x11;
- }
- } else if (unlikely(float64_is_infinity(farg.d))) {
- /* +/- infinity */
- if (isneg) {
- fprf = 0x09;
- } else {
- fprf = 0x05;
- }
- } else {
- if (float64_is_zero(farg.d)) {
- /* +/- zero */
- if (isneg) {
- fprf = 0x12;
- } else {
- fprf = 0x02;
- }
- } else {
- if (isden(farg.d)) {
- /* Denormalized numbers */
- fprf = 0x10;
- } else {
- /* Normalized numbers */
- fprf = 0x00;
- }
- if (isneg) {
- fprf |= 0x08;
- } else {
- fprf |= 0x04;
- }
- }
- }
- /* We update FPSCR_FPRF */
- env->fpscr &= ~(0x1F << FPSCR_FPRF);
- env->fpscr |= fprf << FPSCR_FPRF;
-}
+#define COMPUTE_FPRF(tp) \
+void helper_compute_fprf_##tp(CPUPPCState *env, tp arg) \
+{ \
+ int isneg; \
+ int fprf; \
+ \
+ isneg = tp##_is_neg(arg); \
+ if (unlikely(tp##_is_any_nan(arg))) { \
+ if (tp##_is_signaling_nan(arg, &env->fp_status)) { \
+ /* Signaling NaN: flags are undefined */ \
+ fprf = 0x00; \
+ } else { \
+ /* Quiet NaN */ \
+ fprf = 0x11; \
+ } \
+ } else if (unlikely(tp##_is_infinity(arg))) { \
+ /* +/- infinity */ \
+ if (isneg) { \
+ fprf = 0x09; \
+ } else { \
+ fprf = 0x05; \
+ } \
+ } else { \
+ if (tp##_is_zero(arg)) { \
+ /* +/- zero */ \
+ if (isneg) { \
+ fprf = 0x12; \
+ } else { \
+ fprf = 0x02; \
+ } \
+ } else { \
+ if (tp##_is_zero_or_denormal(arg)) { \
+ /* Denormalized numbers */ \
+ fprf = 0x10; \
+ } else { \
+ /* Normalized numbers */ \
+ fprf = 0x00; \
+ } \
+ if (isneg) { \
+ fprf |= 0x08; \
+ } else { \
+ fprf |= 0x04; \
+ } \
+ } \
+ } \
+ /* We update FPSCR_FPRF */ \
+ env->fpscr &= ~(0x1F << FPSCR_FPRF); \
+ env->fpscr |= fprf << FPSCR_FPRF; \
+}
+
+COMPUTE_FPRF(float16)
+COMPUTE_FPRF(float32)
+COMPUTE_FPRF(float64)
+COMPUTE_FPRF(float128)
/* Floating-point invalid operations exception */
static inline __attribute__((__always_inline__))
@@ -1776,53 +1782,6 @@ uint32_t helper_efdcmpeq(CPUPPCState *env, uint64_t op1, uint64_t op2)
return helper_efdtsteq(env, op1, op2);
}
-#define DECODE_SPLIT(opcode, shift1, nb1, shift2, nb2) \
- (((((opcode) >> (shift1)) & ((1 << (nb1)) - 1)) << nb2) | \
- (((opcode) >> (shift2)) & ((1 << (nb2)) - 1)))
-
-#define xT(opcode) DECODE_SPLIT(opcode, 0, 1, 21, 5)
-#define xA(opcode) DECODE_SPLIT(opcode, 2, 1, 16, 5)
-#define xB(opcode) DECODE_SPLIT(opcode, 1, 1, 11, 5)
-#define xC(opcode) DECODE_SPLIT(opcode, 3, 1, 6, 5)
-#define BF(opcode) (((opcode) >> (31-8)) & 7)
-
-typedef union _ppc_vsr_t {
- uint64_t u64[2];
- uint32_t u32[4];
- float32 f32[4];
- float64 f64[2];
-} ppc_vsr_t;
-
-#if defined(HOST_WORDS_BIGENDIAN)
-#define VsrW(i) u32[i]
-#define VsrD(i) u64[i]
-#else
-#define VsrW(i) u32[3-(i)]
-#define VsrD(i) u64[1-(i)]
-#endif
-
-static void getVSR(int n, ppc_vsr_t *vsr, CPUPPCState *env)
-{
- if (n < 32) {
- vsr->VsrD(0) = env->fpr[n];
- vsr->VsrD(1) = env->vsr[n];
- } else {
- vsr->u64[0] = env->avr[n-32].u64[0];
- vsr->u64[1] = env->avr[n-32].u64[1];
- }
-}
-
-static void putVSR(int n, ppc_vsr_t *vsr, CPUPPCState *env)
-{
- if (n < 32) {
- env->fpr[n] = vsr->VsrD(0);
- env->vsr[n] = vsr->VsrD(1);
- } else {
- env->avr[n-32].u64[0] = vsr->u64[0];
- env->avr[n-32].u64[1] = vsr->u64[1];
- }
-}
-
#define float64_to_float64(x, env) x
@@ -1865,7 +1824,7 @@ void helper_##name(CPUPPCState *env, uint32_t opcode) \
} \
\
if (sfprf) { \
- helper_compute_fprf(env, xt.fld); \
+ helper_compute_fprf_float64(env, xt.fld); \
} \
} \
putVSR(xT(opcode), &xt, env); \
@@ -1881,6 +1840,41 @@ VSX_ADD_SUB(xssubsp, sub, 1, float64, VsrD(0), 1, 1)
VSX_ADD_SUB(xvsubdp, sub, 2, float64, VsrD(i), 0, 0)
VSX_ADD_SUB(xvsubsp, sub, 4, float32, VsrW(i), 0, 0)
+void helper_xsaddqp(CPUPPCState *env, uint32_t opcode)
+{
+ ppc_vsr_t xt, xa, xb;
+ float_status tstat;
+
+ getVSR(rA(opcode) + 32, &xa, env);
+ getVSR(rB(opcode) + 32, &xb, env);
+ getVSR(rD(opcode) + 32, &xt, env);
+ helper_reset_fpstatus(env);
+
+ if (unlikely(Rc(opcode) != 0)) {
+ /* TODO: Support xsadddpo after round-to-odd is implemented */
+ abort();
+ }
+
+ tstat = env->fp_status;
+ set_float_exception_flags(0, &tstat);
+ xt.f128 = float128_add(xa.f128, xb.f128, &tstat);
+ env->fp_status.float_exception_flags |= tstat.float_exception_flags;
+
+ if (unlikely(tstat.float_exception_flags & float_flag_invalid)) {
+ if (float128_is_infinity(xa.f128) && float128_is_infinity(xb.f128)) {
+ float_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, 1);
+ } else if (float128_is_signaling_nan(xa.f128, &tstat) ||
+ float128_is_signaling_nan(xb.f128, &tstat)) {
+ float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
+ }
+ }
+
+ helper_compute_fprf_float128(env, xt.f128);
+
+ putVSR(rD(opcode) + 32, &xt, env);
+ float_check_status(env);
+}
+
/* VSX_MUL - VSX floating point multiply
* op - instruction mnemonic
* nels - number of elements (1, 2 or 4)
@@ -1920,7 +1914,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \
} \
\
if (sfprf) { \
- helper_compute_fprf(env, xt.fld); \
+ helper_compute_fprf_float64(env, xt.fld); \
} \
} \
\
@@ -1933,6 +1927,41 @@ VSX_MUL(xsmulsp, 1, float64, VsrD(0), 1, 1)
VSX_MUL(xvmuldp, 2, float64, VsrD(i), 0, 0)
VSX_MUL(xvmulsp, 4, float32, VsrW(i), 0, 0)
+void helper_xsmulqp(CPUPPCState *env, uint32_t opcode)
+{
+ ppc_vsr_t xt, xa, xb;
+
+ getVSR(rA(opcode) + 32, &xa, env);
+ getVSR(rB(opcode) + 32, &xb, env);
+ getVSR(rD(opcode) + 32, &xt, env);
+
+ if (unlikely(Rc(opcode) != 0)) {
+ /* TODO: Support xsmulpo after round-to-odd is implemented */
+ abort();
+ }
+
+ helper_reset_fpstatus(env);
+
+ float_status tstat = env->fp_status;
+ set_float_exception_flags(0, &tstat);
+ xt.f128 = float128_mul(xa.f128, xb.f128, &tstat);
+ env->fp_status.float_exception_flags |= tstat.float_exception_flags;
+
+ if (unlikely(tstat.float_exception_flags & float_flag_invalid)) {
+ if ((float128_is_infinity(xa.f128) && float128_is_zero(xb.f128)) ||
+ (float128_is_infinity(xb.f128) && float128_is_zero(xa.f128))) {
+ float_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ, 1);
+ } else if (float128_is_signaling_nan(xa.f128, &tstat) ||
+ float128_is_signaling_nan(xb.f128, &tstat)) {
+ float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
+ }
+ }
+ helper_compute_fprf_float128(env, xt.f128);
+
+ putVSR(rD(opcode) + 32, &xt, env);
+ float_check_status(env);
+}
+
/* VSX_DIV - VSX floating point divide
* op - instruction mnemonic
* nels - number of elements (1, 2 or 4)
@@ -1974,7 +2003,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \
} \
\
if (sfprf) { \
- helper_compute_fprf(env, xt.fld); \
+ helper_compute_fprf_float64(env, xt.fld); \
} \
} \
\
@@ -1987,6 +2016,42 @@ VSX_DIV(xsdivsp, 1, float64, VsrD(0), 1, 1)
VSX_DIV(xvdivdp, 2, float64, VsrD(i), 0, 0)
VSX_DIV(xvdivsp, 4, float32, VsrW(i), 0, 0)
+void helper_xsdivqp(CPUPPCState *env, uint32_t opcode)
+{
+ ppc_vsr_t xt, xa, xb;
+
+ getVSR(rA(opcode) + 32, &xa, env);
+ getVSR(rB(opcode) + 32, &xb, env);
+ getVSR(rD(opcode) + 32, &xt, env);
+
+ if (unlikely(Rc(opcode) != 0)) {
+ /* TODO: Support xsdivqpo after round-to-odd is implemented */
+ abort();
+ }
+
+ helper_reset_fpstatus(env);
+ float_status tstat = env->fp_status;
+ set_float_exception_flags(0, &tstat);
+ xt.f128 = float128_div(xa.f128, xb.f128, &tstat);
+ env->fp_status.float_exception_flags |= tstat.float_exception_flags;
+
+ if (unlikely(tstat.float_exception_flags & float_flag_invalid)) {
+ if (float128_is_infinity(xa.f128) && float128_is_infinity(xb.f128)) {
+ float_invalid_op_excp(env, POWERPC_EXCP_FP_VXIDI, 1);
+ } else if (float128_is_zero(xa.f128) &&
+ float128_is_zero(xb.f128)) {
+ float_invalid_op_excp(env, POWERPC_EXCP_FP_VXZDZ, 1);
+ } else if (float128_is_signaling_nan(xa.f128, &tstat) ||
+ float128_is_signaling_nan(xb.f128, &tstat)) {
+ float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
+ }
+ }
+
+ helper_compute_fprf_float128(env, xt.f128);
+ putVSR(rD(opcode) + 32, &xt, env);
+ float_check_status(env);
+}
+
/* VSX_RE - VSX floating point reciprocal estimate
* op - instruction mnemonic
* nels - number of elements (1, 2 or 4)
@@ -2015,7 +2080,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \
} \
\
if (sfprf) { \
- helper_compute_fprf(env, xt.fld); \
+ helper_compute_fprf_float64(env, xt.fld); \
} \
} \
\
@@ -2064,7 +2129,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \
} \
\
if (sfprf) { \
- helper_compute_fprf(env, xt.fld); \
+ helper_compute_fprf_float64(env, xt.fld); \
} \
} \
\
@@ -2114,7 +2179,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \
} \
\
if (sfprf) { \
- helper_compute_fprf(env, xt.fld); \
+ helper_compute_fprf_float64(env, xt.fld); \
} \
} \
\
@@ -2314,7 +2379,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \
} \
\
if (sfprf) { \
- helper_compute_fprf(env, xt_out.fld); \
+ helper_compute_fprf_float64(env, xt_out.fld); \
} \
} \
putVSR(xT(opcode), &xt_out, env); \
@@ -2414,34 +2479,108 @@ VSX_SCALAR_CMP_DP(xscmpgedp, le, 1, 1)
VSX_SCALAR_CMP_DP(xscmpgtdp, lt, 1, 1)
VSX_SCALAR_CMP_DP(xscmpnedp, eq, 0, 0)
+void helper_xscmpexpdp(CPUPPCState *env, uint32_t opcode)
+{
+ ppc_vsr_t xa, xb;
+ int64_t exp_a, exp_b;
+ uint32_t cc;
+
+ getVSR(xA(opcode), &xa, env);
+ getVSR(xB(opcode), &xb, env);
+
+ exp_a = extract64(xa.VsrD(0), 52, 11);
+ exp_b = extract64(xb.VsrD(0), 52, 11);
+
+ if (unlikely(float64_is_any_nan(xa.VsrD(0)) ||
+ float64_is_any_nan(xb.VsrD(0)))) {
+ cc = CRF_SO;
+ } else {
+ if (exp_a < exp_b) {
+ cc = CRF_LT;
+ } else if (exp_a > exp_b) {
+ cc = CRF_GT;
+ } else {
+ cc = CRF_EQ;
+ }
+ }
+
+ env->fpscr &= ~(0x0F << FPSCR_FPRF);
+ env->fpscr |= cc << FPSCR_FPRF;
+ env->crf[BF(opcode)] = cc;
+
+ helper_float_check_status(env);
+}
+
+void helper_xscmpexpqp(CPUPPCState *env, uint32_t opcode)
+{
+ ppc_vsr_t xa, xb;
+ int64_t exp_a, exp_b;
+ uint32_t cc;
+
+ getVSR(rA(opcode) + 32, &xa, env);
+ getVSR(rB(opcode) + 32, &xb, env);
+
+ exp_a = extract64(xa.VsrD(0), 48, 15);
+ exp_b = extract64(xb.VsrD(0), 48, 15);
+
+ if (unlikely(float128_is_any_nan(xa.f128) ||
+ float128_is_any_nan(xb.f128))) {
+ cc = CRF_SO;
+ } else {
+ if (exp_a < exp_b) {
+ cc = CRF_LT;
+ } else if (exp_a > exp_b) {
+ cc = CRF_GT;
+ } else {
+ cc = CRF_EQ;
+ }
+ }
+
+ env->fpscr &= ~(0x0F << FPSCR_FPRF);
+ env->fpscr |= cc << FPSCR_FPRF;
+ env->crf[BF(opcode)] = cc;
+
+ helper_float_check_status(env);
+}
+
#define VSX_SCALAR_CMP(op, ordered) \
void helper_##op(CPUPPCState *env, uint32_t opcode) \
{ \
ppc_vsr_t xa, xb; \
uint32_t cc = 0; \
+ bool vxsnan_flag = false, vxvc_flag = false; \
\
+ helper_reset_fpstatus(env); \
getVSR(xA(opcode), &xa, env); \
getVSR(xB(opcode), &xb, env); \
\
- if (unlikely(float64_is_any_nan(xa.VsrD(0)) || \
- float64_is_any_nan(xb.VsrD(0)))) { \
- if (float64_is_signaling_nan(xa.VsrD(0), &env->fp_status) || \
- float64_is_signaling_nan(xb.VsrD(0), &env->fp_status)) { \
- float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 0); \
+ if (float64_is_signaling_nan(xa.VsrD(0), &env->fp_status) || \
+ float64_is_signaling_nan(xb.VsrD(0), &env->fp_status)) { \
+ vxsnan_flag = true; \
+ cc = CRF_SO; \
+ if (fpscr_ve == 0 && ordered) { \
+ vxvc_flag = true; \
} \
+ } else if (float64_is_quiet_nan(xa.VsrD(0), &env->fp_status) || \
+ float64_is_quiet_nan(xb.VsrD(0), &env->fp_status)) { \
+ cc = CRF_SO; \
if (ordered) { \
- float_invalid_op_excp(env, POWERPC_EXCP_FP_VXVC, 0); \
+ vxvc_flag = true; \
} \
- cc = 1; \
+ } \
+ if (vxsnan_flag) { \
+ float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 0); \
+ } \
+ if (vxvc_flag) { \
+ float_invalid_op_excp(env, POWERPC_EXCP_FP_VXVC, 0); \
+ } \
+ \
+ if (float64_lt(xa.VsrD(0), xb.VsrD(0), &env->fp_status)) { \
+ cc |= CRF_LT; \
+ } else if (!float64_le(xa.VsrD(0), xb.VsrD(0), &env->fp_status)) { \
+ cc |= CRF_GT; \
} else { \
- if (float64_lt(xa.VsrD(0), xb.VsrD(0), &env->fp_status)) { \
- cc = 8; \
- } else if (!float64_le(xa.VsrD(0), xb.VsrD(0), \
- &env->fp_status)) { \
- cc = 4; \
- } else { \
- cc = 2; \
- } \
+ cc |= CRF_EQ; \
} \
\
env->fpscr &= ~(0x0F << FPSCR_FPRF); \
@@ -2454,6 +2593,56 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \
VSX_SCALAR_CMP(xscmpodp, 1)
VSX_SCALAR_CMP(xscmpudp, 0)
+#define VSX_SCALAR_CMPQ(op, ordered) \
+void helper_##op(CPUPPCState *env, uint32_t opcode) \
+{ \
+ ppc_vsr_t xa, xb; \
+ uint32_t cc = 0; \
+ bool vxsnan_flag = false, vxvc_flag = false; \
+ \
+ helper_reset_fpstatus(env); \
+ getVSR(rA(opcode) + 32, &xa, env); \
+ getVSR(rB(opcode) + 32, &xb, env); \
+ \
+ if (float128_is_signaling_nan(xa.f128, &env->fp_status) || \
+ float128_is_signaling_nan(xb.f128, &env->fp_status)) { \
+ vxsnan_flag = true; \
+ cc = CRF_SO; \
+ if (fpscr_ve == 0 && ordered) { \
+ vxvc_flag = true; \
+ } \
+ } else if (float128_is_quiet_nan(xa.f128, &env->fp_status) || \
+ float128_is_quiet_nan(xb.f128, &env->fp_status)) { \
+ cc = CRF_SO; \
+ if (ordered) { \
+ vxvc_flag = true; \
+ } \
+ } \
+ if (vxsnan_flag) { \
+ float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 0); \
+ } \
+ if (vxvc_flag) { \
+ float_invalid_op_excp(env, POWERPC_EXCP_FP_VXVC, 0); \
+ } \
+ \
+ if (float128_lt(xa.f128, xb.f128, &env->fp_status)) { \
+ cc |= CRF_LT; \
+ } else if (!float128_le(xa.f128, xb.f128, &env->fp_status)) { \
+ cc |= CRF_GT; \
+ } else { \
+ cc |= CRF_EQ; \
+ } \
+ \
+ env->fpscr &= ~(0x0F << FPSCR_FPRF); \
+ env->fpscr |= cc << FPSCR_FPRF; \
+ env->crf[BF(opcode)] = cc; \
+ \
+ float_check_status(env); \
+}
+
+VSX_SCALAR_CMPQ(xscmpoqp, 1)
+VSX_SCALAR_CMPQ(xscmpuqp, 0)
+
/* VSX_MAX_MIN - VSX floating point maximum/minimum
* name - instruction mnemonic
* op - operation (max or min)
@@ -2576,8 +2765,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \
xt.tfld = ttp##_snan_to_qnan(xt.tfld); \
} \
if (sfprf) { \
- helper_compute_fprf(env, ttp##_to_float64(xt.tfld, \
- &env->fp_status)); \
+ helper_compute_fprf_##ttp(env, xt.tfld); \
} \
} \
\
@@ -2590,6 +2778,110 @@ VSX_CVT_FP_TO_FP(xscvspdp, 1, float32, float64, VsrW(0), VsrD(0), 1)
VSX_CVT_FP_TO_FP(xvcvdpsp, 2, float64, float32, VsrD(i), VsrW(2*i), 0)
VSX_CVT_FP_TO_FP(xvcvspdp, 2, float32, float64, VsrW(2*i), VsrD(i), 0)
+/* VSX_CVT_FP_TO_FP_VECTOR - VSX floating point/floating point conversion
+ * op - instruction mnemonic
+ * nels - number of elements (1, 2 or 4)
+ * stp - source type (float32 or float64)
+ * ttp - target type (float32 or float64)
+ * sfld - source vsr_t field
+ * tfld - target vsr_t field (f32 or f64)
+ * sfprf - set FPRF
+ */
+#define VSX_CVT_FP_TO_FP_VECTOR(op, nels, stp, ttp, sfld, tfld, sfprf) \
+void helper_##op(CPUPPCState *env, uint32_t opcode) \
+{ \
+ ppc_vsr_t xt, xb; \
+ int i; \
+ \
+ getVSR(rB(opcode) + 32, &xb, env); \
+ getVSR(rD(opcode) + 32, &xt, env); \
+ \
+ for (i = 0; i < nels; i++) { \
+ xt.tfld = stp##_to_##ttp(xb.sfld, &env->fp_status); \
+ if (unlikely(stp##_is_signaling_nan(xb.sfld, \
+ &env->fp_status))) { \
+ float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 0); \
+ xt.tfld = ttp##_snan_to_qnan(xt.tfld); \
+ } \
+ if (sfprf) { \
+ helper_compute_fprf_##ttp(env, xt.tfld); \
+ } \
+ } \
+ \
+ putVSR(rD(opcode) + 32, &xt, env); \
+ float_check_status(env); \
+}
+
+VSX_CVT_FP_TO_FP_VECTOR(xscvdpqp, 1, float64, float128, VsrD(0), f128, 1)
+
+/* VSX_CVT_FP_TO_FP_HP - VSX floating point/floating point conversion
+ * involving one half precision value
+ * op - instruction mnemonic
+ * nels - number of elements (1, 2 or 4)
+ * stp - source type
+ * ttp - target type
+ * sfld - source vsr_t field
+ * tfld - target vsr_t field
+ * sfprf - set FPRF
+ */
+#define VSX_CVT_FP_TO_FP_HP(op, nels, stp, ttp, sfld, tfld, sfprf) \
+void helper_##op(CPUPPCState *env, uint32_t opcode) \
+{ \
+ ppc_vsr_t xt, xb; \
+ int i; \
+ \
+ getVSR(xB(opcode), &xb, env); \
+ memset(&xt, 0, sizeof(xt)); \
+ \
+ for (i = 0; i < nels; i++) { \
+ xt.tfld = stp##_to_##ttp(xb.sfld, 1, &env->fp_status); \
+ if (unlikely(stp##_is_signaling_nan(xb.sfld, \
+ &env->fp_status))) { \
+ float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 0); \
+ xt.tfld = ttp##_snan_to_qnan(xt.tfld); \
+ } \
+ if (sfprf) { \
+ helper_compute_fprf_##ttp(env, xt.tfld); \
+ } \
+ } \
+ \
+ putVSR(xT(opcode), &xt, env); \
+ float_check_status(env); \
+}
+
+VSX_CVT_FP_TO_FP_HP(xscvdphp, 1, float64, float16, VsrD(0), VsrH(3), 1)
+VSX_CVT_FP_TO_FP_HP(xscvhpdp, 1, float16, float64, VsrH(3), VsrD(0), 1)
+VSX_CVT_FP_TO_FP_HP(xvcvsphp, 4, float32, float16, VsrW(i), VsrH(2 * i + 1), 0)
+VSX_CVT_FP_TO_FP_HP(xvcvhpsp, 4, float16, float32, VsrH(2 * i + 1), VsrW(i), 0)
+
+/*
+ * xscvqpdp isn't using VSX_CVT_FP_TO_FP() because xscvqpdpo will be
+ * added to this later.
+ */
+void helper_xscvqpdp(CPUPPCState *env, uint32_t opcode)
+{
+ ppc_vsr_t xt, xb;
+
+ getVSR(rB(opcode) + 32, &xb, env);
+ memset(&xt, 0, sizeof(xt));
+
+ if (unlikely(Rc(opcode) != 0)) {
+ /* TODO: Support xscvqpdpo after round-to-odd is implemented */
+ abort();
+ }
+
+ xt.VsrD(0) = float128_to_float64(xb.f128, &env->fp_status);
+ if (unlikely(float128_is_signaling_nan(xb.f128,
+ &env->fp_status))) {
+ float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 0);
+ xt.VsrD(0) = float64_snan_to_qnan(xt.VsrD(0));
+ }
+ helper_compute_fprf_float64(env, xt.VsrD(0));
+
+ putVSR(rD(opcode) + 32, &xt, env);
+ float_check_status(env);
+}
+
uint64_t helper_xscvdpspn(CPUPPCState *env, uint64_t xb)
{
float_status tstat = env->fp_status;
@@ -2662,6 +2954,46 @@ VSX_CVT_FP_TO_INT(xvcvspsxws, 4, float32, int32, VsrW(i), VsrW(i), 0x80000000U)
VSX_CVT_FP_TO_INT(xvcvspuxds, 2, float32, uint64, VsrW(2*i), VsrD(i), 0ULL)
VSX_CVT_FP_TO_INT(xvcvspuxws, 4, float32, uint32, VsrW(i), VsrW(i), 0U)
+/* VSX_CVT_FP_TO_INT_VECTOR - VSX floating point to integer conversion
+ * op - instruction mnemonic
+ * stp - source type (float32 or float64)
+ * ttp - target type (int32, uint32, int64 or uint64)
+ * sfld - source vsr_t field
+ * tfld - target vsr_t field
+ * rnan - resulting NaN
+ */
+#define VSX_CVT_FP_TO_INT_VECTOR(op, stp, ttp, sfld, tfld, rnan) \
+void helper_##op(CPUPPCState *env, uint32_t opcode) \
+{ \
+ ppc_vsr_t xt, xb; \
+ \
+ getVSR(rB(opcode) + 32, &xb, env); \
+ memset(&xt, 0, sizeof(xt)); \
+ \
+ if (unlikely(stp##_is_any_nan(xb.sfld))) { \
+ if (stp##_is_signaling_nan(xb.sfld, &env->fp_status)) { \
+ float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 0); \
+ } \
+ float_invalid_op_excp(env, POWERPC_EXCP_FP_VXCVI, 0); \
+ xt.tfld = rnan; \
+ } else { \
+ xt.tfld = stp##_to_##ttp##_round_to_zero(xb.sfld, \
+ &env->fp_status); \
+ if (env->fp_status.float_exception_flags & float_flag_invalid) { \
+ float_invalid_op_excp(env, POWERPC_EXCP_FP_VXCVI, 0); \
+ } \
+ } \
+ \
+ putVSR(rD(opcode) + 32, &xt, env); \
+ float_check_status(env); \
+}
+
+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_INT_TO_FP - VSX integer to floating point conversion
* op - instruction mnemonic
* nels - number of elements (1, 2 or 4)
@@ -2687,7 +3019,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \
xt.tfld = helper_frsp(env, xt.tfld); \
} \
if (sfprf) { \
- helper_compute_fprf(env, xt.tfld); \
+ helper_compute_fprf_float64(env, xt.tfld); \
} \
} \
\
@@ -2708,6 +3040,31 @@ VSX_CVT_INT_TO_FP(xvcvuxdsp, 2, uint64, float32, VsrD(i), VsrW(2*i), 0, 0)
VSX_CVT_INT_TO_FP(xvcvsxwsp, 4, int32, float32, VsrW(i), VsrW(i), 0, 0)
VSX_CVT_INT_TO_FP(xvcvuxwsp, 4, uint32, float32, VsrW(i), VsrW(i), 0, 0)
+/* VSX_CVT_INT_TO_FP_VECTOR - VSX integer to floating point conversion
+ * op - instruction mnemonic
+ * stp - source type (int32, uint32, int64 or uint64)
+ * ttp - target type (float32 or float64)
+ * sfld - source vsr_t field
+ * tfld - target vsr_t field
+ */
+#define VSX_CVT_INT_TO_FP_VECTOR(op, stp, ttp, sfld, tfld) \
+void helper_##op(CPUPPCState *env, uint32_t opcode) \
+{ \
+ ppc_vsr_t xt, xb; \
+ \
+ getVSR(rB(opcode) + 32, &xb, env); \
+ getVSR(rD(opcode) + 32, &xt, env); \
+ \
+ xt.tfld = stp##_to_##ttp(xb.sfld, &env->fp_status); \
+ helper_compute_fprf_##ttp(env, xt.tfld); \
+ \
+ putVSR(xT(opcode) + 32, &xt, env); \
+ float_check_status(env); \
+}
+
+VSX_CVT_INT_TO_FP_VECTOR(xscvsdqp, int64, float128, VsrD(0), f128)
+VSX_CVT_INT_TO_FP_VECTOR(xscvudqp, uint64, float128, VsrD(0), f128)
+
/* For "use current rounding mode", define a value that will not be one of
* the existing rounding model enums.
*/
@@ -2743,7 +3100,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \
xt.fld = tp##_round_to_int(xb.fld, &env->fp_status); \
} \
if (sfprf) { \
- helper_compute_fprf(env, xt.fld); \
+ helper_compute_fprf_float64(env, xt.fld); \
} \
} \
\
@@ -2783,7 +3140,140 @@ uint64_t helper_xsrsp(CPUPPCState *env, uint64_t xb)
uint64_t xt = helper_frsp(env, xb);
- helper_compute_fprf(env, xt);
+ helper_compute_fprf_float64(env, xt);
float_check_status(env);
return xt;
}
+
+#define VSX_XXPERM(op, indexed) \
+void helper_##op(CPUPPCState *env, uint32_t opcode) \
+{ \
+ ppc_vsr_t xt, xa, pcv, xto; \
+ int i, idx; \
+ \
+ getVSR(xA(opcode), &xa, env); \
+ getVSR(xT(opcode), &xt, env); \
+ getVSR(xB(opcode), &pcv, env); \
+ \
+ for (i = 0; i < 16; i++) { \
+ idx = pcv.VsrB(i) & 0x1F; \
+ if (indexed) { \
+ idx = 31 - idx; \
+ } \
+ xto.VsrB(i) = (idx <= 15) ? xa.VsrB(idx) : xt.VsrB(idx - 16); \
+ } \
+ putVSR(xT(opcode), &xto, env); \
+}
+
+VSX_XXPERM(xxperm, 0)
+VSX_XXPERM(xxpermr, 1)
+
+void helper_xvxsigsp(CPUPPCState *env, uint32_t opcode)
+{
+ ppc_vsr_t xt, xb;
+ uint32_t exp, i, fraction;
+
+ getVSR(xB(opcode), &xb, env);
+ memset(&xt, 0, sizeof(xt));
+
+ for (i = 0; i < 4; i++) {
+ exp = (xb.VsrW(i) >> 23) & 0xFF;
+ fraction = xb.VsrW(i) & 0x7FFFFF;
+ if (exp != 0 && exp != 255) {
+ xt.VsrW(i) = fraction | 0x00800000;
+ } else {
+ xt.VsrW(i) = fraction;
+ }
+ }
+ putVSR(xT(opcode), &xt, env);
+}
+
+/* VSX_TEST_DC - VSX floating point test data class
+ * op - instruction mnemonic
+ * nels - number of elements (1, 2 or 4)
+ * xbn - VSR register number
+ * tp - type (float32 or float64)
+ * fld - vsr_t field (VsrD(*) or VsrW(*))
+ * tfld - target vsr_t field (VsrD(*) or VsrW(*))
+ * fld_max - target field max
+ * scrf - set result in CR and FPCC
+ */
+#define VSX_TEST_DC(op, nels, xbn, tp, fld, tfld, fld_max, scrf) \
+void helper_##op(CPUPPCState *env, uint32_t opcode) \
+{ \
+ ppc_vsr_t xt, xb; \
+ uint32_t i, sign, dcmx; \
+ uint32_t cc, match = 0; \
+ \
+ getVSR(xbn, &xb, env); \
+ if (!scrf) { \
+ memset(&xt, 0, sizeof(xt)); \
+ dcmx = DCMX_XV(opcode); \
+ } else { \
+ dcmx = DCMX(opcode); \
+ } \
+ \
+ for (i = 0; i < nels; i++) { \
+ sign = tp##_is_neg(xb.fld); \
+ if (tp##_is_any_nan(xb.fld)) { \
+ match = extract32(dcmx, 6, 1); \
+ } else if (tp##_is_infinity(xb.fld)) { \
+ match = extract32(dcmx, 4 + !sign, 1); \
+ } else if (tp##_is_zero(xb.fld)) { \
+ match = extract32(dcmx, 2 + !sign, 1); \
+ } else if (tp##_is_zero_or_denormal(xb.fld)) { \
+ match = extract32(dcmx, 0 + !sign, 1); \
+ } \
+ \
+ if (scrf) { \
+ cc = sign << CRF_LT_BIT | match << CRF_EQ_BIT; \
+ env->fpscr &= ~(0x0F << FPSCR_FPRF); \
+ env->fpscr |= cc << FPSCR_FPRF; \
+ env->crf[BF(opcode)] = cc; \
+ } else { \
+ xt.tfld = match ? fld_max : 0; \
+ } \
+ match = 0; \
+ } \
+ if (!scrf) { \
+ putVSR(xT(opcode), &xt, env); \
+ } \
+}
+
+VSX_TEST_DC(xvtstdcdp, 2, xB(opcode), float64, VsrD(i), VsrD(i), UINT64_MAX, 0)
+VSX_TEST_DC(xvtstdcsp, 4, xB(opcode), float32, VsrW(i), VsrW(i), UINT32_MAX, 0)
+VSX_TEST_DC(xststdcdp, 1, xB(opcode), float64, VsrD(0), VsrD(0), 0, 1)
+VSX_TEST_DC(xststdcqp, 1, (rB(opcode) + 32), float128, f128, VsrD(0), 0, 1)
+
+void helper_xststdcsp(CPUPPCState *env, uint32_t opcode)
+{
+ ppc_vsr_t xb;
+ uint32_t dcmx, sign, exp;
+ uint32_t cc, match = 0, not_sp = 0;
+
+ getVSR(xB(opcode), &xb, env);
+ dcmx = DCMX(opcode);
+ exp = (xb.VsrD(0) >> 52) & 0x7FF;
+
+ sign = float64_is_neg(xb.VsrD(0));
+ if (float64_is_any_nan(xb.VsrD(0))) {
+ match = extract32(dcmx, 6, 1);
+ } else if (float64_is_infinity(xb.VsrD(0))) {
+ match = extract32(dcmx, 4 + !sign, 1);
+ } else if (float64_is_zero(xb.VsrD(0))) {
+ match = extract32(dcmx, 2 + !sign, 1);
+ } else if (float64_is_zero_or_denormal(xb.VsrD(0)) ||
+ (exp > 0 && exp < 0x381)) {
+ match = extract32(dcmx, 0 + !sign, 1);
+ }
+
+ not_sp = !float64_eq(xb.VsrD(0),
+ float32_to_float64(
+ float64_to_float32(xb.VsrD(0), &env->fp_status),
+ &env->fp_status), &env->fp_status);
+
+ cc = sign << CRF_LT_BIT | match << CRF_EQ_BIT | not_sp << CRF_SO_BIT;
+ env->fpscr &= ~(0x0F << FPSCR_FPRF);
+ env->fpscr |= cc << FPSCR_FPRF;
+ env->crf[BF(opcode)] = cc;
+}
diff --git a/target/ppc/helper.h b/target/ppc/helper.h
index 0a8fbba3c5..85af9df36d 100644
--- a/target/ppc/helper.h
+++ b/target/ppc/helper.h
@@ -56,7 +56,7 @@ DEF_HELPER_FLAGS_2(brinc, TCG_CALL_NO_RWG_SE, tl, tl, tl)
DEF_HELPER_1(float_check_status, void, env)
DEF_HELPER_1(reset_fpstatus, void, env)
-DEF_HELPER_2(compute_fprf, void, env, i64)
+DEF_HELPER_2(compute_fprf_float64, void, env, i64)
DEF_HELPER_3(store_fpscr, void, env, i64, i32)
DEF_HELPER_2(fpscr_clrbit, void, env, i32)
DEF_HELPER_2(fpscr_setbit, void, env, i32)
@@ -312,6 +312,12 @@ DEF_HELPER_3(lvewx, void, env, avr, tl)
DEF_HELPER_3(stvebx, void, env, avr, tl)
DEF_HELPER_3(stvehx, void, env, avr, tl)
DEF_HELPER_3(stvewx, void, env, avr, tl)
+#if defined(TARGET_PPC64)
+DEF_HELPER_4(lxvl, void, env, tl, tl, tl)
+DEF_HELPER_4(lxvll, void, env, tl, tl, tl)
+DEF_HELPER_4(stxvl, void, env, tl, tl, tl)
+DEF_HELPER_4(stxvll, void, env, tl, tl, tl)
+#endif
DEF_HELPER_4(vsumsws, void, env, avr, avr, avr)
DEF_HELPER_4(vsum2sws, void, env, avr, avr, avr)
DEF_HELPER_4(vsum4sbs, void, env, avr, avr, avr)
@@ -361,6 +367,12 @@ DEF_HELPER_3(vpmsumb, void, avr, avr, avr)
DEF_HELPER_3(vpmsumh, void, avr, avr, avr)
DEF_HELPER_3(vpmsumw, void, avr, avr, avr)
DEF_HELPER_3(vpmsumd, void, avr, avr, avr)
+DEF_HELPER_2(vextublx, tl, tl, avr)
+DEF_HELPER_2(vextuhlx, tl, tl, avr)
+DEF_HELPER_2(vextuwlx, tl, tl, avr)
+DEF_HELPER_2(vextubrx, tl, tl, avr)
+DEF_HELPER_2(vextuhrx, tl, tl, avr)
+DEF_HELPER_2(vextuwrx, tl, tl, avr)
DEF_HELPER_2(vsbox, void, avr, avr)
DEF_HELPER_3(vcipher, void, avr, avr, avr)
@@ -377,11 +389,23 @@ DEF_HELPER_3(bcdcfn, i32, avr, avr, i32)
DEF_HELPER_3(bcdctn, i32, avr, avr, i32)
DEF_HELPER_3(bcdcfz, i32, avr, avr, i32)
DEF_HELPER_3(bcdctz, i32, avr, avr, i32)
+DEF_HELPER_3(bcdcfsq, i32, avr, avr, i32)
+DEF_HELPER_3(bcdctsq, i32, avr, avr, i32)
+DEF_HELPER_4(bcdcpsgn, i32, avr, avr, avr, i32)
+DEF_HELPER_3(bcdsetsgn, i32, avr, avr, i32)
+DEF_HELPER_4(bcds, i32, avr, avr, avr, i32)
+DEF_HELPER_4(bcdus, i32, avr, avr, avr, i32)
+DEF_HELPER_4(bcdsr, i32, avr, avr, avr, i32)
+DEF_HELPER_4(bcdtrunc, i32, avr, avr, avr, i32)
+DEF_HELPER_4(bcdutrunc, i32, avr, avr, avr, i32)
DEF_HELPER_2(xsadddp, void, env, i32)
+DEF_HELPER_2(xsaddqp, void, env, i32)
DEF_HELPER_2(xssubdp, void, env, i32)
DEF_HELPER_2(xsmuldp, void, env, i32)
+DEF_HELPER_2(xsmulqp, void, env, i32)
DEF_HELPER_2(xsdivdp, void, env, i32)
+DEF_HELPER_2(xsdivqp, void, env, i32)
DEF_HELPER_2(xsredp, void, env, i32)
DEF_HELPER_2(xssqrtdp, void, env, i32)
DEF_HELPER_2(xsrsqrtedp, void, env, i32)
@@ -399,12 +423,23 @@ DEF_HELPER_2(xscmpeqdp, void, env, i32)
DEF_HELPER_2(xscmpgtdp, void, env, i32)
DEF_HELPER_2(xscmpgedp, void, env, i32)
DEF_HELPER_2(xscmpnedp, void, env, i32)
+DEF_HELPER_2(xscmpexpdp, void, env, i32)
+DEF_HELPER_2(xscmpexpqp, void, env, i32)
DEF_HELPER_2(xscmpodp, void, env, i32)
DEF_HELPER_2(xscmpudp, void, env, i32)
+DEF_HELPER_2(xscmpoqp, void, env, i32)
+DEF_HELPER_2(xscmpuqp, void, env, i32)
DEF_HELPER_2(xsmaxdp, void, env, i32)
DEF_HELPER_2(xsmindp, void, env, i32)
+DEF_HELPER_2(xscvdphp, void, env, i32)
+DEF_HELPER_2(xscvdpqp, void, env, i32)
DEF_HELPER_2(xscvdpsp, void, env, i32)
DEF_HELPER_2(xscvdpspn, i64, env, i64)
+DEF_HELPER_2(xscvqpdp, void, env, i32)
+DEF_HELPER_2(xscvqpsdz, void, env, i32)
+DEF_HELPER_2(xscvqpswz, void, env, i32)
+DEF_HELPER_2(xscvhpdp, void, env, i32)
+DEF_HELPER_2(xscvsdqp, void, env, i32)
DEF_HELPER_2(xscvspdp, void, env, i32)
DEF_HELPER_2(xscvspdpn, i64, env, i64)
DEF_HELPER_2(xscvdpsxds, void, env, i32)
@@ -414,7 +449,11 @@ DEF_HELPER_2(xscvdpuxws, void, env, i32)
DEF_HELPER_2(xscvsxddp, void, env, i32)
DEF_HELPER_2(xscvuxdsp, void, env, i32)
DEF_HELPER_2(xscvsxdsp, void, env, i32)
+DEF_HELPER_2(xscvudqp, void, env, i32)
DEF_HELPER_2(xscvuxddp, void, env, i32)
+DEF_HELPER_2(xststdcsp, void, env, i32)
+DEF_HELPER_2(xststdcdp, void, env, i32)
+DEF_HELPER_2(xststdcqp, void, env, i32)
DEF_HELPER_2(xsrdpi, void, env, i32)
DEF_HELPER_2(xsrdpic, void, env, i32)
DEF_HELPER_2(xsrdpim, void, env, i32)
@@ -500,6 +539,8 @@ DEF_HELPER_2(xvcmpgesp, void, env, i32)
DEF_HELPER_2(xvcmpgtsp, void, env, i32)
DEF_HELPER_2(xvcmpnesp, void, env, i32)
DEF_HELPER_2(xvcvspdp, void, env, i32)
+DEF_HELPER_2(xvcvsphp, void, env, i32)
+DEF_HELPER_2(xvcvhpsp, void, env, i32)
DEF_HELPER_2(xvcvspsxds, void, env, i32)
DEF_HELPER_2(xvcvspsxws, void, env, i32)
DEF_HELPER_2(xvcvspuxds, void, env, i32)
@@ -508,11 +549,18 @@ DEF_HELPER_2(xvcvsxdsp, void, env, i32)
DEF_HELPER_2(xvcvuxdsp, void, env, i32)
DEF_HELPER_2(xvcvsxwsp, void, env, i32)
DEF_HELPER_2(xvcvuxwsp, void, env, i32)
+DEF_HELPER_2(xvtstdcsp, void, env, i32)
+DEF_HELPER_2(xvtstdcdp, void, env, i32)
DEF_HELPER_2(xvrspi, void, env, i32)
DEF_HELPER_2(xvrspic, void, env, i32)
DEF_HELPER_2(xvrspim, void, env, i32)
DEF_HELPER_2(xvrspip, void, env, i32)
DEF_HELPER_2(xvrspiz, void, env, i32)
+DEF_HELPER_2(xxperm, void, env, i32)
+DEF_HELPER_2(xxpermr, void, env, i32)
+DEF_HELPER_4(xxextractuw, void, env, tl, tl, i32)
+DEF_HELPER_4(xxinsertw, void, env, tl, tl, i32)
+DEF_HELPER_2(xvxsigsp, void, env, i32)
DEF_HELPER_2(efscfsi, i32, env, i32)
DEF_HELPER_2(efscfui, i32, env, i32)
diff --git a/target/ppc/int_helper.c b/target/ppc/int_helper.c
index 1871792ff6..dd0a8929b3 100644
--- a/target/ppc/int_helper.c
+++ b/target/ppc/int_helper.c
@@ -157,7 +157,7 @@ uint64_t helper_divde(CPUPPCState *env, uint64_t rau, uint64_t rbu, uint32_t oe)
uint32_t helper_cmpeqb(target_ulong ra, target_ulong rb)
{
- return hasvalue(rb, ra) ? 1 << CRF_GT : 0;
+ return hasvalue(rb, ra) ? CRF_GT : 0;
}
#undef pattern
@@ -1773,6 +1773,42 @@ void helper_vlogefp(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *b)
}
}
+#if defined(HOST_WORDS_BIGENDIAN)
+#define VEXTU_X_DO(name, size, left) \
+ target_ulong glue(helper_, name)(target_ulong a, ppc_avr_t *b) \
+ { \
+ int index; \
+ if (left) { \
+ index = (a & 0xf) * 8; \
+ } else { \
+ index = ((15 - (a & 0xf) + 1) * 8) - size; \
+ } \
+ return int128_getlo(int128_rshift(b->s128, index)) & \
+ MAKE_64BIT_MASK(0, size); \
+ }
+#else
+#define VEXTU_X_DO(name, size, left) \
+ target_ulong glue(helper_, name)(target_ulong a, ppc_avr_t *b) \
+ { \
+ int index; \
+ if (left) { \
+ index = ((15 - (a & 0xf) + 1) * 8) - size; \
+ } else { \
+ index = (a & 0xf) * 8; \
+ } \
+ return int128_getlo(int128_rshift(b->s128, index)) & \
+ MAKE_64BIT_MASK(0, size); \
+ }
+#endif
+
+VEXTU_X_DO(vextublx, 8, 1)
+VEXTU_X_DO(vextuhlx, 16, 1)
+VEXTU_X_DO(vextuwlx, 32, 1)
+VEXTU_X_DO(vextubrx, 8, 0)
+VEXTU_X_DO(vextuhrx, 16, 0)
+VEXTU_X_DO(vextuwrx, 32, 0)
+#undef VEXTU_X_DO
+
/* The specification says that the results are undefined if all of the
* shift counts are not identical. We check to make sure that they are
* to conform to what real hardware appears to do. */
@@ -1965,6 +2001,57 @@ VEXTRACT(uw, u32)
VEXTRACT(d, u64)
#undef VEXTRACT
+void helper_xxextractuw(CPUPPCState *env, target_ulong xtn,
+ target_ulong xbn, uint32_t index)
+{
+ ppc_vsr_t xt, xb;
+ size_t es = sizeof(uint32_t);
+ uint32_t ext_index;
+ int i;
+
+ getVSR(xbn, &xb, env);
+ memset(&xt, 0, sizeof(xt));
+
+#if defined(HOST_WORDS_BIGENDIAN)
+ ext_index = index;
+ for (i = 0; i < es; i++, ext_index++) {
+ xt.u8[8 - es + i] = xb.u8[ext_index % 16];
+ }
+#else
+ ext_index = 15 - index;
+ for (i = es - 1; i >= 0; i--, ext_index--) {
+ xt.u8[8 + i] = xb.u8[ext_index % 16];
+ }
+#endif
+
+ putVSR(xtn, &xt, env);
+}
+
+void helper_xxinsertw(CPUPPCState *env, target_ulong xtn,
+ target_ulong xbn, uint32_t index)
+{
+ ppc_vsr_t xt, xb;
+ size_t es = sizeof(uint32_t);
+ int ins_index, i = 0;
+
+ getVSR(xbn, &xb, env);
+ getVSR(xtn, &xt, env);
+
+#if defined(HOST_WORDS_BIGENDIAN)
+ ins_index = index;
+ for (i = 0; i < es && ins_index < 16; i++, ins_index++) {
+ xt.u8[ins_index] = xb.u8[8 - es + i];
+ }
+#else
+ ins_index = 15 - index;
+ for (i = es - 1; i >= 0 && ins_index >= 0; i--, ins_index--) {
+ xt.u8[ins_index] = xb.u8[8 + i];
+ }
+#endif
+
+ putVSR(xtn, &xt, env);
+}
+
#define VEXT_SIGNED(name, element, mask, cast, recast) \
void helper_##name(ppc_avr_t *r, ppc_avr_t *b) \
{ \
@@ -2464,9 +2551,9 @@ void helper_vsubecuq(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
#define NATIONAL_NEG 0x2D
#if defined(HOST_WORDS_BIGENDIAN)
-#define BCD_DIG_BYTE(n) (15 - (n/2))
+#define BCD_DIG_BYTE(n) (15 - ((n) / 2))
#else
-#define BCD_DIG_BYTE(n) (n/2)
+#define BCD_DIG_BYTE(n) ((n) / 2)
#endif
static int bcd_get_sgn(ppc_avr_t *bcd)
@@ -2528,12 +2615,30 @@ static void bcd_put_digit(ppc_avr_t *bcd, uint8_t digit, int n)
}
}
+static bool bcd_is_valid(ppc_avr_t *bcd)
+{
+ int i;
+ int invalid = 0;
+
+ if (bcd_get_sgn(bcd) == 0) {
+ return false;
+ }
+
+ for (i = 1; i < 32; i++) {
+ bcd_get_digit(bcd, i, &invalid);
+ if (unlikely(invalid)) {
+ return false;
+ }
+ }
+ return true;
+}
+
static int bcd_cmp_zero(ppc_avr_t *bcd)
{
if (bcd->u64[HI_IDX] == 0 && (bcd->u64[LO_IDX] >> 4) == 0) {
- return 1 << CRF_EQ;
+ return CRF_EQ;
} else {
- return (bcd_get_sgn(bcd) == 1) ? 1 << CRF_GT : 1 << CRF_LT;
+ return (bcd_get_sgn(bcd) == 1) ? CRF_GT : CRF_LT;
}
}
@@ -2645,25 +2750,25 @@ uint32_t helper_bcdadd(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, uint32_t ps)
if (sgna == sgnb) {
result.u8[BCD_DIG_BYTE(0)] = bcd_preferred_sgn(sgna, ps);
zero = bcd_add_mag(&result, a, b, &invalid, &overflow);
- cr = (sgna > 0) ? 1 << CRF_GT : 1 << CRF_LT;
+ cr = (sgna > 0) ? CRF_GT : CRF_LT;
} else if (bcd_cmp_mag(a, b) > 0) {
result.u8[BCD_DIG_BYTE(0)] = bcd_preferred_sgn(sgna, ps);
zero = bcd_sub_mag(&result, a, b, &invalid, &overflow);
- cr = (sgna > 0) ? 1 << CRF_GT : 1 << CRF_LT;
+ cr = (sgna > 0) ? CRF_GT : CRF_LT;
} else {
result.u8[BCD_DIG_BYTE(0)] = bcd_preferred_sgn(sgnb, ps);
zero = bcd_sub_mag(&result, b, a, &invalid, &overflow);
- cr = (sgnb > 0) ? 1 << CRF_GT : 1 << CRF_LT;
+ cr = (sgnb > 0) ? CRF_GT : CRF_LT;
}
}
if (unlikely(invalid)) {
result.u64[HI_IDX] = result.u64[LO_IDX] = -1;
- cr = 1 << CRF_SO;
+ cr = CRF_SO;
} else if (overflow) {
- cr |= 1 << CRF_SO;
+ cr |= CRF_SO;
} else if (zero) {
- cr = 1 << CRF_EQ;
+ cr = CRF_EQ;
}
*r = result;
@@ -2713,7 +2818,7 @@ uint32_t helper_bcdcfn(ppc_avr_t *r, ppc_avr_t *b, uint32_t ps)
cr = bcd_cmp_zero(&ret);
if (unlikely(invalid)) {
- cr = 1 << CRF_SO;
+ cr = CRF_SO;
}
*r = ret;
@@ -2743,11 +2848,11 @@ uint32_t helper_bcdctn(ppc_avr_t *r, ppc_avr_t *b, uint32_t ps)
cr = bcd_cmp_zero(b);
if (ox_flag) {
- cr |= 1 << CRF_SO;
+ cr |= CRF_SO;
}
if (unlikely(invalid)) {
- cr = 1 << CRF_SO;
+ cr = CRF_SO;
}
*r = ret;
@@ -2771,7 +2876,7 @@ uint32_t helper_bcdcfz(ppc_avr_t *r, ppc_avr_t *b, uint32_t ps)
}
for (i = 0; i < 16; i++) {
- zone_digit = (i * 2) ? b->u8[BCD_DIG_BYTE(i * 2)] >> 4 : zone_lead;
+ zone_digit = i ? b->u8[BCD_DIG_BYTE(i * 2)] >> 4 : zone_lead;
digit = b->u8[BCD_DIG_BYTE(i * 2)] & 0xF;
if (unlikely(zone_digit != zone_lead || digit > 0x9)) {
invalid = 1;
@@ -2791,7 +2896,7 @@ uint32_t helper_bcdcfz(ppc_avr_t *r, ppc_avr_t *b, uint32_t ps)
cr = bcd_cmp_zero(&ret);
if (unlikely(invalid)) {
- cr = 1 << CRF_SO;
+ cr = CRF_SO;
}
*r = ret;
@@ -2830,18 +2935,350 @@ uint32_t helper_bcdctz(ppc_avr_t *r, ppc_avr_t *b, uint32_t ps)
cr = bcd_cmp_zero(b);
if (ox_flag) {
- cr |= 1 << CRF_SO;
+ cr |= CRF_SO;
}
if (unlikely(invalid)) {
- cr = 1 << CRF_SO;
+ cr = CRF_SO;
+ }
+
+ *r = ret;
+
+ return cr;
+}
+
+uint32_t helper_bcdcfsq(ppc_avr_t *r, ppc_avr_t *b, uint32_t ps)
+{
+ int i;
+ int cr = 0;
+ uint64_t lo_value;
+ uint64_t hi_value;
+ ppc_avr_t ret = { .u64 = { 0, 0 } };
+
+ if (b->s64[HI_IDX] < 0) {
+ lo_value = -b->s64[LO_IDX];
+ hi_value = ~b->u64[HI_IDX] + !lo_value;
+ bcd_put_digit(&ret, 0xD, 0);
+ } else {
+ lo_value = b->u64[LO_IDX];
+ hi_value = b->u64[HI_IDX];
+ bcd_put_digit(&ret, bcd_preferred_sgn(0, ps), 0);
+ }
+
+ if (divu128(&lo_value, &hi_value, 1000000000000000ULL) ||
+ lo_value > 9999999999999999ULL) {
+ cr = CRF_SO;
+ }
+
+ for (i = 1; i < 16; hi_value /= 10, i++) {
+ bcd_put_digit(&ret, hi_value % 10, i);
+ }
+
+ for (; i < 32; lo_value /= 10, i++) {
+ bcd_put_digit(&ret, lo_value % 10, i);
}
+ cr |= bcd_cmp_zero(&ret);
+
*r = ret;
return cr;
}
+uint32_t helper_bcdctsq(ppc_avr_t *r, ppc_avr_t *b, uint32_t ps)
+{
+ uint8_t i;
+ int cr;
+ uint64_t carry;
+ uint64_t unused;
+ uint64_t lo_value;
+ uint64_t hi_value = 0;
+ int sgnb = bcd_get_sgn(b);
+ int invalid = (sgnb == 0);
+
+ lo_value = bcd_get_digit(b, 31, &invalid);
+ for (i = 30; i > 0; i--) {
+ mulu64(&lo_value, &carry, lo_value, 10ULL);
+ mulu64(&hi_value, &unused, hi_value, 10ULL);
+ lo_value += bcd_get_digit(b, i, &invalid);
+ hi_value += carry;
+
+ if (unlikely(invalid)) {
+ break;
+ }
+ }
+
+ if (sgnb == -1) {
+ r->s64[LO_IDX] = -lo_value;
+ r->s64[HI_IDX] = ~hi_value + !r->s64[LO_IDX];
+ } else {
+ r->s64[LO_IDX] = lo_value;
+ r->s64[HI_IDX] = hi_value;
+ }
+
+ cr = bcd_cmp_zero(b);
+
+ if (unlikely(invalid)) {
+ cr = CRF_SO;
+ }
+
+ return cr;
+}
+
+uint32_t helper_bcdcpsgn(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, uint32_t ps)
+{
+ int i;
+ int invalid = 0;
+
+ if (bcd_get_sgn(a) == 0 || bcd_get_sgn(b) == 0) {
+ return CRF_SO;
+ }
+
+ *r = *a;
+ bcd_put_digit(r, b->u8[BCD_DIG_BYTE(0)] & 0xF, 0);
+
+ for (i = 1; i < 32; i++) {
+ bcd_get_digit(a, i, &invalid);
+ bcd_get_digit(b, i, &invalid);
+ if (unlikely(invalid)) {
+ return CRF_SO;
+ }
+ }
+
+ return bcd_cmp_zero(r);
+}
+
+uint32_t helper_bcdsetsgn(ppc_avr_t *r, ppc_avr_t *b, uint32_t ps)
+{
+ int sgnb = bcd_get_sgn(b);
+
+ *r = *b;
+ bcd_put_digit(r, bcd_preferred_sgn(sgnb, ps), 0);
+
+ if (bcd_is_valid(b) == false) {
+ return CRF_SO;
+ }
+
+ return bcd_cmp_zero(r);
+}
+
+uint32_t helper_bcds(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, uint32_t ps)
+{
+ int cr;
+#if defined(HOST_WORDS_BIGENDIAN)
+ int i = a->s8[7];
+#else
+ int i = a->s8[8];
+#endif
+ bool ox_flag = false;
+ int sgnb = bcd_get_sgn(b);
+ ppc_avr_t ret = *b;
+ ret.u64[LO_IDX] &= ~0xf;
+
+ if (bcd_is_valid(b) == false) {
+ return CRF_SO;
+ }
+
+ if (unlikely(i > 31)) {
+ i = 31;
+ } else if (unlikely(i < -31)) {
+ i = -31;
+ }
+
+ if (i > 0) {
+ ulshift(&ret.u64[LO_IDX], &ret.u64[HI_IDX], i * 4, &ox_flag);
+ } else {
+ urshift(&ret.u64[LO_IDX], &ret.u64[HI_IDX], -i * 4);
+ }
+ bcd_put_digit(&ret, bcd_preferred_sgn(sgnb, ps), 0);
+
+ *r = ret;
+
+ cr = bcd_cmp_zero(r);
+ if (ox_flag) {
+ cr |= CRF_SO;
+ }
+
+ return cr;
+}
+
+uint32_t helper_bcdus(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, uint32_t ps)
+{
+ int cr;
+ int i;
+ int invalid = 0;
+ bool ox_flag = false;
+ ppc_avr_t ret = *b;
+
+ for (i = 0; i < 32; i++) {
+ bcd_get_digit(b, i, &invalid);
+
+ if (unlikely(invalid)) {
+ return CRF_SO;
+ }
+ }
+
+#if defined(HOST_WORDS_BIGENDIAN)
+ i = a->s8[7];
+#else
+ i = a->s8[8];
+#endif
+ if (i >= 32) {
+ ox_flag = true;
+ ret.u64[LO_IDX] = ret.u64[HI_IDX] = 0;
+ } else if (i <= -32) {
+ ret.u64[LO_IDX] = ret.u64[HI_IDX] = 0;
+ } else if (i > 0) {
+ ulshift(&ret.u64[LO_IDX], &ret.u64[HI_IDX], i * 4, &ox_flag);
+ } else {
+ urshift(&ret.u64[LO_IDX], &ret.u64[HI_IDX], -i * 4);
+ }
+ *r = ret;
+
+ cr = bcd_cmp_zero(r);
+ if (ox_flag) {
+ cr |= CRF_SO;
+ }
+
+ return cr;
+}
+
+uint32_t helper_bcdsr(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, uint32_t ps)
+{
+ int cr;
+ int unused = 0;
+ int invalid = 0;
+ bool ox_flag = false;
+ int sgnb = bcd_get_sgn(b);
+ ppc_avr_t ret = *b;
+ ret.u64[LO_IDX] &= ~0xf;
+
+#if defined(HOST_WORDS_BIGENDIAN)
+ int i = a->s8[7];
+ ppc_avr_t bcd_one = { .u64 = { 0, 0x10 } };
+#else
+ int i = a->s8[8];
+ ppc_avr_t bcd_one = { .u64 = { 0x10, 0 } };
+#endif
+
+ if (bcd_is_valid(b) == false) {
+ return CRF_SO;
+ }
+
+ if (unlikely(i > 31)) {
+ i = 31;
+ } else if (unlikely(i < -31)) {
+ i = -31;
+ }
+
+ if (i > 0) {
+ ulshift(&ret.u64[LO_IDX], &ret.u64[HI_IDX], i * 4, &ox_flag);
+ } else {
+ urshift(&ret.u64[LO_IDX], &ret.u64[HI_IDX], -i * 4);
+
+ if (bcd_get_digit(&ret, 0, &invalid) >= 5) {
+ bcd_add_mag(&ret, &ret, &bcd_one, &invalid, &unused);
+ }
+ }
+ bcd_put_digit(&ret, bcd_preferred_sgn(sgnb, ps), 0);
+
+ cr = bcd_cmp_zero(&ret);
+ if (ox_flag) {
+ cr |= CRF_SO;
+ }
+ *r = ret;
+
+ return cr;
+}
+
+uint32_t helper_bcdtrunc(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, uint32_t ps)
+{
+ uint64_t mask;
+ uint32_t ox_flag = 0;
+#if defined(HOST_WORDS_BIGENDIAN)
+ int i = a->s16[3] + 1;
+#else
+ int i = a->s16[4] + 1;
+#endif
+ ppc_avr_t ret = *b;
+
+ if (bcd_is_valid(b) == false) {
+ return CRF_SO;
+ }
+
+ if (i > 16 && i < 32) {
+ mask = (uint64_t)-1 >> (128 - i * 4);
+ if (ret.u64[HI_IDX] & ~mask) {
+ ox_flag = CRF_SO;
+ }
+
+ ret.u64[HI_IDX] &= mask;
+ } else if (i >= 0 && i <= 16) {
+ mask = (uint64_t)-1 >> (64 - i * 4);
+ if (ret.u64[HI_IDX] || (ret.u64[LO_IDX] & ~mask)) {
+ ox_flag = CRF_SO;
+ }
+
+ ret.u64[LO_IDX] &= mask;
+ ret.u64[HI_IDX] = 0;
+ }
+ bcd_put_digit(&ret, bcd_preferred_sgn(bcd_get_sgn(b), ps), 0);
+ *r = ret;
+
+ return bcd_cmp_zero(&ret) | ox_flag;
+}
+
+uint32_t helper_bcdutrunc(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, uint32_t ps)
+{
+ int i;
+ uint64_t mask;
+ uint32_t ox_flag = 0;
+ int invalid = 0;
+ ppc_avr_t ret = *b;
+
+ for (i = 0; i < 32; i++) {
+ bcd_get_digit(b, i, &invalid);
+
+ if (unlikely(invalid)) {
+ return CRF_SO;
+ }
+ }
+
+#if defined(HOST_WORDS_BIGENDIAN)
+ i = a->s16[3];
+#else
+ i = a->s16[4];
+#endif
+ if (i > 16 && i < 33) {
+ mask = (uint64_t)-1 >> (128 - i * 4);
+ if (ret.u64[HI_IDX] & ~mask) {
+ ox_flag = CRF_SO;
+ }
+
+ ret.u64[HI_IDX] &= mask;
+ } else if (i > 0 && i <= 16) {
+ mask = (uint64_t)-1 >> (64 - i * 4);
+ if (ret.u64[HI_IDX] || (ret.u64[LO_IDX] & ~mask)) {
+ ox_flag = CRF_SO;
+ }
+
+ ret.u64[LO_IDX] &= mask;
+ ret.u64[HI_IDX] = 0;
+ } else if (i == 0) {
+ if (ret.u64[HI_IDX] || ret.u64[LO_IDX]) {
+ ox_flag = CRF_SO;
+ }
+ ret.u64[HI_IDX] = ret.u64[LO_IDX] = 0;
+ }
+
+ *r = ret;
+ if (r->u64[HI_IDX] == 0 && r->u64[LO_IDX] == 0) {
+ return ox_flag | CRF_EQ;
+ }
+
+ return ox_flag | CRF_GT;
+}
+
void helper_vsbox(ppc_avr_t *r, ppc_avr_t *a)
{
int i;
diff --git a/target/ppc/internal.h b/target/ppc/internal.h
index 1ff4896c45..5a2fd68427 100644
--- a/target/ppc/internal.h
+++ b/target/ppc/internal.h
@@ -47,4 +47,206 @@ FUNC_MASK(MASK, target_ulong, 32, UINT32_MAX);
FUNC_MASK(mask_u32, uint32_t, 32, UINT32_MAX);
FUNC_MASK(mask_u64, uint64_t, 64, UINT64_MAX);
+/*****************************************************************************/
+/*** Instruction decoding ***/
+#define EXTRACT_HELPER(name, shift, nb) \
+static inline uint32_t name(uint32_t opcode) \
+{ \
+ return (opcode >> (shift)) & ((1 << (nb)) - 1); \
+}
+
+#define EXTRACT_SHELPER(name, shift, nb) \
+static inline int32_t name(uint32_t opcode) \
+{ \
+ return (int16_t)((opcode >> (shift)) & ((1 << (nb)) - 1)); \
+}
+
+#define EXTRACT_HELPER_SPLIT(name, shift1, nb1, shift2, nb2) \
+static inline uint32_t name(uint32_t opcode) \
+{ \
+ return (((opcode >> (shift1)) & ((1 << (nb1)) - 1)) << nb2) | \
+ ((opcode >> (shift2)) & ((1 << (nb2)) - 1)); \
+}
+
+#define EXTRACT_HELPER_SPLIT_3(name, \
+ d0_bits, shift_op_d0, shift_d0, \
+ d1_bits, shift_op_d1, shift_d1, \
+ d2_bits, shift_op_d2, shift_d2) \
+static inline int16_t name(uint32_t opcode) \
+{ \
+ return \
+ (((opcode >> (shift_op_d0)) & ((1 << (d0_bits)) - 1)) << (shift_d0)) | \
+ (((opcode >> (shift_op_d1)) & ((1 << (d1_bits)) - 1)) << (shift_d1)) | \
+ (((opcode >> (shift_op_d2)) & ((1 << (d2_bits)) - 1)) << (shift_d2)); \
+}
+
+
+/* Opcode part 1 */
+EXTRACT_HELPER(opc1, 26, 6);
+/* Opcode part 2 */
+EXTRACT_HELPER(opc2, 1, 5);
+/* Opcode part 3 */
+EXTRACT_HELPER(opc3, 6, 5);
+/* Opcode part 4 */
+EXTRACT_HELPER(opc4, 16, 5);
+/* Update Cr0 flags */
+EXTRACT_HELPER(Rc, 0, 1);
+/* Update Cr6 flags (Altivec) */
+EXTRACT_HELPER(Rc21, 10, 1);
+/* Destination */
+EXTRACT_HELPER(rD, 21, 5);
+/* Source */
+EXTRACT_HELPER(rS, 21, 5);
+/* First operand */
+EXTRACT_HELPER(rA, 16, 5);
+/* Second operand */
+EXTRACT_HELPER(rB, 11, 5);
+/* Third operand */
+EXTRACT_HELPER(rC, 6, 5);
+/*** Get CRn ***/
+EXTRACT_HELPER(crfD, 23, 3);
+EXTRACT_HELPER(BF, 23, 3);
+EXTRACT_HELPER(crfS, 18, 3);
+EXTRACT_HELPER(crbD, 21, 5);
+EXTRACT_HELPER(crbA, 16, 5);
+EXTRACT_HELPER(crbB, 11, 5);
+/* SPR / TBL */
+EXTRACT_HELPER(_SPR, 11, 10);
+static inline uint32_t SPR(uint32_t opcode)
+{
+ uint32_t sprn = _SPR(opcode);
+
+ return ((sprn >> 5) & 0x1F) | ((sprn & 0x1F) << 5);
+}
+/*** Get constants ***/
+/* 16 bits signed immediate value */
+EXTRACT_SHELPER(SIMM, 0, 16);
+/* 16 bits unsigned immediate value */
+EXTRACT_HELPER(UIMM, 0, 16);
+/* 5 bits signed immediate value */
+EXTRACT_HELPER(SIMM5, 16, 5);
+/* 5 bits signed immediate value */
+EXTRACT_HELPER(UIMM5, 16, 5);
+/* 4 bits unsigned immediate value */
+EXTRACT_HELPER(UIMM4, 16, 4);
+/* Bit count */
+EXTRACT_HELPER(NB, 11, 5);
+/* Shift count */
+EXTRACT_HELPER(SH, 11, 5);
+/* Vector shift count */
+EXTRACT_HELPER(VSH, 6, 4);
+/* Mask start */
+EXTRACT_HELPER(MB, 6, 5);
+/* Mask end */
+EXTRACT_HELPER(ME, 1, 5);
+/* Trap operand */
+EXTRACT_HELPER(TO, 21, 5);
+
+EXTRACT_HELPER(CRM, 12, 8);
+
+#ifndef CONFIG_USER_ONLY
+EXTRACT_HELPER(SR, 16, 4);
+#endif
+
+/* mtfsf/mtfsfi */
+EXTRACT_HELPER(FPBF, 23, 3);
+EXTRACT_HELPER(FPIMM, 12, 4);
+EXTRACT_HELPER(FPL, 25, 1);
+EXTRACT_HELPER(FPFLM, 17, 8);
+EXTRACT_HELPER(FPW, 16, 1);
+
+/* addpcis */
+EXTRACT_HELPER_SPLIT_3(DX, 10, 6, 6, 5, 16, 1, 1, 0, 0)
+#if defined(TARGET_PPC64)
+/* darn */
+EXTRACT_HELPER(L, 16, 2);
+#endif
+
+/*** Jump target decoding ***/
+/* Immediate address */
+static inline target_ulong LI(uint32_t opcode)
+{
+ return (opcode >> 0) & 0x03FFFFFC;
+}
+
+static inline uint32_t BD(uint32_t opcode)
+{
+ return (opcode >> 0) & 0xFFFC;
+}
+
+EXTRACT_HELPER(BO, 21, 5);
+EXTRACT_HELPER(BI, 16, 5);
+/* Absolute/relative address */
+EXTRACT_HELPER(AA, 1, 1);
+/* Link */
+EXTRACT_HELPER(LK, 0, 1);
+
+/* DFP Z22-form */
+EXTRACT_HELPER(DCM, 10, 6)
+
+/* DFP Z23-form */
+EXTRACT_HELPER(RMC, 9, 2)
+
+EXTRACT_HELPER_SPLIT(DQxT, 3, 1, 21, 5);
+EXTRACT_HELPER_SPLIT(xT, 0, 1, 21, 5);
+EXTRACT_HELPER_SPLIT(xS, 0, 1, 21, 5);
+EXTRACT_HELPER_SPLIT(xA, 2, 1, 16, 5);
+EXTRACT_HELPER_SPLIT(xB, 1, 1, 11, 5);
+EXTRACT_HELPER_SPLIT(xC, 3, 1, 6, 5);
+EXTRACT_HELPER(DM, 8, 2);
+EXTRACT_HELPER(UIM, 16, 2);
+EXTRACT_HELPER(SHW, 8, 2);
+EXTRACT_HELPER(SP, 19, 2);
+EXTRACT_HELPER(IMM8, 11, 8);
+EXTRACT_HELPER(DCMX, 16, 7);
+EXTRACT_HELPER_SPLIT_3(DCMX_XV, 5, 16, 0, 1, 2, 5, 1, 6, 6);
+
+typedef union _ppc_vsr_t {
+ uint8_t u8[16];
+ uint16_t u16[8];
+ uint32_t u32[4];
+ uint64_t u64[2];
+ float32 f32[4];
+ float64 f64[2];
+ float128 f128;
+ Int128 s128;
+} ppc_vsr_t;
+
+#if defined(HOST_WORDS_BIGENDIAN)
+#define VsrB(i) u8[i]
+#define VsrH(i) u16[i]
+#define VsrW(i) u32[i]
+#define VsrD(i) u64[i]
+#else
+#define VsrB(i) u8[15 - (i)]
+#define VsrH(i) u16[7 - (i)]
+#define VsrW(i) u32[3 - (i)]
+#define VsrD(i) u64[1 - (i)]
+#endif
+
+static inline void getVSR(int n, ppc_vsr_t *vsr, CPUPPCState *env)
+{
+ if (n < 32) {
+ vsr->VsrD(0) = env->fpr[n];
+ vsr->VsrD(1) = env->vsr[n];
+ } else {
+ vsr->u64[0] = env->avr[n - 32].u64[0];
+ vsr->u64[1] = env->avr[n - 32].u64[1];
+ }
+}
+
+static inline void putVSR(int n, ppc_vsr_t *vsr, CPUPPCState *env)
+{
+ if (n < 32) {
+ env->fpr[n] = vsr->VsrD(0);
+ env->vsr[n] = vsr->VsrD(1);
+ } else {
+ env->avr[n - 32].u64[0] = vsr->u64[0];
+ env->avr[n - 32].u64[1] = vsr->u64[1];
+ }
+}
+
+void helper_compute_fprf_float16(CPUPPCState *env, float16 arg);
+void helper_compute_fprf_float32(CPUPPCState *env, float32 arg);
+void helper_compute_fprf_float128(CPUPPCState *env, float128 arg);
#endif /* PPC_INTERNAL_H */
diff --git a/target/ppc/kvm.c b/target/ppc/kvm.c
index ec92c64159..663d2e79c9 100644
--- a/target/ppc/kvm.c
+++ b/target/ppc/kvm.c
@@ -24,6 +24,7 @@
#include "qemu-common.h"
#include "qemu/error-report.h"
#include "cpu.h"
+#include "cpu-models.h"
#include "qemu/timer.h"
#include "sysemu/sysemu.h"
#include "sysemu/hw_accel.h"
@@ -2108,9 +2109,9 @@ void kvmppc_set_papr(PowerPCCPU *cpu)
cap_papr = 1;
}
-int kvmppc_set_compat(PowerPCCPU *cpu, uint32_t cpu_version)
+int kvmppc_set_compat(PowerPCCPU *cpu, uint32_t compat_pvr)
{
- return kvm_set_one_reg(CPU(cpu), KVM_REG_PPC_ARCH_COMPAT, &cpu_version);
+ return kvm_set_one_reg(CPU(cpu), KVM_REG_PPC_ARCH_COMPAT, &compat_pvr);
}
void kvmppc_set_mpic_proxy(PowerPCCPU *cpu, int mpic_proxy)
@@ -2412,6 +2413,7 @@ static int kvm_ppc_register_host_cpu_type(void)
};
PowerPCCPUClass *pvr_pcc;
DeviceClass *dc;
+ int i;
pvr_pcc = kvm_ppc_get_host_cpu_class();
if (pvr_pcc == NULL) {
@@ -2420,13 +2422,6 @@ static int kvm_ppc_register_host_cpu_type(void)
type_info.parent = object_class_get_name(OBJECT_CLASS(pvr_pcc));
type_register(&type_info);
- /* Register generic family CPU class for a family */
- pvr_pcc = ppc_cpu_get_family_class(pvr_pcc);
- dc = DEVICE_CLASS(pvr_pcc);
- type_info.parent = object_class_get_name(OBJECT_CLASS(pvr_pcc));
- type_info.name = g_strdup_printf("%s-"TYPE_POWERPC_CPU, dc->desc);
- type_register(&type_info);
-
#if defined(TARGET_PPC64)
type_info.name = g_strdup_printf("%s-"TYPE_SPAPR_CPU_CORE, "host");
type_info.parent = TYPE_SPAPR_CPU_CORE,
@@ -2436,14 +2431,29 @@ static int kvm_ppc_register_host_cpu_type(void)
type_info.class_data = (void *) "host";
type_register(&type_info);
g_free((void *)type_info.name);
-
- /* Register generic spapr CPU family class for current host CPU type */
- type_info.name = g_strdup_printf("%s-"TYPE_SPAPR_CPU_CORE, dc->desc);
- type_info.class_data = (void *) dc->desc;
- type_register(&type_info);
- g_free((void *)type_info.name);
#endif
+ /*
+ * Update generic CPU family class alias (e.g. on a POWER8NVL host,
+ * we want "POWER8" to be a "family" alias that points to the current
+ * host CPU type, too)
+ */
+ dc = DEVICE_CLASS(ppc_cpu_get_family_class(pvr_pcc));
+ for (i = 0; ppc_cpu_aliases[i].alias != NULL; i++) {
+ if (strcmp(ppc_cpu_aliases[i].alias, dc->desc) == 0) {
+ ObjectClass *oc = OBJECT_CLASS(pvr_pcc);
+ char *suffix;
+
+ ppc_cpu_aliases[i].model = g_strdup(object_class_get_name(oc));
+ suffix = strstr(ppc_cpu_aliases[i].model, "-"TYPE_POWERPC_CPU);
+ if (suffix) {
+ *suffix = 0;
+ }
+ ppc_cpu_aliases[i].oc = oc;
+ break;
+ }
+ }
+
return 0;
}
diff --git a/target/ppc/kvm_ppc.h b/target/ppc/kvm_ppc.h
index 4b43283913..151c00bac7 100644
--- a/target/ppc/kvm_ppc.h
+++ b/target/ppc/kvm_ppc.h
@@ -26,7 +26,7 @@ void kvmppc_enable_logical_ci_hcalls(void);
void kvmppc_enable_set_mode_hcall(void);
void kvmppc_enable_clear_ref_mod_hcalls(void);
void kvmppc_set_papr(PowerPCCPU *cpu);
-int kvmppc_set_compat(PowerPCCPU *cpu, uint32_t cpu_version);
+int kvmppc_set_compat(PowerPCCPU *cpu, uint32_t compat_pvr);
void kvmppc_set_mpic_proxy(PowerPCCPU *cpu, int mpic_proxy);
int kvmppc_smt_threads(void);
int kvmppc_clear_tsr_bits(PowerPCCPU *cpu, uint32_t tsr_bits);
@@ -123,7 +123,7 @@ static inline void kvmppc_set_papr(PowerPCCPU *cpu)
{
}
-static inline int kvmppc_set_compat(PowerPCCPU *cpu, uint32_t cpu_version)
+static inline int kvmppc_set_compat(PowerPCCPU *cpu, uint32_t compat_pvr)
{
return 0;
}
diff --git a/target/ppc/mem_helper.c b/target/ppc/mem_helper.c
index 1ab8a6eab4..e6383c6bfa 100644
--- a/target/ppc/mem_helper.c
+++ b/target/ppc/mem_helper.c
@@ -24,6 +24,7 @@
#include "helper_regs.h"
#include "exec/cpu_ldst.h"
+#include "internal.h"
//#define DEBUG_OP
@@ -284,6 +285,71 @@ STVE(stvewx, cpu_stl_data_ra, bswap32, u32)
#undef I
#undef LVE
+#ifdef TARGET_PPC64
+#define GET_NB(rb) ((rb >> 56) & 0xFF)
+
+#define VSX_LXVL(name, lj) \
+void helper_##name(CPUPPCState *env, target_ulong addr, \
+ target_ulong xt_num, target_ulong rb) \
+{ \
+ int i; \
+ ppc_vsr_t xt; \
+ uint64_t nb = GET_NB(rb); \
+ \
+ xt.s128 = int128_zero(); \
+ if (nb) { \
+ nb = (nb >= 16) ? 16 : nb; \
+ if (msr_le && !lj) { \
+ for (i = 16; i > 16 - nb; i--) { \
+ xt.VsrB(i - 1) = cpu_ldub_data_ra(env, addr, GETPC()); \
+ addr = addr_add(env, addr, 1); \
+ } \
+ } else { \
+ for (i = 0; i < nb; i++) { \
+ xt.VsrB(i) = cpu_ldub_data_ra(env, addr, GETPC()); \
+ addr = addr_add(env, addr, 1); \
+ } \
+ } \
+ } \
+ putVSR(xt_num, &xt, env); \
+}
+
+VSX_LXVL(lxvl, 0)
+VSX_LXVL(lxvll, 1)
+#undef VSX_LXVL
+
+#define VSX_STXVL(name, lj) \
+void helper_##name(CPUPPCState *env, target_ulong addr, \
+ target_ulong xt_num, target_ulong rb) \
+{ \
+ int i; \
+ ppc_vsr_t xt; \
+ target_ulong nb = GET_NB(rb); \
+ \
+ if (!nb) { \
+ return; \
+ } \
+ getVSR(xt_num, &xt, env); \
+ nb = (nb >= 16) ? 16 : nb; \
+ if (msr_le && !lj) { \
+ for (i = 16; i > 16 - nb; i--) { \
+ cpu_stb_data_ra(env, addr, xt.VsrB(i - 1), GETPC()); \
+ addr = addr_add(env, addr, 1); \
+ } \
+ } else { \
+ for (i = 0; i < nb; i++) { \
+ cpu_stb_data_ra(env, addr, xt.VsrB(i), GETPC()); \
+ addr = addr_add(env, addr, 1); \
+ } \
+ } \
+}
+
+VSX_STXVL(stxvl, 0)
+VSX_STXVL(stxvll, 1)
+#undef VSX_STXVL
+#undef GET_NB
+#endif /* TARGET_PPC64 */
+
#undef HI_IDX
#undef LO_IDX
diff --git a/target/ppc/mmu-hash64.c b/target/ppc/mmu-hash64.c
index 0efc8c63fa..bb78fb5497 100644
--- a/target/ppc/mmu-hash64.c
+++ b/target/ppc/mmu-hash64.c
@@ -181,8 +181,8 @@ int ppc_store_slb(PowerPCCPU *cpu, target_ulong slot,
slb->vsid = vsid;
slb->sps = sps;
- LOG_SLB("%s: %d " TARGET_FMT_lx " - " TARGET_FMT_lx " => %016" PRIx64
- " %016" PRIx64 "\n", __func__, slot, esid, vsid,
+ LOG_SLB("%s: " TARGET_FMT_lu " " TARGET_FMT_lx " - " TARGET_FMT_lx
+ " => %016" PRIx64 " %016" PRIx64 "\n", __func__, slot, esid, vsid,
slb->esid, slb->vsid);
return 0;
diff --git a/target/ppc/mmu-hash64.h b/target/ppc/mmu-hash64.h
index ab5d347a53..7a0b7fca41 100644
--- a/target/ppc/mmu-hash64.h
+++ b/target/ppc/mmu-hash64.h
@@ -85,7 +85,7 @@ void ppc_hash64_update_rmls(CPUPPCState *env);
#define HPTE64_R_C 0x0000000000000080ULL
#define HPTE64_R_R 0x0000000000000100ULL
#define HPTE64_R_KEY_LO 0x0000000000000e00ULL
-#define HPTE64_R_KEY(x) ((((x) & HPTE64_R_KEY_HI) >> 60) | \
+#define HPTE64_R_KEY(x) ((((x) & HPTE64_R_KEY_HI) >> 57) | \
(((x) & HPTE64_R_KEY_LO) >> 9))
#define HPTE64_V_1TB_SEG 0x4000000000000000ULL
diff --git a/target/ppc/translate.c b/target/ppc/translate.c
index 121218087f..b48abaedfb 100644
--- a/target/ppc/translate.c
+++ b/target/ppc/translate.c
@@ -422,157 +422,6 @@ typedef struct opcode_t {
#define CHK_NONE
-
-/*****************************************************************************/
-/*** Instruction decoding ***/
-#define EXTRACT_HELPER(name, shift, nb) \
-static inline uint32_t name(uint32_t opcode) \
-{ \
- return (opcode >> (shift)) & ((1 << (nb)) - 1); \
-}
-
-#define EXTRACT_SHELPER(name, shift, nb) \
-static inline int32_t name(uint32_t opcode) \
-{ \
- return (int16_t)((opcode >> (shift)) & ((1 << (nb)) - 1)); \
-}
-
-#define EXTRACT_HELPER_SPLIT(name, shift1, nb1, shift2, nb2) \
-static inline uint32_t name(uint32_t opcode) \
-{ \
- return (((opcode >> (shift1)) & ((1 << (nb1)) - 1)) << nb2) | \
- ((opcode >> (shift2)) & ((1 << (nb2)) - 1)); \
-}
-
-#define EXTRACT_HELPER_DXFORM(name, \
- d0_bits, shift_op_d0, shift_d0, \
- d1_bits, shift_op_d1, shift_d1, \
- d2_bits, shift_op_d2, shift_d2) \
-static inline int16_t name(uint32_t opcode) \
-{ \
- return \
- (((opcode >> (shift_op_d0)) & ((1 << (d0_bits)) - 1)) << (shift_d0)) | \
- (((opcode >> (shift_op_d1)) & ((1 << (d1_bits)) - 1)) << (shift_d1)) | \
- (((opcode >> (shift_op_d2)) & ((1 << (d2_bits)) - 1)) << (shift_d2)); \
-}
-
-
-/* Opcode part 1 */
-EXTRACT_HELPER(opc1, 26, 6);
-/* Opcode part 2 */
-EXTRACT_HELPER(opc2, 1, 5);
-/* Opcode part 3 */
-EXTRACT_HELPER(opc3, 6, 5);
-/* Opcode part 4 */
-EXTRACT_HELPER(opc4, 16, 5);
-/* Update Cr0 flags */
-EXTRACT_HELPER(Rc, 0, 1);
-/* Update Cr6 flags (Altivec) */
-EXTRACT_HELPER(Rc21, 10, 1);
-/* Destination */
-EXTRACT_HELPER(rD, 21, 5);
-/* Source */
-EXTRACT_HELPER(rS, 21, 5);
-/* First operand */
-EXTRACT_HELPER(rA, 16, 5);
-/* Second operand */
-EXTRACT_HELPER(rB, 11, 5);
-/* Third operand */
-EXTRACT_HELPER(rC, 6, 5);
-/*** Get CRn ***/
-EXTRACT_HELPER(crfD, 23, 3);
-EXTRACT_HELPER(crfS, 18, 3);
-EXTRACT_HELPER(crbD, 21, 5);
-EXTRACT_HELPER(crbA, 16, 5);
-EXTRACT_HELPER(crbB, 11, 5);
-/* SPR / TBL */
-EXTRACT_HELPER(_SPR, 11, 10);
-static inline uint32_t SPR(uint32_t opcode)
-{
- uint32_t sprn = _SPR(opcode);
-
- return ((sprn >> 5) & 0x1F) | ((sprn & 0x1F) << 5);
-}
-/*** Get constants ***/
-/* 16 bits signed immediate value */
-EXTRACT_SHELPER(SIMM, 0, 16);
-/* 16 bits unsigned immediate value */
-EXTRACT_HELPER(UIMM, 0, 16);
-/* 5 bits signed immediate value */
-EXTRACT_HELPER(SIMM5, 16, 5);
-/* 5 bits signed immediate value */
-EXTRACT_HELPER(UIMM5, 16, 5);
-/* 4 bits unsigned immediate value */
-EXTRACT_HELPER(UIMM4, 16, 4);
-/* Bit count */
-EXTRACT_HELPER(NB, 11, 5);
-/* Shift count */
-EXTRACT_HELPER(SH, 11, 5);
-/* Vector shift count */
-EXTRACT_HELPER(VSH, 6, 4);
-/* Mask start */
-EXTRACT_HELPER(MB, 6, 5);
-/* Mask end */
-EXTRACT_HELPER(ME, 1, 5);
-/* Trap operand */
-EXTRACT_HELPER(TO, 21, 5);
-
-EXTRACT_HELPER(CRM, 12, 8);
-
-#ifndef CONFIG_USER_ONLY
-EXTRACT_HELPER(SR, 16, 4);
-#endif
-
-/* mtfsf/mtfsfi */
-EXTRACT_HELPER(FPBF, 23, 3);
-EXTRACT_HELPER(FPIMM, 12, 4);
-EXTRACT_HELPER(FPL, 25, 1);
-EXTRACT_HELPER(FPFLM, 17, 8);
-EXTRACT_HELPER(FPW, 16, 1);
-
-/* addpcis */
-EXTRACT_HELPER_DXFORM(DX, 10, 6, 6, 5, 16, 1, 1, 0, 0)
-#if defined(TARGET_PPC64)
-/* darn */
-EXTRACT_HELPER(L, 16, 2);
-#endif
-
-/*** Jump target decoding ***/
-/* Immediate address */
-static inline target_ulong LI(uint32_t opcode)
-{
- return (opcode >> 0) & 0x03FFFFFC;
-}
-
-static inline uint32_t BD(uint32_t opcode)
-{
- return (opcode >> 0) & 0xFFFC;
-}
-
-EXTRACT_HELPER(BO, 21, 5);
-EXTRACT_HELPER(BI, 16, 5);
-/* Absolute/relative address */
-EXTRACT_HELPER(AA, 1, 1);
-/* Link */
-EXTRACT_HELPER(LK, 0, 1);
-
-/* DFP Z22-form */
-EXTRACT_HELPER(DCM, 10, 6)
-
-/* DFP Z23-form */
-EXTRACT_HELPER(RMC, 9, 2)
-
-EXTRACT_HELPER_SPLIT(xT, 0, 1, 21, 5);
-EXTRACT_HELPER_SPLIT(xS, 0, 1, 21, 5);
-EXTRACT_HELPER_SPLIT(xA, 2, 1, 16, 5);
-EXTRACT_HELPER_SPLIT(xB, 1, 1, 11, 5);
-EXTRACT_HELPER_SPLIT(xC, 3, 1, 6, 5);
-EXTRACT_HELPER(DM, 8, 2);
-EXTRACT_HELPER(UIM, 16, 2);
-EXTRACT_HELPER(SHW, 8, 2);
-EXTRACT_HELPER(SP, 19, 2);
-EXTRACT_HELPER(IMM8, 11, 8);
-
/*****************************************************************************/
/* PowerPC instructions table */
@@ -763,17 +612,17 @@ static inline void gen_op_cmp(TCGv arg0, TCGv arg1, int s, int crf)
tcg_gen_setcond_tl((s ? TCG_COND_LT: TCG_COND_LTU), t0, arg0, arg1);
tcg_gen_trunc_tl_i32(t1, t0);
- tcg_gen_shli_i32(t1, t1, CRF_LT);
+ tcg_gen_shli_i32(t1, t1, CRF_LT_BIT);
tcg_gen_or_i32(cpu_crf[crf], cpu_crf[crf], t1);
tcg_gen_setcond_tl((s ? TCG_COND_GT: TCG_COND_GTU), t0, arg0, arg1);
tcg_gen_trunc_tl_i32(t1, t0);
- tcg_gen_shli_i32(t1, t1, CRF_GT);
+ tcg_gen_shli_i32(t1, t1, CRF_GT_BIT);
tcg_gen_or_i32(cpu_crf[crf], cpu_crf[crf], t1);
tcg_gen_setcond_tl(TCG_COND_EQ, t0, arg0, arg1);
tcg_gen_trunc_tl_i32(t1, t0);
- tcg_gen_shli_i32(t1, t1, CRF_EQ);
+ tcg_gen_shli_i32(t1, t1, CRF_EQ_BIT);
tcg_gen_or_i32(cpu_crf[crf], cpu_crf[crf], t1);
tcg_temp_free(t0);
@@ -899,7 +748,7 @@ static void gen_cmprb(DisasContext *ctx)
tcg_gen_and_i32(src2lo, src2lo, src2hi);
tcg_gen_or_i32(crf, crf, src2lo);
}
- tcg_gen_shli_i32(crf, crf, CRF_GT);
+ tcg_gen_shli_i32(crf, crf, CRF_GT_BIT);
tcg_temp_free_i32(src1);
tcg_temp_free_i32(src2);
tcg_temp_free_i32(src2lo);
@@ -3148,7 +2997,7 @@ static void gen_conditional_store(DisasContext *ctx, TCGv EA,
tcg_gen_trunc_tl_i32(cpu_crf[0], cpu_so);
l1 = gen_new_label();
tcg_gen_brcond_tl(TCG_COND_NE, EA, cpu_reserve, l1);
- tcg_gen_ori_i32(cpu_crf[0], cpu_crf[0], 1 << CRF_EQ);
+ tcg_gen_ori_i32(cpu_crf[0], cpu_crf[0], CRF_EQ);
tcg_gen_qemu_st_tl(cpu_gpr[reg], EA, ctx->mem_idx, memop);
gen_set_label(l1);
tcg_gen_movi_tl(cpu_reserve, -1);
@@ -3242,7 +3091,7 @@ static void gen_stqcx_(DisasContext *ctx)
tcg_gen_trunc_tl_i32(cpu_crf[0], cpu_so);
l1 = gen_new_label();
tcg_gen_brcond_tl(TCG_COND_NE, EA, cpu_reserve, l1);
- tcg_gen_ori_i32(cpu_crf[0], cpu_crf[0], 1 << CRF_EQ);
+ tcg_gen_ori_i32(cpu_crf[0], cpu_crf[0], CRF_EQ);
if (unlikely(ctx->le_mode)) {
gpr1 = cpu_gpr[reg + 1];
@@ -3323,6 +3172,11 @@ static void gen_nap(DisasContext *ctx)
#endif /* defined(CONFIG_USER_ONLY) */
}
+static void gen_stop(DisasContext *ctx)
+{
+ gen_nap(ctx);
+}
+
static void gen_sleep(DisasContext *ctx)
{
#if defined(CONFIG_USER_ONLY)
@@ -4423,7 +4277,7 @@ static void gen_slbfee_(DisasContext *ctx)
l2 = gen_new_label();
tcg_gen_trunc_tl_i32(cpu_crf[0], cpu_so);
tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_gpr[rS(ctx->opcode)], -1, l1);
- tcg_gen_ori_i32(cpu_crf[0], cpu_crf[0], 1 << CRF_EQ);
+ tcg_gen_ori_i32(cpu_crf[0], cpu_crf[0], CRF_EQ);
tcg_gen_br(l2);
gen_set_label(l1);
tcg_gen_movi_tl(cpu_gpr[rS(ctx->opcode)], 0);
@@ -6166,6 +6020,10 @@ GEN_TM_NOOP(tabortwci);
GEN_TM_NOOP(tabortdc);
GEN_TM_NOOP(tabortdci);
GEN_TM_NOOP(tsr);
+static inline void gen_cp_abort(DisasContext *ctx)
+{
+ // Do Nothing
+}
static void gen_tcheck(DisasContext *ctx)
{
@@ -6223,6 +6081,67 @@ GEN_TM_PRIV_NOOP(trechkpt);
#include "translate/spe-impl.inc.c"
+/* Handles lfdp, lxsd, lxssp */
+static void gen_dform39(DisasContext *ctx)
+{
+ switch (ctx->opcode & 0x3) {
+ case 0: /* lfdp */
+ if (ctx->insns_flags2 & PPC2_ISA205) {
+ return gen_lfdp(ctx);
+ }
+ break;
+ case 2: /* lxsd */
+ if (ctx->insns_flags2 & PPC2_ISA300) {
+ return gen_lxsd(ctx);
+ }
+ break;
+ case 3: /* lxssp */
+ if (ctx->insns_flags2 & PPC2_ISA300) {
+ return gen_lxssp(ctx);
+ }
+ break;
+ }
+ return gen_invalid(ctx);
+}
+
+/* handles stfdp, lxv, stxsd, stxssp lxvx */
+static void gen_dform3D(DisasContext *ctx)
+{
+ if ((ctx->opcode & 3) == 1) { /* DQ-FORM */
+ switch (ctx->opcode & 0x7) {
+ case 1: /* lxv */
+ if (ctx->insns_flags2 & PPC2_ISA300) {
+ return gen_lxv(ctx);
+ }
+ break;
+ case 5: /* stxv */
+ if (ctx->insns_flags2 & PPC2_ISA300) {
+ return gen_stxv(ctx);
+ }
+ break;
+ }
+ } else { /* DS-FORM */
+ switch (ctx->opcode & 0x3) {
+ case 0: /* stfdp */
+ if (ctx->insns_flags2 & PPC2_ISA205) {
+ return gen_stfdp(ctx);
+ }
+ break;
+ case 2: /* stxsd */
+ if (ctx->insns_flags2 & PPC2_ISA300) {
+ return gen_stxsd(ctx);
+ }
+ break;
+ case 3: /* stxssp */
+ if (ctx->insns_flags2 & PPC2_ISA300) {
+ return gen_stxssp(ctx);
+ }
+ break;
+ }
+ }
+ return gen_invalid(ctx);
+}
+
static opcode_t opcodes[] = {
GEN_HANDLER(invalid, 0x00, 0x00, 0x00, 0xFFFFFFFF, PPC_NONE),
GEN_HANDLER(cmp, 0x1F, 0x00, 0x00, 0x00400000, PPC_INTEGER),
@@ -6255,6 +6174,7 @@ GEN_HANDLER2(andi_, "andi.", 0x1C, 0xFF, 0xFF, 0x00000000, PPC_INTEGER),
GEN_HANDLER2(andis_, "andis.", 0x1D, 0xFF, 0xFF, 0x00000000, PPC_INTEGER),
GEN_HANDLER(cntlzw, 0x1F, 0x1A, 0x00, 0x00000000, PPC_INTEGER),
GEN_HANDLER_E(cnttzw, 0x1F, 0x1A, 0x10, 0x00000000, PPC_NONE, PPC2_ISA300),
+GEN_HANDLER_E(cp_abort, 0x1F, 0x06, 0x1A, 0x03FFF801, PPC_NONE, PPC2_ISA300),
GEN_HANDLER(or, 0x1F, 0x1C, 0x0D, 0x00000000, PPC_INTEGER),
GEN_HANDLER(xor, 0x1F, 0x1C, 0x09, 0x00000000, PPC_INTEGER),
GEN_HANDLER(ori, 0x18, 0xFF, 0xFF, 0x00000000, PPC_INTEGER),
@@ -6295,6 +6215,10 @@ GEN_HANDLER(ld, 0x3A, 0xFF, 0xFF, 0x00000000, PPC_64B),
GEN_HANDLER(lq, 0x38, 0xFF, 0xFF, 0x00000000, PPC_64BX),
GEN_HANDLER(std, 0x3E, 0xFF, 0xFF, 0x00000000, PPC_64B),
#endif
+/* handles lfdp, lxsd, lxssp */
+GEN_HANDLER_E(dform39, 0x39, 0xFF, 0xFF, 0x00000000, PPC_NONE, PPC2_ISA205),
+/* handles stfdp, lxv, stxsd, stxssp, stxv */
+GEN_HANDLER_E(dform3D, 0x3D, 0xFF, 0xFF, 0x00000000, PPC_NONE, PPC2_ISA205),
GEN_HANDLER(lmw, 0x2E, 0xFF, 0xFF, 0x00000000, PPC_INTEGER),
GEN_HANDLER(stmw, 0x2F, 0xFF, 0xFF, 0x00000000, PPC_INTEGER),
GEN_HANDLER(lswi, 0x1F, 0x15, 0x12, 0x00000001, PPC_STRING),
@@ -6326,6 +6250,7 @@ GEN_HANDLER(mcrf, 0x13, 0x00, 0xFF, 0x00000001, PPC_INTEGER),
GEN_HANDLER(rfi, 0x13, 0x12, 0x01, 0x03FF8001, PPC_FLOW),
#if defined(TARGET_PPC64)
GEN_HANDLER(rfid, 0x13, 0x12, 0x00, 0x03FF8001, PPC_64B),
+GEN_HANDLER_E(stop, 0x13, 0x12, 0x0b, 0x03FFF801, PPC_NONE, PPC2_ISA300),
GEN_HANDLER_E(doze, 0x13, 0x12, 0x0c, 0x03FFF801, PPC_NONE, PPC2_PM_ISA206),
GEN_HANDLER_E(nap, 0x13, 0x12, 0x0d, 0x03FFF801, PPC_NONE, PPC2_PM_ISA206),
GEN_HANDLER_E(sleep, 0x13, 0x12, 0x0e, 0x03FFF801, PPC_NONE, PPC2_PM_ISA206),
@@ -6910,6 +6835,9 @@ void ppc_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf,
}
#endif
+ if (env->spr_cb[SPR_LPCR].name)
+ cpu_fprintf(f, " LPCR " TARGET_FMT_lx "\n", env->spr[SPR_LPCR]);
+
switch (env->mmu_model) {
case POWERPC_MMU_32B:
case POWERPC_MMU_601:
diff --git a/target/ppc/translate/fp-impl.inc.c b/target/ppc/translate/fp-impl.inc.c
index 872af7b56f..2fbd4d4f38 100644
--- a/target/ppc/translate/fp-impl.inc.c
+++ b/target/ppc/translate/fp-impl.inc.c
@@ -9,9 +9,9 @@ static inline void gen_reset_fpstatus(void)
gen_helper_reset_fpstatus(cpu_env);
}
-static inline void gen_compute_fprf(TCGv_i64 arg)
+static inline void gen_compute_fprf_float64(TCGv_i64 arg)
{
- gen_helper_compute_fprf(cpu_env, arg);
+ gen_helper_compute_fprf_float64(cpu_env, arg);
gen_helper_float_check_status(cpu_env);
}
@@ -47,7 +47,7 @@ static void gen_f##name(DisasContext *ctx) \
cpu_fpr[rD(ctx->opcode)]); \
} \
if (set_fprf) { \
- gen_compute_fprf(cpu_fpr[rD(ctx->opcode)]); \
+ gen_compute_fprf_float64(cpu_fpr[rD(ctx->opcode)]); \
} \
if (unlikely(Rc(ctx->opcode) != 0)) { \
gen_set_cr1_from_fpscr(ctx); \
@@ -74,7 +74,7 @@ static void gen_f##name(DisasContext *ctx) \
cpu_fpr[rD(ctx->opcode)]); \
} \
if (set_fprf) { \
- gen_compute_fprf(cpu_fpr[rD(ctx->opcode)]); \
+ gen_compute_fprf_float64(cpu_fpr[rD(ctx->opcode)]); \
} \
if (unlikely(Rc(ctx->opcode) != 0)) { \
gen_set_cr1_from_fpscr(ctx); \
@@ -100,7 +100,7 @@ static void gen_f##name(DisasContext *ctx) \
cpu_fpr[rD(ctx->opcode)]); \
} \
if (set_fprf) { \
- gen_compute_fprf(cpu_fpr[rD(ctx->opcode)]); \
+ gen_compute_fprf_float64(cpu_fpr[rD(ctx->opcode)]); \
} \
if (unlikely(Rc(ctx->opcode) != 0)) { \
gen_set_cr1_from_fpscr(ctx); \
@@ -121,7 +121,7 @@ static void gen_f##name(DisasContext *ctx) \
gen_helper_f##name(cpu_fpr[rD(ctx->opcode)], cpu_env, \
cpu_fpr[rB(ctx->opcode)]); \
if (set_fprf) { \
- gen_compute_fprf(cpu_fpr[rD(ctx->opcode)]); \
+ gen_compute_fprf_float64(cpu_fpr[rD(ctx->opcode)]); \
} \
if (unlikely(Rc(ctx->opcode) != 0)) { \
gen_set_cr1_from_fpscr(ctx); \
@@ -139,7 +139,7 @@ static void gen_f##name(DisasContext *ctx) \
gen_helper_f##name(cpu_fpr[rD(ctx->opcode)], cpu_env, \
cpu_fpr[rB(ctx->opcode)]); \
if (set_fprf) { \
- gen_compute_fprf(cpu_fpr[rD(ctx->opcode)]); \
+ gen_compute_fprf_float64(cpu_fpr[rD(ctx->opcode)]); \
} \
if (unlikely(Rc(ctx->opcode) != 0)) { \
gen_set_cr1_from_fpscr(ctx); \
@@ -174,7 +174,7 @@ static void gen_frsqrtes(DisasContext *ctx)
cpu_fpr[rB(ctx->opcode)]);
gen_helper_frsp(cpu_fpr[rD(ctx->opcode)], cpu_env,
cpu_fpr[rD(ctx->opcode)]);
- gen_compute_fprf(cpu_fpr[rD(ctx->opcode)]);
+ gen_compute_fprf_float64(cpu_fpr[rD(ctx->opcode)]);
if (unlikely(Rc(ctx->opcode) != 0)) {
gen_set_cr1_from_fpscr(ctx);
}
@@ -196,7 +196,7 @@ static void gen_fsqrt(DisasContext *ctx)
gen_reset_fpstatus();
gen_helper_fsqrt(cpu_fpr[rD(ctx->opcode)], cpu_env,
cpu_fpr[rB(ctx->opcode)]);
- gen_compute_fprf(cpu_fpr[rD(ctx->opcode)]);
+ gen_compute_fprf_float64(cpu_fpr[rD(ctx->opcode)]);
if (unlikely(Rc(ctx->opcode) != 0)) {
gen_set_cr1_from_fpscr(ctx);
}
@@ -213,7 +213,7 @@ static void gen_fsqrts(DisasContext *ctx)
cpu_fpr[rB(ctx->opcode)]);
gen_helper_frsp(cpu_fpr[rD(ctx->opcode)], cpu_env,
cpu_fpr[rD(ctx->opcode)]);
- gen_compute_fprf(cpu_fpr[rD(ctx->opcode)]);
+ gen_compute_fprf_float64(cpu_fpr[rD(ctx->opcode)]);
if (unlikely(Rc(ctx->opcode) != 0)) {
gen_set_cr1_from_fpscr(ctx);
}
diff --git a/target/ppc/translate/fp-ops.inc.c b/target/ppc/translate/fp-ops.inc.c
index d36ab4ecc3..3c6d05a074 100644
--- a/target/ppc/translate/fp-ops.inc.c
+++ b/target/ppc/translate/fp-ops.inc.c
@@ -68,7 +68,6 @@ GEN_LDFS(lfd, ld64, 0x12, PPC_FLOAT)
GEN_LDFS(lfs, ld32fs, 0x10, PPC_FLOAT)
GEN_HANDLER_E(lfiwax, 0x1f, 0x17, 0x1a, 0x00000001, PPC_NONE, PPC2_ISA205),
GEN_HANDLER_E(lfiwzx, 0x1f, 0x17, 0x1b, 0x1, PPC_NONE, PPC2_FP_CVT_ISA206),
-GEN_HANDLER_E(lfdp, 0x39, 0xFF, 0xFF, 0x00200003, PPC_NONE, PPC2_ISA205),
GEN_HANDLER_E(lfdpx, 0x1F, 0x17, 0x18, 0x00200001, PPC_NONE, PPC2_ISA205),
#define GEN_STF(name, stop, opc, type) \
@@ -88,7 +87,6 @@ GEN_STXF(name, stop, 0x17, op | 0x00, type)
GEN_STFS(stfd, st64_i64, 0x16, PPC_FLOAT)
GEN_STFS(stfs, st32fs, 0x14, PPC_FLOAT)
GEN_STXF(stfiw, st32fiw, 0x17, 0x1E, PPC_FLOAT_STFIWX)
-GEN_HANDLER_E(stfdp, 0x3D, 0xFF, 0xFF, 0x00200003, PPC_NONE, PPC2_ISA205),
GEN_HANDLER_E(stfdpx, 0x1F, 0x17, 0x1C, 0x00200001, PPC_NONE, PPC2_ISA205),
GEN_HANDLER(frsqrtes, 0x3B, 0x1A, 0xFF, 0x001F07C0, PPC_FLOAT_FRSQRTES),
diff --git a/target/ppc/translate/vmx-impl.inc.c b/target/ppc/translate/vmx-impl.inc.c
index 7143eb3a39..3cb6fc2926 100644
--- a/target/ppc/translate/vmx-impl.inc.c
+++ b/target/ppc/translate/vmx-impl.inc.c
@@ -340,6 +340,19 @@ static void glue(gen_, name0##_##name1)(DisasContext *ctx) \
} \
}
+#define GEN_VXFORM_HETRO(name, opc2, opc3) \
+static void glue(gen_, name)(DisasContext *ctx) \
+{ \
+ TCGv_ptr rb; \
+ if (unlikely(!ctx->altivec_enabled)) { \
+ gen_exception(ctx, POWERPC_EXCP_VPU); \
+ return; \
+ } \
+ rb = gen_avr_ptr(rB(ctx->opcode)); \
+ gen_helper_##name(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], rb); \
+ tcg_temp_free_ptr(rb); \
+}
+
GEN_VXFORM(vaddubm, 0, 0);
GEN_VXFORM_DUAL_EXT(vaddubm, PPC_ALTIVEC, PPC_NONE, 0, \
vmul10cuq, PPC_NONE, PPC2_ISA300, 0x0000F800)
@@ -525,6 +538,16 @@ GEN_VXFORM_ENV(vaddfp, 5, 0);
GEN_VXFORM_ENV(vsubfp, 5, 1);
GEN_VXFORM_ENV(vmaxfp, 5, 16);
GEN_VXFORM_ENV(vminfp, 5, 17);
+GEN_VXFORM_HETRO(vextublx, 6, 24)
+GEN_VXFORM_HETRO(vextuhlx, 6, 25)
+GEN_VXFORM_HETRO(vextuwlx, 6, 26)
+GEN_VXFORM_DUAL(vmrgow, PPC_NONE, PPC2_ALTIVEC_207,
+ vextuwlx, PPC_NONE, PPC2_ISA300)
+GEN_VXFORM_HETRO(vextubrx, 6, 28)
+GEN_VXFORM_HETRO(vextuhrx, 6, 29)
+GEN_VXFORM_HETRO(vextuwrx, 6, 30)
+GEN_VXFORM_DUAL(vmrgew, PPC_NONE, PPC2_ALTIVEC_207, \
+ vextuwrx, PPC_NONE, PPC2_ISA300)
#define GEN_VXRFORM1(opname, name, str, opc2, opc3) \
static void glue(gen_, name)(DisasContext *ctx) \
@@ -989,10 +1012,25 @@ GEN_BCD2(bcdcfn)
GEN_BCD2(bcdctn)
GEN_BCD2(bcdcfz)
GEN_BCD2(bcdctz)
+GEN_BCD2(bcdcfsq)
+GEN_BCD2(bcdctsq)
+GEN_BCD2(bcdsetsgn)
+GEN_BCD(bcdcpsgn);
+GEN_BCD(bcds);
+GEN_BCD(bcdus);
+GEN_BCD(bcdsr);
+GEN_BCD(bcdtrunc);
+GEN_BCD(bcdutrunc);
static void gen_xpnd04_1(DisasContext *ctx)
{
switch (opc4(ctx->opcode)) {
+ case 0:
+ gen_bcdctsq(ctx);
+ break;
+ case 2:
+ gen_bcdcfsq(ctx);
+ break;
case 4:
gen_bcdctz(ctx);
break;
@@ -1005,6 +1043,9 @@ static void gen_xpnd04_1(DisasContext *ctx)
case 7:
gen_bcdcfn(ctx);
break;
+ case 31:
+ gen_bcdsetsgn(ctx);
+ break;
default:
gen_invalid(ctx);
break;
@@ -1014,6 +1055,12 @@ static void gen_xpnd04_1(DisasContext *ctx)
static void gen_xpnd04_2(DisasContext *ctx)
{
switch (opc4(ctx->opcode)) {
+ case 0:
+ gen_bcdctsq(ctx);
+ break;
+ case 2:
+ gen_bcdcfsq(ctx);
+ break;
case 4:
gen_bcdctz(ctx);
break;
@@ -1023,12 +1070,16 @@ static void gen_xpnd04_2(DisasContext *ctx)
case 7:
gen_bcdcfn(ctx);
break;
+ case 31:
+ gen_bcdsetsgn(ctx);
+ break;
default:
gen_invalid(ctx);
break;
}
}
+
GEN_VXFORM_DUAL(vsubcuw, PPC_ALTIVEC, PPC_NONE, \
xpnd04_1, PPC_NONE, PPC2_ISA300)
GEN_VXFORM_DUAL(vsubsws, PPC_ALTIVEC, PPC_NONE, \
@@ -1042,6 +1093,19 @@ GEN_VXFORM_DUAL(vsubuhm, PPC_ALTIVEC, PPC_NONE, \
bcdsub, PPC_NONE, PPC2_ALTIVEC_207)
GEN_VXFORM_DUAL(vsubuhs, PPC_ALTIVEC, PPC_NONE, \
bcdsub, PPC_NONE, PPC2_ALTIVEC_207)
+GEN_VXFORM_DUAL(vaddshs, PPC_ALTIVEC, PPC_NONE, \
+ bcdcpsgn, PPC_NONE, PPC2_ISA300)
+GEN_VXFORM_DUAL(vsubudm, PPC2_ALTIVEC_207, PPC_NONE, \
+ bcds, PPC_NONE, PPC2_ISA300)
+GEN_VXFORM_DUAL(vsubuwm, PPC_ALTIVEC, PPC_NONE, \
+ bcdus, PPC_NONE, PPC2_ISA300)
+GEN_VXFORM_DUAL(vsubsbs, PPC_ALTIVEC, PPC_NONE, \
+ bcdtrunc, PPC_NONE, PPC2_ISA300)
+GEN_VXFORM_DUAL(vsubuqm, PPC2_ALTIVEC_207, PPC_NONE, \
+ bcdtrunc, PPC_NONE, PPC2_ISA300)
+GEN_VXFORM_DUAL(vsubcuq, PPC2_ALTIVEC_207, PPC_NONE, \
+ bcdutrunc, PPC_NONE, PPC2_ISA300)
+
static void gen_vsbox(DisasContext *ctx)
{
diff --git a/target/ppc/translate/vmx-ops.inc.c b/target/ppc/translate/vmx-ops.inc.c
index f02b3bed50..139f80cb24 100644
--- a/target/ppc/translate/vmx-ops.inc.c
+++ b/target/ppc/translate/vmx-ops.inc.c
@@ -61,8 +61,9 @@ GEN_VXFORM(vadduwm, 0, 2),
GEN_VXFORM_207(vaddudm, 0, 3),
GEN_VXFORM_DUAL(vsububm, bcdadd, 0, 16, PPC_ALTIVEC, PPC_NONE),
GEN_VXFORM_DUAL(vsubuhm, bcdsub, 0, 17, PPC_ALTIVEC, PPC_NONE),
-GEN_VXFORM(vsubuwm, 0, 18),
-GEN_VXFORM_207(vsubudm, 0, 19),
+GEN_VXFORM_DUAL(vsubuwm, bcdus, 0, 18, PPC_ALTIVEC, PPC2_ISA300),
+GEN_VXFORM_DUAL(vsubudm, bcds, 0, 19, PPC2_ALTIVEC_207, PPC2_ISA300),
+GEN_VXFORM_300(bcds, 0, 27),
GEN_VXFORM(vmaxub, 1, 0),
GEN_VXFORM(vmaxuh, 1, 1),
GEN_VXFORM(vmaxuw, 1, 2),
@@ -91,8 +92,12 @@ GEN_VXFORM(vmrghw, 6, 2),
GEN_VXFORM(vmrglb, 6, 4),
GEN_VXFORM(vmrglh, 6, 5),
GEN_VXFORM(vmrglw, 6, 6),
-GEN_VXFORM_207(vmrgew, 6, 30),
-GEN_VXFORM_207(vmrgow, 6, 26),
+GEN_VXFORM_300(vextublx, 6, 24),
+GEN_VXFORM_300(vextuhlx, 6, 25),
+GEN_VXFORM_DUAL(vmrgow, vextuwlx, 6, 26, PPC_NONE, PPC2_ALTIVEC_207),
+GEN_VXFORM_300(vextubrx, 6, 28),
+GEN_VXFORM_300(vextuhrx, 6, 29),
+GEN_VXFORM_DUAL(vmrgew, vextuwrx, 6, 30, PPC_NONE, PPC2_ALTIVEC_207),
GEN_VXFORM(vmuloub, 4, 0),
GEN_VXFORM(vmulouh, 4, 1),
GEN_VXFORM_DUAL(vmulouw, vmuluwm, 4, 2, PPC_ALTIVEC, PPC_NONE),
@@ -127,23 +132,25 @@ GEN_HANDLER_E_2(vprtybd, 0x4, 0x1, 0x18, 9, 0, PPC_NONE, PPC2_ISA300),
GEN_HANDLER_E_2(vprtybq, 0x4, 0x1, 0x18, 10, 0, PPC_NONE, PPC2_ISA300),
GEN_VXFORM_DUAL(vsubcuw, xpnd04_1, 0, 22, PPC_ALTIVEC, PPC_NONE),
+GEN_VXFORM_300(bcdsr, 0, 23),
+GEN_VXFORM_300(bcdsr, 0, 31),
GEN_VXFORM_DUAL(vaddubs, vmul10uq, 0, 8, PPC_ALTIVEC, PPC_NONE),
GEN_VXFORM_DUAL(vadduhs, vmul10euq, 0, 9, PPC_ALTIVEC, PPC_NONE),
GEN_VXFORM(vadduws, 0, 10),
GEN_VXFORM(vaddsbs, 0, 12),
-GEN_VXFORM(vaddshs, 0, 13),
+GEN_VXFORM_DUAL(vaddshs, bcdcpsgn, 0, 13, PPC_ALTIVEC, PPC_NONE),
GEN_VXFORM(vaddsws, 0, 14),
GEN_VXFORM_DUAL(vsububs, bcdadd, 0, 24, PPC_ALTIVEC, PPC_NONE),
GEN_VXFORM_DUAL(vsubuhs, bcdsub, 0, 25, PPC_ALTIVEC, PPC_NONE),
GEN_VXFORM(vsubuws, 0, 26),
-GEN_VXFORM(vsubsbs, 0, 28),
+GEN_VXFORM_DUAL(vsubsbs, bcdtrunc, 0, 28, PPC_NONE, PPC2_ISA300),
GEN_VXFORM(vsubshs, 0, 29),
GEN_VXFORM_DUAL(vsubsws, xpnd04_2, 0, 30, PPC_ALTIVEC, PPC_NONE),
GEN_VXFORM_207(vadduqm, 0, 4),
GEN_VXFORM_207(vaddcuq, 0, 5),
GEN_VXFORM_DUAL(vaddeuqm, vaddecuq, 30, 0xFF, PPC_NONE, PPC2_ALTIVEC_207),
-GEN_VXFORM_207(vsubuqm, 0, 20),
-GEN_VXFORM_207(vsubcuq, 0, 21),
+GEN_VXFORM_DUAL(vsubuqm, bcdtrunc, 0, 20, PPC2_ALTIVEC_207, PPC2_ISA300),
+GEN_VXFORM_DUAL(vsubcuq, bcdutrunc, 0, 21, PPC2_ALTIVEC_207, PPC2_ISA300),
GEN_VXFORM_DUAL(vsubeuqm, vsubecuq, 31, 0xFF, PPC_NONE, PPC2_ALTIVEC_207),
GEN_VXFORM(vrlb, 2, 0),
GEN_VXFORM(vrlh, 2, 1),
diff --git a/target/ppc/translate/vsx-impl.inc.c b/target/ppc/translate/vsx-impl.inc.c
index 5a27be4bd4..a44c0034a8 100644
--- a/target/ppc/translate/vsx-impl.inc.c
+++ b/target/ppc/translate/vsx-impl.inc.c
@@ -190,6 +190,109 @@ static void gen_lxvb16x(DisasContext *ctx)
tcg_temp_free(EA);
}
+#define VSX_VECTOR_LOAD_STORE(name, op, indexed) \
+static void gen_##name(DisasContext *ctx) \
+{ \
+ int xt; \
+ TCGv EA; \
+ TCGv_i64 xth, xtl; \
+ \
+ if (indexed) { \
+ xt = xT(ctx->opcode); \
+ } else { \
+ xt = DQxT(ctx->opcode); \
+ } \
+ xth = cpu_vsrh(xt); \
+ xtl = cpu_vsrl(xt); \
+ \
+ if (xt < 32) { \
+ if (unlikely(!ctx->vsx_enabled)) { \
+ gen_exception(ctx, POWERPC_EXCP_VSXU); \
+ return; \
+ } \
+ } else { \
+ if (unlikely(!ctx->altivec_enabled)) { \
+ gen_exception(ctx, POWERPC_EXCP_VPU); \
+ return; \
+ } \
+ } \
+ gen_set_access_type(ctx, ACCESS_INT); \
+ EA = tcg_temp_new(); \
+ if (indexed) { \
+ gen_addr_reg_index(ctx, EA); \
+ } else { \
+ gen_addr_imm_index(ctx, EA, 0x0F); \
+ } \
+ if (ctx->le_mode) { \
+ tcg_gen_qemu_##op(xtl, EA, ctx->mem_idx, MO_LEQ); \
+ tcg_gen_addi_tl(EA, EA, 8); \
+ tcg_gen_qemu_##op(xth, EA, ctx->mem_idx, MO_LEQ); \
+ } else { \
+ tcg_gen_qemu_##op(xth, EA, ctx->mem_idx, MO_BEQ); \
+ tcg_gen_addi_tl(EA, EA, 8); \
+ tcg_gen_qemu_##op(xtl, EA, ctx->mem_idx, MO_BEQ); \
+ } \
+ tcg_temp_free(EA); \
+}
+
+VSX_VECTOR_LOAD_STORE(lxv, ld_i64, 0)
+VSX_VECTOR_LOAD_STORE(stxv, st_i64, 0)
+VSX_VECTOR_LOAD_STORE(lxvx, ld_i64, 1)
+VSX_VECTOR_LOAD_STORE(stxvx, st_i64, 1)
+
+#ifdef TARGET_PPC64
+#define VSX_VECTOR_LOAD_STORE_LENGTH(name) \
+static void gen_##name(DisasContext *ctx) \
+{ \
+ TCGv EA, xt; \
+ \
+ if (xT(ctx->opcode) < 32) { \
+ if (unlikely(!ctx->vsx_enabled)) { \
+ gen_exception(ctx, POWERPC_EXCP_VSXU); \
+ return; \
+ } \
+ } else { \
+ if (unlikely(!ctx->altivec_enabled)) { \
+ gen_exception(ctx, POWERPC_EXCP_VPU); \
+ return; \
+ } \
+ } \
+ EA = tcg_temp_new(); \
+ xt = tcg_const_tl(xT(ctx->opcode)); \
+ gen_set_access_type(ctx, ACCESS_INT); \
+ gen_addr_register(ctx, EA); \
+ gen_helper_##name(cpu_env, EA, xt, cpu_gpr[rB(ctx->opcode)]); \
+ tcg_temp_free(EA); \
+ tcg_temp_free(xt); \
+}
+
+VSX_VECTOR_LOAD_STORE_LENGTH(lxvl)
+VSX_VECTOR_LOAD_STORE_LENGTH(lxvll)
+VSX_VECTOR_LOAD_STORE_LENGTH(stxvl)
+VSX_VECTOR_LOAD_STORE_LENGTH(stxvll)
+#endif
+
+#define VSX_LOAD_SCALAR_DS(name, operation) \
+static void gen_##name(DisasContext *ctx) \
+{ \
+ TCGv EA; \
+ TCGv_i64 xth = cpu_vsrh(rD(ctx->opcode) + 32); \
+ \
+ if (unlikely(!ctx->altivec_enabled)) { \
+ gen_exception(ctx, POWERPC_EXCP_VPU); \
+ return; \
+ } \
+ gen_set_access_type(ctx, ACCESS_INT); \
+ EA = tcg_temp_new(); \
+ gen_addr_imm_index(ctx, EA, 0x03); \
+ gen_qemu_##operation(ctx, xth, EA); \
+ /* NOTE: cpu_vsrl is undefined */ \
+ tcg_temp_free(EA); \
+}
+
+VSX_LOAD_SCALAR_DS(lxsd, ld64_i64)
+VSX_LOAD_SCALAR_DS(lxssp, ld32fs)
+
#define VSX_STORE_SCALAR(name, operation) \
static void gen_##name(DisasContext *ctx) \
{ \
@@ -311,6 +414,27 @@ static void gen_stxvb16x(DisasContext *ctx)
tcg_temp_free(EA);
}
+#define VSX_STORE_SCALAR_DS(name, operation) \
+static void gen_##name(DisasContext *ctx) \
+{ \
+ TCGv EA; \
+ TCGv_i64 xth = cpu_vsrh(rD(ctx->opcode) + 32); \
+ \
+ if (unlikely(!ctx->altivec_enabled)) { \
+ gen_exception(ctx, POWERPC_EXCP_VPU); \
+ return; \
+ } \
+ gen_set_access_type(ctx, ACCESS_INT); \
+ EA = tcg_temp_new(); \
+ gen_addr_imm_index(ctx, EA, 0x03); \
+ gen_qemu_##operation(ctx, xth, EA); \
+ /* NOTE: cpu_vsrl is undefined */ \
+ tcg_temp_free(EA); \
+}
+
+VSX_LOAD_SCALAR_DS(stxsd, st64_i64)
+VSX_LOAD_SCALAR_DS(stxssp, st32fs)
+
#define MV_VSRW(name, tcgop1, tcgop2, target, source) \
static void gen_##name(DisasContext *ctx) \
{ \
@@ -517,6 +641,55 @@ VSX_SCALAR_MOVE(xsnabsdp, OP_NABS, SGN_MASK_DP)
VSX_SCALAR_MOVE(xsnegdp, OP_NEG, SGN_MASK_DP)
VSX_SCALAR_MOVE(xscpsgndp, OP_CPSGN, SGN_MASK_DP)
+#define VSX_SCALAR_MOVE_QP(name, op, sgn_mask) \
+static void glue(gen_, name)(DisasContext *ctx) \
+{ \
+ int xa; \
+ int xt = rD(ctx->opcode) + 32; \
+ int xb = rB(ctx->opcode) + 32; \
+ TCGv_i64 xah, xbh, xbl, sgm; \
+ \
+ if (unlikely(!ctx->vsx_enabled)) { \
+ gen_exception(ctx, POWERPC_EXCP_VSXU); \
+ return; \
+ } \
+ xbh = tcg_temp_new_i64(); \
+ xbl = tcg_temp_new_i64(); \
+ sgm = tcg_temp_new_i64(); \
+ tcg_gen_mov_i64(xbh, cpu_vsrh(xb)); \
+ tcg_gen_mov_i64(xbl, cpu_vsrl(xb)); \
+ tcg_gen_movi_i64(sgm, sgn_mask); \
+ switch (op) { \
+ case OP_ABS: \
+ tcg_gen_andc_i64(xbh, xbh, sgm); \
+ break; \
+ case OP_NABS: \
+ tcg_gen_or_i64(xbh, xbh, sgm); \
+ break; \
+ case OP_NEG: \
+ tcg_gen_xor_i64(xbh, xbh, sgm); \
+ break; \
+ case OP_CPSGN: \
+ xah = tcg_temp_new_i64(); \
+ xa = rA(ctx->opcode) + 32; \
+ tcg_gen_and_i64(xah, cpu_vsrh(xa), sgm); \
+ tcg_gen_andc_i64(xbh, xbh, sgm); \
+ tcg_gen_or_i64(xbh, xbh, xah); \
+ tcg_temp_free_i64(xah); \
+ break; \
+ } \
+ tcg_gen_mov_i64(cpu_vsrh(xt), xbh); \
+ tcg_gen_mov_i64(cpu_vsrl(xt), xbl); \
+ tcg_temp_free_i64(xbl); \
+ tcg_temp_free_i64(xbh); \
+ tcg_temp_free_i64(sgm); \
+}
+
+VSX_SCALAR_MOVE_QP(xsabsqp, OP_ABS, SGN_MASK_DP)
+VSX_SCALAR_MOVE_QP(xsnabsqp, OP_NABS, SGN_MASK_DP)
+VSX_SCALAR_MOVE_QP(xsnegqp, OP_NEG, SGN_MASK_DP)
+VSX_SCALAR_MOVE_QP(xscpsgnqp, OP_CPSGN, SGN_MASK_DP)
+
#define VSX_VECTOR_MOVE(name, op, sgn_mask) \
static void glue(gen_, name)(DisasContext * ctx) \
{ \
@@ -604,9 +777,12 @@ static void gen_##name(DisasContext * ctx) \
}
GEN_VSX_HELPER_2(xsadddp, 0x00, 0x04, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xsaddqp, 0x04, 0x00, 0, PPC2_ISA300)
GEN_VSX_HELPER_2(xssubdp, 0x00, 0x05, 0, PPC2_VSX)
GEN_VSX_HELPER_2(xsmuldp, 0x00, 0x06, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xsmulqp, 0x04, 0x01, 0, PPC2_ISA300)
GEN_VSX_HELPER_2(xsdivdp, 0x00, 0x07, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xsdivqp, 0x04, 0x11, 0, PPC2_ISA300)
GEN_VSX_HELPER_2(xsredp, 0x14, 0x05, 0, PPC2_VSX)
GEN_VSX_HELPER_2(xssqrtdp, 0x16, 0x04, 0, PPC2_VSX)
GEN_VSX_HELPER_2(xsrsqrtedp, 0x14, 0x04, 0, PPC2_VSX)
@@ -624,12 +800,23 @@ GEN_VSX_HELPER_2(xscmpeqdp, 0x0C, 0x00, 0, PPC2_ISA300)
GEN_VSX_HELPER_2(xscmpgtdp, 0x0C, 0x01, 0, PPC2_ISA300)
GEN_VSX_HELPER_2(xscmpgedp, 0x0C, 0x02, 0, PPC2_ISA300)
GEN_VSX_HELPER_2(xscmpnedp, 0x0C, 0x03, 0, PPC2_ISA300)
+GEN_VSX_HELPER_2(xscmpexpdp, 0x0C, 0x07, 0, PPC2_ISA300)
+GEN_VSX_HELPER_2(xscmpexpqp, 0x04, 0x05, 0, PPC2_ISA300)
GEN_VSX_HELPER_2(xscmpodp, 0x0C, 0x05, 0, PPC2_VSX)
GEN_VSX_HELPER_2(xscmpudp, 0x0C, 0x04, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xscmpoqp, 0x04, 0x04, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xscmpuqp, 0x04, 0x14, 0, PPC2_VSX)
GEN_VSX_HELPER_2(xsmaxdp, 0x00, 0x14, 0, PPC2_VSX)
GEN_VSX_HELPER_2(xsmindp, 0x00, 0x15, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xscvdphp, 0x16, 0x15, 0x11, PPC2_ISA300)
GEN_VSX_HELPER_2(xscvdpsp, 0x12, 0x10, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xscvdpqp, 0x04, 0x1A, 0x16, PPC2_ISA300)
GEN_VSX_HELPER_XT_XB_ENV(xscvdpspn, 0x16, 0x10, 0, PPC2_VSX207)
+GEN_VSX_HELPER_2(xscvqpdp, 0x04, 0x1A, 0x14, PPC2_ISA300)
+GEN_VSX_HELPER_2(xscvqpsdz, 0x04, 0x1A, 0x19, PPC2_ISA300)
+GEN_VSX_HELPER_2(xscvqpswz, 0x04, 0x1A, 0x09, PPC2_ISA300)
+GEN_VSX_HELPER_2(xscvhpdp, 0x16, 0x15, 0x10, PPC2_ISA300)
+GEN_VSX_HELPER_2(xscvsdqp, 0x04, 0x1A, 0x0A, PPC2_ISA300)
GEN_VSX_HELPER_2(xscvspdp, 0x12, 0x14, 0, PPC2_VSX)
GEN_VSX_HELPER_XT_XB_ENV(xscvspdpn, 0x16, 0x14, 0, PPC2_VSX207)
GEN_VSX_HELPER_2(xscvdpsxds, 0x10, 0x15, 0, PPC2_VSX)
@@ -637,6 +824,7 @@ GEN_VSX_HELPER_2(xscvdpsxws, 0x10, 0x05, 0, PPC2_VSX)
GEN_VSX_HELPER_2(xscvdpuxds, 0x10, 0x14, 0, PPC2_VSX)
GEN_VSX_HELPER_2(xscvdpuxws, 0x10, 0x04, 0, PPC2_VSX)
GEN_VSX_HELPER_2(xscvsxddp, 0x10, 0x17, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xscvudqp, 0x04, 0x1A, 0x02, PPC2_ISA300)
GEN_VSX_HELPER_2(xscvuxddp, 0x10, 0x16, 0, PPC2_VSX)
GEN_VSX_HELPER_2(xsrdpi, 0x12, 0x04, 0, PPC2_VSX)
GEN_VSX_HELPER_2(xsrdpic, 0x16, 0x06, 0, PPC2_VSX)
@@ -662,6 +850,9 @@ GEN_VSX_HELPER_2(xsnmsubasp, 0x04, 0x12, 0, PPC2_VSX207)
GEN_VSX_HELPER_2(xsnmsubmsp, 0x04, 0x13, 0, PPC2_VSX207)
GEN_VSX_HELPER_2(xscvsxdsp, 0x10, 0x13, 0, PPC2_VSX207)
GEN_VSX_HELPER_2(xscvuxdsp, 0x10, 0x12, 0, PPC2_VSX207)
+GEN_VSX_HELPER_2(xststdcsp, 0x14, 0x12, 0, PPC2_ISA300)
+GEN_VSX_HELPER_2(xststdcdp, 0x14, 0x16, 0, PPC2_ISA300)
+GEN_VSX_HELPER_2(xststdcqp, 0x04, 0x16, 0, PPC2_ISA300)
GEN_VSX_HELPER_2(xvadddp, 0x00, 0x0C, 0, PPC2_VSX)
GEN_VSX_HELPER_2(xvsubdp, 0x00, 0x0D, 0, PPC2_VSX)
@@ -725,6 +916,8 @@ GEN_VSX_HELPER_2(xvcmpgtsp, 0x0C, 0x09, 0, PPC2_VSX)
GEN_VSX_HELPER_2(xvcmpgesp, 0x0C, 0x0A, 0, PPC2_VSX)
GEN_VSX_HELPER_2(xvcmpnesp, 0x0C, 0x0B, 0, PPC2_VSX)
GEN_VSX_HELPER_2(xvcvspdp, 0x12, 0x1C, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xvcvhpsp, 0x16, 0x1D, 0x18, PPC2_ISA300)
+GEN_VSX_HELPER_2(xvcvsphp, 0x16, 0x1D, 0x19, PPC2_ISA300)
GEN_VSX_HELPER_2(xvcvspsxds, 0x10, 0x19, 0, PPC2_VSX)
GEN_VSX_HELPER_2(xvcvspsxws, 0x10, 0x09, 0, PPC2_VSX)
GEN_VSX_HELPER_2(xvcvspuxds, 0x10, 0x18, 0, PPC2_VSX)
@@ -738,6 +931,10 @@ GEN_VSX_HELPER_2(xvrspic, 0x16, 0x0A, 0, PPC2_VSX)
GEN_VSX_HELPER_2(xvrspim, 0x12, 0x0B, 0, PPC2_VSX)
GEN_VSX_HELPER_2(xvrspip, 0x12, 0x0A, 0, PPC2_VSX)
GEN_VSX_HELPER_2(xvrspiz, 0x12, 0x09, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xvtstdcsp, 0x14, 0x1A, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xvtstdcdp, 0x14, 0x1E, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xxperm, 0x08, 0x03, 0, PPC2_ISA300)
+GEN_VSX_HELPER_2(xxpermr, 0x08, 0x07, 0, PPC2_ISA300)
static void gen_xxbrd(DisasContext *ctx)
{
@@ -1001,6 +1198,293 @@ static void gen_xxsldwi(DisasContext *ctx)
tcg_temp_free_i64(xtl);
}
+#define VSX_EXTRACT_INSERT(name) \
+static void gen_##name(DisasContext *ctx) \
+{ \
+ TCGv xt, xb; \
+ TCGv_i32 t0 = tcg_temp_new_i32(); \
+ uint8_t uimm = UIMM4(ctx->opcode); \
+ \
+ if (unlikely(!ctx->vsx_enabled)) { \
+ gen_exception(ctx, POWERPC_EXCP_VSXU); \
+ return; \
+ } \
+ xt = tcg_const_tl(xT(ctx->opcode)); \
+ xb = tcg_const_tl(xB(ctx->opcode)); \
+ /* uimm > 15 out of bound and for \
+ * uimm > 12 handle as per hardware in helper \
+ */ \
+ if (uimm > 15) { \
+ tcg_gen_movi_i64(cpu_vsrh(xT(ctx->opcode)), 0); \
+ tcg_gen_movi_i64(cpu_vsrl(xT(ctx->opcode)), 0); \
+ return; \
+ } \
+ tcg_gen_movi_i32(t0, uimm); \
+ gen_helper_##name(cpu_env, xt, xb, t0); \
+ tcg_temp_free(xb); \
+ tcg_temp_free(xt); \
+ tcg_temp_free_i32(t0); \
+}
+
+VSX_EXTRACT_INSERT(xxextractuw)
+VSX_EXTRACT_INSERT(xxinsertw)
+
+#ifdef TARGET_PPC64
+static void gen_xsxexpdp(DisasContext *ctx)
+{
+ TCGv rt = cpu_gpr[rD(ctx->opcode)];
+ if (unlikely(!ctx->vsx_enabled)) {
+ gen_exception(ctx, POWERPC_EXCP_VSXU);
+ return;
+ }
+ tcg_gen_shri_i64(rt, cpu_vsrh(xB(ctx->opcode)), 52);
+ tcg_gen_andi_i64(rt, rt, 0x7FF);
+}
+
+static void gen_xsxexpqp(DisasContext *ctx)
+{
+ TCGv_i64 xth = cpu_vsrh(rD(ctx->opcode) + 32);
+ TCGv_i64 xtl = cpu_vsrl(rD(ctx->opcode) + 32);
+ TCGv_i64 xbh = cpu_vsrh(rB(ctx->opcode) + 32);
+
+ if (unlikely(!ctx->vsx_enabled)) {
+ gen_exception(ctx, POWERPC_EXCP_VSXU);
+ return;
+ }
+ tcg_gen_shri_i64(xth, xbh, 48);
+ tcg_gen_andi_i64(xth, xth, 0x7FFF);
+ tcg_gen_movi_i64(xtl, 0);
+}
+
+static void gen_xsiexpdp(DisasContext *ctx)
+{
+ TCGv_i64 xth = cpu_vsrh(xT(ctx->opcode));
+ TCGv ra = cpu_gpr[rA(ctx->opcode)];
+ TCGv rb = cpu_gpr[rB(ctx->opcode)];
+ TCGv_i64 t0;
+
+ if (unlikely(!ctx->vsx_enabled)) {
+ gen_exception(ctx, POWERPC_EXCP_VSXU);
+ return;
+ }
+ t0 = tcg_temp_new_i64();
+ tcg_gen_andi_i64(xth, ra, 0x800FFFFFFFFFFFFF);
+ tcg_gen_andi_i64(t0, rb, 0x7FF);
+ tcg_gen_shli_i64(t0, t0, 52);
+ tcg_gen_or_i64(xth, xth, t0);
+ /* dword[1] is undefined */
+ tcg_temp_free_i64(t0);
+}
+
+static void gen_xsiexpqp(DisasContext *ctx)
+{
+ TCGv_i64 xth = cpu_vsrh(rD(ctx->opcode) + 32);
+ TCGv_i64 xtl = cpu_vsrl(rD(ctx->opcode) + 32);
+ TCGv_i64 xah = cpu_vsrh(rA(ctx->opcode) + 32);
+ TCGv_i64 xal = cpu_vsrl(rA(ctx->opcode) + 32);
+ TCGv_i64 xbh = cpu_vsrh(rB(ctx->opcode) + 32);
+ TCGv_i64 t0;
+
+ if (unlikely(!ctx->vsx_enabled)) {
+ gen_exception(ctx, POWERPC_EXCP_VSXU);
+ return;
+ }
+ t0 = tcg_temp_new_i64();
+ tcg_gen_andi_i64(xth, xah, 0x8000FFFFFFFFFFFF);
+ tcg_gen_andi_i64(t0, xbh, 0x7FFF);
+ tcg_gen_shli_i64(t0, t0, 48);
+ tcg_gen_or_i64(xth, xth, t0);
+ tcg_gen_mov_i64(xtl, xal);
+ tcg_temp_free_i64(t0);
+}
+
+static void gen_xsxsigdp(DisasContext *ctx)
+{
+ TCGv rt = cpu_gpr[rD(ctx->opcode)];
+ TCGv_i64 t0, zr, nan, exp;
+
+ if (unlikely(!ctx->vsx_enabled)) {
+ gen_exception(ctx, POWERPC_EXCP_VSXU);
+ return;
+ }
+ exp = tcg_temp_new_i64();
+ t0 = tcg_temp_new_i64();
+ zr = tcg_const_i64(0);
+ nan = tcg_const_i64(2047);
+
+ tcg_gen_shri_i64(exp, cpu_vsrh(xB(ctx->opcode)), 52);
+ tcg_gen_andi_i64(exp, exp, 0x7FF);
+ tcg_gen_movi_i64(t0, 0x0010000000000000);
+ tcg_gen_movcond_i64(TCG_COND_EQ, t0, exp, zr, zr, t0);
+ tcg_gen_movcond_i64(TCG_COND_EQ, t0, exp, nan, zr, t0);
+ tcg_gen_andi_i64(rt, cpu_vsrh(xB(ctx->opcode)), 0x000FFFFFFFFFFFFF);
+ tcg_gen_or_i64(rt, rt, t0);
+
+ tcg_temp_free_i64(t0);
+ tcg_temp_free_i64(exp);
+ tcg_temp_free_i64(zr);
+ tcg_temp_free_i64(nan);
+}
+
+static void gen_xsxsigqp(DisasContext *ctx)
+{
+ TCGv_i64 t0, zr, nan, exp;
+ TCGv_i64 xth = cpu_vsrh(rD(ctx->opcode) + 32);
+ TCGv_i64 xtl = cpu_vsrl(rD(ctx->opcode) + 32);
+
+ if (unlikely(!ctx->vsx_enabled)) {
+ gen_exception(ctx, POWERPC_EXCP_VSXU);
+ return;
+ }
+ exp = tcg_temp_new_i64();
+ t0 = tcg_temp_new_i64();
+ zr = tcg_const_i64(0);
+ nan = tcg_const_i64(32767);
+
+ tcg_gen_shri_i64(exp, cpu_vsrh(rB(ctx->opcode) + 32), 48);
+ tcg_gen_andi_i64(exp, exp, 0x7FFF);
+ tcg_gen_movi_i64(t0, 0x0001000000000000);
+ tcg_gen_movcond_i64(TCG_COND_EQ, t0, exp, zr, zr, t0);
+ tcg_gen_movcond_i64(TCG_COND_EQ, t0, exp, nan, zr, t0);
+ tcg_gen_andi_i64(xth, cpu_vsrh(rB(ctx->opcode) + 32), 0x0000FFFFFFFFFFFF);
+ tcg_gen_or_i64(xth, xth, t0);
+ tcg_gen_mov_i64(xtl, cpu_vsrl(rB(ctx->opcode) + 32));
+
+ tcg_temp_free_i64(t0);
+ tcg_temp_free_i64(exp);
+ tcg_temp_free_i64(zr);
+ tcg_temp_free_i64(nan);
+}
+#endif
+
+static void gen_xviexpsp(DisasContext *ctx)
+{
+ TCGv_i64 xth = cpu_vsrh(xT(ctx->opcode));
+ TCGv_i64 xtl = cpu_vsrl(xT(ctx->opcode));
+ TCGv_i64 xah = cpu_vsrh(xA(ctx->opcode));
+ TCGv_i64 xal = cpu_vsrl(xA(ctx->opcode));
+ TCGv_i64 xbh = cpu_vsrh(xB(ctx->opcode));
+ TCGv_i64 xbl = cpu_vsrl(xB(ctx->opcode));
+ TCGv_i64 t0;
+
+ if (unlikely(!ctx->vsx_enabled)) {
+ gen_exception(ctx, POWERPC_EXCP_VSXU);
+ return;
+ }
+ t0 = tcg_temp_new_i64();
+ tcg_gen_andi_i64(xth, xah, 0x807FFFFF807FFFFF);
+ tcg_gen_andi_i64(t0, xbh, 0xFF000000FF);
+ tcg_gen_shli_i64(t0, t0, 23);
+ tcg_gen_or_i64(xth, xth, t0);
+ tcg_gen_andi_i64(xtl, xal, 0x807FFFFF807FFFFF);
+ tcg_gen_andi_i64(t0, xbl, 0xFF000000FF);
+ tcg_gen_shli_i64(t0, t0, 23);
+ tcg_gen_or_i64(xtl, xtl, t0);
+ tcg_temp_free_i64(t0);
+}
+
+static void gen_xviexpdp(DisasContext *ctx)
+{
+ TCGv_i64 xth = cpu_vsrh(xT(ctx->opcode));
+ TCGv_i64 xtl = cpu_vsrl(xT(ctx->opcode));
+ TCGv_i64 xah = cpu_vsrh(xA(ctx->opcode));
+ TCGv_i64 xal = cpu_vsrl(xA(ctx->opcode));
+ TCGv_i64 xbh = cpu_vsrh(xB(ctx->opcode));
+ TCGv_i64 xbl = cpu_vsrl(xB(ctx->opcode));
+ TCGv_i64 t0;
+
+ if (unlikely(!ctx->vsx_enabled)) {
+ gen_exception(ctx, POWERPC_EXCP_VSXU);
+ return;
+ }
+ t0 = tcg_temp_new_i64();
+ tcg_gen_andi_i64(xth, xah, 0x800FFFFFFFFFFFFF);
+ tcg_gen_andi_i64(t0, xbh, 0x7FF);
+ tcg_gen_shli_i64(t0, t0, 52);
+ tcg_gen_or_i64(xth, xth, t0);
+ tcg_gen_andi_i64(xtl, xal, 0x800FFFFFFFFFFFFF);
+ tcg_gen_andi_i64(t0, xbl, 0x7FF);
+ tcg_gen_shli_i64(t0, t0, 52);
+ tcg_gen_or_i64(xtl, xtl, t0);
+ tcg_temp_free_i64(t0);
+}
+
+static void gen_xvxexpsp(DisasContext *ctx)
+{
+ TCGv_i64 xth = cpu_vsrh(xT(ctx->opcode));
+ TCGv_i64 xtl = cpu_vsrl(xT(ctx->opcode));
+ TCGv_i64 xbh = cpu_vsrh(xB(ctx->opcode));
+ TCGv_i64 xbl = cpu_vsrl(xB(ctx->opcode));
+
+ if (unlikely(!ctx->vsx_enabled)) {
+ gen_exception(ctx, POWERPC_EXCP_VSXU);
+ return;
+ }
+ tcg_gen_shri_i64(xth, xbh, 23);
+ tcg_gen_andi_i64(xth, xth, 0xFF000000FF);
+ tcg_gen_shri_i64(xtl, xbl, 23);
+ tcg_gen_andi_i64(xtl, xtl, 0xFF000000FF);
+}
+
+static void gen_xvxexpdp(DisasContext *ctx)
+{
+ TCGv_i64 xth = cpu_vsrh(xT(ctx->opcode));
+ TCGv_i64 xtl = cpu_vsrl(xT(ctx->opcode));
+ TCGv_i64 xbh = cpu_vsrh(xB(ctx->opcode));
+ TCGv_i64 xbl = cpu_vsrl(xB(ctx->opcode));
+
+ if (unlikely(!ctx->vsx_enabled)) {
+ gen_exception(ctx, POWERPC_EXCP_VSXU);
+ return;
+ }
+ tcg_gen_shri_i64(xth, xbh, 52);
+ tcg_gen_andi_i64(xth, xth, 0x7FF);
+ tcg_gen_shri_i64(xtl, xbl, 52);
+ tcg_gen_andi_i64(xtl, xtl, 0x7FF);
+}
+
+GEN_VSX_HELPER_2(xvxsigsp, 0x00, 0x04, 0, PPC2_ISA300)
+
+static void gen_xvxsigdp(DisasContext *ctx)
+{
+ TCGv_i64 xth = cpu_vsrh(xT(ctx->opcode));
+ TCGv_i64 xtl = cpu_vsrl(xT(ctx->opcode));
+ TCGv_i64 xbh = cpu_vsrh(xB(ctx->opcode));
+ TCGv_i64 xbl = cpu_vsrl(xB(ctx->opcode));
+
+ TCGv_i64 t0, zr, nan, exp;
+
+ if (unlikely(!ctx->vsx_enabled)) {
+ gen_exception(ctx, POWERPC_EXCP_VSXU);
+ return;
+ }
+ exp = tcg_temp_new_i64();
+ t0 = tcg_temp_new_i64();
+ zr = tcg_const_i64(0);
+ nan = tcg_const_i64(2047);
+
+ tcg_gen_shri_i64(exp, xbh, 52);
+ tcg_gen_andi_i64(exp, exp, 0x7FF);
+ tcg_gen_movi_i64(t0, 0x0010000000000000);
+ tcg_gen_movcond_i64(TCG_COND_EQ, t0, exp, zr, zr, t0);
+ tcg_gen_movcond_i64(TCG_COND_EQ, t0, exp, nan, zr, t0);
+ tcg_gen_andi_i64(xth, xbh, 0x000FFFFFFFFFFFFF);
+ tcg_gen_or_i64(xth, xth, t0);
+
+ tcg_gen_shri_i64(exp, xbl, 52);
+ tcg_gen_andi_i64(exp, exp, 0x7FF);
+ tcg_gen_movi_i64(t0, 0x0010000000000000);
+ tcg_gen_movcond_i64(TCG_COND_EQ, t0, exp, zr, zr, t0);
+ tcg_gen_movcond_i64(TCG_COND_EQ, t0, exp, nan, zr, t0);
+ tcg_gen_andi_i64(xtl, xbl, 0x000FFFFFFFFFFFFF);
+ tcg_gen_or_i64(xtl, xtl, t0);
+
+ tcg_temp_free_i64(t0);
+ tcg_temp_free_i64(exp);
+ tcg_temp_free_i64(zr);
+ tcg_temp_free_i64(nan);
+}
+
#undef GEN_XX2FORM
#undef GEN_XX3FORM
#undef GEN_XX2IFORM
diff --git a/target/ppc/translate/vsx-ops.inc.c b/target/ppc/translate/vsx-ops.inc.c
index 3d9104155a..7dc9f6f477 100644
--- a/target/ppc/translate/vsx-ops.inc.c
+++ b/target/ppc/translate/vsx-ops.inc.c
@@ -9,6 +9,11 @@ GEN_HANDLER_E(lxvdsx, 0x1F, 0x0C, 0x0A, 0, PPC_NONE, PPC2_VSX),
GEN_HANDLER_E(lxvw4x, 0x1F, 0x0C, 0x18, 0, PPC_NONE, PPC2_VSX),
GEN_HANDLER_E(lxvh8x, 0x1F, 0x0C, 0x19, 0, PPC_NONE, PPC2_ISA300),
GEN_HANDLER_E(lxvb16x, 0x1F, 0x0C, 0x1B, 0, PPC_NONE, PPC2_ISA300),
+GEN_HANDLER_E(lxvx, 0x1F, 0x0C, 0x08, 0x00000040, PPC_NONE, PPC2_ISA300),
+#if defined(TARGET_PPC64)
+GEN_HANDLER_E(lxvl, 0x1F, 0x0D, 0x08, 0, PPC_NONE, PPC2_ISA300),
+GEN_HANDLER_E(lxvll, 0x1F, 0x0D, 0x09, 0, PPC_NONE, PPC2_ISA300),
+#endif
GEN_HANDLER_E(stxsdx, 0x1F, 0xC, 0x16, 0, PPC_NONE, PPC2_VSX),
GEN_HANDLER_E(stxsibx, 0x1F, 0xD, 0x1C, 0, PPC_NONE, PPC2_ISA300),
@@ -19,6 +24,11 @@ GEN_HANDLER_E(stxvd2x, 0x1F, 0xC, 0x1E, 0, PPC_NONE, PPC2_VSX),
GEN_HANDLER_E(stxvw4x, 0x1F, 0xC, 0x1C, 0, PPC_NONE, PPC2_VSX),
GEN_HANDLER_E(stxvh8x, 0x1F, 0x0C, 0x1D, 0, PPC_NONE, PPC2_ISA300),
GEN_HANDLER_E(stxvb16x, 0x1F, 0x0C, 0x1F, 0, PPC_NONE, PPC2_ISA300),
+GEN_HANDLER_E(stxvx, 0x1F, 0x0C, 0x0C, 0, PPC_NONE, PPC2_ISA300),
+#if defined(TARGET_PPC64)
+GEN_HANDLER_E(stxvl, 0x1F, 0x0D, 0x0C, 0, PPC_NONE, PPC2_ISA300),
+GEN_HANDLER_E(stxvll, 0x1F, 0x0D, 0x0D, 0, PPC_NONE, PPC2_ISA300),
+#endif
GEN_HANDLER_E(mfvsrwz, 0x1F, 0x13, 0x03, 0x0000F800, PPC_NONE, PPC2_VSX207),
GEN_HANDLER_E(mtvsrwa, 0x1F, 0x13, 0x06, 0x0000F800, PPC_NONE, PPC2_VSX207),
@@ -39,6 +49,10 @@ GEN_HANDLER2_E(name, #name, 0x3C, opc2 | 1, opc3, 0, PPC_NONE, fl2)
GEN_HANDLER2_E(name, #name, 0x3C, opc2 | 0, opc3, 0, PPC_NONE, fl2), \
GEN_HANDLER2_E(name, #name, 0x3C, opc2 | 1, opc3, 0, PPC_NONE, fl2)
+#define GEN_XX2FORM_EXT(name, opc2, opc3, fl2) \
+GEN_HANDLER2_E(name, #name, 0x3C, opc2 | 0, opc3, 0x00100000, PPC_NONE, fl2), \
+GEN_HANDLER2_E(name, #name, 0x3C, opc2 | 1, opc3, 0x00100000, PPC_NONE, fl2)
+
#define GEN_XX2FORM_EO(name, opc2, opc3, opc4, fl2) \
GEN_HANDLER2_E_2(name, #name, 0x3C, opc2 | 0, opc3, opc4, 0, PPC_NONE, fl2), \
GEN_HANDLER2_E_2(name, #name, 0x3C, opc2 | 1, opc3, opc4, 0, PPC_NONE, fl2)
@@ -83,11 +97,54 @@ GEN_HANDLER2_E(name, #name, 0x3C, opc2|0x01, opc3|0x0C, 0, PPC_NONE, PPC2_VSX),\
GEN_HANDLER2_E(name, #name, 0x3C, opc2|0x02, opc3|0x0C, 0, PPC_NONE, PPC2_VSX),\
GEN_HANDLER2_E(name, #name, 0x3C, opc2|0x03, opc3|0x0C, 0, PPC_NONE, PPC2_VSX)
+#define GEN_VSX_XFORM_300(name, opc2, opc3, inval) \
+GEN_HANDLER_E(name, 0x3F, opc2, opc3, inval, PPC_NONE, PPC2_ISA300)
+
+#define GEN_VSX_XFORM_300_EO(name, opc2, opc3, opc4, inval) \
+GEN_HANDLER_E_2(name, 0x3F, opc2, opc3, opc4, inval, PPC_NONE, PPC2_ISA300)
+
GEN_XX2FORM(xsabsdp, 0x12, 0x15, PPC2_VSX),
GEN_XX2FORM(xsnabsdp, 0x12, 0x16, PPC2_VSX),
GEN_XX2FORM(xsnegdp, 0x12, 0x17, PPC2_VSX),
GEN_XX3FORM(xscpsgndp, 0x00, 0x16, PPC2_VSX),
+GEN_VSX_XFORM_300_EO(xsabsqp, 0x04, 0x19, 0x00, 0x00000001),
+GEN_VSX_XFORM_300_EO(xsnabsqp, 0x04, 0x19, 0x08, 0x00000001),
+GEN_VSX_XFORM_300_EO(xsnegqp, 0x04, 0x19, 0x10, 0x00000001),
+GEN_VSX_XFORM_300(xscpsgnqp, 0x04, 0x03, 0x00000001),
+GEN_VSX_XFORM_300_EO(xscvdpqp, 0x04, 0x1A, 0x16, 0x00000001),
+GEN_VSX_XFORM_300_EO(xscvqpdp, 0x04, 0x1A, 0x14, 0x0),
+GEN_VSX_XFORM_300_EO(xscvqpsdz, 0x04, 0x1A, 0x19, 0x00000001),
+GEN_VSX_XFORM_300_EO(xscvqpswz, 0x04, 0x1A, 0x09, 0x00000001),
+
+#ifdef TARGET_PPC64
+GEN_XX2FORM_EO(xsxexpdp, 0x16, 0x15, 0x00, PPC2_ISA300),
+GEN_VSX_XFORM_300_EO(xsxexpqp, 0x04, 0x19, 0x02, 0x00000001),
+GEN_XX2FORM_EO(xsxsigdp, 0x16, 0x15, 0x01, PPC2_ISA300),
+GEN_VSX_XFORM_300_EO(xsxsigqp, 0x04, 0x19, 0x12, 0x00000001),
+GEN_HANDLER_E(xsiexpdp, 0x3C, 0x16, 0x1C, 0, PPC_NONE, PPC2_ISA300),
+GEN_VSX_XFORM_300(xsiexpqp, 0x4, 0x1B, 0x00000001),
+#endif
+
+GEN_XX2FORM(xststdcdp, 0x14, 0x16, PPC2_ISA300),
+GEN_XX2FORM(xststdcsp, 0x14, 0x12, PPC2_ISA300),
+GEN_VSX_XFORM_300(xststdcqp, 0x04, 0x16, 0x00000001),
+
+GEN_XX3FORM(xviexpsp, 0x00, 0x1B, PPC2_ISA300),
+GEN_XX3FORM(xviexpdp, 0x00, 0x1F, PPC2_ISA300),
+GEN_XX2FORM_EO(xvxexpdp, 0x16, 0x1D, 0x00, PPC2_ISA300),
+GEN_XX2FORM_EO(xvxsigdp, 0x16, 0x1D, 0x01, PPC2_ISA300),
+GEN_XX2FORM_EO(xvxexpsp, 0x16, 0x1D, 0x08, PPC2_ISA300),
+GEN_XX2FORM_EO(xvxsigsp, 0x16, 0x1D, 0x09, PPC2_ISA300),
+
+/* DCMX = bit[25] << 6 | bit[29] << 5 | bit[11:15] */
+#define GEN_XX2FORM_DCMX(name, opc2, opc3, fl2) \
+GEN_XX3FORM(name, opc2, opc3 | 0, fl2), \
+GEN_XX3FORM(name, opc2, opc3 | 1, fl2)
+
+GEN_XX2FORM_DCMX(xvtstdcdp, 0x14, 0x1E, PPC2_ISA300),
+GEN_XX2FORM_DCMX(xvtstdcsp, 0x14, 0x1A, PPC2_ISA300),
+
GEN_XX2FORM(xvabsdp, 0x12, 0x1D, PPC2_VSX),
GEN_XX2FORM(xvnabsdp, 0x12, 0x1E, PPC2_VSX),
GEN_XX2FORM(xvnegdp, 0x12, 0x1F, PPC2_VSX),
@@ -98,8 +155,10 @@ GEN_XX2FORM(xvnegsp, 0x12, 0x1B, PPC2_VSX),
GEN_XX3FORM(xvcpsgnsp, 0x00, 0x1A, PPC2_VSX),
GEN_XX3FORM(xsadddp, 0x00, 0x04, PPC2_VSX),
+GEN_VSX_XFORM_300(xsaddqp, 0x04, 0x00, 0x0),
GEN_XX3FORM(xssubdp, 0x00, 0x05, PPC2_VSX),
GEN_XX3FORM(xsmuldp, 0x00, 0x06, PPC2_VSX),
+GEN_VSX_XFORM_300(xsmulqp, 0x04, 0x01, 0x0),
GEN_XX3FORM(xsdivdp, 0x00, 0x07, PPC2_VSX),
GEN_XX2FORM(xsredp, 0x14, 0x05, PPC2_VSX),
GEN_XX2FORM(xssqrtdp, 0x16, 0x04, PPC2_VSX),
@@ -118,12 +177,19 @@ GEN_XX3FORM(xscmpeqdp, 0x0C, 0x00, PPC2_ISA300),
GEN_XX3FORM(xscmpgtdp, 0x0C, 0x01, PPC2_ISA300),
GEN_XX3FORM(xscmpgedp, 0x0C, 0x02, PPC2_ISA300),
GEN_XX3FORM(xscmpnedp, 0x0C, 0x03, PPC2_ISA300),
+GEN_XX3FORM(xscmpexpdp, 0x0C, 0x07, PPC2_ISA300),
+GEN_VSX_XFORM_300(xscmpexpqp, 0x04, 0x05, 0x00600001),
GEN_XX2IFORM(xscmpodp, 0x0C, 0x05, PPC2_VSX),
GEN_XX2IFORM(xscmpudp, 0x0C, 0x04, PPC2_VSX),
+GEN_VSX_XFORM_300(xscmpoqp, 0x04, 0x04, 0x00600001),
+GEN_VSX_XFORM_300(xscmpuqp, 0x04, 0x14, 0x00600001),
GEN_XX3FORM(xsmaxdp, 0x00, 0x14, PPC2_VSX),
GEN_XX3FORM(xsmindp, 0x00, 0x15, PPC2_VSX),
+GEN_XX2FORM_EO(xscvdphp, 0x16, 0x15, 0x11, PPC2_ISA300),
GEN_XX2FORM(xscvdpsp, 0x12, 0x10, PPC2_VSX),
GEN_XX2FORM(xscvdpspn, 0x16, 0x10, PPC2_VSX207),
+GEN_XX2FORM_EO(xscvhpdp, 0x16, 0x15, 0x10, PPC2_ISA300),
+GEN_VSX_XFORM_300_EO(xscvsdqp, 0x04, 0x1A, 0x0A, 0x00000001),
GEN_XX2FORM(xscvspdp, 0x12, 0x14, PPC2_VSX),
GEN_XX2FORM(xscvspdpn, 0x16, 0x14, PPC2_VSX207),
GEN_XX2FORM(xscvdpsxds, 0x10, 0x15, PPC2_VSX),
@@ -131,6 +197,7 @@ GEN_XX2FORM(xscvdpsxws, 0x10, 0x05, PPC2_VSX),
GEN_XX2FORM(xscvdpuxds, 0x10, 0x14, PPC2_VSX),
GEN_XX2FORM(xscvdpuxws, 0x10, 0x04, PPC2_VSX),
GEN_XX2FORM(xscvsxddp, 0x10, 0x17, PPC2_VSX),
+GEN_VSX_XFORM_300_EO(xscvudqp, 0x04, 0x1A, 0x02, 0x00000001),
GEN_XX2FORM(xscvuxddp, 0x10, 0x16, PPC2_VSX),
GEN_XX2FORM(xsrdpi, 0x12, 0x04, PPC2_VSX),
GEN_XX2FORM(xsrdpic, 0x16, 0x06, PPC2_VSX),
@@ -142,6 +209,7 @@ GEN_XX3FORM(xsaddsp, 0x00, 0x00, PPC2_VSX207),
GEN_XX3FORM(xssubsp, 0x00, 0x01, PPC2_VSX207),
GEN_XX3FORM(xsmulsp, 0x00, 0x02, PPC2_VSX207),
GEN_XX3FORM(xsdivsp, 0x00, 0x03, PPC2_VSX207),
+GEN_VSX_XFORM_300(xsdivqp, 0x04, 0x11, 0x0),
GEN_XX2FORM(xsresp, 0x14, 0x01, PPC2_VSX207),
GEN_XX2FORM(xsrsp, 0x12, 0x11, PPC2_VSX207),
GEN_XX2FORM(xssqrtsp, 0x16, 0x00, PPC2_VSX207),
@@ -235,6 +303,8 @@ GEN_XX2FORM(xvrspiz, 0x12, 0x09, PPC2_VSX),
GEN_XX2FORM_EO(xxbrh, 0x16, 0x1D, 0x07, PPC2_ISA300),
GEN_XX2FORM_EO(xxbrw, 0x16, 0x1D, 0x0F, PPC2_ISA300),
GEN_XX2FORM_EO(xxbrd, 0x16, 0x1D, 0x17, PPC2_ISA300),
+GEN_XX2FORM_EO(xvcvhpsp, 0x16, 0x1D, 0x18, PPC2_ISA300),
+GEN_XX2FORM_EO(xvcvsphp, 0x16, 0x1D, 0x19, PPC2_ISA300),
GEN_XX2FORM_EO(xxbrq, 0x16, 0x1D, 0x1F, PPC2_ISA300),
#define VSX_LOGICAL(name, opc2, opc3, fl2) \
@@ -250,9 +320,13 @@ VSX_LOGICAL(xxlnand, 0x8, 0x16, PPC2_VSX207),
VSX_LOGICAL(xxlorc, 0x8, 0x15, PPC2_VSX207),
GEN_XX3FORM(xxmrghw, 0x08, 0x02, PPC2_VSX),
GEN_XX3FORM(xxmrglw, 0x08, 0x06, PPC2_VSX),
+GEN_XX3FORM(xxperm, 0x08, 0x03, PPC2_ISA300),
+GEN_XX3FORM(xxpermr, 0x08, 0x07, PPC2_ISA300),
GEN_XX2FORM(xxspltw, 0x08, 0x0A, PPC2_VSX),
GEN_XX1FORM(xxspltib, 0x08, 0x0B, PPC2_ISA300),
GEN_XX3FORM_DM(xxsldwi, 0x08, 0x00),
+GEN_XX2FORM_EXT(xxextractuw, 0x0A, 0x0A, PPC2_ISA300),
+GEN_XX2FORM_EXT(xxinsertw, 0x0A, 0x0B, PPC2_ISA300),
#define GEN_XXSEL_ROW(opc3) \
GEN_HANDLER2_E(xxsel, "xxsel", 0x3C, 0x18, opc3, 0, PPC_NONE, PPC2_VSX), \
diff --git a/target/ppc/translate_init.c b/target/ppc/translate_init.c
index 94dfcd7afc..76f79fa77b 100644
--- a/target/ppc/translate_init.c
+++ b/target/ppc/translate_init.c
@@ -5217,28 +5217,6 @@ POWERPC_FAMILY(e5500)(ObjectClass *oc, void *data)
/* Non-embedded PowerPC */
-/* POWER : same as 601, without mfmsr, mfsr */
-POWERPC_FAMILY(POWER)(ObjectClass *oc, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(oc);
- PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc);
-
- dc->desc = "POWER";
- /* pcc->insns_flags = XXX_TODO; */
- /* POWER RSC (from RAD6000) */
- pcc->msr_mask = (1ull << MSR_EE) |
- (1ull << MSR_PR) |
- (1ull << MSR_FP) |
- (1ull << MSR_ME) |
- (1ull << MSR_FE0) |
- (1ull << MSR_SE) |
- (1ull << MSR_DE) |
- (1ull << MSR_AL) |
- (1ull << MSR_EP) |
- (1ull << MSR_IR) |
- (1ull << MSR_DR);
-}
-
#define POWERPC_MSRR_601 (0x0000000000001040ULL)
static void init_proc_601 (CPUPPCState *env)
@@ -8797,6 +8775,8 @@ POWERPC_FAMILY(POWER9)(ObjectClass *oc, void *data)
dc->props = powerpc_servercpu_properties;
pcc->pvr_match = ppc_pvr_match_power9;
pcc->pcr_mask = PCR_COMPAT_2_05 | PCR_COMPAT_2_06 | PCR_COMPAT_2_07;
+ pcc->pcr_supported = PCR_COMPAT_3_00 | PCR_COMPAT_2_07 | PCR_COMPAT_2_06 |
+ PCR_COMPAT_2_05;
pcc->init_proc = init_proc_POWER9;
pcc->check_pow = check_pow_nocheck;
pcc->insns_flags = PPC_INSNS_BASE | PPC_ISEL | PPC_STRING | PPC_MFTB |
@@ -8857,6 +8837,11 @@ POWERPC_FAMILY(POWER9)(ObjectClass *oc, void *data)
#if !defined(CONFIG_USER_ONLY)
+void cpu_ppc_set_vhyp(PowerPCCPU *cpu, PPCVirtualHypervisor *vhyp)
+{
+ cpu->vhyp = vhyp;
+}
+
void cpu_ppc_set_papr(PowerPCCPU *cpu)
{
CPUPPCState *env = &cpu->env;
@@ -9947,67 +9932,6 @@ static void ppc_cpu_unrealizefn(DeviceState *dev, Error **errp)
}
}
-int ppc_get_compat_smt_threads(PowerPCCPU *cpu)
-{
- CPUState *cs = CPU(cpu);
- int ret = MIN(cs->nr_threads, kvmppc_smt_threads());
-
- switch (cpu->cpu_version) {
- case CPU_POWERPC_LOGICAL_2_05:
- ret = MIN(ret, 2);
- break;
- case CPU_POWERPC_LOGICAL_2_06:
- ret = MIN(ret, 4);
- break;
- case CPU_POWERPC_LOGICAL_2_07:
- ret = MIN(ret, 8);
- break;
- }
-
- return ret;
-}
-
-#ifdef TARGET_PPC64
-void ppc_set_compat(PowerPCCPU *cpu, uint32_t cpu_version, Error **errp)
-{
- int ret = 0;
- CPUPPCState *env = &cpu->env;
- PowerPCCPUClass *host_pcc;
-
- cpu->cpu_version = cpu_version;
-
- switch (cpu_version) {
- case CPU_POWERPC_LOGICAL_2_05:
- env->spr[SPR_PCR] = PCR_TM_DIS | PCR_VSX_DIS | PCR_COMPAT_2_07 |
- PCR_COMPAT_2_06 | PCR_COMPAT_2_05;
- break;
- case CPU_POWERPC_LOGICAL_2_06:
- case CPU_POWERPC_LOGICAL_2_06_PLUS:
- env->spr[SPR_PCR] = PCR_TM_DIS | PCR_COMPAT_2_07 | PCR_COMPAT_2_06;
- break;
- case CPU_POWERPC_LOGICAL_2_07:
- env->spr[SPR_PCR] = PCR_COMPAT_2_07;
- break;
- default:
- env->spr[SPR_PCR] = 0;
- break;
- }
-
- host_pcc = kvm_ppc_get_host_cpu_class();
- if (host_pcc) {
- env->spr[SPR_PCR] &= host_pcc->pcr_mask;
- }
-
- if (kvm_enabled()) {
- ret = kvmppc_set_compat(cpu, cpu->cpu_version);
- if (ret < 0) {
- error_setg_errno(errp, -ret,
- "Unable to set CPU compatibility mode in KVM");
- }
- }
-}
-#endif
-
static gint ppc_cpu_compare_class_pvr(gconstpointer a, gconstpointer b)
{
ObjectClass *oc = (ObjectClass *)a;
@@ -10591,9 +10515,16 @@ static const TypeInfo ppc_cpu_type_info = {
.class_init = ppc_cpu_class_init,
};
+static const TypeInfo ppc_vhyp_type_info = {
+ .name = TYPE_PPC_VIRTUAL_HYPERVISOR,
+ .parent = TYPE_INTERFACE,
+ .class_size = sizeof(PPCVirtualHypervisorClass),
+};
+
static void ppc_cpu_register_types(void)
{
type_register_static(&ppc_cpu_type_info);
+ type_register_static(&ppc_vhyp_type_info);
}
type_init(ppc_cpu_register_types)