aboutsummaryrefslogtreecommitdiff
path: root/target/ppc/translate.c
diff options
context:
space:
mode:
Diffstat (limited to 'target/ppc/translate.c')
-rw-r--r--target/ppc/translate.c115
1 files changed, 101 insertions, 14 deletions
diff --git a/target/ppc/translate.c b/target/ppc/translate.c
index 3ba2616b8a..6e6868b7a0 100644
--- a/target/ppc/translate.c
+++ b/target/ppc/translate.c
@@ -71,7 +71,7 @@ static TCGv cpu_lr;
#if defined(TARGET_PPC64)
static TCGv cpu_cfar;
#endif
-static TCGv cpu_xer, cpu_so, cpu_ov, cpu_ca;
+static TCGv cpu_xer, cpu_so, cpu_ov, cpu_ca, cpu_ov32, cpu_ca32;
static TCGv cpu_reserve;
static TCGv cpu_fpscr;
static TCGv_i32 cpu_access_type;
@@ -173,6 +173,10 @@ void ppc_translate_init(void)
offsetof(CPUPPCState, ov), "OV");
cpu_ca = tcg_global_mem_new(cpu_env,
offsetof(CPUPPCState, ca), "CA");
+ cpu_ov32 = tcg_global_mem_new(cpu_env,
+ offsetof(CPUPPCState, ov32), "OV32");
+ cpu_ca32 = tcg_global_mem_new(cpu_env,
+ offsetof(CPUPPCState, ca32), "CA32");
cpu_reserve = tcg_global_mem_new(cpu_env,
offsetof(CPUPPCState, reserve_addr),
@@ -806,12 +810,40 @@ static inline void gen_op_arith_compute_ov(DisasContext *ctx, TCGv arg0,
}
tcg_temp_free(t0);
if (NARROW_MODE(ctx)) {
- tcg_gen_ext32s_tl(cpu_ov, cpu_ov);
+ tcg_gen_extract_tl(cpu_ov, cpu_ov, 31, 1);
+ if (is_isa300(ctx)) {
+ tcg_gen_mov_tl(cpu_ov32, cpu_ov);
+ }
+ } else {
+ if (is_isa300(ctx)) {
+ tcg_gen_extract_tl(cpu_ov32, cpu_ov, 31, 1);
+ }
+ tcg_gen_extract_tl(cpu_ov, cpu_ov, 63, 1);
}
- tcg_gen_shri_tl(cpu_ov, cpu_ov, TARGET_LONG_BITS - 1);
tcg_gen_or_tl(cpu_so, cpu_so, cpu_ov);
}
+static inline void gen_op_arith_compute_ca32(DisasContext *ctx,
+ TCGv res, TCGv arg0, TCGv arg1,
+ int sub)
+{
+ TCGv t0;
+
+ if (!is_isa300(ctx)) {
+ return;
+ }
+
+ t0 = tcg_temp_new();
+ if (sub) {
+ tcg_gen_eqv_tl(t0, arg0, arg1);
+ } else {
+ tcg_gen_xor_tl(t0, arg0, arg1);
+ }
+ tcg_gen_xor_tl(t0, t0, res);
+ tcg_gen_extract_tl(cpu_ca32, t0, 32, 1);
+ tcg_temp_free(t0);
+}
+
/* Common add function */
static inline void gen_op_arith_add(DisasContext *ctx, TCGv ret, TCGv arg1,
TCGv arg2, bool add_ca, bool compute_ca,
@@ -838,6 +870,9 @@ static inline void gen_op_arith_add(DisasContext *ctx, TCGv ret, TCGv arg1,
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);
+ if (is_isa300(ctx)) {
+ tcg_gen_mov_tl(cpu_ca32, cpu_ca);
+ }
} else {
TCGv zero = tcg_const_tl(0);
if (add_ca) {
@@ -846,6 +881,7 @@ static inline void gen_op_arith_add(DisasContext *ctx, TCGv ret, TCGv arg1,
} else {
tcg_gen_add2_tl(t0, cpu_ca, arg1, zero, arg2, zero);
}
+ gen_op_arith_compute_ca32(ctx, t0, arg1, arg2, 0);
tcg_temp_free(zero);
}
} else {
@@ -985,6 +1021,9 @@ static inline void gen_op_arith_divw(DisasContext *ctx, TCGv ret, TCGv arg1,
}
if (compute_ov) {
tcg_gen_extu_i32_tl(cpu_ov, t2);
+ if (is_isa300(ctx)) {
+ tcg_gen_extu_i32_tl(cpu_ov32, t2);
+ }
tcg_gen_or_tl(cpu_so, cpu_so, cpu_ov);
}
tcg_temp_free_i32(t0);
@@ -1056,6 +1095,9 @@ static inline void gen_op_arith_divd(DisasContext *ctx, TCGv ret, TCGv arg1,
}
if (compute_ov) {
tcg_gen_mov_tl(cpu_ov, t2);
+ if (is_isa300(ctx)) {
+ tcg_gen_mov_tl(cpu_ov32, t2);
+ }
tcg_gen_or_tl(cpu_so, cpu_so, cpu_ov);
}
tcg_temp_free_i64(t0);
@@ -1074,10 +1116,10 @@ static void glue(gen_, name)(DisasContext *ctx)
cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)], \
sign, compute_ov); \
}
-/* divwu divwu. divwuo divwuo. */
+/* divdu divdu. divduo divduo. */
GEN_INT_ARITH_DIVD(divdu, 0x0E, 0, 0);
GEN_INT_ARITH_DIVD(divduo, 0x1E, 0, 1);
-/* divw divw. divwo divwo. */
+/* divd divd. divdo divdo. */
GEN_INT_ARITH_DIVD(divd, 0x0F, 1, 0);
GEN_INT_ARITH_DIVD(divdo, 0x1F, 1, 1);
@@ -1249,6 +1291,9 @@ static void gen_mullwo(DisasContext *ctx)
tcg_gen_sari_i32(t0, t0, 31);
tcg_gen_setcond_i32(TCG_COND_NE, t0, t0, t1);
tcg_gen_extu_i32_tl(cpu_ov, t0);
+ if (is_isa300(ctx)) {
+ tcg_gen_mov_tl(cpu_ov32, cpu_ov);
+ }
tcg_gen_or_tl(cpu_so, cpu_so, cpu_ov);
tcg_temp_free_i32(t0);
@@ -1310,6 +1355,9 @@ static void gen_mulldo(DisasContext *ctx)
tcg_gen_sari_i64(t0, t0, 63);
tcg_gen_setcond_i64(TCG_COND_NE, cpu_ov, t0, t1);
+ if (is_isa300(ctx)) {
+ tcg_gen_mov_tl(cpu_ov32, cpu_ov);
+ }
tcg_gen_or_tl(cpu_so, cpu_so, cpu_ov);
tcg_temp_free_i64(t0);
@@ -1353,17 +1401,22 @@ static inline void gen_op_arith_subf(DisasContext *ctx, TCGv ret, TCGv arg1,
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);
+ if (is_isa300(ctx)) {
+ tcg_gen_mov_tl(cpu_ca32, cpu_ca);
+ }
} else if (add_ca) {
TCGv zero, inv1 = tcg_temp_new();
tcg_gen_not_tl(inv1, arg1);
zero = tcg_const_tl(0);
tcg_gen_add2_tl(t0, cpu_ca, arg2, zero, cpu_ca, zero);
tcg_gen_add2_tl(t0, cpu_ca, t0, cpu_ca, inv1, zero);
+ gen_op_arith_compute_ca32(ctx, t0, inv1, arg2, 0);
tcg_temp_free(zero);
tcg_temp_free(inv1);
} else {
tcg_gen_setcond_tl(TCG_COND_GEU, cpu_ca, arg2, arg1);
tcg_gen_sub_tl(t0, arg2, arg1);
+ gen_op_arith_compute_ca32(ctx, t0, arg1, arg2, 1);
}
} else if (add_ca) {
/* Since we're ignoring carry-out, we can simplify the
@@ -1442,7 +1495,10 @@ static inline void gen_op_arith_neg(DisasContext *ctx, bool compute_ov)
static void gen_neg(DisasContext *ctx)
{
- gen_op_arith_neg(ctx, 0);
+ tcg_gen_neg_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]);
+ if (unlikely(Rc(ctx->opcode))) {
+ gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]);
+ }
}
static void gen_nego(DisasContext *ctx)
@@ -3703,7 +3759,7 @@ static void gen_tdi(DisasContext *ctx)
/*** Processor control ***/
-static void gen_read_xer(TCGv dst)
+static void gen_read_xer(DisasContext *ctx, TCGv dst)
{
TCGv t0 = tcg_temp_new();
TCGv t1 = tcg_temp_new();
@@ -3715,6 +3771,12 @@ static void gen_read_xer(TCGv dst)
tcg_gen_or_tl(t0, t0, t1);
tcg_gen_or_tl(dst, dst, t2);
tcg_gen_or_tl(dst, dst, t0);
+ if (is_isa300(ctx)) {
+ tcg_gen_shli_tl(t0, cpu_ov32, XER_OV32);
+ tcg_gen_or_tl(dst, dst, t0);
+ tcg_gen_shli_tl(t0, cpu_ca32, XER_CA32);
+ tcg_gen_or_tl(dst, dst, t0);
+ }
tcg_temp_free(t0);
tcg_temp_free(t1);
tcg_temp_free(t2);
@@ -3722,14 +3784,16 @@ static void gen_read_xer(TCGv dst)
static void gen_write_xer(TCGv src)
{
+ /* Write all flags, while reading back check for isa300 */
tcg_gen_andi_tl(cpu_xer, src,
- ~((1u << XER_SO) | (1u << XER_OV) | (1u << XER_CA)));
- tcg_gen_shri_tl(cpu_so, src, XER_SO);
- tcg_gen_shri_tl(cpu_ov, src, XER_OV);
- tcg_gen_shri_tl(cpu_ca, src, XER_CA);
- tcg_gen_andi_tl(cpu_so, cpu_so, 1);
- tcg_gen_andi_tl(cpu_ov, cpu_ov, 1);
- tcg_gen_andi_tl(cpu_ca, cpu_ca, 1);
+ ~((1u << XER_SO) |
+ (1u << XER_OV) | (1u << XER_OV32) |
+ (1u << XER_CA) | (1u << XER_CA32)));
+ tcg_gen_extract_tl(cpu_ov32, src, XER_OV32, 1);
+ tcg_gen_extract_tl(cpu_ca32, src, XER_CA32, 1);
+ tcg_gen_extract_tl(cpu_so, src, XER_SO, 1);
+ tcg_gen_extract_tl(cpu_ov, src, XER_OV, 1);
+ tcg_gen_extract_tl(cpu_ca, src, XER_CA, 1);
}
/* mcrxr */
@@ -3755,6 +3819,28 @@ static void gen_mcrxr(DisasContext *ctx)
tcg_gen_movi_tl(cpu_ca, 0);
}
+#ifdef TARGET_PPC64
+/* mcrxrx */
+static void gen_mcrxrx(DisasContext *ctx)
+{
+ TCGv t0 = tcg_temp_new();
+ TCGv t1 = tcg_temp_new();
+ TCGv_i32 dst = cpu_crf[crfD(ctx->opcode)];
+
+ /* copy OV and OV32 */
+ tcg_gen_shli_tl(t0, cpu_ov, 1);
+ tcg_gen_or_tl(t0, t0, cpu_ov32);
+ tcg_gen_shli_tl(t0, t0, 2);
+ /* copy CA and CA32 */
+ tcg_gen_shli_tl(t1, cpu_ca, 1);
+ tcg_gen_or_tl(t1, t1, cpu_ca32);
+ tcg_gen_or_tl(t0, t0, t1);
+ tcg_gen_trunc_tl_i32(dst, t0);
+ tcg_temp_free(t0);
+ tcg_temp_free(t1);
+}
+#endif
+
/* mfcr mfocrf */
static void gen_mfcr(DisasContext *ctx)
{
@@ -6424,6 +6510,7 @@ GEN_HANDLER(mtcrf, 0x1F, 0x10, 0x04, 0x00000801, PPC_MISC),
#if defined(TARGET_PPC64)
GEN_HANDLER(mtmsrd, 0x1F, 0x12, 0x05, 0x001EF801, PPC_64B),
GEN_HANDLER_E(setb, 0x1F, 0x00, 0x04, 0x0003F801, PPC_NONE, PPC2_ISA300),
+GEN_HANDLER_E(mcrxrx, 0x1F, 0x00, 0x12, 0x007FF801, PPC_NONE, PPC2_ISA300),
#endif
GEN_HANDLER(mtmsr, 0x1F, 0x12, 0x04, 0x001EF801, PPC_MISC),
GEN_HANDLER(mtspr, 0x1F, 0x13, 0x0E, 0x00000000, PPC_MISC),