aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAurelien Jarno <aurelien@aurel32.net>2012-09-16 13:12:20 +0200
committerAurelien Jarno <aurelien@aurel32.net>2012-09-21 19:53:16 +0200
commitad8d25a11f13cb8acc69558d03cd69202f5a3cc2 (patch)
tree05f1d6d9cd83669476ae546b87c0a4d83cd26a2d
parent22b88fd77e2fbb8aefb6e50a6a24d670b0ecb022 (diff)
target-sh4: implement addv and subv using TCG
addv and subv helpers implementation is directly copied from the SH4 manual and looks quite complex. It is however possible to explain it without branches, and is therefore possible to implement it with TCG. Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
-rw-r--r--target-sh4/helper.h2
-rw-r--r--target-sh4/op_helper.c58
-rw-r--r--target-sh4/translate.c36
3 files changed, 34 insertions, 62 deletions
diff --git a/target-sh4/helper.h b/target-sh4/helper.h
index 92d6dd7656..a00b7dd1e7 100644
--- a/target-sh4/helper.h
+++ b/target-sh4/helper.h
@@ -13,8 +13,6 @@ DEF_HELPER_3(movcal, void, env, i32, i32)
DEF_HELPER_1(discard_movcal_backup, void, env)
DEF_HELPER_2(ocbi, void, env, i32)
-DEF_HELPER_3(addv, i32, env, i32, i32)
-DEF_HELPER_3(subv, i32, env, i32, i32)
DEF_HELPER_3(div1, i32, env, i32, i32)
DEF_HELPER_3(macl, void, env, i32, i32)
DEF_HELPER_3(macw, void, env, i32, i32)
diff --git a/target-sh4/op_helper.c b/target-sh4/op_helper.c
index 3ad10bab94..4f1f754680 100644
--- a/target-sh4/op_helper.c
+++ b/target-sh4/op_helper.c
@@ -177,35 +177,6 @@ void helper_ocbi(CPUSH4State *env, uint32_t address)
}
}
-uint32_t helper_addv(CPUSH4State *env, uint32_t arg0, uint32_t arg1)
-{
- uint32_t dest, src, ans;
-
- if ((int32_t) arg1 >= 0)
- dest = 0;
- else
- dest = 1;
- if ((int32_t) arg0 >= 0)
- src = 0;
- else
- src = 1;
- src += dest;
- arg1 += arg0;
- if ((int32_t) arg1 >= 0)
- ans = 0;
- else
- ans = 1;
- ans += dest;
- if (src == 0 || src == 2) {
- if (ans == 1)
- env->sr |= SR_T;
- else
- env->sr &= ~SR_T;
- } else
- env->sr &= ~SR_T;
- return arg1;
-}
-
#define T (env->sr & SR_T)
#define Q (env->sr & SR_Q ? 1 : 0)
#define M (env->sr & SR_M ? 1 : 0)
@@ -359,35 +330,6 @@ void helper_macw(CPUSH4State *env, uint32_t arg0, uint32_t arg1)
}
}
-uint32_t helper_subv(CPUSH4State *env, uint32_t arg0, uint32_t arg1)
-{
- int32_t dest, src, ans;
-
- if ((int32_t) arg1 >= 0)
- dest = 0;
- else
- dest = 1;
- if ((int32_t) arg0 >= 0)
- src = 0;
- else
- src = 1;
- src += dest;
- arg1 -= arg0;
- if ((int32_t) arg1 >= 0)
- ans = 0;
- else
- ans = 1;
- ans += dest;
- if (src == 1) {
- if (ans == 1)
- env->sr |= SR_T;
- else
- env->sr &= ~SR_T;
- } else
- env->sr &= ~SR_T;
- return arg1;
-}
-
static inline void set_t(CPUSH4State *env)
{
env->sr |= SR_T;
diff --git a/target-sh4/translate.c b/target-sh4/translate.c
index 92f9b462ff..41a1f228c7 100644
--- a/target-sh4/translate.c
+++ b/target-sh4/translate.c
@@ -781,7 +781,23 @@ static void _decode_opc(DisasContext * ctx)
}
return;
case 0x300f: /* addv Rm,Rn */
- gen_helper_addv(REG(B11_8), cpu_env, REG(B7_4), REG(B11_8));
+ {
+ TCGv t0, t1, t2;
+ t0 = tcg_temp_new();
+ tcg_gen_add_i32(t0, REG(B7_4), REG(B11_8));
+ t1 = tcg_temp_new();
+ tcg_gen_xor_i32(t1, t0, REG(B11_8));
+ t2 = tcg_temp_new();
+ tcg_gen_xor_i32(t2, REG(B7_4), REG(B11_8));
+ tcg_gen_andc_i32(t1, t1, t2);
+ tcg_temp_free(t2);
+ tcg_gen_shri_i32(t1, t1, 31);
+ tcg_gen_andi_i32(cpu_sr, cpu_sr, ~SR_T);
+ tcg_gen_or_i32(cpu_sr, cpu_sr, t1);
+ tcg_temp_free(t1);
+ tcg_gen_mov_i32(REG(B7_4), t0);
+ tcg_temp_free(t0);
+ }
return;
case 0x2009: /* and Rm,Rn */
tcg_gen_and_i32(REG(B11_8), REG(B11_8), REG(B7_4));
@@ -1050,7 +1066,23 @@ static void _decode_opc(DisasContext * ctx)
}
return;
case 0x300b: /* subv Rm,Rn */
- gen_helper_subv(REG(B11_8), cpu_env, REG(B7_4), REG(B11_8));
+ {
+ TCGv t0, t1, t2;
+ t0 = tcg_temp_new();
+ tcg_gen_sub_i32(t0, REG(B11_8), REG(B7_4));
+ t1 = tcg_temp_new();
+ tcg_gen_xor_i32(t1, t0, REG(B7_4));
+ t2 = tcg_temp_new();
+ tcg_gen_xor_i32(t2, REG(B11_8), REG(B7_4));
+ tcg_gen_and_i32(t1, t1, t2);
+ tcg_temp_free(t2);
+ tcg_gen_shri_i32(t1, t1, 31);
+ tcg_gen_andi_i32(cpu_sr, cpu_sr, ~SR_T);
+ tcg_gen_or_i32(cpu_sr, cpu_sr, t1);
+ tcg_temp_free(t1);
+ tcg_gen_mov_i32(REG(B11_8), t0);
+ tcg_temp_free(t0);
+ }
return;
case 0x2008: /* tst Rm,Rn */
{