aboutsummaryrefslogtreecommitdiff
path: root/target-ppc
diff options
context:
space:
mode:
Diffstat (limited to 'target-ppc')
-rw-r--r--target-ppc/cpu-qom.h1
-rw-r--r--target-ppc/cpu.h6
-rw-r--r--target-ppc/fpu_helper.c71
-rw-r--r--target-ppc/helper.h4
-rw-r--r--target-ppc/int_helper.c15
-rw-r--r--target-ppc/kvm.c237
-rw-r--r--target-ppc/kvm_ppc.h30
-rw-r--r--target-ppc/machine.c2
-rw-r--r--target-ppc/mem_helper.c2
-rw-r--r--target-ppc/translate.c296
-rw-r--r--target-ppc/translate_init.c117
11 files changed, 645 insertions, 136 deletions
diff --git a/target-ppc/cpu-qom.h b/target-ppc/cpu-qom.h
index c27cef7e32..eb03a00799 100644
--- a/target-ppc/cpu-qom.h
+++ b/target-ppc/cpu-qom.h
@@ -63,6 +63,7 @@ typedef struct PowerPCCPUClass {
powerpc_input_t bus_model;
uint32_t flags;
int bfd_mach;
+ uint32_t l1_dcache_size, l1_icache_size;
#if defined(TARGET_PPC64)
const struct ppc_segment_page_sizes *sps;
#endif
diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h
index 42c36e2829..7cacb56bc5 100644
--- a/target-ppc/cpu.h
+++ b/target-ppc/cpu.h
@@ -1026,7 +1026,6 @@ struct CPUPPCState {
/* Exception vectors */
target_ulong excp_vectors[POWERPC_EXCP_NB];
target_ulong excp_prefix;
- target_ulong hreset_excp_prefix;
target_ulong ivor_mask;
target_ulong ivpr_mask;
target_ulong hreset_vector;
@@ -1446,6 +1445,7 @@ static inline void cpu_clone_regs(CPUPPCState *env, target_ulong newsp)
#define SPR_PERF2 (0x302)
#define SPR_RCPU_MI_RBA2 (0x302)
#define SPR_MPC_MI_AP (0x302)
+#define SPR_MMCRA (0x302)
#define SPR_PERF3 (0x303)
#define SPR_RCPU_MI_RBA3 (0x303)
#define SPR_MPC_MI_EPN (0x303)
@@ -1870,8 +1870,10 @@ enum {
PPC2_PRCNTL = 0x0000000000000008ULL,
/* Byte-reversed, indexed, double-word load and store */
PPC2_DBRX = 0x0000000000000010ULL,
+ /* Book I 2.05 PowerPC specification */
+ PPC2_ISA205 = 0x0000000000000020ULL,
-#define PPC_TCG_INSNS2 (PPC2_BOOKE206 | PPC2_PRCNTL | PPC2_DBRX)
+#define PPC_TCG_INSNS2 (PPC2_BOOKE206 | PPC2_PRCNTL | PPC2_DBRX | PPC2_ISA205)
};
/*****************************************************************************/
diff --git a/target-ppc/fpu_helper.c b/target-ppc/fpu_helper.c
index 9e779eace6..4f6021835f 100644
--- a/target-ppc/fpu_helper.c
+++ b/target-ppc/fpu_helper.c
@@ -430,20 +430,17 @@ void helper_fpscr_setbit(CPUPPCState *env, uint32_t bit)
void helper_store_fpscr(CPUPPCState *env, uint64_t arg, uint32_t mask)
{
- /*
- * We use only the 32 LSB of the incoming fpr
- */
- uint32_t prev, new;
+ target_ulong prev, new;
int i;
prev = env->fpscr;
- new = (uint32_t)arg;
- new &= ~0x60000000;
- new |= prev & 0x60000000;
- for (i = 0; i < 8; i++) {
+ new = (target_ulong)arg;
+ new &= ~0x60000000LL;
+ new |= prev & 0x60000000LL;
+ for (i = 0; i < sizeof(target_ulong) * 2; i++) {
if (mask & (1 << i)) {
- env->fpscr &= ~(0xF << (4 * i));
- env->fpscr |= new & (0xF << (4 * i));
+ env->fpscr &= ~(0xFLL << (4 * i));
+ env->fpscr |= new & (0xFLL << (4 * i));
}
}
/* Update VX and FEX */
@@ -470,6 +467,18 @@ void store_fpscr(CPUPPCState *env, uint64_t arg, uint32_t mask)
void helper_float_check_status(CPUPPCState *env)
{
+ int status = get_float_exception_flags(&env->fp_status);
+
+ if (status & float_flag_divbyzero) {
+ float_zero_divide_excp(env);
+ } else if (status & float_flag_overflow) {
+ float_overflow_excp(env);
+ } else if (status & float_flag_underflow) {
+ float_underflow_excp(env);
+ } else if (status & float_flag_inexact) {
+ float_inexact_excp(env);
+ }
+
if (env->exception_index == POWERPC_EXCP_PROGRAM &&
(env->error_code & POWERPC_EXCP_FP)) {
/* Differred floating-point exception after target FPR update */
@@ -477,17 +486,6 @@ void helper_float_check_status(CPUPPCState *env)
helper_raise_exception_err(env, env->exception_index,
env->error_code);
}
- } else {
- int status = get_float_exception_flags(&env->fp_status);
- if (status & float_flag_divbyzero) {
- float_zero_divide_excp(env);
- } else if (status & float_flag_overflow) {
- float_overflow_excp(env);
- } else if (status & float_flag_underflow) {
- float_underflow_excp(env);
- } else if (status & float_flag_inexact) {
- float_inexact_excp(env);
- }
}
}
@@ -595,37 +593,6 @@ uint64_t helper_fdiv(CPUPPCState *env, uint64_t arg1, uint64_t arg2)
return farg1.ll;
}
-/* fabs */
-uint64_t helper_fabs(CPUPPCState *env, uint64_t arg)
-{
- CPU_DoubleU farg;
-
- farg.ll = arg;
- farg.d = float64_abs(farg.d);
- return farg.ll;
-}
-
-/* fnabs */
-uint64_t helper_fnabs(CPUPPCState *env, uint64_t arg)
-{
- CPU_DoubleU farg;
-
- farg.ll = arg;
- farg.d = float64_abs(farg.d);
- farg.d = float64_chs(farg.d);
- return farg.ll;
-}
-
-/* fneg */
-uint64_t helper_fneg(CPUPPCState *env, uint64_t arg)
-{
- CPU_DoubleU farg;
-
- farg.ll = arg;
- farg.d = float64_chs(farg.d);
- return farg.ll;
-}
-
/* fctiw - fctiw. */
uint64_t helper_fctiw(CPUPPCState *env, uint64_t arg)
{
diff --git a/target-ppc/helper.h b/target-ppc/helper.h
index d33ee66b53..56814b501f 100644
--- a/target-ppc/helper.h
+++ b/target-ppc/helper.h
@@ -36,6 +36,7 @@ DEF_HELPER_3(mulldo, i64, env, i64, i64)
DEF_HELPER_FLAGS_1(cntlzw, TCG_CALL_NO_RWG_SE, tl, tl)
DEF_HELPER_FLAGS_1(popcntb, TCG_CALL_NO_RWG_SE, tl, tl)
DEF_HELPER_FLAGS_1(popcntw, TCG_CALL_NO_RWG_SE, tl, tl)
+DEF_HELPER_FLAGS_2(cmpb, TCG_CALL_NO_RWG_SE, tl, tl, tl)
DEF_HELPER_3(sraw, tl, env, tl, tl)
#if defined(TARGET_PPC64)
DEF_HELPER_FLAGS_1(cntlzd, TCG_CALL_NO_RWG_SE, tl, tl)
@@ -80,9 +81,6 @@ DEF_HELPER_4(fmadd, i64, env, i64, i64, i64)
DEF_HELPER_4(fmsub, i64, env, i64, i64, i64)
DEF_HELPER_4(fnmadd, i64, env, i64, i64, i64)
DEF_HELPER_4(fnmsub, i64, env, i64, i64, i64)
-DEF_HELPER_2(fabs, i64, env, i64)
-DEF_HELPER_2(fnabs, i64, env, i64)
-DEF_HELPER_2(fneg, i64, env, i64)
DEF_HELPER_2(fsqrt, i64, env, i64)
DEF_HELPER_2(fre, i64, env, i64)
DEF_HELPER_2(fres, i64, env, i64)
diff --git a/target-ppc/int_helper.c b/target-ppc/int_helper.c
index 54eca9bbee..e50bdd20ec 100644
--- a/target-ppc/int_helper.c
+++ b/target-ppc/int_helper.c
@@ -53,6 +53,21 @@ target_ulong helper_cntlzd(target_ulong t)
}
#endif
+target_ulong helper_cmpb(target_ulong rs, target_ulong rb)
+{
+ target_ulong mask = 0xff;
+ target_ulong ra = 0;
+ int i;
+
+ for (i = 0; i < sizeof(target_ulong); i++) {
+ if ((rs & mask) == (rb & mask)) {
+ ra |= mask;
+ }
+ mask <<= 8;
+ }
+ return ra;
+}
+
/* shift right arithmetic helper */
target_ulong helper_sraw(CPUPPCState *env, target_ulong value,
target_ulong shift)
diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c
index 5e9dddbb54..725071e6a7 100644
--- a/target-ppc/kvm.c
+++ b/target-ppc/kvm.c
@@ -37,6 +37,7 @@
#include "hw/sysbus.h"
#include "hw/ppc/spapr.h"
#include "hw/ppc/spapr_vio.h"
+#include "sysemu/watchdog.h"
//#define DEBUG_KVM
@@ -63,6 +64,9 @@ static int cap_ppc_rma;
static int cap_spapr_tce;
static int cap_hior;
static int cap_one_reg;
+static int cap_epr;
+static int cap_ppc_watchdog;
+static int cap_papr;
/* XXX We have a race condition where we actually have a level triggered
* interrupt, but the infrastructure can't expose that yet, so the guest
@@ -95,6 +99,10 @@ int kvm_arch_init(KVMState *s)
cap_spapr_tce = kvm_check_extension(s, KVM_CAP_SPAPR_TCE);
cap_one_reg = kvm_check_extension(s, KVM_CAP_ONE_REG);
cap_hior = kvm_check_extension(s, KVM_CAP_PPC_HIOR);
+ cap_epr = kvm_check_extension(s, KVM_CAP_PPC_EPR);
+ cap_ppc_watchdog = kvm_check_extension(s, KVM_CAP_PPC_BOOKE_WATCHDOG);
+ /* Note: we don't set cap_papr here, because this capability is
+ * only activated after this by kvmppc_set_papr() */
if (!cap_interrupt_level) {
fprintf(stderr, "KVM: Couldn't find level irq capability. Expect the "
@@ -652,6 +660,103 @@ static int kvm_get_fp(CPUState *cs)
return 0;
}
+#if defined(TARGET_PPC64)
+static int kvm_get_vpa(CPUState *cs)
+{
+ PowerPCCPU *cpu = POWERPC_CPU(cs);
+ CPUPPCState *env = &cpu->env;
+ struct kvm_one_reg reg;
+ int ret;
+
+ reg.id = KVM_REG_PPC_VPA_ADDR;
+ reg.addr = (uintptr_t)&env->vpa_addr;
+ ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &reg);
+ if (ret < 0) {
+ dprintf("Unable to get VPA address from KVM: %s\n", strerror(errno));
+ return ret;
+ }
+
+ assert((uintptr_t)&env->slb_shadow_size
+ == ((uintptr_t)&env->slb_shadow_addr + 8));
+ reg.id = KVM_REG_PPC_VPA_SLB;
+ reg.addr = (uintptr_t)&env->slb_shadow_addr;
+ ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &reg);
+ if (ret < 0) {
+ dprintf("Unable to get SLB shadow state from KVM: %s\n",
+ strerror(errno));
+ return ret;
+ }
+
+ assert((uintptr_t)&env->dtl_size == ((uintptr_t)&env->dtl_addr + 8));
+ reg.id = KVM_REG_PPC_VPA_DTL;
+ reg.addr = (uintptr_t)&env->dtl_addr;
+ ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &reg);
+ if (ret < 0) {
+ dprintf("Unable to get dispatch trace log state from KVM: %s\n",
+ strerror(errno));
+ return ret;
+ }
+
+ return 0;
+}
+
+static int kvm_put_vpa(CPUState *cs)
+{
+ PowerPCCPU *cpu = POWERPC_CPU(cs);
+ CPUPPCState *env = &cpu->env;
+ struct kvm_one_reg reg;
+ int ret;
+
+ /* SLB shadow or DTL can't be registered unless a master VPA is
+ * registered. That means when restoring state, if a VPA *is*
+ * registered, we need to set that up first. If not, we need to
+ * deregister the others before deregistering the master VPA */
+ assert(env->vpa_addr || !(env->slb_shadow_addr || env->dtl_addr));
+
+ if (env->vpa_addr) {
+ reg.id = KVM_REG_PPC_VPA_ADDR;
+ reg.addr = (uintptr_t)&env->vpa_addr;
+ ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &reg);
+ if (ret < 0) {
+ dprintf("Unable to set VPA address to KVM: %s\n", strerror(errno));
+ return ret;
+ }
+ }
+
+ assert((uintptr_t)&env->slb_shadow_size
+ == ((uintptr_t)&env->slb_shadow_addr + 8));
+ reg.id = KVM_REG_PPC_VPA_SLB;
+ reg.addr = (uintptr_t)&env->slb_shadow_addr;
+ ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &reg);
+ if (ret < 0) {
+ dprintf("Unable to set SLB shadow state to KVM: %s\n", strerror(errno));
+ return ret;
+ }
+
+ assert((uintptr_t)&env->dtl_size == ((uintptr_t)&env->dtl_addr + 8));
+ reg.id = KVM_REG_PPC_VPA_DTL;
+ reg.addr = (uintptr_t)&env->dtl_addr;
+ ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &reg);
+ if (ret < 0) {
+ dprintf("Unable to set dispatch trace log state to KVM: %s\n",
+ strerror(errno));
+ return ret;
+ }
+
+ if (!env->vpa_addr) {
+ reg.id = KVM_REG_PPC_VPA_ADDR;
+ reg.addr = (uintptr_t)&env->vpa_addr;
+ ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &reg);
+ if (ret < 0) {
+ dprintf("Unable to set VPA address to KVM: %s\n", strerror(errno));
+ return ret;
+ }
+ }
+
+ return 0;
+}
+#endif /* TARGET_PPC64 */
+
int kvm_arch_put_registers(CPUState *cs, int level)
{
PowerPCCPU *cpu = POWERPC_CPU(cs);
@@ -752,6 +857,14 @@ int kvm_arch_put_registers(CPUState *cs, int level)
kvm_put_one_spr(cs, id, i);
}
}
+
+#ifdef TARGET_PPC64
+ if (cap_papr) {
+ if (kvm_put_vpa(cs) < 0) {
+ dprintf("Warning: Unable to set VPA information to KVM\n");
+ }
+ }
+#endif /* TARGET_PPC64 */
}
return ret;
@@ -953,6 +1066,14 @@ int kvm_arch_get_registers(CPUState *cs)
kvm_get_one_spr(cs, id, i);
}
}
+
+#ifdef TARGET_PPC64
+ if (cap_papr) {
+ if (kvm_get_vpa(cs) < 0) {
+ dprintf("Warning: Unable to get VPA information from KVM\n");
+ }
+ }
+#endif
}
return 0;
@@ -1092,6 +1213,12 @@ int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run)
run->epr.epr = ldl_phys(env->mpic_iack);
ret = 0;
break;
+ case KVM_EXIT_WATCHDOG:
+ dprintf("handle watchdog expiry\n");
+ watchdog_perform_action();
+ ret = 0;
+ break;
+
default:
fprintf(stderr, "KVM: unknown exit reason %d\n", run->exit_reason);
ret = -1;
@@ -1101,6 +1228,71 @@ int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run)
return ret;
}
+int kvmppc_or_tsr_bits(PowerPCCPU *cpu, uint32_t tsr_bits)
+{
+ CPUState *cs = CPU(cpu);
+ uint32_t bits = tsr_bits;
+ struct kvm_one_reg reg = {
+ .id = KVM_REG_PPC_OR_TSR,
+ .addr = (uintptr_t) &bits,
+ };
+
+ return kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &reg);
+}
+
+int kvmppc_clear_tsr_bits(PowerPCCPU *cpu, uint32_t tsr_bits)
+{
+
+ CPUState *cs = CPU(cpu);
+ uint32_t bits = tsr_bits;
+ struct kvm_one_reg reg = {
+ .id = KVM_REG_PPC_CLEAR_TSR,
+ .addr = (uintptr_t) &bits,
+ };
+
+ return kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &reg);
+}
+
+int kvmppc_set_tcr(PowerPCCPU *cpu)
+{
+ CPUState *cs = CPU(cpu);
+ CPUPPCState *env = &cpu->env;
+ uint32_t tcr = env->spr[SPR_BOOKE_TCR];
+
+ struct kvm_one_reg reg = {
+ .id = KVM_REG_PPC_TCR,
+ .addr = (uintptr_t) &tcr,
+ };
+
+ return kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &reg);
+}
+
+int kvmppc_booke_watchdog_enable(PowerPCCPU *cpu)
+{
+ CPUState *cs = CPU(cpu);
+ struct kvm_enable_cap encap = {};
+ int ret;
+
+ if (!kvm_enabled()) {
+ return -1;
+ }
+
+ if (!cap_ppc_watchdog) {
+ printf("warning: KVM does not support watchdog");
+ return -1;
+ }
+
+ encap.cap = KVM_CAP_PPC_BOOKE_WATCHDOG;
+ ret = kvm_vcpu_ioctl(cs, KVM_ENABLE_CAP, &encap);
+ if (ret < 0) {
+ fprintf(stderr, "%s: couldn't enable KVM_CAP_PPC_BOOKE_WATCHDOG: %s\n",
+ __func__, strerror(-ret));
+ return ret;
+ }
+
+ return ret;
+}
+
static int read_cpuinfo(const char *field, char *value, int len)
{
FILE *f;
@@ -1301,6 +1493,10 @@ void kvmppc_set_papr(PowerPCCPU *cpu)
if (ret) {
cpu_abort(env, "This KVM version does not support PAPR\n");
}
+
+ /* Update the capability flag so we sync the right information
+ * with kvm */
+ cap_papr = 1;
}
void kvmppc_set_mpic_proxy(PowerPCCPU *cpu, int mpic_proxy)
@@ -1370,11 +1566,35 @@ off_t kvmppc_alloc_rma(const char *name, MemoryRegion *sysmem)
uint64_t kvmppc_rma_size(uint64_t current_size, unsigned int hash_shift)
{
+ struct kvm_ppc_smmu_info info;
+ long rampagesize, best_page_shift;
+ int i;
+
if (cap_ppc_rma >= 2) {
return current_size;
}
+
+ /* Find the largest hardware supported page size that's less than
+ * or equal to the (logical) backing page size of guest RAM */
+ kvm_get_smmu_info(ppc_env_get_cpu(first_cpu), &info);
+ rampagesize = getrampagesize();
+ best_page_shift = 0;
+
+ for (i = 0; i < KVM_PPC_PAGE_SIZES_MAX_SZ; i++) {
+ struct kvm_ppc_one_seg_page_size *sps = &info.sps[i];
+
+ if (!sps->page_shift) {
+ continue;
+ }
+
+ if ((sps->page_shift > best_page_shift)
+ && ((1UL << sps->page_shift) <= rampagesize)) {
+ best_page_shift = sps->page_shift;
+ }
+ }
+
return MIN(current_size,
- getrampagesize() << (hash_shift - 7));
+ 1ULL << (best_page_shift + hash_shift - 7));
}
#endif
@@ -1503,6 +1723,8 @@ static void kvmppc_host_cpu_class_init(ObjectClass *oc, void *data)
PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc);
uint32_t vmx = kvmppc_get_vmx();
uint32_t dfp = kvmppc_get_dfp();
+ uint32_t dcache_size = kvmppc_read_int_cpu_dt("d-cache-size");
+ uint32_t icache_size = kvmppc_read_int_cpu_dt("i-cache-size");
/* Now fix up the class with information we can query from the host */
@@ -1515,6 +1737,14 @@ static void kvmppc_host_cpu_class_init(ObjectClass *oc, void *data)
/* Only override when we know what the host supports */
alter_insns(&pcc->insns_flags2, PPC2_DFP, dfp);
}
+
+ if (dcache_size != -1) {
+ pcc->l1_dcache_size = dcache_size;
+ }
+
+ if (icache_size != -1) {
+ pcc->l1_icache_size = icache_size;
+ }
}
int kvmppc_fixup_cpu(PowerPCCPU *cpu)
@@ -1530,6 +1760,11 @@ int kvmppc_fixup_cpu(PowerPCCPU *cpu)
return 0;
}
+bool kvmppc_has_cap_epr(void)
+{
+ return cap_epr;
+}
+
static int kvm_ppc_register_host_cpu_type(void)
{
TypeInfo type_info = {
diff --git a/target-ppc/kvm_ppc.h b/target-ppc/kvm_ppc.h
index 6bcc5cc36c..771cfbe82b 100644
--- a/target-ppc/kvm_ppc.h
+++ b/target-ppc/kvm_ppc.h
@@ -25,6 +25,10 @@ int kvmppc_set_interrupt(PowerPCCPU *cpu, int irq, int level);
void kvmppc_set_papr(PowerPCCPU *cpu);
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);
+int kvmppc_or_tsr_bits(PowerPCCPU *cpu, uint32_t tsr_bits);
+int kvmppc_set_tcr(PowerPCCPU *cpu);
+int kvmppc_booke_watchdog_enable(PowerPCCPU *cpu);
#ifndef CONFIG_USER_ONLY
off_t kvmppc_alloc_rma(const char *name, MemoryRegion *sysmem);
void *kvmppc_create_spapr_tce(uint32_t liobn, uint32_t window_size, int *pfd);
@@ -33,6 +37,7 @@ int kvmppc_reset_htab(int shift_hint);
uint64_t kvmppc_rma_size(uint64_t current_size, unsigned int hash_shift);
#endif /* !CONFIG_USER_ONLY */
int kvmppc_fixup_cpu(PowerPCCPU *cpu);
+bool kvmppc_has_cap_epr(void);
#else
@@ -89,6 +94,26 @@ static inline int kvmppc_smt_threads(void)
return 1;
}
+static inline int kvmppc_or_tsr_bits(PowerPCCPU *cpu, uint32_t tsr_bits)
+{
+ return 0;
+}
+
+static inline int kvmppc_clear_tsr_bits(PowerPCCPU *cpu, uint32_t tsr_bits)
+{
+ return 0;
+}
+
+static inline int kvmppc_set_tcr(PowerPCCPU *cpu)
+{
+ return 0;
+}
+
+static inline int kvmppc_booke_watchdog_enable(PowerPCCPU *cpu)
+{
+ return -1;
+}
+
#ifndef CONFIG_USER_ONLY
static inline off_t kvmppc_alloc_rma(const char *name, MemoryRegion *sysmem)
{
@@ -129,6 +154,11 @@ static inline int kvmppc_fixup_cpu(PowerPCCPU *cpu)
{
return -1;
}
+
+static inline bool kvmppc_has_cap_epr(void)
+{
+ return false;
+}
#endif
#ifndef CONFIG_KVM
diff --git a/target-ppc/machine.c b/target-ppc/machine.c
index 235b0d5f49..2d10adb60d 100644
--- a/target-ppc/machine.c
+++ b/target-ppc/machine.c
@@ -78,7 +78,6 @@ void cpu_save(QEMUFile *f, void *opaque)
for (i = 0; i < POWERPC_EXCP_NB; i++)
qemu_put_betls(f, &env->excp_vectors[i]);
qemu_put_betls(f, &env->excp_prefix);
- qemu_put_betls(f, &env->hreset_excp_prefix);
qemu_put_betls(f, &env->ivor_mask);
qemu_put_betls(f, &env->ivpr_mask);
qemu_put_betls(f, &env->hreset_vector);
@@ -167,7 +166,6 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id)
for (i = 0; i < POWERPC_EXCP_NB; i++)
qemu_get_betls(f, &env->excp_vectors[i]);
qemu_get_betls(f, &env->excp_prefix);
- qemu_get_betls(f, &env->hreset_excp_prefix);
qemu_get_betls(f, &env->ivor_mask);
qemu_get_betls(f, &env->ivpr_mask);
qemu_get_betls(f, &env->hreset_vector);
diff --git a/target-ppc/mem_helper.c b/target-ppc/mem_helper.c
index 9783e52b0c..d8e63ca7d2 100644
--- a/target-ppc/mem_helper.c
+++ b/target-ppc/mem_helper.c
@@ -140,7 +140,7 @@ void helper_dcbz(CPUPPCState *env, target_ulong addr, uint32_t is_dcbzl)
{
int dcbz_size = env->dcache_line_size;
-#if !defined(CONFIG_USER_ONLY) && defined(TARGET_PPC64)
+#if defined(TARGET_PPC64)
if (!is_dcbzl &&
(env->excp_model == POWERPC_EXCP_970) &&
((env->spr[SPR_970_HID5] >> 7) & 0x3) == 1) {
diff --git a/target-ppc/translate.c b/target-ppc/translate.c
index 5e741d1ab4..6182bd7471 100644
--- a/target-ppc/translate.c
+++ b/target-ppc/translate.c
@@ -202,6 +202,8 @@ typedef struct DisasContext {
int spe_enabled;
ppc_spr_t *spr_cb; /* Needed to check rights for mfspr/mtspr */
int singlestep_enabled;
+ uint64_t insns_flags;
+ uint64_t insns_flags2;
} DisasContext;
/* True when active word size < size of target_long. */
@@ -423,9 +425,14 @@ EXTRACT_HELPER(ME, 1, 5);
EXTRACT_HELPER(TO, 21, 5);
EXTRACT_HELPER(CRM, 12, 8);
-EXTRACT_HELPER(FM, 17, 8);
EXTRACT_HELPER(SR, 16, 4);
+
+/* mtfsf/mtfsfi */
+EXTRACT_HELPER(FPBF, 19, 3);
EXTRACT_HELPER(FPIMM, 12, 4);
+EXTRACT_HELPER(FPL, 21, 1);
+EXTRACT_HELPER(FPFLM, 17, 8);
+EXTRACT_HELPER(FPW, 16, 1);
/*** Jump target decoding ***/
/* Displacement */
@@ -739,6 +746,13 @@ static void gen_isel(DisasContext *ctx)
tcg_temp_free_i32(t0);
}
+/* cmpb: PowerPC 2.05 specification */
+static void gen_cmpb(DisasContext *ctx)
+{
+ gen_helper_cmpb(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)],
+ cpu_gpr[rB(ctx->opcode)]);
+}
+
/*** Integer arithmetic ***/
static inline void gen_op_arith_compute_ov(DisasContext *ctx, TCGv arg0,
@@ -746,7 +760,7 @@ static inline void gen_op_arith_compute_ov(DisasContext *ctx, TCGv arg0,
{
TCGv t0 = tcg_temp_new();
- tcg_gen_xor_tl(cpu_ov, arg0, arg1);
+ tcg_gen_xor_tl(cpu_ov, arg0, arg2);
tcg_gen_xor_tl(t0, arg1, arg2);
if (sub) {
tcg_gen_and_tl(cpu_ov, cpu_ov, t0);
@@ -768,22 +782,25 @@ static inline void gen_op_arith_add(DisasContext *ctx, TCGv ret, TCGv arg1,
{
TCGv t0 = ret;
- if (((compute_ca && add_ca) || compute_ov)
- && (TCGV_EQUAL(ret, arg1) || TCGV_EQUAL(ret, arg2))) {
+ if (compute_ca || compute_ov) {
t0 = tcg_temp_new();
}
if (compute_ca) {
if (NARROW_MODE(ctx)) {
+ /* Caution: a non-obvious corner case of the spec is that we
+ must produce the *entire* 64-bit addition, but produce the
+ carry into bit 32. */
TCGv t1 = tcg_temp_new();
- tcg_gen_ext32u_tl(t1, arg2);
- tcg_gen_ext32u_tl(t0, arg1);
- tcg_gen_add_tl(t0, t0, t1);
- tcg_temp_free(t1);
+ tcg_gen_xor_tl(t1, arg1, arg2); /* add without carry */
+ tcg_gen_add_tl(t0, arg1, arg2);
if (add_ca) {
tcg_gen_add_tl(t0, t0, cpu_ca);
}
- tcg_gen_shri_tl(cpu_ca, t0, 32);
+ tcg_gen_xor_tl(cpu_ca, t0, t1); /* bits changed w/ carry */
+ tcg_temp_free(t1);
+ tcg_gen_shri_tl(cpu_ca, cpu_ca, 32); /* extract bit 32 */
+ tcg_gen_andi_tl(cpu_ca, cpu_ca, 1);
} else {
TCGv zero = tcg_const_tl(0);
if (add_ca) {
@@ -1122,24 +1139,30 @@ static inline void gen_op_arith_subf(DisasContext *ctx, TCGv ret, TCGv arg1,
{
TCGv t0 = ret;
- if (compute_ov && (TCGV_EQUAL(ret, arg1) || TCGV_EQUAL(ret, arg2))) {
+ if (compute_ca || compute_ov) {
t0 = tcg_temp_new();
}
if (compute_ca) {
/* dest = ~arg1 + arg2 [+ ca]. */
if (NARROW_MODE(ctx)) {
+ /* Caution: a non-obvious corner case of the spec is that we
+ must produce the *entire* 64-bit addition, but produce the
+ carry into bit 32. */
TCGv inv1 = tcg_temp_new();
+ TCGv t1 = tcg_temp_new();
tcg_gen_not_tl(inv1, arg1);
- tcg_gen_ext32u_tl(t0, arg2);
- tcg_gen_ext32u_tl(inv1, inv1);
if (add_ca) {
- tcg_gen_add_tl(t0, t0, cpu_ca);
+ tcg_gen_add_tl(t0, arg2, cpu_ca);
} else {
- tcg_gen_addi_tl(t0, t0, 1);
+ tcg_gen_addi_tl(t0, arg2, 1);
}
+ tcg_gen_xor_tl(t1, arg2, inv1); /* add without carry */
tcg_gen_add_tl(t0, t0, inv1);
- tcg_gen_shri_tl(cpu_ca, t0, 32);
+ tcg_gen_xor_tl(cpu_ca, t0, t1); /* bits changes w/ carry */
+ tcg_temp_free(t1);
+ tcg_gen_shri_tl(cpu_ca, cpu_ca, 32); /* extract bit 32 */
+ tcg_gen_andi_tl(cpu_ca, cpu_ca, 1);
} else if (add_ca) {
TCGv zero, inv1 = tcg_temp_new();
tcg_gen_not_tl(inv1, arg1);
@@ -1451,6 +1474,38 @@ static void gen_popcntd(DisasContext *ctx)
}
#endif
+/* prtyw: PowerPC 2.05 specification */
+static void gen_prtyw(DisasContext *ctx)
+{
+ TCGv ra = cpu_gpr[rA(ctx->opcode)];
+ TCGv rs = cpu_gpr[rS(ctx->opcode)];
+ TCGv t0 = tcg_temp_new();
+ tcg_gen_shri_tl(t0, rs, 16);
+ tcg_gen_xor_tl(ra, rs, t0);
+ tcg_gen_shri_tl(t0, ra, 8);
+ tcg_gen_xor_tl(ra, ra, t0);
+ tcg_gen_andi_tl(ra, ra, (target_ulong)0x100000001ULL);
+ tcg_temp_free(t0);
+}
+
+#if defined(TARGET_PPC64)
+/* prtyd: PowerPC 2.05 specification */
+static void gen_prtyd(DisasContext *ctx)
+{
+ TCGv ra = cpu_gpr[rA(ctx->opcode)];
+ TCGv rs = cpu_gpr[rS(ctx->opcode)];
+ TCGv t0 = tcg_temp_new();
+ tcg_gen_shri_tl(t0, rs, 32);
+ tcg_gen_xor_tl(ra, rs, t0);
+ tcg_gen_shri_tl(t0, ra, 16);
+ tcg_gen_xor_tl(ra, ra, t0);
+ tcg_gen_shri_tl(t0, ra, 8);
+ tcg_gen_xor_tl(ra, ra, t0);
+ tcg_gen_andi_tl(ra, ra, 1);
+ tcg_temp_free(t0);
+}
+#endif
+
#if defined(TARGET_PPC64)
/* extsw & extsw. */
GEN_LOGICAL1(extsw, tcg_gen_ext32s_tl, 0x1E, PPC_64B);
@@ -2161,7 +2216,16 @@ static void gen_fcmpu(DisasContext *ctx)
/*** Floating-point move ***/
/* fabs */
/* XXX: beware that fabs never checks for NaNs nor update FPSCR */
-GEN_FLOAT_B(abs, 0x08, 0x08, 0, PPC_FLOAT);
+static void gen_fabs(DisasContext *ctx)
+{
+ if (unlikely(!ctx->fpu_enabled)) {
+ gen_exception(ctx, POWERPC_EXCP_FPU);
+ return;
+ }
+ tcg_gen_andi_i64(cpu_fpr[rD(ctx->opcode)], cpu_fpr[rB(ctx->opcode)],
+ ~(1ULL << 63));
+ gen_compute_fprf(cpu_fpr[rD(ctx->opcode)], 0, Rc(ctx->opcode) != 0);
+}
/* fmr - fmr. */
/* XXX: beware that fmr never checks for NaNs nor update FPSCR */
@@ -2177,10 +2241,42 @@ static void gen_fmr(DisasContext *ctx)
/* fnabs */
/* XXX: beware that fnabs never checks for NaNs nor update FPSCR */
-GEN_FLOAT_B(nabs, 0x08, 0x04, 0, PPC_FLOAT);
+static void gen_fnabs(DisasContext *ctx)
+{
+ if (unlikely(!ctx->fpu_enabled)) {
+ gen_exception(ctx, POWERPC_EXCP_FPU);
+ return;
+ }
+ tcg_gen_ori_i64(cpu_fpr[rD(ctx->opcode)], cpu_fpr[rB(ctx->opcode)],
+ 1ULL << 63);
+ gen_compute_fprf(cpu_fpr[rD(ctx->opcode)], 0, Rc(ctx->opcode) != 0);
+}
+
/* fneg */
/* XXX: beware that fneg never checks for NaNs nor update FPSCR */
-GEN_FLOAT_B(neg, 0x08, 0x01, 0, PPC_FLOAT);
+static void gen_fneg(DisasContext *ctx)
+{
+ if (unlikely(!ctx->fpu_enabled)) {
+ gen_exception(ctx, POWERPC_EXCP_FPU);
+ return;
+ }
+ tcg_gen_xori_i64(cpu_fpr[rD(ctx->opcode)], cpu_fpr[rB(ctx->opcode)],
+ 1ULL << 63);
+ gen_compute_fprf(cpu_fpr[rD(ctx->opcode)], 0, Rc(ctx->opcode) != 0);
+}
+
+/* fcpsgn: PowerPC 2.05 specification */
+/* XXX: beware that fcpsgn never checks for NaNs nor update FPSCR */
+static void gen_fcpsgn(DisasContext *ctx)
+{
+ if (unlikely(!ctx->fpu_enabled)) {
+ gen_exception(ctx, POWERPC_EXCP_FPU);
+ return;
+ }
+ tcg_gen_deposit_i64(cpu_fpr[rD(ctx->opcode)], cpu_fpr[rA(ctx->opcode)],
+ cpu_fpr[rB(ctx->opcode)], 0, 63);
+ gen_compute_fprf(cpu_fpr[rD(ctx->opcode)], 0, Rc(ctx->opcode) != 0);
+}
/*** Floating-Point status & ctrl register ***/
@@ -2271,19 +2367,27 @@ static void gen_mtfsb1(DisasContext *ctx)
static void gen_mtfsf(DisasContext *ctx)
{
TCGv_i32 t0;
- int L = ctx->opcode & 0x02000000;
+ int flm, l, w;
if (unlikely(!ctx->fpu_enabled)) {
gen_exception(ctx, POWERPC_EXCP_FPU);
return;
}
+ flm = FPFLM(ctx->opcode);
+ l = FPL(ctx->opcode);
+ w = FPW(ctx->opcode);
+ if (unlikely(w & !(ctx->insns_flags2 & PPC2_ISA205))) {
+ gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);
+ return;
+ }
/* NIP cannot be restored if the memory exception comes from an helper */
gen_update_nip(ctx, ctx->nip - 4);
gen_reset_fpstatus();
- if (L)
- t0 = tcg_const_i32(0xff);
- else
- t0 = tcg_const_i32(FM(ctx->opcode));
+ if (l) {
+ t0 = tcg_const_i32((ctx->insns_flags2 & PPC2_ISA205) ? 0xffff : 0xff);
+ } else {
+ t0 = tcg_const_i32(flm << (w * 8));
+ }
gen_helper_store_fpscr(cpu_env, cpu_fpr[rB(ctx->opcode)], t0);
tcg_temp_free_i32(t0);
if (unlikely(Rc(ctx->opcode) != 0)) {
@@ -2297,7 +2401,7 @@ static void gen_mtfsf(DisasContext *ctx)
/* mtfsfi */
static void gen_mtfsfi(DisasContext *ctx)
{
- int bf, sh;
+ int bf, sh, w;
TCGv_i64 t0;
TCGv_i32 t1;
@@ -2305,12 +2409,17 @@ static void gen_mtfsfi(DisasContext *ctx)
gen_exception(ctx, POWERPC_EXCP_FPU);
return;
}
- bf = crbD(ctx->opcode) >> 2;
- sh = 7 - bf;
+ w = FPW(ctx->opcode);
+ bf = FPBF(ctx->opcode);
+ if (unlikely(w & !(ctx->insns_flags2 & PPC2_ISA205))) {
+ gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);
+ return;
+ }
+ sh = (8 * w) + 7 - bf;
/* NIP cannot be restored if the memory exception comes from an helper */
gen_update_nip(ctx, ctx->nip - 4);
gen_reset_fpstatus();
- t0 = tcg_const_i64(FPIMM(ctx->opcode) << (4 * sh));
+ t0 = tcg_const_i64(((uint64_t)FPIMM(ctx->opcode)) << (4 * sh));
t1 = tcg_const_i32(1 << sh);
gen_helper_store_fpscr(cpu_env, t0, t1);
tcg_temp_free_i64(t0);
@@ -3211,6 +3320,72 @@ GEN_LDFS(lfd, ld64, 0x12, PPC_FLOAT);
/* lfs lfsu lfsux lfsx */
GEN_LDFS(lfs, ld32fs, 0x10, PPC_FLOAT);
+/* lfdp */
+static void gen_lfdp(DisasContext *ctx)
+{
+ TCGv EA;
+ if (unlikely(!ctx->fpu_enabled)) {
+ gen_exception(ctx, POWERPC_EXCP_FPU);
+ return;
+ }
+ gen_set_access_type(ctx, ACCESS_FLOAT);
+ EA = tcg_temp_new();
+ gen_addr_imm_index(ctx, EA, 0); \
+ if (unlikely(ctx->le_mode)) {
+ gen_qemu_ld64(ctx, cpu_fpr[rD(ctx->opcode) + 1], EA);
+ tcg_gen_addi_tl(EA, EA, 8);
+ gen_qemu_ld64(ctx, cpu_fpr[rD(ctx->opcode)], EA);
+ } else {
+ gen_qemu_ld64(ctx, cpu_fpr[rD(ctx->opcode)], EA);
+ tcg_gen_addi_tl(EA, EA, 8);
+ gen_qemu_ld64(ctx, cpu_fpr[rD(ctx->opcode) + 1], EA);
+ }
+ tcg_temp_free(EA);
+}
+
+/* lfdpx */
+static void gen_lfdpx(DisasContext *ctx)
+{
+ TCGv EA;
+ if (unlikely(!ctx->fpu_enabled)) {
+ gen_exception(ctx, POWERPC_EXCP_FPU);
+ return;
+ }
+ gen_set_access_type(ctx, ACCESS_FLOAT);
+ EA = tcg_temp_new();
+ gen_addr_reg_index(ctx, EA);
+ if (unlikely(ctx->le_mode)) {
+ gen_qemu_ld64(ctx, cpu_fpr[rD(ctx->opcode) + 1], EA);
+ tcg_gen_addi_tl(EA, EA, 8);
+ gen_qemu_ld64(ctx, cpu_fpr[rD(ctx->opcode)], EA);
+ } else {
+ gen_qemu_ld64(ctx, cpu_fpr[rD(ctx->opcode)], EA);
+ tcg_gen_addi_tl(EA, EA, 8);
+ gen_qemu_ld64(ctx, cpu_fpr[rD(ctx->opcode) + 1], EA);
+ }
+ tcg_temp_free(EA);
+}
+
+/* lfiwax */
+static void gen_lfiwax(DisasContext *ctx)
+{
+ TCGv EA;
+ TCGv t0;
+ if (unlikely(!ctx->fpu_enabled)) {
+ gen_exception(ctx, POWERPC_EXCP_FPU);
+ return;
+ }
+ gen_set_access_type(ctx, ACCESS_FLOAT);
+ EA = tcg_temp_new();
+ t0 = tcg_temp_new();
+ gen_addr_reg_index(ctx, EA);
+ gen_qemu_ld32u(ctx, t0, EA);
+ tcg_gen_ext_tl_i64(cpu_fpr[rD(ctx->opcode)], t0);
+ tcg_gen_ext32s_i64(cpu_fpr[rD(ctx->opcode)], cpu_fpr[rD(ctx->opcode)]);
+ tcg_temp_free(EA);
+ tcg_temp_free(t0);
+}
+
/*** Floating-point store ***/
#define GEN_STF(name, stop, opc, type) \
static void glue(gen_, name)(DisasContext *ctx) \
@@ -3304,6 +3479,52 @@ GEN_STFS(stfd, st64, 0x16, PPC_FLOAT);
/* stfs stfsu stfsux stfsx */
GEN_STFS(stfs, st32fs, 0x14, PPC_FLOAT);
+/* stfdp */
+static void gen_stfdp(DisasContext *ctx)
+{
+ TCGv EA;
+ if (unlikely(!ctx->fpu_enabled)) {
+ gen_exception(ctx, POWERPC_EXCP_FPU);
+ return;
+ }
+ gen_set_access_type(ctx, ACCESS_FLOAT);
+ EA = tcg_temp_new();
+ gen_addr_imm_index(ctx, EA, 0); \
+ if (unlikely(ctx->le_mode)) {
+ gen_qemu_st64(ctx, cpu_fpr[rD(ctx->opcode) + 1], EA);
+ tcg_gen_addi_tl(EA, EA, 8);
+ gen_qemu_st64(ctx, cpu_fpr[rD(ctx->opcode)], EA);
+ } else {
+ gen_qemu_st64(ctx, cpu_fpr[rD(ctx->opcode)], EA);
+ tcg_gen_addi_tl(EA, EA, 8);
+ gen_qemu_st64(ctx, cpu_fpr[rD(ctx->opcode) + 1], EA);
+ }
+ tcg_temp_free(EA);
+}
+
+/* stfdpx */
+static void gen_stfdpx(DisasContext *ctx)
+{
+ TCGv EA;
+ if (unlikely(!ctx->fpu_enabled)) {
+ gen_exception(ctx, POWERPC_EXCP_FPU);
+ return;
+ }
+ gen_set_access_type(ctx, ACCESS_FLOAT);
+ EA = tcg_temp_new();
+ gen_addr_reg_index(ctx, EA);
+ if (unlikely(ctx->le_mode)) {
+ gen_qemu_st64(ctx, cpu_fpr[rD(ctx->opcode) + 1], EA);
+ tcg_gen_addi_tl(EA, EA, 8);
+ gen_qemu_st64(ctx, cpu_fpr[rD(ctx->opcode)], EA);
+ } else {
+ gen_qemu_st64(ctx, cpu_fpr[rD(ctx->opcode)], EA);
+ tcg_gen_addi_tl(EA, EA, 8);
+ gen_qemu_st64(ctx, cpu_fpr[rD(ctx->opcode) + 1], EA);
+ }
+ tcg_temp_free(EA);
+}
+
/* Optional: */
static inline void gen_qemu_st32fiw(DisasContext *ctx, TCGv_i64 arg1, TCGv arg2)
{
@@ -8426,6 +8647,7 @@ GEN_HANDLER(cmp, 0x1F, 0x00, 0x00, 0x00400000, PPC_INTEGER),
GEN_HANDLER(cmpi, 0x0B, 0xFF, 0xFF, 0x00400000, PPC_INTEGER),
GEN_HANDLER(cmpl, 0x1F, 0x00, 0x01, 0x00400000, PPC_INTEGER),
GEN_HANDLER(cmpli, 0x0A, 0xFF, 0xFF, 0x00400000, PPC_INTEGER),
+GEN_HANDLER_E(cmpb, 0x1F, 0x1C, 0x0F, 0x00000001, PPC_NONE, PPC2_ISA205),
GEN_HANDLER(isel, 0x1F, 0x0F, 0xFF, 0x00000001, PPC_ISEL),
GEN_HANDLER(addi, 0x0E, 0xFF, 0xFF, 0x00000000, PPC_INTEGER),
GEN_HANDLER(addic, 0x0C, 0xFF, 0xFF, 0x00000000, PPC_INTEGER),
@@ -8453,9 +8675,11 @@ GEN_HANDLER(xori, 0x1A, 0xFF, 0xFF, 0x00000000, PPC_INTEGER),
GEN_HANDLER(xoris, 0x1B, 0xFF, 0xFF, 0x00000000, PPC_INTEGER),
GEN_HANDLER(popcntb, 0x1F, 0x03, 0x03, 0x0000F801, PPC_POPCNTB),
GEN_HANDLER(popcntw, 0x1F, 0x1A, 0x0b, 0x0000F801, PPC_POPCNTWD),
+GEN_HANDLER_E(prtyw, 0x1F, 0x1A, 0x04, 0x0000F801, PPC_NONE, PPC2_ISA205),
#if defined(TARGET_PPC64)
GEN_HANDLER(popcntd, 0x1F, 0x1A, 0x0F, 0x0000F801, PPC_POPCNTWD),
GEN_HANDLER(cntlzd, 0x1F, 0x1A, 0x01, 0x00000000, PPC_64B),
+GEN_HANDLER_E(prtyd, 0x1F, 0x1A, 0x05, 0x0000F801, PPC_NONE, PPC2_ISA205),
#endif
GEN_HANDLER(rlwimi, 0x14, 0xFF, 0xFF, 0x00000000, PPC_INTEGER),
GEN_HANDLER(rlwinm, 0x15, 0xFF, 0xFF, 0x00000000, PPC_INTEGER),
@@ -8476,13 +8700,17 @@ GEN_HANDLER(fsqrt, 0x3F, 0x16, 0xFF, 0x001F07C0, PPC_FLOAT_FSQRT),
GEN_HANDLER(fsqrts, 0x3B, 0x16, 0xFF, 0x001F07C0, PPC_FLOAT_FSQRT),
GEN_HANDLER(fcmpo, 0x3F, 0x00, 0x01, 0x00600001, PPC_FLOAT),
GEN_HANDLER(fcmpu, 0x3F, 0x00, 0x00, 0x00600001, PPC_FLOAT),
+GEN_HANDLER(fabs, 0x3F, 0x08, 0x08, 0x001F0000, PPC_FLOAT),
GEN_HANDLER(fmr, 0x3F, 0x08, 0x02, 0x001F0000, PPC_FLOAT),
+GEN_HANDLER(fnabs, 0x3F, 0x08, 0x04, 0x001F0000, PPC_FLOAT),
+GEN_HANDLER(fneg, 0x3F, 0x08, 0x01, 0x001F0000, PPC_FLOAT),
+GEN_HANDLER_E(fcpsgn, 0x3F, 0x08, 0x00, 0x00000000, PPC_NONE, PPC2_ISA205),
GEN_HANDLER(mcrfs, 0x3F, 0x00, 0x02, 0x0063F801, PPC_FLOAT),
GEN_HANDLER(mffs, 0x3F, 0x07, 0x12, 0x001FF800, PPC_FLOAT),
GEN_HANDLER(mtfsb0, 0x3F, 0x06, 0x02, 0x001FF800, PPC_FLOAT),
GEN_HANDLER(mtfsb1, 0x3F, 0x06, 0x01, 0x001FF800, PPC_FLOAT),
-GEN_HANDLER(mtfsf, 0x3F, 0x07, 0x16, 0x00010000, PPC_FLOAT),
-GEN_HANDLER(mtfsfi, 0x3F, 0x06, 0x04, 0x006f0800, PPC_FLOAT),
+GEN_HANDLER(mtfsf, 0x3F, 0x07, 0x16, 0x00000000, PPC_FLOAT),
+GEN_HANDLER(mtfsfi, 0x3F, 0x06, 0x04, 0x006e0800, PPC_FLOAT),
#if defined(TARGET_PPC64)
GEN_HANDLER(ld, 0x3A, 0xFF, 0xFF, 0x00000000, PPC_64B),
GEN_HANDLER(lq, 0x38, 0xFF, 0xFF, 0x00000000, PPC_64BX),
@@ -8833,9 +9061,6 @@ GEN_FLOAT_B(rin, 0x08, 0x0C, 1, PPC_FLOAT_EXT),
GEN_FLOAT_B(riz, 0x08, 0x0D, 1, PPC_FLOAT_EXT),
GEN_FLOAT_B(rip, 0x08, 0x0E, 1, PPC_FLOAT_EXT),
GEN_FLOAT_B(rim, 0x08, 0x0F, 1, PPC_FLOAT_EXT),
-GEN_FLOAT_B(abs, 0x08, 0x08, 0, PPC_FLOAT),
-GEN_FLOAT_B(nabs, 0x08, 0x04, 0, PPC_FLOAT),
-GEN_FLOAT_B(neg, 0x08, 0x01, 0, PPC_FLOAT),
#undef GEN_LD
#undef GEN_LDU
@@ -8921,6 +9146,9 @@ GEN_LDXF(name, ldop, 0x17, op | 0x00, type)
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(lfdp, 0x39, 0xFF, 0xFF, 0x00200003, PPC_NONE, PPC2_ISA205),
+GEN_HANDLER_E(lfdpx, 0x1F, 0x17, 0x18, 0x00200001, PPC_NONE, PPC2_ISA205),
#undef GEN_STF
#undef GEN_STUF
@@ -8944,6 +9172,8 @@ GEN_STXF(name, stop, 0x17, op | 0x00, type)
GEN_STFS(stfd, st64, 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),
#undef GEN_CRLOGIC
#define GEN_CRLOGIC(name, tcg_op, opc) \
@@ -9518,6 +9748,8 @@ static inline void gen_intermediate_code_internal(CPUPPCState *env,
ctx.exception = POWERPC_EXCP_NONE;
ctx.spr_cb = env->spr_cb;
ctx.mem_idx = env->mmu_idx;
+ ctx.insns_flags = env->insns_flags;
+ ctx.insns_flags2 = env->insns_flags2;
ctx.access_type = -1;
ctx.le_mode = env->hflags & (1 << MSR_LE) ? 1 : 0;
#if defined(TARGET_PPC64)
diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c
index 781170fb05..6feb62abcd 100644
--- a/target-ppc/translate_init.c
+++ b/target-ppc/translate_init.c
@@ -1149,6 +1149,13 @@ static void gen_spr_603 (CPUPPCState *env)
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
0x00000000);
+ /* Breakpoints */
+ /* XXX : not implemented */
+ spr_register(env, SPR_IABR, "IABR",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+
}
/* SPR specific to PowerPC G2 implementation */
@@ -2593,7 +2600,6 @@ static void init_excp_4xx_real (CPUPPCState *env)
env->excp_vectors[POWERPC_EXCP_FIT] = 0x00001010;
env->excp_vectors[POWERPC_EXCP_WDT] = 0x00001020;
env->excp_vectors[POWERPC_EXCP_DEBUG] = 0x00002000;
- env->hreset_excp_prefix = 0x00000000UL;
env->ivor_mask = 0x0000FFF0UL;
env->ivpr_mask = 0xFFFF0000UL;
/* Hardware reset vector */
@@ -2618,7 +2624,6 @@ static void init_excp_4xx_softmmu (CPUPPCState *env)
env->excp_vectors[POWERPC_EXCP_DTLB] = 0x00001100;
env->excp_vectors[POWERPC_EXCP_ITLB] = 0x00001200;
env->excp_vectors[POWERPC_EXCP_DEBUG] = 0x00002000;
- env->hreset_excp_prefix = 0x00000000UL;
env->ivor_mask = 0x0000FFF0UL;
env->ivpr_mask = 0xFFFF0000UL;
/* Hardware reset vector */
@@ -2644,11 +2649,10 @@ static void init_excp_MPC5xx (CPUPPCState *env)
env->excp_vectors[POWERPC_EXCP_IABR] = 0x00001C00;
env->excp_vectors[POWERPC_EXCP_MEXTBR] = 0x00001E00;
env->excp_vectors[POWERPC_EXCP_NMEXTBR] = 0x00001F00;
- env->hreset_excp_prefix = 0x00000000UL;
env->ivor_mask = 0x0000FFF0UL;
env->ivpr_mask = 0xFFFF0000UL;
/* Hardware reset vector */
- env->hreset_vector = 0xFFFFFFFCUL;
+ env->hreset_vector = 0x00000100UL;
#endif
}
@@ -2676,11 +2680,10 @@ static void init_excp_MPC8xx (CPUPPCState *env)
env->excp_vectors[POWERPC_EXCP_IABR] = 0x00001C00;
env->excp_vectors[POWERPC_EXCP_MEXTBR] = 0x00001E00;
env->excp_vectors[POWERPC_EXCP_NMEXTBR] = 0x00001F00;
- env->hreset_excp_prefix = 0x00000000UL;
env->ivor_mask = 0x0000FFF0UL;
env->ivpr_mask = 0xFFFF0000UL;
/* Hardware reset vector */
- env->hreset_vector = 0xFFFFFFFCUL;
+ env->hreset_vector = 0x00000100UL;
#endif
}
@@ -2704,9 +2707,8 @@ static void init_excp_G2 (CPUPPCState *env)
env->excp_vectors[POWERPC_EXCP_DSTLB] = 0x00001200;
env->excp_vectors[POWERPC_EXCP_IABR] = 0x00001300;
env->excp_vectors[POWERPC_EXCP_SMI] = 0x00001400;
- env->hreset_excp_prefix = 0x00000000UL;
/* Hardware reset vector */
- env->hreset_vector = 0xFFFFFFFCUL;
+ env->hreset_vector = 0x00000100UL;
#endif
}
@@ -2733,7 +2735,6 @@ static void init_excp_e200(CPUPPCState *env, target_ulong ivpr_mask)
env->excp_vectors[POWERPC_EXCP_SPEU] = 0x00000000;
env->excp_vectors[POWERPC_EXCP_EFPDI] = 0x00000000;
env->excp_vectors[POWERPC_EXCP_EFPRI] = 0x00000000;
- env->hreset_excp_prefix = 0x00000000UL;
env->ivor_mask = 0x0000FFF7UL;
env->ivpr_mask = ivpr_mask;
/* Hardware reset vector */
@@ -2760,7 +2761,6 @@ static void init_excp_BookE (CPUPPCState *env)
env->excp_vectors[POWERPC_EXCP_DTLB] = 0x00000000;
env->excp_vectors[POWERPC_EXCP_ITLB] = 0x00000000;
env->excp_vectors[POWERPC_EXCP_DEBUG] = 0x00000000;
- env->hreset_excp_prefix = 0x00000000UL;
env->ivor_mask = 0x0000FFE0UL;
env->ivpr_mask = 0xFFFF0000UL;
/* Hardware reset vector */
@@ -2783,7 +2783,6 @@ static void init_excp_601 (CPUPPCState *env)
env->excp_vectors[POWERPC_EXCP_IO] = 0x00000A00;
env->excp_vectors[POWERPC_EXCP_SYSCALL] = 0x00000C00;
env->excp_vectors[POWERPC_EXCP_RUNM] = 0x00002000;
- env->hreset_excp_prefix = 0xFFF00000UL;
/* Hardware reset vector */
env->hreset_vector = 0x00000100UL;
#endif
@@ -2811,9 +2810,8 @@ static void init_excp_602 (CPUPPCState *env)
env->excp_vectors[POWERPC_EXCP_SMI] = 0x00001400;
env->excp_vectors[POWERPC_EXCP_WDT] = 0x00001500;
env->excp_vectors[POWERPC_EXCP_EMUL] = 0x00001600;
- env->hreset_excp_prefix = 0xFFF00000UL;
/* Hardware reset vector */
- env->hreset_vector = 0xFFFFFFFCUL;
+ env->hreset_vector = 0x00000100UL;
#endif
}
@@ -2836,9 +2834,8 @@ static void init_excp_603 (CPUPPCState *env)
env->excp_vectors[POWERPC_EXCP_DSTLB] = 0x00001200;
env->excp_vectors[POWERPC_EXCP_IABR] = 0x00001300;
env->excp_vectors[POWERPC_EXCP_SMI] = 0x00001400;
- env->hreset_excp_prefix = 0x00000000UL;
/* Hardware reset vector */
- env->hreset_vector = 0xFFFFFFFCUL;
+ env->hreset_vector = 0x00000100UL;
#endif
}
@@ -2859,7 +2856,6 @@ static void init_excp_604 (CPUPPCState *env)
env->excp_vectors[POWERPC_EXCP_PERFM] = 0x00000F00;
env->excp_vectors[POWERPC_EXCP_IABR] = 0x00001300;
env->excp_vectors[POWERPC_EXCP_SMI] = 0x00001400;
- env->hreset_excp_prefix = 0xFFF00000UL;
/* Hardware reset vector */
env->hreset_vector = 0x00000100UL;
#endif
@@ -2883,9 +2879,8 @@ static void init_excp_7x0 (CPUPPCState *env)
env->excp_vectors[POWERPC_EXCP_IABR] = 0x00001300;
env->excp_vectors[POWERPC_EXCP_SMI] = 0x00001400;
env->excp_vectors[POWERPC_EXCP_THERM] = 0x00001700;
- env->hreset_excp_prefix = 0x00000000UL;
/* Hardware reset vector */
- env->hreset_vector = 0xFFFFFFFCUL;
+ env->hreset_vector = 0x00000100UL;
#endif
}
@@ -2906,9 +2901,8 @@ static void init_excp_750cl (CPUPPCState *env)
env->excp_vectors[POWERPC_EXCP_PERFM] = 0x00000F00;
env->excp_vectors[POWERPC_EXCP_IABR] = 0x00001300;
env->excp_vectors[POWERPC_EXCP_SMI] = 0x00001400;
- env->hreset_excp_prefix = 0x00000000UL;
/* Hardware reset vector */
- env->hreset_vector = 0xFFFFFFFCUL;
+ env->hreset_vector = 0x00000100UL;
#endif
}
@@ -2929,9 +2923,8 @@ static void init_excp_750cx (CPUPPCState *env)
env->excp_vectors[POWERPC_EXCP_PERFM] = 0x00000F00;
env->excp_vectors[POWERPC_EXCP_IABR] = 0x00001300;
env->excp_vectors[POWERPC_EXCP_THERM] = 0x00001700;
- env->hreset_excp_prefix = 0x00000000UL;
/* Hardware reset vector */
- env->hreset_vector = 0xFFFFFFFCUL;
+ env->hreset_vector = 0x00000100UL;
#endif
}
@@ -2957,9 +2950,8 @@ static void init_excp_7x5 (CPUPPCState *env)
env->excp_vectors[POWERPC_EXCP_IABR] = 0x00001300;
env->excp_vectors[POWERPC_EXCP_SMI] = 0x00001400;
env->excp_vectors[POWERPC_EXCP_THERM] = 0x00001700;
- env->hreset_excp_prefix = 0x00000000UL;
/* Hardware reset vector */
- env->hreset_vector = 0xFFFFFFFCUL;
+ env->hreset_vector = 0x00000100UL;
#endif
}
@@ -2983,9 +2975,8 @@ static void init_excp_7400 (CPUPPCState *env)
env->excp_vectors[POWERPC_EXCP_SMI] = 0x00001400;
env->excp_vectors[POWERPC_EXCP_VPUA] = 0x00001600;
env->excp_vectors[POWERPC_EXCP_THERM] = 0x00001700;
- env->hreset_excp_prefix = 0x00000000UL;
/* Hardware reset vector */
- env->hreset_vector = 0xFFFFFFFCUL;
+ env->hreset_vector = 0x00000100UL;
#endif
}
@@ -3011,9 +3002,8 @@ static void init_excp_7450 (CPUPPCState *env)
env->excp_vectors[POWERPC_EXCP_IABR] = 0x00001300;
env->excp_vectors[POWERPC_EXCP_SMI] = 0x00001400;
env->excp_vectors[POWERPC_EXCP_VPUA] = 0x00001600;
- env->hreset_excp_prefix = 0x00000000UL;
/* Hardware reset vector */
- env->hreset_vector = 0xFFFFFFFCUL;
+ env->hreset_vector = 0x00000100UL;
#endif
}
@@ -3041,7 +3031,6 @@ static void init_excp_970 (CPUPPCState *env)
env->excp_vectors[POWERPC_EXCP_MAINT] = 0x00001600;
env->excp_vectors[POWERPC_EXCP_VPUA] = 0x00001700;
env->excp_vectors[POWERPC_EXCP_THERM] = 0x00001800;
- env->hreset_excp_prefix = 0x00000000FFF00000ULL;
/* Hardware reset vector */
env->hreset_vector = 0x0000000000000100ULL;
#endif
@@ -3070,7 +3059,6 @@ static void init_excp_POWER7 (CPUPPCState *env)
env->excp_vectors[POWERPC_EXCP_MAINT] = 0x00001600;
env->excp_vectors[POWERPC_EXCP_VPUA] = 0x00001700;
env->excp_vectors[POWERPC_EXCP_THERM] = 0x00001800;
- env->hreset_excp_prefix = 0;
/* Hardware reset vector */
env->hreset_vector = 0x0000000000000100ULL;
#endif
@@ -4157,6 +4145,33 @@ static void init_proc_G2LE (CPUPPCState *env)
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
0x00000000);
+ /* Breakpoints */
+ /* XXX : not implemented */
+ spr_register(env, SPR_DABR, "DABR",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* XXX : not implemented */
+ spr_register(env, SPR_DABR2, "DABR2",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* XXX : not implemented */
+ spr_register(env, SPR_IABR2, "IABR2",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* XXX : not implemented */
+ spr_register(env, SPR_IBCR, "IBCR",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* XXX : not implemented */
+ spr_register(env, SPR_DBCR, "DBCR",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+
/* Memory management */
gen_low_BATs(env);
gen_high_BATs(env);
@@ -6962,6 +6977,18 @@ static void init_proc_POWER7 (CPUPPCState *env)
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
KVM_REG_PPC_DSCR, 0x00000000);
+ spr_register_kvm(env, SPR_MMCRA, "SPR_MMCRA",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ KVM_REG_PPC_MMCRA, 0x00000000);
+ spr_register_kvm(env, SPR_PMC5, "SPR_PMC5",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ KVM_REG_PPC_PMC5, 0x00000000);
+ spr_register_kvm(env, SPR_PMC6, "SPR_PMC6",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ KVM_REG_PPC_PMC6, 0x00000000);
#endif /* !CONFIG_USER_ONLY */
/* Memory management */
/* XXX : not implemented */
@@ -6989,6 +7016,7 @@ static void init_proc_POWER7 (CPUPPCState *env)
init_excp_POWER7(env);
env->dcache_line_size = 128;
env->icache_line_size = 128;
+
/* Allocate hardware IRQ controller */
ppcPOWER7_irq_init(env);
/* Can't find information on what this should be on reset. This
@@ -7004,7 +7032,7 @@ POWERPC_FAMILY(POWER7)(ObjectClass *oc, void *data)
dc->desc = "POWER7";
pcc->init_proc = init_proc_POWER7;
pcc->check_pow = check_pow_nocheck;
- pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |
+ pcc->insns_flags = PPC_INSNS_BASE | PPC_ISEL | PPC_STRING | PPC_MFTB |
PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE |
PPC_FLOAT_STFIWX |
@@ -7014,7 +7042,7 @@ POWERPC_FAMILY(POWER7)(ObjectClass *oc, void *data)
PPC_64B | PPC_ALTIVEC |
PPC_SEGMENT_64B | PPC_SLBI |
PPC_POPCNTB | PPC_POPCNTWD;
- pcc->insns_flags2 = PPC2_VSX | PPC2_DFP | PPC2_DBRX;
+ pcc->insns_flags2 = PPC2_VSX | PPC2_DFP | PPC2_DBRX | PPC2_ISA205;
pcc->msr_mask = 0x800000000204FF36ULL;
pcc->mmu_model = POWERPC_MMU_2_06;
#if defined(CONFIG_SOFTMMU)
@@ -7026,6 +7054,8 @@ POWERPC_FAMILY(POWER7)(ObjectClass *oc, void *data)
pcc->flags = POWERPC_FLAG_VRE | POWERPC_FLAG_SE |
POWERPC_FLAG_BE | POWERPC_FLAG_PMM |
POWERPC_FLAG_BUS_CLK | POWERPC_FLAG_CFAR;
+ pcc->l1_dcache_size = 0x8000;
+ pcc->l1_icache_size = 0x8000;
}
#endif /* defined (TARGET_PPC64) */
@@ -7043,7 +7073,6 @@ static void init_ppc_proc(PowerPCCPU *cpu)
/* Set all exception vectors to an invalid address */
for (i = 0; i < POWERPC_EXCP_NB; i++)
env->excp_vectors[i] = (target_ulong)(-1ULL);
- env->hreset_excp_prefix = 0x00000000;
env->ivor_mask = 0x00000000;
env->ivpr_mask = 0x00000000;
/* Default MMU definitions */
@@ -7080,9 +7109,7 @@ static void init_ppc_proc(PowerPCCPU *cpu)
}
/* PowerPC implementation specific initialisations (SPRs, timers, ...) */
(*pcc->init_proc)(env);
-#if !defined(CONFIG_USER_ONLY)
- env->excp_prefix = env->hreset_excp_prefix;
-#endif
+
/* MSR bits & flags consistency checks */
if (env->msr_mask & (1 << 25)) {
switch (env->flags & (POWERPC_FLAG_SPE | POWERPC_FLAG_VRE)) {
@@ -8182,19 +8209,23 @@ static void ppc_cpu_reset(CPUState *s)
msr |= (target_ulong)1 << MSR_VR; /* Allow altivec usage */
msr |= (target_ulong)1 << MSR_SPE; /* Allow SPE usage */
msr |= (target_ulong)1 << MSR_PR;
-#else
- env->excp_prefix = env->hreset_excp_prefix;
- env->nip = env->hreset_vector | env->excp_prefix;
- if (env->mmu_model != POWERPC_MMU_REAL) {
- ppc_tlb_invalidate_all(env);
- }
#endif
- env->msr = msr & env->msr_mask;
+
#if defined(TARGET_PPC64)
if (env->mmu_model & POWERPC_MMU_64) {
env->msr |= (1ULL << MSR_SF);
}
#endif
+
+ hreg_store_msr(env, msr, 1);
+
+#if !defined(CONFIG_USER_ONLY)
+ env->nip = env->hreset_vector | env->excp_prefix;
+ if (env->mmu_model != POWERPC_MMU_REAL) {
+ ppc_tlb_invalidate_all(env);
+ }
+#endif
+
hreg_compute_hflags(env);
env->reserve_addr = (target_ulong)-1ULL;
/* Be sure no exception or interrupt is pending */