summaryrefslogtreecommitdiff
path: root/target-ppc
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2015-01-10 19:50:21 +0000
committerPeter Maydell <peter.maydell@linaro.org>2015-01-10 19:50:21 +0000
commit97052d64e4fb934bcf25f4a6b42dc06f6ecbf9eb (patch)
treec4a72adc118c1cc1ca6e0c51c4072158ce3d1bc1 /target-ppc
parente77d927f1a1876ef341b4df287939b0c935703d5 (diff)
parent75c74ccbe1d4175edb79c6f810c2207dcf5edb22 (diff)
downloadqemu-97052d64e4fb934bcf25f4a6b42dc06f6ecbf9eb.tar.gz
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.h26
-rw-r--r--target-ppc/fpu_helper.c85
-rw-r--r--target-ppc/helper.h4
-rw-r--r--target-ppc/kvm.c20
-rw-r--r--target-ppc/mem_helper.c22
-rw-r--r--target-ppc/translate.c271
-rw-r--r--target-ppc/translate_init.c5
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;