diff options
author | Peter Maydell <peter.maydell@linaro.org> | 2018-08-21 13:27:11 +0100 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2018-08-21 13:27:11 +0100 |
commit | ee135aa0428fe5af2af7be04ff16d2b596a9330a (patch) | |
tree | e88095d1ea78607c88962a0fc89f3b63765979d4 /target | |
parent | 659b11e7a7239529cfdb4968418268ff9aa22d88 (diff) | |
parent | 0e3bf4890906fa7066a5deafd6ab033934b8d100 (diff) | |
download | qemu-ee135aa0428fe5af2af7be04ff16d2b596a9330a.zip qemu-ee135aa0428fe5af2af7be04ff16d2b596a9330a.tar.gz qemu-ee135aa0428fe5af2af7be04ff16d2b596a9330a.tar.bz2 |
Merge remote-tracking branch 'remotes/dgibson/tags/ppc-for-3.1-20180821' into staging
ppc patch queue 2018-08-21
Here's my first ppc & spapr pull request for qemu-3.1. This contains
a bunch of things that have accumulated while 3.0 was in freeze.
Highlights are:
* SLOF firmware update
* A number of floating point cleanups from Richard Henderson and
Yasmin Beatriz
* A new model for assigning irq numbers on spapr, this is an
important preliminary step towards implementing the POWER9
"XIVE" interrupt controller
# gpg: Signature made Tue 21 Aug 2018 05:32:44 BST
# gpg: using RSA key 6C38CACA20D9B392
# gpg: Good signature from "David Gibson <david@gibson.dropbear.id.au>"
# gpg: aka "David Gibson (Red Hat) <dgibson@redhat.com>"
# gpg: aka "David Gibson (ozlabs.org) <dgibson@ozlabs.org>"
# gpg: aka "David Gibson (kernel.org) <dwg@kernel.org>"
# Primary key fingerprint: 75F4 6586 AE61 A66C C44E 87DC 6C38 CACA 20D9 B392
* remotes/dgibson/tags/ppc-for-3.1-20180821: (26 commits)
ppc: add DBCR based debugging
spapr_pci: factorize the use of SPAPR_MACHINE_GET_CLASS()
mac_newworld: don't use legacy fw_cfg_init_mem() function
mac_oldworld: don't use legacy fw_cfg_init_mem() function
40p: don't use legacy fw_cfg_init_mem() function
qemu-doc: mark ppc/prep machine as deprecated
hw/ppc: deprecate the machine type 'prep', replaced by '40p'
spapr: introduce a IRQ controller backend to the machine
hw/ppc/ppc405_uc: Convert away from old_mmio
hw/ppc/ppc_boards: Don't use old_mmio for ref405ep_fpga
hw/ppc/prep: Remove ifdeffed-out stub of XCSR code
spapr: introduce a fixed IRQ number space
spapr: Add a pseries-3.1 machine type
target/ppc: simplify bcdadd/sub functions
xics: don't include "target/ppc/cpu-qom.h" in "hw/ppc/xics.h"
vfio/spapr: Allow backing bigger guest IOMMU pages with smaller physical pages
target/ppc: bcdsub fix sign when result is zero
target/ppc: Use non-arithmetic conversions for fp load/store
target/ppc: Honor fpscr_ze semantics and tidy fre, fresqrt
target/ppc: Tidy helper_fsqrt
...
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'target')
-rw-r--r-- | target/ppc/cpu.h | 5 | ||||
-rw-r--r-- | target/ppc/excp_helper.c | 11 | ||||
-rw-r--r-- | target/ppc/fpu_helper.c | 292 | ||||
-rw-r--r-- | target/ppc/helper.h | 14 | ||||
-rw-r--r-- | target/ppc/int_helper.c | 46 | ||||
-rw-r--r-- | target/ppc/translate.c | 107 | ||||
-rw-r--r-- | target/ppc/translate/fp-impl.inc.c | 26 | ||||
-rw-r--r-- | target/ppc/translate_init.inc.c | 19 |
8 files changed, 316 insertions, 204 deletions
diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h index 4edcf62..ec14934 100644 --- a/target/ppc/cpu.h +++ b/target/ppc/cpu.h @@ -481,6 +481,11 @@ struct ppc_slb_t { #define msr_ts ((env->msr >> MSR_TS1) & 3) #define msr_tm ((env->msr >> MSR_TM) & 1) +#define DBCR0_ICMP (1 << 27) +#define DBCR0_BRT (1 << 26) +#define DBSR_ICMP (1 << 27) +#define DBSR_BRT (1 << 26) + /* Hypervisor bit is more specific */ #if defined(TARGET_PPC64) #define MSR_HVB (1ULL << MSR_SHV) diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c index d6e97a9..0ec7ae1 100644 --- a/target/ppc/excp_helper.c +++ b/target/ppc/excp_helper.c @@ -348,19 +348,16 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp) case POWERPC_EXCP_ITLB: /* Instruction TLB error */ break; case POWERPC_EXCP_DEBUG: /* Debug interrupt */ - switch (excp_model) { - case POWERPC_EXCP_BOOKE: + if (env->flags & POWERPC_FLAG_DE) { /* FIXME: choose one or the other based on CPU type */ srr0 = SPR_BOOKE_DSRR0; srr1 = SPR_BOOKE_DSRR1; asrr0 = SPR_BOOKE_CSRR0; asrr1 = SPR_BOOKE_CSRR1; - break; - default: - break; + /* DBSR already modified by caller */ + } else { + cpu_abort(cs, "Debug exception triggered on unsupported model\n"); } - /* XXX: TODO */ - cpu_abort(cs, "Debug exception is not implemented yet !\n"); break; case POWERPC_EXCP_SPEU: /* SPE/embedded floating-point unavailable */ env->spr[SPR_BOOKE_ESR] = ESR_SPV; diff --git a/target/ppc/fpu_helper.c b/target/ppc/fpu_helper.c index 8675d93..b9bb1b8 100644 --- a/target/ppc/fpu_helper.c +++ b/target/ppc/fpu_helper.c @@ -36,26 +36,72 @@ static inline float128 float128_snan_to_qnan(float128 x) #define float32_snan_to_qnan(x) ((x) | 0x00400000) #define float16_snan_to_qnan(x) ((x) | 0x0200) +static inline bool fp_exceptions_enabled(CPUPPCState *env) +{ +#ifdef CONFIG_USER_ONLY + return true; +#else + return (env->msr & ((1U << MSR_FE0) | (1U << MSR_FE1))) != 0; +#endif +} + /*****************************************************************************/ /* Floating point operations helpers */ -uint64_t helper_float32_to_float64(CPUPPCState *env, uint32_t arg) + +/* + * This is the non-arithmatic conversion that happens e.g. on loads. + * In the Power ISA pseudocode, this is called DOUBLE. + */ +uint64_t helper_todouble(uint32_t arg) { - CPU_FloatU f; - CPU_DoubleU d; + uint32_t abs_arg = arg & 0x7fffffff; + uint64_t ret; - f.l = arg; - d.d = float32_to_float64(f.f, &env->fp_status); - return d.ll; + if (likely(abs_arg >= 0x00800000)) { + /* Normalized operand, or Inf, or NaN. */ + ret = (uint64_t)extract32(arg, 30, 2) << 62; + ret |= ((extract32(arg, 30, 1) ^ 1) * (uint64_t)7) << 59; + ret |= (uint64_t)extract32(arg, 0, 30) << 29; + } else { + /* Zero or Denormalized operand. */ + ret = (uint64_t)extract32(arg, 31, 1) << 63; + if (unlikely(abs_arg != 0)) { + /* Denormalized operand. */ + int shift = clz32(abs_arg) - 9; + int exp = -126 - shift + 1023; + ret |= (uint64_t)exp << 52; + ret |= abs_arg << (shift + 29); + } + } + return ret; } -uint32_t helper_float64_to_float32(CPUPPCState *env, uint64_t arg) +/* + * This is the non-arithmatic conversion that happens e.g. on stores. + * In the Power ISA pseudocode, this is called SINGLE. + */ +uint32_t helper_tosingle(uint64_t arg) { - CPU_FloatU f; - CPU_DoubleU d; + int exp = extract64(arg, 52, 11); + uint32_t ret; - d.ll = arg; - f.f = float64_to_float32(d.d, &env->fp_status); - return f.l; + if (likely(exp > 896)) { + /* No denormalization required (includes Inf, NaN). */ + ret = extract64(arg, 62, 2) << 30; + ret |= extract64(arg, 29, 30); + } else { + /* Zero or Denormal result. If the exponent is in bounds for + * a single-precision denormal result, extract the proper bits. + * If the input is not zero, and the exponent is out of bounds, + * then the result is undefined; this underflows to zero. + */ + ret = extract64(arg, 63, 1) << 31; + if (unlikely(exp >= 874)) { + /* Denormal result. */ + ret |= ((1ULL << 52) | extract64(arg, 0, 52)) >> (896 + 30 - exp); + } + } + return ret; } static inline int ppc_float32_get_unbiased_exp(float32 f) @@ -207,7 +253,7 @@ uint64_t float_invalid_op_excp(CPUPPCState *env, int op, int set_fpcc) if (ve != 0) { /* Update the floating-point enabled exception summary */ env->fpscr |= 1 << FPSCR_FEX; - if (msr_fe0 != 0 || msr_fe1 != 0) { + if (fp_exceptions_enabled(env)) { /* GETPC() works here because this is inline */ raise_exception_err_ra(env, POWERPC_EXCP_PROGRAM, POWERPC_EXCP_FP | op, GETPC()); @@ -225,7 +271,7 @@ static inline void float_zero_divide_excp(CPUPPCState *env, uintptr_t raddr) if (fpscr_ze != 0) { /* Update the floating-point enabled exception summary */ env->fpscr |= 1 << FPSCR_FEX; - if (msr_fe0 != 0 || msr_fe1 != 0) { + if (fp_exceptions_enabled(env)) { raise_exception_err_ra(env, POWERPC_EXCP_PROGRAM, POWERPC_EXCP_FP | POWERPC_EXCP_FP_ZX, raddr); @@ -536,9 +582,7 @@ static void do_float_check_status(CPUPPCState *env, uintptr_t raddr) int status = get_float_exception_flags(&env->fp_status); bool inexact_happened = false; - if (status & float_flag_divbyzero) { - float_zero_divide_excp(env, raddr); - } else if (status & float_flag_overflow) { + if (status & float_flag_overflow) { float_overflow_excp(env); } else if (status & float_flag_underflow) { float_underflow_excp(env); @@ -555,7 +599,7 @@ static void do_float_check_status(CPUPPCState *env, uintptr_t raddr) if (cs->exception_index == POWERPC_EXCP_PROGRAM && (env->error_code & POWERPC_EXCP_FP)) { /* Differred floating-point exception after target FPR update */ - if (msr_fe0 != 0 || msr_fe1 != 0) { + if (fp_exceptions_enabled(env)) { raise_exception_err_ra(env, cs->exception_index, env->error_code, raddr); } @@ -580,102 +624,93 @@ void helper_reset_fpstatus(CPUPPCState *env) } /* fadd - fadd. */ -uint64_t helper_fadd(CPUPPCState *env, uint64_t arg1, uint64_t arg2) +float64 helper_fadd(CPUPPCState *env, float64 arg1, float64 arg2) { - CPU_DoubleU farg1, farg2; - - farg1.ll = arg1; - farg2.ll = arg2; + float64 ret = float64_add(arg1, arg2, &env->fp_status); + int status = get_float_exception_flags(&env->fp_status); - if (unlikely(float64_is_infinity(farg1.d) && float64_is_infinity(farg2.d) && - float64_is_neg(farg1.d) != float64_is_neg(farg2.d))) { - /* Magnitude subtraction of infinities */ - farg1.ll = float_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, 1); - } else { - if (unlikely(float64_is_signaling_nan(farg1.d, &env->fp_status) || - float64_is_signaling_nan(farg2.d, &env->fp_status))) { + if (unlikely(status & float_flag_invalid)) { + if (float64_is_infinity(arg1) && float64_is_infinity(arg2)) { + /* Magnitude subtraction of infinities */ + float_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, 1); + } else if (float64_is_signaling_nan(arg1, &env->fp_status) || + float64_is_signaling_nan(arg2, &env->fp_status)) { /* sNaN addition */ float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1); } - farg1.d = float64_add(farg1.d, farg2.d, &env->fp_status); } - return farg1.ll; + return ret; } /* fsub - fsub. */ -uint64_t helper_fsub(CPUPPCState *env, uint64_t arg1, uint64_t arg2) +float64 helper_fsub(CPUPPCState *env, float64 arg1, float64 arg2) { - CPU_DoubleU farg1, farg2; - - farg1.ll = arg1; - farg2.ll = arg2; + float64 ret = float64_sub(arg1, arg2, &env->fp_status); + int status = get_float_exception_flags(&env->fp_status); - if (unlikely(float64_is_infinity(farg1.d) && float64_is_infinity(farg2.d) && - float64_is_neg(farg1.d) == float64_is_neg(farg2.d))) { - /* Magnitude subtraction of infinities */ - farg1.ll = float_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, 1); - } else { - if (unlikely(float64_is_signaling_nan(farg1.d, &env->fp_status) || - float64_is_signaling_nan(farg2.d, &env->fp_status))) { - /* sNaN subtraction */ + if (unlikely(status & float_flag_invalid)) { + if (float64_is_infinity(arg1) && float64_is_infinity(arg2)) { + /* Magnitude subtraction of infinities */ + float_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, 1); + } else if (float64_is_signaling_nan(arg1, &env->fp_status) || + float64_is_signaling_nan(arg2, &env->fp_status)) { + /* sNaN addition */ float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1); } - farg1.d = float64_sub(farg1.d, farg2.d, &env->fp_status); } - return farg1.ll; + return ret; } /* fmul - fmul. */ -uint64_t helper_fmul(CPUPPCState *env, uint64_t arg1, uint64_t arg2) +float64 helper_fmul(CPUPPCState *env, float64 arg1, float64 arg2) { - CPU_DoubleU farg1, farg2; - - farg1.ll = arg1; - farg2.ll = arg2; + float64 ret = float64_mul(arg1, arg2, &env->fp_status); + int status = get_float_exception_flags(&env->fp_status); - if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) || - (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) { - /* Multiplication of zero by infinity */ - farg1.ll = float_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ, 1); - } else { - if (unlikely(float64_is_signaling_nan(farg1.d, &env->fp_status) || - float64_is_signaling_nan(farg2.d, &env->fp_status))) { + if (unlikely(status & float_flag_invalid)) { + if ((float64_is_infinity(arg1) && float64_is_zero(arg2)) || + (float64_is_zero(arg1) && float64_is_infinity(arg2))) { + /* Multiplication of zero by infinity */ + float_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ, 1); + } else if (float64_is_signaling_nan(arg1, &env->fp_status) || + float64_is_signaling_nan(arg2, &env->fp_status)) { /* sNaN multiplication */ float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1); } - farg1.d = float64_mul(farg1.d, farg2.d, &env->fp_status); } - return farg1.ll; + return ret; } /* fdiv - fdiv. */ -uint64_t helper_fdiv(CPUPPCState *env, uint64_t arg1, uint64_t arg2) +float64 helper_fdiv(CPUPPCState *env, float64 arg1, float64 arg2) { - CPU_DoubleU farg1, farg2; - - farg1.ll = arg1; - farg2.ll = arg2; + float64 ret = float64_div(arg1, arg2, &env->fp_status); + int status = get_float_exception_flags(&env->fp_status); - if (unlikely(float64_is_infinity(farg1.d) && - float64_is_infinity(farg2.d))) { - /* Division of infinity by infinity */ - farg1.ll = float_invalid_op_excp(env, POWERPC_EXCP_FP_VXIDI, 1); - } else if (unlikely(float64_is_zero(farg1.d) && float64_is_zero(farg2.d))) { - /* Division of zero by zero */ - farg1.ll = float_invalid_op_excp(env, POWERPC_EXCP_FP_VXZDZ, 1); - } else { - if (unlikely(float64_is_signaling_nan(farg1.d, &env->fp_status) || - float64_is_signaling_nan(farg2.d, &env->fp_status))) { - /* sNaN division */ - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1); + if (unlikely(status)) { + if (status & float_flag_invalid) { + /* Determine what kind of invalid operation was seen. */ + if (float64_is_infinity(arg1) && float64_is_infinity(arg2)) { + /* Division of infinity by infinity */ + float_invalid_op_excp(env, POWERPC_EXCP_FP_VXIDI, 1); + } else if (float64_is_zero(arg1) && float64_is_zero(arg2)) { + /* Division of zero by zero */ + float_invalid_op_excp(env, POWERPC_EXCP_FP_VXZDZ, 1); + } else if (float64_is_signaling_nan(arg1, &env->fp_status) || + float64_is_signaling_nan(arg2, &env->fp_status)) { + /* sNaN division */ + float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1); + } + } + if (status & float_flag_divbyzero) { + float_zero_divide_excp(env, GETPC()); } - farg1.d = float64_div(farg1.d, farg2.d, &env->fp_status); } - return farg1.ll; + return ret; } @@ -860,40 +895,48 @@ uint64_t helper_frsp(CPUPPCState *env, uint64_t arg) } /* fsqrt - fsqrt. */ -uint64_t helper_fsqrt(CPUPPCState *env, uint64_t arg) +float64 helper_fsqrt(CPUPPCState *env, float64 arg) { - CPU_DoubleU farg; - - farg.ll = arg; + float64 ret = float64_sqrt(arg, &env->fp_status); + int status = get_float_exception_flags(&env->fp_status); - if (unlikely(float64_is_any_nan(farg.d))) { - if (unlikely(float64_is_signaling_nan(farg.d, &env->fp_status))) { - /* sNaN reciprocal square root */ - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1); - farg.ll = float64_snan_to_qnan(farg.ll); + if (unlikely(status & float_flag_invalid)) { + if (unlikely(float64_is_any_nan(arg))) { + if (unlikely(float64_is_signaling_nan(arg, &env->fp_status))) { + /* sNaN square root */ + float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1); + } + } else { + /* Square root of a negative nonzero number */ + float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSQRT, 1); } - } else if (unlikely(float64_is_neg(farg.d) && !float64_is_zero(farg.d))) { - /* Square root of a negative nonzero number */ - farg.ll = float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSQRT, 1); - } else { - farg.d = float64_sqrt(farg.d, &env->fp_status); } - return farg.ll; + + return ret; } /* fre - fre. */ -uint64_t helper_fre(CPUPPCState *env, uint64_t arg) +float64 helper_fre(CPUPPCState *env, float64 arg) { - CPU_DoubleU farg; - - farg.ll = arg; + /* "Estimate" the reciprocal with actual division. */ + float64 ret = float64_div(float64_one, arg, &env->fp_status); + int status = get_float_exception_flags(&env->fp_status); - if (unlikely(float64_is_signaling_nan(farg.d, &env->fp_status))) { - /* sNaN reciprocal */ - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1); + if (unlikely(status)) { + if (status & float_flag_invalid) { + if (float64_is_signaling_nan(arg, &env->fp_status)) { + /* sNaN reciprocal */ + float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1); + } + } + if (status & float_flag_divbyzero) { + float_zero_divide_excp(env, GETPC()); + /* For FPSCR.ZE == 0, the result is 1/2. */ + ret = float64_set_sign(float64_half, float64_is_neg(arg)); + } } - farg.d = float64_div(float64_one, farg.d, &env->fp_status); - return farg.d; + + return ret; } /* fres - fres. */ @@ -916,27 +959,30 @@ uint64_t helper_fres(CPUPPCState *env, uint64_t arg) } /* frsqrte - frsqrte. */ -uint64_t helper_frsqrte(CPUPPCState *env, uint64_t arg) +float64 helper_frsqrte(CPUPPCState *env, float64 arg) { - CPU_DoubleU farg; - - farg.ll = arg; + /* "Estimate" the reciprocal with actual division. */ + float64 rets = float64_sqrt(arg, &env->fp_status); + float64 retd = float64_div(float64_one, rets, &env->fp_status); + int status = get_float_exception_flags(&env->fp_status); - if (unlikely(float64_is_any_nan(farg.d))) { - if (unlikely(float64_is_signaling_nan(farg.d, &env->fp_status))) { - /* sNaN reciprocal square root */ - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1); - farg.ll = float64_snan_to_qnan(farg.ll); + if (unlikely(status)) { + if (status & float_flag_invalid) { + if (float64_is_signaling_nan(arg, &env->fp_status)) { + /* sNaN reciprocal */ + float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1); + } else { + /* Square root of a negative nonzero number */ + float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSQRT, 1); + } + } + if (status & float_flag_divbyzero) { + /* Reciprocal of (square root of) zero. */ + float_zero_divide_excp(env, GETPC()); } - } else if (unlikely(float64_is_neg(farg.d) && !float64_is_zero(farg.d))) { - /* Reciprocal square root of a negative nonzero number */ - farg.ll = float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSQRT, 1); - } else { - farg.d = float64_sqrt(farg.d, &env->fp_status); - farg.d = float64_div(float64_one, farg.d, &env->fp_status); } - return farg.ll; + return retd; } /* fsel - fsel. */ @@ -1920,6 +1966,9 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \ float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, sfprf); \ } \ } \ + if (unlikely(tstat.float_exception_flags & float_flag_divbyzero)) { \ + float_zero_divide_excp(env, GETPC()); \ + } \ \ if (r2sp) { \ xt.fld = helper_frsp(env, xt.fld); \ @@ -1969,6 +2018,9 @@ void helper_xsdivqp(CPUPPCState *env, uint32_t opcode) float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1); } } + if (unlikely(tstat.float_exception_flags & float_flag_divbyzero)) { + float_zero_divide_excp(env, GETPC()); + } helper_compute_fprf_float128(env, xt.f128); putVSR(rD(opcode) + 32, &xt, env); diff --git a/target/ppc/helper.h b/target/ppc/helper.h index 5706c24..ef64248 100644 --- a/target/ppc/helper.h +++ b/target/ppc/helper.h @@ -61,8 +61,8 @@ 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) -DEF_HELPER_2(float64_to_float32, i32, env, i64) -DEF_HELPER_2(float32_to_float64, i64, env, i32) +DEF_HELPER_FLAGS_1(todouble, TCG_CALL_NO_RWG_SE, i64, i32) +DEF_HELPER_FLAGS_1(tosingle, TCG_CALL_NO_RWG_SE, i32, i64) DEF_HELPER_4(fcmpo, void, env, i64, i64, i32) DEF_HELPER_4(fcmpu, void, env, i64, i64, i32) @@ -85,15 +85,15 @@ DEF_HELPER_2(friz, i64, env, i64) DEF_HELPER_2(frip, i64, env, i64) DEF_HELPER_2(frim, i64, env, i64) -DEF_HELPER_3(fadd, i64, env, i64, i64) -DEF_HELPER_3(fsub, i64, env, i64, i64) -DEF_HELPER_3(fmul, i64, env, i64, i64) -DEF_HELPER_3(fdiv, i64, env, i64, i64) +DEF_HELPER_3(fadd, f64, env, f64, f64) +DEF_HELPER_3(fsub, f64, env, f64, f64) +DEF_HELPER_3(fmul, f64, env, f64, f64) +DEF_HELPER_3(fdiv, f64, env, f64, f64) 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(fsqrt, i64, env, i64) +DEF_HELPER_2(fsqrt, f64, env, f64) DEF_HELPER_2(fre, i64, env, i64) DEF_HELPER_2(fres, i64, env, i64) DEF_HELPER_2(frsqrte, i64, env, i64) diff --git a/target/ppc/int_helper.c b/target/ppc/int_helper.c index d52338e..fcac90a 100644 --- a/target/ppc/int_helper.c +++ b/target/ppc/int_helper.c @@ -2671,16 +2671,14 @@ static int bcd_cmp_mag(ppc_avr_t *a, ppc_avr_t *b) return 0; } -static int bcd_add_mag(ppc_avr_t *t, ppc_avr_t *a, ppc_avr_t *b, int *invalid, +static void bcd_add_mag(ppc_avr_t *t, ppc_avr_t *a, ppc_avr_t *b, int *invalid, int *overflow) { int carry = 0; int i; - int is_zero = 1; for (i = 1; i <= 31; i++) { uint8_t digit = bcd_get_digit(a, i, invalid) + bcd_get_digit(b, i, invalid) + carry; - is_zero &= (digit == 0); if (digit > 9) { carry = 1; digit -= 10; @@ -2689,26 +2687,20 @@ static int bcd_add_mag(ppc_avr_t *t, ppc_avr_t *a, ppc_avr_t *b, int *invalid, } bcd_put_digit(t, digit, i); - - if (unlikely(*invalid)) { - return -1; - } } *overflow = carry; - return is_zero; } -static int bcd_sub_mag(ppc_avr_t *t, ppc_avr_t *a, ppc_avr_t *b, int *invalid, +static void bcd_sub_mag(ppc_avr_t *t, ppc_avr_t *a, ppc_avr_t *b, int *invalid, int *overflow) { int carry = 0; int i; - int is_zero = 1; + for (i = 1; i <= 31; i++) { uint8_t digit = bcd_get_digit(a, i, invalid) - bcd_get_digit(b, i, invalid) + carry; - is_zero &= (digit == 0); if (digit & 0x80) { carry = -1; digit += 10; @@ -2717,14 +2709,9 @@ static int bcd_sub_mag(ppc_avr_t *t, ppc_avr_t *a, ppc_avr_t *b, int *invalid, } bcd_put_digit(t, digit, i); - - if (unlikely(*invalid)) { - return -1; - } } *overflow = carry; - return is_zero; } uint32_t helper_bcdadd(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, uint32_t ps) @@ -2734,23 +2721,28 @@ uint32_t helper_bcdadd(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, uint32_t ps) int sgnb = bcd_get_sgn(b); int invalid = (sgna == 0) || (sgnb == 0); int overflow = 0; - int zero = 0; uint32_t cr = 0; ppc_avr_t result = { .u64 = { 0, 0 } }; if (!invalid) { 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) ? 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) ? CRF_GT : CRF_LT; + bcd_add_mag(&result, a, b, &invalid, &overflow); + cr = bcd_cmp_zero(&result); } else { - result.u8[BCD_DIG_BYTE(0)] = bcd_preferred_sgn(sgnb, ps); - zero = bcd_sub_mag(&result, b, a, &invalid, &overflow); - cr = (sgnb > 0) ? CRF_GT : CRF_LT; + int magnitude = bcd_cmp_mag(a, b); + if (magnitude > 0) { + result.u8[BCD_DIG_BYTE(0)] = bcd_preferred_sgn(sgna, ps); + bcd_sub_mag(&result, a, b, &invalid, &overflow); + cr = (sgna > 0) ? CRF_GT : CRF_LT; + } else if (magnitude < 0) { + result.u8[BCD_DIG_BYTE(0)] = bcd_preferred_sgn(sgnb, ps); + bcd_sub_mag(&result, b, a, &invalid, &overflow); + cr = (sgnb > 0) ? CRF_GT : CRF_LT; + } else { + result.u8[BCD_DIG_BYTE(0)] = bcd_preferred_sgn(0, ps); + cr = CRF_EQ; + } } } @@ -2759,8 +2751,6 @@ uint32_t helper_bcdadd(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, uint32_t ps) cr = CRF_SO; } else if (overflow) { cr |= CRF_SO; - } else if (zero) { - cr = CRF_EQ; } *r = result; diff --git a/target/ppc/translate.c b/target/ppc/translate.c index 9eaa10b..8817435 100644 --- a/target/ppc/translate.c +++ b/target/ppc/translate.c @@ -211,6 +211,7 @@ struct DisasContext { bool gtse; ppc_spr_t *spr_cb; /* Needed to check rights for mfspr/mtspr */ int singlestep_enabled; + uint32_t flags; uint64_t insns_flags; uint64_t insns_flags2; }; @@ -251,6 +252,17 @@ struct opc_handler_t { #endif }; +/* SPR load/store helpers */ +static inline void gen_load_spr(TCGv t, int reg) +{ + tcg_gen_ld_tl(t, cpu_env, offsetof(CPUPPCState, spr[reg])); +} + +static inline void gen_store_spr(int reg, TCGv t) +{ + tcg_gen_st_tl(t, cpu_env, offsetof(CPUPPCState, spr[reg])); +} + static inline void gen_set_access_type(DisasContext *ctx, int access_type) { if (ctx->need_access_type && ctx->access_type != access_type) { @@ -313,6 +325,38 @@ static void gen_exception_nip(DisasContext *ctx, uint32_t excp, ctx->exception = (excp); } +/* Translates the EXCP_TRACE/BRANCH exceptions used on most PowerPCs to + * EXCP_DEBUG, if we are running on cores using the debug enable bit (e.g. + * BookE). + */ +static uint32_t gen_prep_dbgex(DisasContext *ctx, uint32_t excp) +{ + if ((ctx->singlestep_enabled & CPU_SINGLE_STEP) + && (excp == POWERPC_EXCP_BRANCH)) { + /* Trace excpt. has priority */ + excp = POWERPC_EXCP_TRACE; + } + if (ctx->flags & POWERPC_FLAG_DE) { + target_ulong dbsr = 0; + switch (excp) { + case POWERPC_EXCP_TRACE: + dbsr = DBCR0_ICMP; + break; + case POWERPC_EXCP_BRANCH: + dbsr = DBCR0_BRT; + break; + } + TCGv t0 = tcg_temp_new(); + gen_load_spr(t0, SPR_BOOKE_DBSR); + tcg_gen_ori_tl(t0, t0, dbsr); + gen_store_spr(SPR_BOOKE_DBSR, t0); + tcg_temp_free(t0); + return POWERPC_EXCP_DEBUG; + } else { + return excp; + } +} + static void gen_debug_exception(DisasContext *ctx) { TCGv_i32 t0; @@ -575,17 +619,6 @@ typedef struct opcode_t { } #endif -/* SPR load/store helpers */ -static inline void gen_load_spr(TCGv t, int reg) -{ - tcg_gen_ld_tl(t, cpu_env, offsetof(CPUPPCState, spr[reg])); -} - -static inline void gen_store_spr(int reg, TCGv t) -{ - tcg_gen_st_tl(t, cpu_env, offsetof(CPUPPCState, spr[reg])); -} - /* Invalid instruction */ static void gen_invalid(DisasContext *ctx) { @@ -3602,6 +3635,24 @@ static inline bool use_goto_tb(DisasContext *ctx, target_ulong dest) #endif } +static void gen_lookup_and_goto_ptr(DisasContext *ctx) +{ + int sse = ctx->singlestep_enabled; + if (unlikely(sse)) { + if (sse & GDBSTUB_SINGLE_STEP) { + gen_debug_exception(ctx); + } else if (sse & (CPU_SINGLE_STEP | CPU_BRANCH_STEP)) { + uint32_t excp = gen_prep_dbgex(ctx, POWERPC_EXCP_BRANCH); + if (excp != POWERPC_EXCP_NONE) { + gen_exception(ctx, excp); + } + } + tcg_gen_exit_tb(NULL, 0); + } else { + tcg_gen_lookup_and_goto_ptr(); + } +} + /*** Branch ***/ static void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest) { @@ -3614,18 +3665,7 @@ static void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest) tcg_gen_exit_tb(ctx->base.tb, n); } else { tcg_gen_movi_tl(cpu_nip, dest & ~3); - if (unlikely(ctx->singlestep_enabled)) { - if ((ctx->singlestep_enabled & - (CPU_BRANCH_STEP | CPU_SINGLE_STEP)) && - (ctx->exception == POWERPC_EXCP_BRANCH || - ctx->exception == POWERPC_EXCP_TRACE)) { - gen_exception_nip(ctx, POWERPC_EXCP_TRACE, dest); - } - if (ctx->singlestep_enabled & GDBSTUB_SINGLE_STEP) { - gen_debug_exception(ctx); - } - } - tcg_gen_lookup_and_goto_ptr(); + gen_lookup_and_goto_ptr(ctx); } } @@ -3668,8 +3708,8 @@ static void gen_bcond(DisasContext *ctx, int type) uint32_t bo = BO(ctx->opcode); TCGLabel *l1; TCGv target; - ctx->exception = POWERPC_EXCP_BRANCH; + if (type == BCOND_LR || type == BCOND_CTR || type == BCOND_TAR) { target = tcg_temp_local_new(); if (type == BCOND_CTR) @@ -3733,10 +3773,11 @@ static void gen_bcond(DisasContext *ctx, int type) } else { tcg_gen_andi_tl(cpu_nip, target, ~3); } - tcg_gen_lookup_and_goto_ptr(); + gen_lookup_and_goto_ptr(ctx); tcg_temp_free(target); } if ((bo & 0x14) != 0x14) { + /* fallthrough case */ gen_set_label(l1); gen_goto_tb(ctx, 1, ctx->base.pc_next); } @@ -7419,6 +7460,7 @@ static void ppc_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs) ctx->need_access_type = !(env->mmu_model & POWERPC_MMU_64B); ctx->le_mode = !!(env->hflags & (1 << MSR_LE)); ctx->default_tcg_memop_mask = ctx->le_mode ? MO_LE : MO_BE; + ctx->flags = env->flags; #if defined(TARGET_PPC64) ctx->sf_mode = msr_is_64bit(env, env->msr); ctx->has_cfar = !!(env->flags & POWERPC_FLAG_CFAR); @@ -7455,6 +7497,17 @@ static void ppc_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs) ctx->singlestep_enabled = 0; if ((env->flags & POWERPC_FLAG_BE) && msr_be) ctx->singlestep_enabled |= CPU_BRANCH_STEP; + if ((env->flags & POWERPC_FLAG_DE) && msr_de) { + ctx->singlestep_enabled = 0; + target_ulong dbcr0 = env->spr[SPR_BOOKE_DBCR0]; + if (dbcr0 & DBCR0_ICMP) { + ctx->singlestep_enabled |= CPU_SINGLE_STEP; + } + if (dbcr0 & DBCR0_BRT) { + ctx->singlestep_enabled |= CPU_BRANCH_STEP; + } + + } if (unlikely(ctx->base.singlestep_enabled)) { ctx->singlestep_enabled |= GDBSTUB_SINGLE_STEP; } @@ -7565,7 +7618,9 @@ static void ppc_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs) ctx->exception != POWERPC_SYSCALL && ctx->exception != POWERPC_EXCP_TRAP && ctx->exception != POWERPC_EXCP_BRANCH)) { - gen_exception_nip(ctx, POWERPC_EXCP_TRACE, ctx->base.pc_next); + uint32_t excp = gen_prep_dbgex(ctx, POWERPC_EXCP_TRACE); + if (excp != POWERPC_EXCP_NONE) + gen_exception_nip(ctx, excp, ctx->base.pc_next); } if (tcg_check_temp_count()) { diff --git a/target/ppc/translate/fp-impl.inc.c b/target/ppc/translate/fp-impl.inc.c index 2fbd4d4..a6f522b 100644 --- a/target/ppc/translate/fp-impl.inc.c +++ b/target/ppc/translate/fp-impl.inc.c @@ -660,15 +660,12 @@ GEN_LDUF(name, ldop, op | 0x21, type); \ GEN_LDUXF(name, ldop, op | 0x01, type); \ GEN_LDXF(name, ldop, 0x17, op | 0x00, type) -static inline void gen_qemu_ld32fs(DisasContext *ctx, TCGv_i64 arg1, TCGv arg2) +static void gen_qemu_ld32fs(DisasContext *ctx, TCGv_i64 dest, TCGv addr) { - TCGv t0 = tcg_temp_new(); - TCGv_i32 t1 = tcg_temp_new_i32(); - gen_qemu_ld32u(ctx, t0, arg2); - tcg_gen_trunc_tl_i32(t1, t0); - tcg_temp_free(t0); - gen_helper_float32_to_float64(arg1, cpu_env, t1); - tcg_temp_free_i32(t1); + TCGv_i32 tmp = tcg_temp_new_i32(); + tcg_gen_qemu_ld_i32(tmp, addr, ctx->mem_idx, DEF_MEMOP(MO_UL)); + gen_helper_todouble(dest, tmp); + tcg_temp_free_i32(tmp); } /* lfd lfdu lfdux lfdx */ @@ -836,15 +833,12 @@ GEN_STUF(name, stop, op | 0x21, type); \ GEN_STUXF(name, stop, op | 0x01, type); \ GEN_STXF(name, stop, 0x17, op | 0x00, type) -static inline void gen_qemu_st32fs(DisasContext *ctx, TCGv_i64 arg1, TCGv arg2) +static void gen_qemu_st32fs(DisasContext *ctx, TCGv_i64 src, TCGv addr) { - TCGv_i32 t0 = tcg_temp_new_i32(); - TCGv t1 = tcg_temp_new(); - gen_helper_float64_to_float32(t0, cpu_env, arg1); - tcg_gen_extu_i32_tl(t1, t0); - tcg_temp_free_i32(t0); - gen_qemu_st32(ctx, t1, arg2); - tcg_temp_free(t1); + TCGv_i32 tmp = tcg_temp_new_i32(); + gen_helper_tosingle(tmp, src); + tcg_gen_qemu_st_i32(tmp, addr, ctx->mem_idx, DEF_MEMOP(MO_UL)); + tcg_temp_free_i32(tmp); } /* stfd stfdu stfdux stfdx */ diff --git a/target/ppc/translate_init.inc.c b/target/ppc/translate_init.inc.c index 7813b1b..d920d3e 100644 --- a/target/ppc/translate_init.inc.c +++ b/target/ppc/translate_init.inc.c @@ -498,6 +498,7 @@ static void spr_write_40x_pit(DisasContext *ctx, int sprn, int gprn) static void spr_write_40x_dbcr0(DisasContext *ctx, int sprn, int gprn) { + gen_store_spr(sprn, cpu_gpr[gprn]); gen_helper_store_40x_dbcr0(cpu_env, cpu_gpr[gprn]); /* We must stop translation as we may have rebooted */ gen_stop_exception(ctx); @@ -1769,6 +1770,14 @@ static void gen_spr_BookE(CPUPPCState *env, uint64_t ivor_mask) SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); + spr_register(env, SPR_BOOKE_DSRR0, "DSRR0", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_BOOKE_DSRR1, "DSRR1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); /* XXX : not implemented */ spr_register(env, SPR_BOOKE_DBSR, "DBSR", SPR_NOACCESS, SPR_NOACCESS, @@ -1841,6 +1850,14 @@ static void gen_spr_BookE(CPUPPCState *env, uint64_t ivor_mask) SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); + spr_register(env, SPR_BOOKE_SPRG8, "SPRG8", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_BOOKE_SPRG9, "SPRG9", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); } static inline uint32_t gen_tlbncfg(uint32_t assoc, uint32_t minsize, @@ -10278,6 +10295,8 @@ static void ppc_cpu_reset(CPUState *s) #endif #if defined(CONFIG_USER_ONLY) msr |= (target_ulong)1 << MSR_FP; /* Allow floating point usage */ + msr |= (target_ulong)1 << MSR_FE0; /* Allow floating point exceptions */ + msr |= (target_ulong)1 << MSR_FE1; msr |= (target_ulong)1 << MSR_VR; /* Allow altivec usage */ msr |= (target_ulong)1 << MSR_VSX; /* Allow VSX usage */ msr |= (target_ulong)1 << MSR_SPE; /* Allow SPE usage */ |