summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--target-ppc/helper.h8
-rw-r--r--target-ppc/op.c112
-rw-r--r--target-ppc/op_helper.c133
-rw-r--r--target-ppc/op_helper.h9
-rw-r--r--target-ppc/translate.c244
5 files changed, 219 insertions, 287 deletions
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);
- } 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->xer |= (1 << XER_OV) | (1 << XER_SO);
- } else {
- env->xer &= ~(1 << XER_OV);
- }
- T0 = tmp;
- }
-}
-
-void do_POWER_divs (void)
-{
- 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;
- } else {
- env->spr[SPR_MQ] = T0 % T1;
- T0 = (int32_t)T0 / (int32_t)T1;
- }
-}
-
-void do_POWER_divso (void)
-{
- 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;
- env->xer |= (1 << XER_OV) | (1 << XER_SO);
+ return INT32_MIN;
} 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->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);
}
- } else {
- T0 = 0;
- env->xer &= ~(1 << XER_OV);
+ return tmp;
}
}
-void do_POWER_maskg (void)
+target_ulong helper_divs (target_ulong arg1, target_ulong arg2)
{
- uint32_t ret;
-
- if ((uint32_t)T0 == (uint32_t)(T1 + 1)) {
- ret = UINT32_MAX;
+ 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 {
- ret = (UINT32_MAX >> ((uint32_t)T0)) ^
- ((UINT32_MAX >> ((uint32_t)T1)) >> 1);
- if ((uint32_t)T0 > (uint32_t)T1)
- ret = ~ret;
+ env->spr[SPR_MQ] = (int32_t)arg1 % (int32_t)arg2;
+ return (int32_t)arg1 / (int32_t)arg2;
}
- T0 = ret;
}
-void do_POWER_mulo (void)
+target_ulong helper_divso (target_ulong arg1, target_ulong arg2)
{
- 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)) {
+ 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;
+ 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
}