diff options
author | Edgar E. Iglesias <edgar.iglesias@gmail.com> | 2011-01-22 12:39:16 +0100 |
---|---|---|
committer | Edgar E. Iglesias <edgar.iglesias@gmail.com> | 2011-01-22 12:39:16 +0100 |
commit | e0a42ebc0831e3ae18e965cc202b5d6649cc38f2 (patch) | |
tree | 1b2158cd5d44b15e573794edfc47a8d2e9e70986 /target-microblaze | |
parent | 7e9e4330080f40a964cfed2b334b5e231e967792 (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>
Diffstat (limited to 'target-microblaze')
-rw-r--r-- | target-microblaze/helper.h | 1 | ||||
-rw-r--r-- | target-microblaze/op_helper.c | 22 | ||||
-rw-r--r-- | target-microblaze/translate.c | 64 |
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) |