aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEdgar E. Iglesias <edgar.iglesias@gmail.com>2011-01-22 12:39:16 +0100
committerEdgar E. Iglesias <edgar.iglesias@gmail.com>2011-01-22 12:39:16 +0100
commite0a42ebc0831e3ae18e965cc202b5d6649cc38f2 (patch)
tree1b2158cd5d44b15e573794edfc47a8d2e9e70986
parent7e9e4330080f40a964cfed2b334b5e231e967792 (diff)
microblaze: Improve subkc
Move code from the helper into the translator. The remaining helper parts can reuse helper_addkc, making it possible to remove helper_subkc entirely. Signed-off-by: Edgar E. Iglesias <edgar.iglesias@gmail.com>
-rw-r--r--target-microblaze/helper.h1
-rw-r--r--target-microblaze/op_helper.c22
-rw-r--r--target-microblaze/translate.c64
3 files changed, 49 insertions, 38 deletions
diff --git a/target-microblaze/helper.h b/target-microblaze/helper.h
index 4871406f8f..9c2a1e4b6d 100644
--- a/target-microblaze/helper.h
+++ b/target-microblaze/helper.h
@@ -3,7 +3,6 @@
DEF_HELPER_1(raise_exception, void, i32)
DEF_HELPER_0(debug, void)
DEF_HELPER_FLAGS_3(addkc, TCG_CALL_PURE | TCG_CALL_CONST, i32, i32, i32, i32)
-DEF_HELPER_4(subkc, i32, i32, i32, i32, i32)
DEF_HELPER_2(cmp, i32, i32, i32)
DEF_HELPER_2(cmpu, i32, i32, i32)
diff --git a/target-microblaze/op_helper.c b/target-microblaze/op_helper.c
index eb5a8b7df3..59e4674ded 100644
--- a/target-microblaze/op_helper.c
+++ b/target-microblaze/op_helper.c
@@ -138,28 +138,6 @@ uint32_t helper_addkc(uint32_t a, uint32_t b, uint32_t cf)
return ncf;
}
-uint32_t helper_subkc(uint32_t a, uint32_t b, uint32_t k, uint32_t c)
-{
- uint32_t d, cf = 1, ncf;
-
- if (c)
- cf = env->sregs[SR_MSR] >> 31;
- assert(cf == 0 || cf == 1);
- d = b + ~a + cf;
-
- if (!k) {
- ncf = compute_carry(b, ~a, cf);
- assert(ncf == 0 || ncf == 1);
- if (ncf)
- env->sregs[SR_MSR] |= MSR_C | MSR_CC;
- else
- env->sregs[SR_MSR] &= ~(MSR_C | MSR_CC);
- }
- D(qemu_log("%x = %x + %x cf=%d ncf=%d k=%d c=%d\n",
- d, a, b, cf, ncf, k, c));
- return d;
-}
-
static inline int div_prepare(uint32_t a, uint32_t b)
{
if (b == 0) {
diff --git a/target-microblaze/translate.c b/target-microblaze/translate.c
index 264395b74c..0c5edc3583 100644
--- a/target-microblaze/translate.c
+++ b/target-microblaze/translate.c
@@ -247,6 +247,7 @@ static void dec_add(DisasContext *dc)
static void dec_sub(DisasContext *dc)
{
unsigned int u, cmp, k, c;
+ TCGv cf, na;
u = dc->imm & 2;
k = dc->opcode & 4;
@@ -261,24 +262,57 @@ static void dec_sub(DisasContext *dc)
else
gen_helper_cmp(cpu_R[dc->rd], cpu_R[dc->ra], cpu_R[dc->rb]);
}
- } else {
- LOG_DIS("sub%s%s r%d, r%d r%d\n",
- k ? "k" : "", c ? "c" : "", dc->rd, dc->ra, dc->rb);
+ return;
+ }
- if (!k || c) {
- TCGv t;
- t = tcg_temp_new();
- if (dc->rd)
- gen_helper_subkc(cpu_R[dc->rd], cpu_R[dc->ra], *(dec_alu_op_b(dc)),
- tcg_const_tl(k), tcg_const_tl(c));
- else
- gen_helper_subkc(t, cpu_R[dc->ra], *(dec_alu_op_b(dc)),
- tcg_const_tl(k), tcg_const_tl(c));
- tcg_temp_free(t);
- }
- else if (dc->rd)
+ LOG_DIS("sub%s%s r%d, r%d r%d\n",
+ k ? "k" : "", c ? "c" : "", dc->rd, dc->ra, dc->rb);
+
+ /* Take care of the easy cases first. */
+ if (k) {
+ /* k - keep carry, no need to update MSR. */
+ /* If rd == r0, it's a nop. */
+ if (dc->rd) {
tcg_gen_sub_tl(cpu_R[dc->rd], *(dec_alu_op_b(dc)), cpu_R[dc->ra]);
+
+ if (c) {
+ /* c - Add carry into the result. */
+ cf = tcg_temp_new();
+
+ read_carry(dc, cf);
+ tcg_gen_add_tl(cpu_R[dc->rd], cpu_R[dc->rd], cf);
+ tcg_temp_free(cf);
+ }
+ }
+ return;
+ }
+
+ /* From now on, we can assume k is zero. So we need to update MSR. */
+ /* Extract carry. And complement a into na. */
+ cf = tcg_temp_new();
+ na = tcg_temp_new();
+ if (c) {
+ read_carry(dc, cf);
+ } else {
+ tcg_gen_movi_tl(cf, 1);
+ }
+
+ /* d = b + ~a + c. carry defaults to 1. */
+ tcg_gen_not_tl(na, cpu_R[dc->ra]);
+
+ if (dc->rd) {
+ TCGv ncf = tcg_temp_new();
+ gen_helper_addkc(ncf, na, *(dec_alu_op_b(dc)), cf);
+ tcg_gen_add_tl(cpu_R[dc->rd], na, *(dec_alu_op_b(dc)));
+ tcg_gen_add_tl(cpu_R[dc->rd], cpu_R[dc->rd], cf);
+ write_carry(dc, ncf);
+ tcg_temp_free(ncf);
+ } else {
+ gen_helper_addkc(cf, na, *(dec_alu_op_b(dc)), cf);
+ write_carry(dc, cf);
}
+ tcg_temp_free(cf);
+ tcg_temp_free(na);
}
static void dec_pattern(DisasContext *dc)