qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] [5891] target-ppc: convert POWER bridge instructions to TCG


From: Aurelien Jarno
Subject: [Qemu-devel] [5891] target-ppc: convert POWER bridge instructions to TCG
Date: Sat, 06 Dec 2008 12:19:15 +0000

Revision: 5891
          http://svn.sv.gnu.org/viewvc/?view=rev&root=qemu&revision=5891
Author:   aurel32
Date:     2008-12-06 12:19:14 +0000 (Sat, 06 Dec 2008)

Log Message:
-----------
target-ppc: convert POWER bridge instructions to TCG

Signed-off-by: Aurelien Jarno <address@hidden>

Modified Paths:
--------------
    trunk/target-ppc/helper.h
    trunk/target-ppc/op.c
    trunk/target-ppc/op_helper.c
    trunk/target-ppc/op_helper.h
    trunk/target-ppc/translate.c

Modified: trunk/target-ppc/helper.h
===================================================================
--- trunk/target-ppc/helper.h   2008-12-06 10:46:35 UTC (rev 5890)
+++ trunk/target-ppc/helper.h   2008-12-06 12:19:14 UTC (rev 5891)
@@ -171,5 +171,13 @@
 #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"

Modified: trunk/target-ppc/op.c
===================================================================
--- trunk/target-ppc/op.c       2008-12-06 10:46:35 UTC (rev 5890)
+++ trunk/target-ppc/op.c       2008-12-06 12:19:14 UTC (rev 5891)
@@ -370,112 +370,6 @@
 }
 #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 @@
     T0 = env->sr[T1];
     RETURN();
 }
-
-void OPPROTO op_POWER_rac (void)
-{
-    do_POWER_rac();
-    RETURN();
-}
 #endif
 
 /* PowerPC 4xx specific micro-ops */

Modified: trunk/target-ppc/op_helper.c
===================================================================
--- trunk/target-ppc/op_helper.c        2008-12-06 10:46:35 UTC (rev 5890)
+++ trunk/target-ppc/op_helper.c        2008-12-06 12:19:14 UTC (rev 5891)
@@ -1587,147 +1587,101 @@
     }
 }
 
-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);
-        env->spr[SPR_MQ] = 0;
+    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 {
-        T0 = (int32_t)T0 / (int32_t)T1;
-        env->spr[SPR_MQ] = (int32_t)T0 % (int32_t)T1;
         env->xer &= ~(1 << XER_OV);
+        env->spr[SPR_MQ] = (int32_t)arg1 % (int32_t)arg2;
+        return (int32_t)arg1 / (int32_t)arg2;
     }
 }
 
-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);
-    } else {
-        env->xer &= ~(1 << XER_OV);
-    }
-}
-
 #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 @@
     /* 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)

Modified: trunk/target-ppc/op_helper.h
===================================================================
--- trunk/target-ppc/op_helper.h        2008-12-06 10:46:35 UTC (rev 5890)
+++ trunk/target-ppc/op_helper.h        2008-12-06 12:19:14 UTC (rev 5891)
@@ -33,15 +33,6 @@
 #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);

Modified: trunk/target-ppc/translate.c
===================================================================
--- trunk/target-ppc/translate.c        2008-12-06 10:46:35 UTC (rev 5890)
+++ trunk/target-ppc/translate.c        2008-12-06 12:19:14 UTC (rev 5891)
@@ -4435,105 +4435,139 @@
 /* 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 @@
 /* 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 @@
 #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
 }
 






reply via email to

[Prev in Thread] Current Thread [Next in Thread]