diff --git a/target-ppc/helper.h b/target-ppc/helper.h index 5a9483e9b3..ddd3f28cbb 100644 --- a/target-ppc/helper.h +++ b/target-ppc/helper.h @@ -171,5 +171,13 @@ DEF_HELPER_1(602_mfrom, tl, tl) #endif DEF_HELPER_3(dlmzb, tl, tl, tl, i32) +DEF_HELPER_1(clcs, tl, i32) +#if !defined(CONFIG_USER_ONLY) +DEF_HELPER_1(rac, tl, tl) +#endif +DEF_HELPER_2(div, tl, tl, tl) +DEF_HELPER_2(divo, tl, tl, tl) +DEF_HELPER_2(divs, tl, tl, tl) +DEF_HELPER_2(divso, tl, tl, tl) #include "def-helper.h" diff --git a/target-ppc/op.c b/target-ppc/op.c index 9d9661a8ec..d3df7fc0c8 100644 --- a/target-ppc/op.c +++ b/target-ppc/op.c @@ -370,112 +370,6 @@ void OPPROTO op_store_601_batu (void) } #endif /* !defined(CONFIG_USER_ONLY) */ -/* PowerPC 601 specific instructions (POWER bridge) */ -/* XXX: those micro-ops need tests ! */ -void OPPROTO op_POWER_abs (void) -{ - if ((int32_t)T0 == INT32_MIN) - T0 = INT32_MAX; - else if ((int32_t)T0 < 0) - T0 = -T0; - RETURN(); -} - -void OPPROTO op_POWER_abso (void) -{ - do_POWER_abso(); - RETURN(); -} - -void OPPROTO op_POWER_clcs (void) -{ - do_POWER_clcs(); - RETURN(); -} - -void OPPROTO op_POWER_div (void) -{ - do_POWER_div(); - RETURN(); -} - -void OPPROTO op_POWER_divo (void) -{ - do_POWER_divo(); - RETURN(); -} - -void OPPROTO op_POWER_divs (void) -{ - do_POWER_divs(); - RETURN(); -} - -void OPPROTO op_POWER_divso (void) -{ - do_POWER_divso(); - RETURN(); -} - -void OPPROTO op_POWER_doz (void) -{ - if ((int32_t)T1 > (int32_t)T0) - T0 = T1 - T0; - else - T0 = 0; - RETURN(); -} - -void OPPROTO op_POWER_dozo (void) -{ - do_POWER_dozo(); - RETURN(); -} - -void OPPROTO op_POWER_maskg (void) -{ - do_POWER_maskg(); - RETURN(); -} - -void OPPROTO op_POWER_maskir (void) -{ - T0 = (T0 & ~T2) | (T1 & T2); - RETURN(); -} - -void OPPROTO op_POWER_mul (void) -{ - uint64_t tmp; - - tmp = (uint64_t)T0 * (uint64_t)T1; - env->spr[SPR_MQ] = tmp >> 32; - T0 = tmp; - RETURN(); -} - -void OPPROTO op_POWER_mulo (void) -{ - do_POWER_mulo(); - RETURN(); -} - -void OPPROTO op_POWER_nabs (void) -{ - if (T0 > 0) - T0 = -T0; - RETURN(); -} - -void OPPROTO op_POWER_nabso (void) -{ - /* nabs never overflows */ - if (T0 > 0) - T0 = -T0; - env->xer &= ~(1 << XER_OV); - RETURN(); -} - /* POWER instructions not implemented in PowerPC 601 */ #if !defined(CONFIG_USER_ONLY) void OPPROTO op_POWER_mfsri (void) @@ -484,12 +378,6 @@ void OPPROTO op_POWER_mfsri (void) T0 = env->sr[T1]; RETURN(); } - -void OPPROTO op_POWER_rac (void) -{ - do_POWER_rac(); - RETURN(); -} #endif /* PowerPC 4xx specific micro-ops */ diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c index de6369a9bb..7f028fa791 100644 --- a/target-ppc/op_helper.c +++ b/target-ppc/op_helper.c @@ -1587,147 +1587,101 @@ void do_POWER_abso (void) } } -void do_POWER_clcs (void) +target_ulong helper_clcs (uint32_t arg) { - switch (T0) { + switch (arg) { case 0x0CUL: /* Instruction cache line size */ - T0 = env->icache_line_size; + return env->icache_line_size; break; case 0x0DUL: /* Data cache line size */ - T0 = env->dcache_line_size; + return env->dcache_line_size; break; case 0x0EUL: /* Minimum cache line size */ - T0 = env->icache_line_size < env->dcache_line_size ? - env->icache_line_size : env->dcache_line_size; + return (env->icache_line_size < env->dcache_line_size) ? + env->icache_line_size : env->dcache_line_size; break; case 0x0FUL: /* Maximum cache line size */ - T0 = env->icache_line_size > env->dcache_line_size ? - env->icache_line_size : env->dcache_line_size; + return (env->icache_line_size > env->dcache_line_size) ? + env->icache_line_size : env->dcache_line_size; break; default: /* Undefined */ + return 0; break; } } -void do_POWER_div (void) +target_ulong helper_div (target_ulong arg1, target_ulong arg2) { - uint64_t tmp; + uint64_t tmp = (uint64_t)arg1 << 32 | env->spr[SPR_MQ]; - if (((int32_t)T0 == INT32_MIN && (int32_t)T1 == (int32_t)-1) || - (int32_t)T1 == 0) { - T0 = UINT32_MAX * ((uint32_t)T0 >> 31); + if (((int32_t)tmp == INT32_MIN && (int32_t)arg2 == (int32_t)-1) || + (int32_t)arg2 == 0) { env->spr[SPR_MQ] = 0; + return INT32_MIN; } else { - tmp = ((uint64_t)T0 << 32) | env->spr[SPR_MQ]; - env->spr[SPR_MQ] = tmp % T1; - T0 = tmp / (int32_t)T1; + env->spr[SPR_MQ] = tmp % arg2; + return tmp / (int32_t)arg2; } } -void do_POWER_divo (void) +target_ulong helper_divo (target_ulong arg1, target_ulong arg2) { - int64_t tmp; + uint64_t tmp = (uint64_t)arg1 << 32 | env->spr[SPR_MQ]; - if (((int32_t)T0 == INT32_MIN && (int32_t)T1 == (int32_t)-1) || - (int32_t)T1 == 0) { - T0 = UINT32_MAX * ((uint32_t)T0 >> 31); - env->spr[SPR_MQ] = 0; + if (((int32_t)tmp == INT32_MIN && (int32_t)arg2 == (int32_t)-1) || + (int32_t)arg2 == 0) { env->xer |= (1 << XER_OV) | (1 << XER_SO); + env->spr[SPR_MQ] = 0; + return INT32_MIN; } else { - tmp = ((uint64_t)T0 << 32) | env->spr[SPR_MQ]; - env->spr[SPR_MQ] = tmp % T1; - tmp /= (int32_t)T1; - if (tmp > (int64_t)INT32_MAX || tmp < (int64_t)INT32_MIN) { + env->spr[SPR_MQ] = tmp % arg2; + tmp /= (int32_t)arg2; + if ((int32_t)tmp != tmp) { env->xer |= (1 << XER_OV) | (1 << XER_SO); } else { env->xer &= ~(1 << XER_OV); } - T0 = tmp; + return tmp; } } -void do_POWER_divs (void) +target_ulong helper_divs (target_ulong arg1, target_ulong arg2) { - if (((int32_t)T0 == INT32_MIN && (int32_t)T1 == (int32_t)-1) || - (int32_t)T1 == 0) { - T0 = UINT32_MAX * ((uint32_t)T0 >> 31); + if (((int32_t)arg1 == INT32_MIN && (int32_t)arg2 == (int32_t)-1) || + (int32_t)arg2 == 0) { env->spr[SPR_MQ] = 0; + return INT32_MIN; } else { - env->spr[SPR_MQ] = T0 % T1; - T0 = (int32_t)T0 / (int32_t)T1; + env->spr[SPR_MQ] = (int32_t)arg1 % (int32_t)arg2; + return (int32_t)arg1 / (int32_t)arg2; } } -void do_POWER_divso (void) +target_ulong helper_divso (target_ulong arg1, target_ulong arg2) { - if (((int32_t)T0 == INT32_MIN && (int32_t)T1 == (int32_t)-1) || - (int32_t)T1 == 0) { - T0 = UINT32_MAX * ((uint32_t)T0 >> 31); + if (((int32_t)arg1 == INT32_MIN && (int32_t)arg2 == (int32_t)-1) || + (int32_t)arg2 == 0) { + env->xer |= (1 << XER_OV) | (1 << XER_SO); env->spr[SPR_MQ] = 0; - env->xer |= (1 << XER_OV) | (1 << XER_SO); - } else { - T0 = (int32_t)T0 / (int32_t)T1; - env->spr[SPR_MQ] = (int32_t)T0 % (int32_t)T1; - env->xer &= ~(1 << XER_OV); - } -} - -void do_POWER_dozo (void) -{ - if ((int32_t)T1 > (int32_t)T0) { - T2 = T0; - T0 = T1 - T0; - if (((uint32_t)(~T2) ^ (uint32_t)T1 ^ UINT32_MAX) & - ((uint32_t)(~T2) ^ (uint32_t)T0) & (1UL << 31)) { - env->xer |= (1 << XER_OV) | (1 << XER_SO); - } else { - env->xer &= ~(1 << XER_OV); - } - } else { - T0 = 0; - env->xer &= ~(1 << XER_OV); - } -} - -void do_POWER_maskg (void) -{ - uint32_t ret; - - if ((uint32_t)T0 == (uint32_t)(T1 + 1)) { - ret = UINT32_MAX; - } else { - ret = (UINT32_MAX >> ((uint32_t)T0)) ^ - ((UINT32_MAX >> ((uint32_t)T1)) >> 1); - if ((uint32_t)T0 > (uint32_t)T1) - ret = ~ret; - } - T0 = ret; -} - -void do_POWER_mulo (void) -{ - uint64_t tmp; - - tmp = (uint64_t)T0 * (uint64_t)T1; - env->spr[SPR_MQ] = tmp >> 32; - T0 = tmp; - if (tmp >> 32 != ((uint64_t)T0 >> 16) * ((uint64_t)T1 >> 16)) { - env->xer |= (1 << XER_OV) | (1 << XER_SO); + return INT32_MIN; } else { env->xer &= ~(1 << XER_OV); + env->spr[SPR_MQ] = (int32_t)arg1 % (int32_t)arg2; + return (int32_t)arg1 / (int32_t)arg2; } } #if !defined (CONFIG_USER_ONLY) -void do_POWER_rac (void) +target_ulong helper_rac (target_ulong addr) { mmu_ctx_t ctx; int nb_BATs; + target_ulong ret = 0; /* We don't have to generate many instances of this instruction, * as rac is supervisor only. @@ -1735,9 +1689,10 @@ void do_POWER_rac (void) /* XXX: FIX THIS: Pretend we have no BAT */ nb_BATs = env->nb_BATs; env->nb_BATs = 0; - if (get_physical_address(env, &ctx, T0, 0, ACCESS_INT) == 0) - T0 = ctx.raddr; + if (get_physical_address(env, &ctx, addr, 0, ACCESS_INT) == 0) + ret = ctx.raddr; env->nb_BATs = nb_BATs; + return ret; } void helper_rfsvc (void) diff --git a/target-ppc/op_helper.h b/target-ppc/op_helper.h index 7ee88340bf..e79526b3d7 100644 --- a/target-ppc/op_helper.h +++ b/target-ppc/op_helper.h @@ -33,15 +33,6 @@ void do_store_msr (void); #endif /* POWER / PowerPC 601 specific helpers */ -void do_POWER_abso (void); -void do_POWER_clcs (void); -void do_POWER_div (void); -void do_POWER_divo (void); -void do_POWER_divs (void); -void do_POWER_divso (void); -void do_POWER_dozo (void); -void do_POWER_maskg (void); -void do_POWER_mulo (void); #if !defined(CONFIG_USER_ONLY) void do_POWER_rac (void); void do_store_hid0_601 (void); diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 8312ccb65b..06d261109a 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -4435,105 +4435,139 @@ GEN_HANDLER(ecowx, 0x1F, 0x16, 0x09, 0x00000001, PPC_EXTERN) /* abs - abs. */ GEN_HANDLER(abs, 0x1F, 0x08, 0x0B, 0x0000F800, PPC_POWER_BR) { - tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rA(ctx->opcode)]); - gen_op_POWER_abs(); - tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]); + int l1 = gen_new_label(); + int l2 = gen_new_label(); + tcg_gen_brcondi_tl(TCG_COND_GE, cpu_gpr[rA(ctx->opcode)], 0, l1); + tcg_gen_neg_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]); + tcg_gen_br(l2); + gen_set_label(l1); + tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]); + gen_set_label(l2); if (unlikely(Rc(ctx->opcode) != 0)) - gen_set_Rc0(ctx, cpu_T[0]); + gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]); } /* abso - abso. */ GEN_HANDLER(abso, 0x1F, 0x08, 0x1B, 0x0000F800, PPC_POWER_BR) { - tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rA(ctx->opcode)]); - gen_op_POWER_abso(); - tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]); + int l1 = gen_new_label(); + int l2 = gen_new_label(); + int l3 = gen_new_label(); + /* Start with XER OV disabled, the most likely case */ + tcg_gen_andi_tl(cpu_xer, cpu_xer, ~(1 << XER_OV)); + tcg_gen_brcondi_tl(TCG_COND_GE, cpu_gpr[rA(ctx->opcode)], 0, l2); + tcg_gen_brcondi_tl(TCG_COND_NE, cpu_gpr[rA(ctx->opcode)], 0x80000000, l1); + tcg_gen_ori_tl(cpu_xer, cpu_xer, (1 << XER_OV) | (1 << XER_SO)); + tcg_gen_br(l2); + gen_set_label(l1); + tcg_gen_neg_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]); + tcg_gen_br(l3); + gen_set_label(l2); + tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]); + gen_set_label(l3); if (unlikely(Rc(ctx->opcode) != 0)) - gen_set_Rc0(ctx, cpu_T[0]); + gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]); } /* clcs */ GEN_HANDLER(clcs, 0x1F, 0x10, 0x13, 0x0000F800, PPC_POWER_BR) { - tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rA(ctx->opcode)]); - gen_op_POWER_clcs(); + TCGv_i32 t0 = tcg_const_i32(rA(ctx->opcode)); + gen_helper_clcs(cpu_gpr[rD(ctx->opcode)], t0); + tcg_temp_free_i32(t0); /* Rc=1 sets CR0 to an undefined state */ - tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]); } /* div - div. */ GEN_HANDLER(div, 0x1F, 0x0B, 0x0A, 0x00000000, PPC_POWER_BR) { - tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rA(ctx->opcode)]); - tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rB(ctx->opcode)]); - gen_op_POWER_div(); - tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]); + gen_helper_div(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]); if (unlikely(Rc(ctx->opcode) != 0)) - gen_set_Rc0(ctx, cpu_T[0]); + gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]); } /* divo - divo. */ GEN_HANDLER(divo, 0x1F, 0x0B, 0x1A, 0x00000000, PPC_POWER_BR) { - tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rA(ctx->opcode)]); - tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rB(ctx->opcode)]); - gen_op_POWER_divo(); - tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]); + gen_helper_divo(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]); if (unlikely(Rc(ctx->opcode) != 0)) - gen_set_Rc0(ctx, cpu_T[0]); + gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]); } /* divs - divs. */ GEN_HANDLER(divs, 0x1F, 0x0B, 0x0B, 0x00000000, PPC_POWER_BR) { - tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rA(ctx->opcode)]); - tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rB(ctx->opcode)]); - gen_op_POWER_divs(); - tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]); + gen_helper_divs(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]); if (unlikely(Rc(ctx->opcode) != 0)) - gen_set_Rc0(ctx, cpu_T[0]); + gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]); } /* divso - divso. */ GEN_HANDLER(divso, 0x1F, 0x0B, 0x1B, 0x00000000, PPC_POWER_BR) { - tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rA(ctx->opcode)]); - tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rB(ctx->opcode)]); - gen_op_POWER_divso(); - tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]); + gen_helper_divso(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]); if (unlikely(Rc(ctx->opcode) != 0)) - gen_set_Rc0(ctx, cpu_T[0]); + gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]); } /* doz - doz. */ GEN_HANDLER(doz, 0x1F, 0x08, 0x08, 0x00000000, PPC_POWER_BR) { - tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rA(ctx->opcode)]); - tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rB(ctx->opcode)]); - gen_op_POWER_doz(); - tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]); + int l1 = gen_new_label(); + int l2 = gen_new_label(); + tcg_gen_brcond_tl(TCG_COND_GE, cpu_gpr[rB(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], l1); + tcg_gen_sub_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rB(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]); + tcg_gen_br(l2); + gen_set_label(l1); + tcg_gen_movi_tl(cpu_gpr[rD(ctx->opcode)], 0); + gen_set_label(l2); if (unlikely(Rc(ctx->opcode) != 0)) - gen_set_Rc0(ctx, cpu_T[0]); + gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]); } /* dozo - dozo. */ GEN_HANDLER(dozo, 0x1F, 0x08, 0x18, 0x00000000, PPC_POWER_BR) { - tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rA(ctx->opcode)]); - tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rB(ctx->opcode)]); - gen_op_POWER_dozo(); - tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]); + int l1 = gen_new_label(); + int l2 = gen_new_label(); + TCGv t0 = tcg_temp_new(); + TCGv t1 = tcg_temp_new(); + TCGv t2 = tcg_temp_new(); + /* Start with XER OV disabled, the most likely case */ + tcg_gen_andi_tl(cpu_xer, cpu_xer, ~(1 << XER_OV)); + tcg_gen_brcond_tl(TCG_COND_GE, cpu_gpr[rB(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], l1); + tcg_gen_sub_tl(t0, cpu_gpr[rB(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]); + tcg_gen_xor_tl(t1, cpu_gpr[rB(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]); + tcg_gen_xor_tl(t2, cpu_gpr[rA(ctx->opcode)], t0); + tcg_gen_andc_tl(t1, t1, t2); + tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], t0); + tcg_gen_brcondi_tl(TCG_COND_GE, t1, 0, l2); + tcg_gen_ori_tl(cpu_xer, cpu_xer, (1 << XER_OV) | (1 << XER_SO)); + tcg_gen_br(l2); + gen_set_label(l1); + tcg_gen_movi_tl(cpu_gpr[rD(ctx->opcode)], 0); + gen_set_label(l2); + tcg_temp_free(t0); + tcg_temp_free(t1); + tcg_temp_free(t2); if (unlikely(Rc(ctx->opcode) != 0)) - gen_set_Rc0(ctx, cpu_T[0]); + gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]); } /* dozi */ GEN_HANDLER(dozi, 0x09, 0xFF, 0xFF, 0x00000000, PPC_POWER_BR) { - tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rA(ctx->opcode)]); - tcg_gen_movi_tl(cpu_T[1], SIMM(ctx->opcode)); - gen_op_POWER_doz(); - tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]); + target_long simm = SIMM(ctx->opcode); + int l1 = gen_new_label(); + int l2 = gen_new_label(); + tcg_gen_brcondi_tl(TCG_COND_LT, cpu_gpr[rA(ctx->opcode)], simm, l1); + tcg_gen_subfi_tl(cpu_gpr[rD(ctx->opcode)], simm, cpu_gpr[rA(ctx->opcode)]); + tcg_gen_br(l2); + gen_set_label(l1); + tcg_gen_movi_tl(cpu_gpr[rD(ctx->opcode)], 0); + gen_set_label(l2); + if (unlikely(Rc(ctx->opcode) != 0)) + gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]); } /* lscbx - lscbx. */ @@ -4561,66 +4595,120 @@ GEN_HANDLER(lscbx, 0x1F, 0x15, 0x08, 0x00000000, PPC_POWER_BR) /* maskg - maskg. */ GEN_HANDLER(maskg, 0x1F, 0x1D, 0x00, 0x00000000, PPC_POWER_BR) { - tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rS(ctx->opcode)]); - tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rB(ctx->opcode)]); - gen_op_POWER_maskg(); - tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], cpu_T[0]); + int l1 = gen_new_label(); + TCGv t0 = tcg_temp_new(); + TCGv t1 = tcg_temp_new(); + TCGv t2 = tcg_temp_new(); + TCGv t3 = tcg_temp_new(); + tcg_gen_movi_tl(t3, 0xFFFFFFFF); + tcg_gen_andi_tl(t0, cpu_gpr[rB(ctx->opcode)], 0x1F); + tcg_gen_andi_tl(t1, cpu_gpr[rS(ctx->opcode)], 0x1F); + tcg_gen_addi_tl(t2, t0, 1); + tcg_gen_shr_tl(t2, t3, t2); + tcg_gen_shr_tl(t3, t3, t1); + tcg_gen_xor_tl(cpu_gpr[rA(ctx->opcode)], t2, t3); + tcg_gen_brcond_tl(TCG_COND_GE, t0, t1, l1); + tcg_gen_neg_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]); + gen_set_label(l1); + tcg_temp_free(t0); + tcg_temp_free(t1); + tcg_temp_free(t2); + tcg_temp_free(t3); if (unlikely(Rc(ctx->opcode) != 0)) - gen_set_Rc0(ctx, cpu_T[0]); + gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]); } /* maskir - maskir. */ GEN_HANDLER(maskir, 0x1F, 0x1D, 0x10, 0x00000000, PPC_POWER_BR) { - tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rA(ctx->opcode)]); - tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rS(ctx->opcode)]); - tcg_gen_mov_tl(cpu_T[2], cpu_gpr[rB(ctx->opcode)]); - gen_op_POWER_maskir(); - tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], cpu_T[0]); + TCGv t0 = tcg_temp_new(); + TCGv t1 = tcg_temp_new(); + tcg_gen_and_tl(t0, cpu_gpr[rS(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]); + tcg_gen_andc_tl(t1, cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]); + tcg_gen_or_tl(cpu_gpr[rA(ctx->opcode)], t0, t1); + tcg_temp_free(t0); + tcg_temp_free(t1); if (unlikely(Rc(ctx->opcode) != 0)) - gen_set_Rc0(ctx, cpu_T[0]); + gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]); } /* mul - mul. */ GEN_HANDLER(mul, 0x1F, 0x0B, 0x03, 0x00000000, PPC_POWER_BR) { - tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rA(ctx->opcode)]); - tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rB(ctx->opcode)]); - gen_op_POWER_mul(); - tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]); + TCGv_i64 t0 = tcg_temp_new_i64(); + TCGv_i64 t1 = tcg_temp_new_i64(); + TCGv t2 = tcg_temp_new(); + tcg_gen_extu_tl_i64(t0, cpu_gpr[rA(ctx->opcode)]); + tcg_gen_extu_tl_i64(t1, cpu_gpr[rB(ctx->opcode)]); + tcg_gen_mul_i64(t0, t0, t1); + tcg_gen_trunc_i64_tl(t2, t0); + gen_store_spr(SPR_MQ, t2); + tcg_gen_shri_i64(t1, t0, 32); + tcg_gen_trunc_i64_tl(cpu_gpr[rD(ctx->opcode)], t1); + tcg_temp_free_i64(t0); + tcg_temp_free_i64(t1); + tcg_temp_free(t2); if (unlikely(Rc(ctx->opcode) != 0)) - gen_set_Rc0(ctx, cpu_T[0]); + gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]); } /* mulo - mulo. */ GEN_HANDLER(mulo, 0x1F, 0x0B, 0x13, 0x00000000, PPC_POWER_BR) { - tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rA(ctx->opcode)]); - tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rB(ctx->opcode)]); - gen_op_POWER_mulo(); - tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]); + int l1 = gen_new_label(); + TCGv_i64 t0 = tcg_temp_new_i64(); + TCGv_i64 t1 = tcg_temp_new_i64(); + TCGv t2 = tcg_temp_new(); + /* Start with XER OV disabled, the most likely case */ + tcg_gen_andi_tl(cpu_xer, cpu_xer, ~(1 << XER_OV)); + tcg_gen_extu_tl_i64(t0, cpu_gpr[rA(ctx->opcode)]); + tcg_gen_extu_tl_i64(t1, cpu_gpr[rB(ctx->opcode)]); + tcg_gen_mul_i64(t0, t0, t1); + tcg_gen_trunc_i64_tl(t2, t0); + gen_store_spr(SPR_MQ, t2); + tcg_gen_shri_i64(t1, t0, 32); + tcg_gen_trunc_i64_tl(cpu_gpr[rD(ctx->opcode)], t1); + tcg_gen_ext32s_i64(t1, t0); + tcg_gen_brcond_i64(TCG_COND_EQ, t0, t1, l1); + tcg_gen_ori_tl(cpu_xer, cpu_xer, (1 << XER_OV) | (1 << XER_SO)); + gen_set_label(l1); + tcg_temp_free_i64(t0); + tcg_temp_free_i64(t1); + tcg_temp_free(t2); if (unlikely(Rc(ctx->opcode) != 0)) - gen_set_Rc0(ctx, cpu_T[0]); + gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]); } /* nabs - nabs. */ GEN_HANDLER(nabs, 0x1F, 0x08, 0x0F, 0x00000000, PPC_POWER_BR) { - tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rA(ctx->opcode)]); - gen_op_POWER_nabs(); - tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]); + int l1 = gen_new_label(); + int l2 = gen_new_label(); + tcg_gen_brcondi_tl(TCG_COND_GT, cpu_gpr[rA(ctx->opcode)], 0, l1); + tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]); + tcg_gen_br(l2); + gen_set_label(l1); + tcg_gen_neg_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]); + gen_set_label(l2); if (unlikely(Rc(ctx->opcode) != 0)) - gen_set_Rc0(ctx, cpu_T[0]); + gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]); } /* nabso - nabso. */ GEN_HANDLER(nabso, 0x1F, 0x08, 0x1F, 0x00000000, PPC_POWER_BR) { - tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rA(ctx->opcode)]); - gen_op_POWER_nabso(); - tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]); + int l1 = gen_new_label(); + int l2 = gen_new_label(); + tcg_gen_brcondi_tl(TCG_COND_GT, cpu_gpr[rA(ctx->opcode)], 0, l1); + tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]); + tcg_gen_br(l2); + gen_set_label(l1); + tcg_gen_neg_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]); + gen_set_label(l2); + /* nabs never overflows */ + tcg_gen_andi_tl(cpu_xer, cpu_xer, ~(1 << XER_OV)); if (unlikely(Rc(ctx->opcode) != 0)) - gen_set_Rc0(ctx, cpu_T[0]); + gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]); } /* rlmi - rlmi. */ @@ -5122,13 +5210,15 @@ GEN_HANDLER(rac, 0x1F, 0x12, 0x19, 0x00000001, PPC_POWER) #if defined(CONFIG_USER_ONLY) GEN_EXCP_PRIVOPC(ctx); #else + TCGv t0; if (unlikely(!ctx->supervisor)) { GEN_EXCP_PRIVOPC(ctx); return; } - gen_addr_reg_index(cpu_T[0], ctx); - gen_op_POWER_rac(); - tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]); + t0 = tcg_temp_new(); + gen_addr_reg_index(t0, ctx); + gen_helper_rac(cpu_gpr[rD(ctx->opcode)], t0); + tcg_temp_free(t0); #endif }