diff options
author | Peter Maydell <peter.maydell@linaro.org> | 2015-01-10 19:50:21 +0000 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2015-01-10 19:50:21 +0000 |
commit | 97052d64e4fb934bcf25f4a6b42dc06f6ecbf9eb (patch) | |
tree | c4a72adc118c1cc1ca6e0c51c4072158ce3d1bc1 /target-ppc | |
parent | e77d927f1a1876ef341b4df287939b0c935703d5 (diff) | |
parent | 75c74ccbe1d4175edb79c6f810c2207dcf5edb22 (diff) |
Merge remote-tracking branch 'remotes/agraf/tags/signed-ppc-for-upstream' into staging
Patch queue for ppc - 2015-01-07
New year's release. This time's highlights:
- E500: More RAM support
- pseries: New SLOF release
- Migration fixes
- Simplify USB spawning logic, removes support for explicit usb=off
- TCG: Simple untansactional TM emulation
# gpg: Signature made Wed 07 Jan 2015 15:19:37 GMT using RSA key ID 03FEDC60
# gpg: Good signature from "Alexander Graf <agraf@suse.de>"
# gpg: aka "Alexander Graf <alex@csgraf.de>"
* remotes/agraf/tags/signed-ppc-for-upstream: (37 commits)
hw/ppc/mac_newworld: simplify usb controller creation logic
hw/ppc/spapr: simplify usb controller creation logic
hw/ppc/mac_newworld: QOMified mac99 machines
hw/usb: simplified usb_enabled
hw/machine: added machine_usb wrapper
hw/ppc: modified the condition for usb controllers to be created for some ppc machines
target-ppc: Cast ssize_t to size_t before printing with %zx
target-ppc: Mark SR() and gen_sync_exception() as !CONFIG_USER_ONLY
PPC: e500: Fix GPIO controller interrupt number
target-ppc: Introduce Privileged TM Noops
target-ppc: Introduce tcheck
target-ppc: Introduce TM Noops
target-ppc: Introduce tbegin
target-ppc: Introduce TEXASRU Bit Fields
target-ppc: Power8 Supports Transactional Memory
target-ppc: Introduce tm_enabled Bit to CPU State
target-ppc: Introduce Feature Flag for Transactional Memory
target-ppc: Introduce Instruction Type for Transactional Memory
pseries: Update SLOF firmware image to 20141202
PPC: Fix crash on spapr_tce_table_finalize()
...
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'target-ppc')
-rw-r--r-- | target-ppc/cpu.h | 26 | ||||
-rw-r--r-- | target-ppc/fpu_helper.c | 85 | ||||
-rw-r--r-- | target-ppc/helper.h | 4 | ||||
-rw-r--r-- | target-ppc/kvm.c | 20 | ||||
-rw-r--r-- | target-ppc/mem_helper.c | 22 | ||||
-rw-r--r-- | target-ppc/translate.c | 271 | ||||
-rw-r--r-- | target-ppc/translate_init.c | 5 |
7 files changed, 323 insertions, 110 deletions
diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index f42589c478..c62097bb8a 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -559,6 +559,26 @@ struct ppc_slb_t { #define ESR_VLEMI (1 << (63 - 58)) /* VLE operation */ #define ESR_MIF (1 << (63 - 62)) /* Misaligned instruction (VLE) */ +/* Transaction EXception And Summary Register bits */ +#define TEXASR_FAILURE_PERSISTENT (63 - 7) +#define TEXASR_DISALLOWED (63 - 8) +#define TEXASR_NESTING_OVERFLOW (63 - 9) +#define TEXASR_FOOTPRINT_OVERFLOW (63 - 10) +#define TEXASR_SELF_INDUCED_CONFLICT (63 - 11) +#define TEXASR_NON_TRANSACTIONAL_CONFLICT (63 - 12) +#define TEXASR_TRANSACTION_CONFLICT (63 - 13) +#define TEXASR_TRANSLATION_INVALIDATION_CONFLICT (63 - 14) +#define TEXASR_IMPLEMENTATION_SPECIFIC (63 - 15) +#define TEXASR_INSTRUCTION_FETCH_CONFLICT (63 - 16) +#define TEXASR_ABORT (63 - 31) +#define TEXASR_SUSPENDED (63 - 32) +#define TEXASR_PRIVILEGE_HV (63 - 34) +#define TEXASR_PRIVILEGE_PR (63 - 35) +#define TEXASR_FAILURE_SUMMARY (63 - 36) +#define TEXASR_TFIAR_EXACT (63 - 37) +#define TEXASR_ROT (63 - 38) +#define TEXASR_TRANSACTION_LEVEL (63 - 52) /* 12 bits */ + enum { POWERPC_FLAG_NONE = 0x00000000, /* Flag for MSR bit 25 signification (VRE/SPE) */ @@ -585,6 +605,8 @@ enum { POWERPC_FLAG_CFAR = 0x00040000, /* Has VSX */ POWERPC_FLAG_VSX = 0x00080000, + /* Has Transaction Memory (ISA 2.07) */ + POWERPC_FLAG_TM = 0x00100000, }; /*****************************************************************************/ @@ -2011,6 +2033,8 @@ enum { PPC2_ISA207S = 0x0000000000008000ULL, /* Double precision floating point conversion for signed integer 64 */ PPC2_FP_CVT_S64 = 0x0000000000010000ULL, + /* Transactional Memory (ISA 2.07, Book II) */ + PPC2_TM = 0x0000000000020000ULL, #define PPC_TCG_INSNS2 (PPC2_BOOKE206 | PPC2_VSX | PPC2_PRCNTL | PPC2_DBRX | \ PPC2_ISA205 | PPC2_VSX207 | PPC2_PERM_ISA206 | \ @@ -2018,7 +2042,7 @@ enum { PPC2_FP_CVT_ISA206 | PPC2_FP_TST_ISA206 | \ PPC2_BCTAR_ISA207 | PPC2_LSQ_ISA207 | \ PPC2_ALTIVEC_207 | PPC2_ISA207S | PPC2_DFP | \ - PPC2_FP_CVT_S64) + PPC2_FP_CVT_S64 | PPC2_TM) }; /*****************************************************************************/ diff --git a/target-ppc/fpu_helper.c b/target-ppc/fpu_helper.c index 7f74466f32..6cceffc556 100644 --- a/target-ppc/fpu_helper.c +++ b/target-ppc/fpu_helper.c @@ -19,6 +19,9 @@ #include "cpu.h" #include "exec/helper-proto.h" +#define float64_snan_to_qnan(x) ((x) | 0x0008000000000000ULL) +#define float32_snan_to_qnan(x) ((x) | 0x00400000) + /*****************************************************************************/ /* Floating point operations helpers */ uint64_t helper_float32_to_float64(CPUPPCState *env, uint32_t arg) @@ -60,59 +63,55 @@ static inline int ppc_float64_get_unbiased_exp(float64 f) return ((f >> 52) & 0x7FF) - 1023; } -uint32_t helper_compute_fprf(CPUPPCState *env, uint64_t arg, uint32_t set_fprf) +void helper_compute_fprf(CPUPPCState *env, uint64_t arg) { CPU_DoubleU farg; int isneg; - int ret; + 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)) { /* Signaling NaN: flags are undefined */ - ret = 0x00; + fprf = 0x00; } else { /* Quiet NaN */ - ret = 0x11; + fprf = 0x11; } } else if (unlikely(float64_is_infinity(farg.d))) { /* +/- infinity */ if (isneg) { - ret = 0x09; + fprf = 0x09; } else { - ret = 0x05; + fprf = 0x05; } } else { if (float64_is_zero(farg.d)) { /* +/- zero */ if (isneg) { - ret = 0x12; + fprf = 0x12; } else { - ret = 0x02; + fprf = 0x02; } } else { if (isden(farg.d)) { /* Denormalized numbers */ - ret = 0x10; + fprf = 0x10; } else { /* Normalized numbers */ - ret = 0x00; + fprf = 0x00; } if (isneg) { - ret |= 0x08; + fprf |= 0x08; } else { - ret |= 0x04; + fprf |= 0x04; } } } - if (set_fprf) { - /* We update FPSCR_FPRF */ - env->fpscr &= ~(0x1F << FPSCR_FPRF); - env->fpscr |= ret << FPSCR_FPRF; - } - /* We just need fpcc to update Rc1 */ - return ret & 0xF; + /* We update FPSCR_FPRF */ + env->fpscr &= ~(0x1F << FPSCR_FPRF); + env->fpscr |= fprf << FPSCR_FPRF; } /* Floating-point invalid operations exception */ @@ -920,14 +919,16 @@ uint64_t helper_fsqrt(CPUPPCState *env, uint64_t arg) farg.ll = arg; - if (unlikely(float64_is_neg(farg.d) && !float64_is_zero(farg.d))) { - /* Square root of a negative nonzero number */ - farg.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSQRT, 1); - } else { + if (unlikely(float64_is_any_nan(farg.d))) { if (unlikely(float64_is_signaling_nan(farg.d))) { - /* sNaN square root */ + /* sNaN reciprocal square root */ fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1); + farg.ll = float64_snan_to_qnan(farg.ll); } + } else if (unlikely(float64_is_neg(farg.d) && !float64_is_zero(farg.d))) { + /* Square root of a negative nonzero number */ + farg.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSQRT, 1); + } else { farg.d = float64_sqrt(farg.d, &env->fp_status); } return farg.ll; @@ -974,17 +975,20 @@ uint64_t helper_frsqrte(CPUPPCState *env, uint64_t arg) farg.ll = arg; - if (unlikely(float64_is_neg(farg.d) && !float64_is_zero(farg.d))) { - /* Reciprocal square root of a negative nonzero number */ - farg.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSQRT, 1); - } else { + if (unlikely(float64_is_any_nan(farg.d))) { if (unlikely(float64_is_signaling_nan(farg.d))) { /* sNaN reciprocal square root */ fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1); + farg.ll = float64_snan_to_qnan(farg.ll); } + } else if (unlikely(float64_is_neg(farg.d) && !float64_is_zero(farg.d))) { + /* Reciprocal square root of a negative nonzero number */ + farg.ll = fload_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; } @@ -1845,7 +1849,7 @@ void helper_##name(CPUPPCState *env, uint32_t opcode) \ } \ \ if (sfprf) { \ - helper_compute_fprf(env, xt.fld, sfprf); \ + helper_compute_fprf(env, xt.fld); \ } \ } \ putVSR(xT(opcode), &xt, env); \ @@ -1900,7 +1904,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \ } \ \ if (sfprf) { \ - helper_compute_fprf(env, xt.fld, sfprf); \ + helper_compute_fprf(env, xt.fld); \ } \ } \ \ @@ -1954,7 +1958,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \ } \ \ if (sfprf) { \ - helper_compute_fprf(env, xt.fld, sfprf); \ + helper_compute_fprf(env, xt.fld); \ } \ } \ \ @@ -1995,7 +1999,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \ } \ \ if (sfprf) { \ - helper_compute_fprf(env, xt.fld, sfprf); \ + helper_compute_fprf(env, xt.fld); \ } \ } \ \ @@ -2044,7 +2048,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \ } \ \ if (sfprf) { \ - helper_compute_fprf(env, xt.fld, sfprf); \ + helper_compute_fprf(env, xt.fld); \ } \ } \ \ @@ -2094,7 +2098,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \ } \ \ if (sfprf) { \ - helper_compute_fprf(env, xt.fld, sfprf); \ + helper_compute_fprf(env, xt.fld); \ } \ } \ \ @@ -2294,7 +2298,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \ } \ \ if (sfprf) { \ - helper_compute_fprf(env, xt_out.fld, sfprf); \ + helper_compute_fprf(env, xt_out.fld); \ } \ } \ putVSR(xT(opcode), &xt_out, env); \ @@ -2382,9 +2386,6 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \ VSX_SCALAR_CMP(xscmpodp, 1) VSX_SCALAR_CMP(xscmpudp, 0) -#define float64_snan_to_qnan(x) ((x) | 0x0008000000000000ULL) -#define float32_snan_to_qnan(x) ((x) | 0x00400000) - /* VSX_MAX_MIN - VSX floating point maximum/minimum * name - instruction mnemonic * op - operation (max or min) @@ -2504,7 +2505,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \ } \ if (sfprf) { \ helper_compute_fprf(env, ttp##_to_float64(xt.tfld, \ - &env->fp_status), sfprf); \ + &env->fp_status)); \ } \ } \ \ @@ -2614,7 +2615,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \ xt.tfld = helper_frsp(env, xt.tfld); \ } \ if (sfprf) { \ - helper_compute_fprf(env, xt.tfld, sfprf); \ + helper_compute_fprf(env, xt.tfld); \ } \ } \ \ @@ -2669,7 +2670,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, sfprf); \ + helper_compute_fprf(env, xt.fld); \ } \ } \ \ @@ -2709,7 +2710,7 @@ uint64_t helper_xsrsp(CPUPPCState *env, uint64_t xb) uint64_t xt = helper_frsp(env, xb); - helper_compute_fprf(env, xt, 1); + helper_compute_fprf(env, xt); helper_float_check_status(env); return xt; } diff --git a/target-ppc/helper.h b/target-ppc/helper.h index 210fd97f6a..869be1509d 100644 --- a/target-ppc/helper.h +++ b/target-ppc/helper.h @@ -52,7 +52,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_3(compute_fprf, i32, env, i64, i32) +DEF_HELPER_2(compute_fprf, 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) @@ -665,3 +665,5 @@ DEF_HELPER_4(dscri, void, env, fprp, fprp, i32) DEF_HELPER_4(dscriq, void, env, fprp, fprp, i32) DEF_HELPER_4(dscli, void, env, fprp, fprp, i32) DEF_HELPER_4(dscliq, void, env, fprp, fprp, i32) + +DEF_HELPER_1(tbegin, void, env) diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c index 6843fa0b98..911f91212a 100644 --- a/target-ppc/kvm.c +++ b/target-ppc/kvm.c @@ -2246,8 +2246,23 @@ int kvmppc_save_htab(QEMUFile *f, int fd, size_t bufsize, int64_t max_ns) strerror(errno)); return rc; } else if (rc) { - /* Kernel already retuns data in BE format for the file */ - qemu_put_buffer(f, buf, rc); + uint8_t *buffer = buf; + ssize_t n = rc; + while (n) { + struct kvm_get_htab_header *head = + (struct kvm_get_htab_header *) buffer; + size_t chunksize = sizeof(*head) + + HASH_PTE_SIZE_64 * head->n_valid; + + qemu_put_be32(f, head->index); + qemu_put_be16(f, head->n_valid); + qemu_put_be16(f, head->n_invalid); + qemu_put_buffer(f, (void *)(head + 1), + HASH_PTE_SIZE_64 * head->n_valid); + + buffer += chunksize; + n -= chunksize; + } } } while ((rc != 0) && ((max_ns < 0) @@ -2264,7 +2279,6 @@ int kvmppc_load_htab_chunk(QEMUFile *f, int fd, uint32_t index, ssize_t rc; buf = alloca(chunksize); - /* This is KVM on ppc, so this is all big-endian */ buf->index = index; buf->n_valid = n_valid; buf->n_invalid = n_invalid; diff --git a/target-ppc/mem_helper.c b/target-ppc/mem_helper.c index 50344b81cf..6d37dae7b0 100644 --- a/target-ppc/mem_helper.c +++ b/target-ppc/mem_helper.c @@ -269,3 +269,25 @@ STVE(stvewx, cpu_stl_data, bswap32, u32) #undef HI_IDX #undef LO_IDX + +void helper_tbegin(CPUPPCState *env) +{ + /* As a degenerate implementation, always fail tbegin. The reason + * given is "Nesting overflow". The "persistent" bit is set, + * providing a hint to the error handler to not retry. The TFIAR + * captures the address of the failure, which is this tbegin + * instruction. Instruction execution will continue with the + * next instruction in memory, which is precisely what we want. + */ + + env->spr[SPR_TEXASR] = + (1ULL << TEXASR_FAILURE_PERSISTENT) | + (1ULL << TEXASR_NESTING_OVERFLOW) | + (msr_hv << TEXASR_PRIVILEGE_HV) | + (msr_pr << TEXASR_PRIVILEGE_PR) | + (1ULL << TEXASR_FAILURE_SUMMARY) | + (1ULL << TEXASR_TFIAR_EXACT); + env->spr[SPR_TFIAR] = env->nip | (msr_hv << 1) | msr_pr; + env->spr[SPR_TFHAR] = env->nip + 4; + env->crf[0] = 0xB; /* 0b1010 = transaction failure */ +} diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 2e32e8d8b8..7c801f36e3 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -203,6 +203,7 @@ struct DisasContext { int altivec_enabled; int vsx_enabled; int spe_enabled; + int tm_enabled; ppc_spr_t *spr_cb; /* Needed to check rights for mfspr/mtspr */ int singlestep_enabled; uint64_t insns_flags; @@ -250,26 +251,10 @@ static inline void gen_reset_fpstatus(void) gen_helper_reset_fpstatus(cpu_env); } -static inline void gen_compute_fprf(TCGv_i64 arg, int set_fprf, int set_rc) +static inline void gen_compute_fprf(TCGv_i64 arg) { - TCGv_i32 t0 = tcg_temp_new_i32(); - - if (set_fprf != 0) { - /* This case might be optimized later */ - tcg_gen_movi_i32(t0, 1); - gen_helper_compute_fprf(t0, cpu_env, arg, t0); - if (unlikely(set_rc)) { - tcg_gen_mov_i32(cpu_crf[1], t0); - } - gen_helper_float_check_status(cpu_env); - } else if (unlikely(set_rc)) { - /* We always need to compute fpcc */ - tcg_gen_movi_i32(t0, 0); - gen_helper_compute_fprf(t0, cpu_env, arg, t0); - tcg_gen_mov_i32(cpu_crf[1], t0); - } - - tcg_temp_free_i32(t0); + gen_helper_compute_fprf(cpu_env, arg); + gen_helper_float_check_status(cpu_env); } static inline void gen_set_access_type(DisasContext *ctx, int access_type) @@ -346,11 +331,13 @@ static inline void gen_stop_exception(DisasContext *ctx) ctx->exception = POWERPC_EXCP_STOP; } +#ifndef CONFIG_USER_ONLY /* No need to update nip here, as execution flow will change */ static inline void gen_sync_exception(DisasContext *ctx) { ctx->exception = POWERPC_EXCP_SYNC; } +#endif #define GEN_HANDLER(name, opc1, opc2, opc3, inval, type) \ GEN_OPCODE(name, opc1, opc2, opc3, inval, type, PPC_NONE) @@ -452,7 +439,10 @@ EXTRACT_HELPER(ME, 1, 5); 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); @@ -2077,6 +2067,21 @@ static void gen_srd(DisasContext *ctx) } #endif +#if defined(TARGET_PPC64) +static void gen_set_cr1_from_fpscr(DisasContext *ctx) +{ + TCGv_i32 tmp = tcg_temp_new_i32(); + tcg_gen_trunc_tl_i32(tmp, cpu_fpscr); + tcg_gen_shri_i32(cpu_crf[1], tmp, 28); + tcg_temp_free_i32(tmp); +} +#else +static void gen_set_cr1_from_fpscr(DisasContext *ctx) +{ + tcg_gen_shri_tl(cpu_crf[1], cpu_fpscr, 28); +} +#endif + /*** Floating-Point arithmetic ***/ #define _GEN_FLOAT_ACB(name, op, op1, op2, isfloat, set_fprf, type) \ static void gen_f##name(DisasContext *ctx) \ @@ -2095,8 +2100,12 @@ static void gen_f##name(DisasContext *ctx) \ gen_helper_frsp(cpu_fpr[rD(ctx->opcode)], cpu_env, \ cpu_fpr[rD(ctx->opcode)]); \ } \ - gen_compute_fprf(cpu_fpr[rD(ctx->opcode)], set_fprf, \ - Rc(ctx->opcode) != 0); \ + if (set_fprf) { \ + gen_compute_fprf(cpu_fpr[rD(ctx->opcode)]); \ + } \ + if (unlikely(Rc(ctx->opcode) != 0)) { \ + gen_set_cr1_from_fpscr(ctx); \ + } \ } #define GEN_FLOAT_ACB(name, op2, set_fprf, type) \ @@ -2120,8 +2129,12 @@ static void gen_f##name(DisasContext *ctx) \ gen_helper_frsp(cpu_fpr[rD(ctx->opcode)], cpu_env, \ cpu_fpr[rD(ctx->opcode)]); \ } \ - gen_compute_fprf(cpu_fpr[rD(ctx->opcode)], \ - set_fprf, Rc(ctx->opcode) != 0); \ + if (set_fprf) { \ + gen_compute_fprf(cpu_fpr[rD(ctx->opcode)]); \ + } \ + if (unlikely(Rc(ctx->opcode) != 0)) { \ + gen_set_cr1_from_fpscr(ctx); \ + } \ } #define GEN_FLOAT_AB(name, op2, inval, set_fprf, type) \ _GEN_FLOAT_AB(name, name, 0x3F, op2, inval, 0, set_fprf, type); \ @@ -2144,8 +2157,12 @@ static void gen_f##name(DisasContext *ctx) \ gen_helper_frsp(cpu_fpr[rD(ctx->opcode)], cpu_env, \ cpu_fpr[rD(ctx->opcode)]); \ } \ - gen_compute_fprf(cpu_fpr[rD(ctx->opcode)], \ - set_fprf, Rc(ctx->opcode) != 0); \ + if (set_fprf) { \ + gen_compute_fprf(cpu_fpr[rD(ctx->opcode)]); \ + } \ + if (unlikely(Rc(ctx->opcode) != 0)) { \ + gen_set_cr1_from_fpscr(ctx); \ + } \ } #define GEN_FLOAT_AC(name, op2, inval, set_fprf, type) \ _GEN_FLOAT_AC(name, name, 0x3F, op2, inval, 0, set_fprf, type); \ @@ -2163,8 +2180,12 @@ static void gen_f##name(DisasContext *ctx) \ gen_reset_fpstatus(); \ gen_helper_f##name(cpu_fpr[rD(ctx->opcode)], cpu_env, \ cpu_fpr[rB(ctx->opcode)]); \ - gen_compute_fprf(cpu_fpr[rD(ctx->opcode)], \ - set_fprf, Rc(ctx->opcode) != 0); \ + if (set_fprf) { \ + gen_compute_fprf(cpu_fpr[rD(ctx->opcode)]); \ + } \ + if (unlikely(Rc(ctx->opcode) != 0)) { \ + gen_set_cr1_from_fpscr(ctx); \ + } \ } #define GEN_FLOAT_BS(name, op1, op2, set_fprf, type) \ @@ -2179,8 +2200,12 @@ static void gen_f##name(DisasContext *ctx) \ gen_reset_fpstatus(); \ gen_helper_f##name(cpu_fpr[rD(ctx->opcode)], cpu_env, \ cpu_fpr[rB(ctx->opcode)]); \ - gen_compute_fprf(cpu_fpr[rD(ctx->opcode)], \ - set_fprf, Rc(ctx->opcode) != 0); \ + if (set_fprf) { \ + gen_compute_fprf(cpu_fpr[rD(ctx->opcode)]); \ + } \ + if (unlikely(Rc(ctx->opcode) != 0)) { \ + gen_set_cr1_from_fpscr(ctx); \ + } \ } /* fadd - fadds */ @@ -2213,7 +2238,10 @@ 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)], 1, Rc(ctx->opcode) != 0); + gen_compute_fprf(cpu_fpr[rD(ctx->opcode)]); + if (unlikely(Rc(ctx->opcode) != 0)) { + gen_set_cr1_from_fpscr(ctx); + } } /* fsel */ @@ -2234,7 +2262,10 @@ 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)], 1, Rc(ctx->opcode) != 0); + gen_compute_fprf(cpu_fpr[rD(ctx->opcode)]); + if (unlikely(Rc(ctx->opcode) != 0)) { + gen_set_cr1_from_fpscr(ctx); + } } static void gen_fsqrts(DisasContext *ctx) @@ -2250,7 +2281,10 @@ 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)], 1, Rc(ctx->opcode) != 0); + gen_compute_fprf(cpu_fpr[rD(ctx->opcode)]); + if (unlikely(Rc(ctx->opcode) != 0)) { + gen_set_cr1_from_fpscr(ctx); + } } /*** Floating-Point multiply-and-add ***/ @@ -2370,7 +2404,9 @@ static void gen_fabs(DisasContext *ctx) } 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); + if (unlikely(Rc(ctx->opcode))) { + gen_set_cr1_from_fpscr(ctx); + } } /* fmr - fmr. */ @@ -2382,7 +2418,9 @@ static void gen_fmr(DisasContext *ctx) return; } tcg_gen_mov_i64(cpu_fpr[rD(ctx->opcode)], cpu_fpr[rB(ctx->opcode)]); - gen_compute_fprf(cpu_fpr[rD(ctx->opcode)], 0, Rc(ctx->opcode) != 0); + if (unlikely(Rc(ctx->opcode))) { + gen_set_cr1_from_fpscr(ctx); + } } /* fnabs */ @@ -2395,7 +2433,9 @@ static void gen_fnabs(DisasContext *ctx) } 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); + if (unlikely(Rc(ctx->opcode))) { + gen_set_cr1_from_fpscr(ctx); + } } /* fneg */ @@ -2408,7 +2448,9 @@ static void gen_fneg(DisasContext *ctx) } 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); + if (unlikely(Rc(ctx->opcode))) { + gen_set_cr1_from_fpscr(ctx); + } } /* fcpsgn: PowerPC 2.05 specification */ @@ -2421,7 +2463,9 @@ static void gen_fcpsgn(DisasContext *ctx) } 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); + if (unlikely(Rc(ctx->opcode))) { + gen_set_cr1_from_fpscr(ctx); + } } static void gen_fmrgew(DisasContext *ctx) @@ -2479,7 +2523,9 @@ static void gen_mffs(DisasContext *ctx) } gen_reset_fpstatus(); tcg_gen_extu_tl_i64(cpu_fpr[rD(ctx->opcode)], cpu_fpscr); - gen_compute_fprf(cpu_fpr[rD(ctx->opcode)], 0, Rc(ctx->opcode) != 0); + if (unlikely(Rc(ctx->opcode))) { + gen_set_cr1_from_fpscr(ctx); + } } /* mtfsb0 */ @@ -6743,7 +6789,7 @@ static void gen_st##name(DisasContext *ctx) \ tcg_temp_free(EA); \ } -#define GEN_VR_LVE(name, opc2, opc3) \ +#define GEN_VR_LVE(name, opc2, opc3, size) \ static void gen_lve##name(DisasContext *ctx) \ { \ TCGv EA; \ @@ -6755,13 +6801,16 @@ static void gen_lve##name(DisasContext *ctx) \ gen_set_access_type(ctx, ACCESS_INT); \ EA = tcg_temp_new(); \ gen_addr_reg_index(ctx, EA); \ + if (size > 1) { \ + tcg_gen_andi_tl(EA, EA, ~(size - 1)); \ + } \ rs = gen_avr_ptr(rS(ctx->opcode)); \ gen_helper_lve##name(cpu_env, rs, EA); \ tcg_temp_free(EA); \ tcg_temp_free_ptr(rs); \ } -#define GEN_VR_STVE(name, opc2, opc3) \ +#define GEN_VR_STVE(name, opc2, opc3, size) \ static void gen_stve##name(DisasContext *ctx) \ { \ TCGv EA; \ @@ -6773,6 +6822,9 @@ static void gen_stve##name(DisasContext *ctx) \ gen_set_access_type(ctx, ACCESS_INT); \ EA = tcg_temp_new(); \ gen_addr_reg_index(ctx, EA); \ + if (size > 1) { \ + tcg_gen_andi_tl(EA, EA, ~(size - 1)); \ + } \ rs = gen_avr_ptr(rS(ctx->opcode)); \ gen_helper_stve##name(cpu_env, rs, EA); \ tcg_temp_free(EA); \ @@ -6783,17 +6835,17 @@ GEN_VR_LDX(lvx, 0x07, 0x03); /* As we don't emulate the cache, lvxl is stricly equivalent to lvx */ GEN_VR_LDX(lvxl, 0x07, 0x0B); -GEN_VR_LVE(bx, 0x07, 0x00); -GEN_VR_LVE(hx, 0x07, 0x01); -GEN_VR_LVE(wx, 0x07, 0x02); +GEN_VR_LVE(bx, 0x07, 0x00, 1); +GEN_VR_LVE(hx, 0x07, 0x01, 2); +GEN_VR_LVE(wx, 0x07, 0x02, 4); GEN_VR_STX(svx, 0x07, 0x07); /* As we don't emulate the cache, stvxl is stricly equivalent to stvx */ GEN_VR_STX(svxl, 0x07, 0x0F); -GEN_VR_STVE(bx, 0x07, 0x04); -GEN_VR_STVE(hx, 0x07, 0x05); -GEN_VR_STVE(wx, 0x07, 0x06); +GEN_VR_STVE(bx, 0x07, 0x04, 1); +GEN_VR_STVE(hx, 0x07, 0x05, 2); +GEN_VR_STVE(wx, 0x07, 0x06, 4); static void gen_lvsl(DisasContext *ctx) { @@ -8205,21 +8257,6 @@ static inline TCGv_ptr gen_fprp_ptr(int reg) return r; } -#if defined(TARGET_PPC64) -static void gen_set_cr1_from_fpscr(DisasContext *ctx) -{ - TCGv_i32 tmp = tcg_temp_new_i32(); - tcg_gen_trunc_tl_i32(tmp, cpu_fpscr); - tcg_gen_shri_i32(cpu_crf[1], tmp, 28); - tcg_temp_free_i32(tmp); -} -#else -static void gen_set_cr1_from_fpscr(DisasContext *ctx) -{ - tcg_gen_shri_tl(cpu_crf[1], cpu_fpscr, 28); -} -#endif - #define GEN_DFP_T_A_B_Rc(name) \ static void gen_##name(DisasContext *ctx) \ { \ @@ -9642,6 +9679,88 @@ GEN_SPE(efdctsiz, speundef, 0x1D, 0x0B, 0x00180000, 0xFFFFFFFF, PPC_SPE_DOUBLE GEN_SPE(efdtstgt, efdtstlt, 0x1E, 0x0B, 0x00600000, 0x00600000, PPC_SPE_DOUBLE); // GEN_SPE(efdtsteq, speundef, 0x1F, 0x0B, 0x00600000, 0xFFFFFFFF, PPC_SPE_DOUBLE); // +static void gen_tbegin(DisasContext *ctx) +{ + if (unlikely(!ctx->tm_enabled)) { + gen_exception_err(ctx, POWERPC_EXCP_FU, FSCR_IC_TM); + return; + } + gen_helper_tbegin(cpu_env); +} + +#define GEN_TM_NOOP(name) \ +static inline void gen_##name(DisasContext *ctx) \ +{ \ + if (unlikely(!ctx->tm_enabled)) { \ + gen_exception_err(ctx, POWERPC_EXCP_FU, FSCR_IC_TM); \ + return; \ + } \ + /* Because tbegin always fails in QEMU, these user \ + * space instructions all have a simple implementation: \ + * \ + * CR[0] = 0b0 || MSR[TS] || 0b0 \ + * = 0b0 || 0b00 || 0b0 \ + */ \ + tcg_gen_movi_i32(cpu_crf[0], 0); \ +} + +GEN_TM_NOOP(tend); +GEN_TM_NOOP(tabort); +GEN_TM_NOOP(tabortwc); +GEN_TM_NOOP(tabortwci); +GEN_TM_NOOP(tabortdc); +GEN_TM_NOOP(tabortdci); +GEN_TM_NOOP(tsr); + +static void gen_tcheck(DisasContext *ctx) +{ + if (unlikely(!ctx->tm_enabled)) { + gen_exception_err(ctx, POWERPC_EXCP_FU, FSCR_IC_TM); + return; + } + /* Because tbegin always fails, the tcheck implementation + * is simple: + * + * CR[CRF] = TDOOMED || MSR[TS] || 0b0 + * = 0b1 || 0b00 || 0b0 + */ + tcg_gen_movi_i32(cpu_crf[crfD(ctx->opcode)], 0x8); +} + +#if defined(CONFIG_USER_ONLY) +#define GEN_TM_PRIV_NOOP(name) \ +static inline void gen_##name(DisasContext *ctx) \ +{ \ + gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); \ +} + +#else + +#define GEN_TM_PRIV_NOOP(name) \ +static inline void gen_##name(DisasContext *ctx) \ +{ \ + if (unlikely(ctx->pr)) { \ + gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); \ + return; \ + } \ + if (unlikely(!ctx->tm_enabled)) { \ + gen_exception_err(ctx, POWERPC_EXCP_FU, FSCR_IC_TM); \ + return; \ + } \ + /* Because tbegin always fails, the implementation is \ + * simple: \ + * \ + * CR[0] = 0b0 || MSR[TS] || 0b0 \ + * = 0b0 || 0b00 | 0b0 \ + */ \ + tcg_gen_movi_i32(cpu_crf[0], 0); \ +} + +#endif + +GEN_TM_PRIV_NOOP(treclaim); +GEN_TM_PRIV_NOOP(trechkpt); + static opcode_t opcodes[] = { GEN_HANDLER(invalid, 0x00, 0x00, 0x00, 0xFFFFFFFF, PPC_NONE), GEN_HANDLER(cmp, 0x1F, 0x00, 0x00, 0x00400000, PPC_INTEGER), @@ -11054,6 +11173,29 @@ GEN_SPEOP_LDST(evstwhe, 0x18, 2), GEN_SPEOP_LDST(evstwho, 0x1A, 2), GEN_SPEOP_LDST(evstwwe, 0x1C, 2), GEN_SPEOP_LDST(evstwwo, 0x1E, 2), + +GEN_HANDLER2_E(tbegin, "tbegin", 0x1F, 0x0E, 0x14, 0x01DFF800, \ + PPC_NONE, PPC2_TM), +GEN_HANDLER2_E(tend, "tend", 0x1F, 0x0E, 0x15, 0x01FFF800, \ + PPC_NONE, PPC2_TM), +GEN_HANDLER2_E(tabort, "tabort", 0x1F, 0x0E, 0x1C, 0x03E0F800, \ + PPC_NONE, PPC2_TM), +GEN_HANDLER2_E(tabortwc, "tabortwc", 0x1F, 0x0E, 0x18, 0x00000000, \ + PPC_NONE, PPC2_TM), +GEN_HANDLER2_E(tabortwci, "tabortwci", 0x1F, 0x0E, 0x1A, 0x00000000, \ + PPC_NONE, PPC2_TM), +GEN_HANDLER2_E(tabortdc, "tabortdc", 0x1F, 0x0E, 0x19, 0x00000000, \ + PPC_NONE, PPC2_TM), +GEN_HANDLER2_E(tabortdci, "tabortdci", 0x1F, 0x0E, 0x1B, 0x00000000, \ + PPC_NONE, PPC2_TM), +GEN_HANDLER2_E(tsr, "tsr", 0x1F, 0x0E, 0x17, 0x03DFF800, \ + PPC_NONE, PPC2_TM), +GEN_HANDLER2_E(tcheck, "tcheck", 0x1F, 0x0E, 0x16, 0x007FF800, \ + PPC_NONE, PPC2_TM), +GEN_HANDLER2_E(treclaim, "treclaim", 0x1F, 0x0E, 0x1D, 0x03E0F800, \ + PPC_NONE, PPC2_TM), +GEN_HANDLER2_E(trechkpt, "trechkpt", 0x1F, 0x0E, 0x1F, 0x03FFF800, \ + PPC_NONE, PPC2_TM), }; #include "helper_regs.h" @@ -11311,6 +11453,13 @@ static inline void gen_intermediate_code_internal(PowerPCCPU *cpu, } else { ctx.vsx_enabled = 0; } +#if defined(TARGET_PPC64) + if ((env->flags & POWERPC_FLAG_TM) && msr_tm) { + ctx.tm_enabled = msr_tm; + } else { + ctx.tm_enabled = 0; + } +#endif if ((env->flags & POWERPC_FLAG_SE) && msr_se) ctx.singlestep_enabled = CPU_SINGLE_STEP; else diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index f0a29992df..df1a62c4c6 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -8214,7 +8214,8 @@ POWERPC_FAMILY(POWER8)(ObjectClass *oc, void *data) PPC2_ATOMIC_ISA206 | PPC2_FP_CVT_ISA206 | PPC2_FP_TST_ISA206 | PPC2_BCTAR_ISA207 | PPC2_LSQ_ISA207 | PPC2_ALTIVEC_207 | - PPC2_ISA205 | PPC2_ISA207S | PPC2_FP_CVT_S64; + PPC2_ISA205 | PPC2_ISA207S | PPC2_FP_CVT_S64 | + PPC2_TM; pcc->msr_mask = (1ull << MSR_SF) | (1ull << MSR_TM) | (1ull << MSR_VR) | @@ -8242,7 +8243,7 @@ POWERPC_FAMILY(POWER8)(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 | - POWERPC_FLAG_VSX; + POWERPC_FLAG_VSX | POWERPC_FLAG_TM; pcc->l1_dcache_size = 0x8000; pcc->l1_icache_size = 0x8000; pcc->interrupts_big_endian = ppc_cpu_interrupts_big_endian_lpcr; |