aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAurelien Jarno <aurelien@aurel32.net>2010-12-31 17:50:27 +0100
committerAurelien Jarno <aurelien@aurel32.net>2010-12-31 22:22:26 +0100
commit8aac08b10b2e8c131b9385d2dc37e4a02e1d12c1 (patch)
tree2e04d62a85f6bcd15f11cdea14a7e4f83482eabf
parent6d5c34fa027d1477c0572ea74421e21b0f733838 (diff)
target-arm: fix UMAAL instruction
UMAAL should use unsigned multiply instead of signed. This patch fixes this issue by handling UMAAL separately from UMULL/UMLAL/SMULL/SMLAL as these instructions are different enough. It also explicitly list instructions in case and catch nonexistent instruction as illegal. Also fixes a few style issues. This fixes the issues reported in https://bugs.launchpad.net/qemu/+bug/696015 Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
-rw-r--r--target-arm/translate.c32
1 files changed, 22 insertions, 10 deletions
diff --git a/target-arm/translate.c b/target-arm/translate.c
index 8d494ec924..2598268405 100644
--- a/target-arm/translate.c
+++ b/target-arm/translate.c
@@ -6637,26 +6637,38 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
gen_logic_CC(tmp);
store_reg(s, rd, tmp);
break;
- default:
- /* 64 bit mul */
+ case 4:
+ /* 64 bit mul double accumulate (UMAAL) */
+ ARCH(6);
tmp = load_reg(s, rs);
tmp2 = load_reg(s, rm);
- if (insn & (1 << 22))
+ tmp64 = gen_mulu_i64_i32(tmp, tmp2);
+ gen_addq_lo(s, tmp64, rn);
+ gen_addq_lo(s, tmp64, rd);
+ gen_storeq_reg(s, rn, rd, tmp64);
+ tcg_temp_free_i64(tmp64);
+ break;
+ case 8: case 9: case 10: case 11:
+ case 12: case 13: case 14: case 15:
+ /* 64 bit mul: UMULL, UMLAL, SMULL, SMLAL. */
+ tmp = load_reg(s, rs);
+ tmp2 = load_reg(s, rm);
+ if (insn & (1 << 22)) {
tmp64 = gen_muls_i64_i32(tmp, tmp2);
- else
+ } else {
tmp64 = gen_mulu_i64_i32(tmp, tmp2);
- if (insn & (1 << 21)) /* mult accumulate */
+ }
+ if (insn & (1 << 21)) { /* mult accumulate */
gen_addq(s, tmp64, rn, rd);
- if (!(insn & (1 << 23))) { /* double accumulate */
- ARCH(6);
- gen_addq_lo(s, tmp64, rn);
- gen_addq_lo(s, tmp64, rd);
}
- if (insn & (1 << 20))
+ if (insn & (1 << 20)) {
gen_logicq_cc(tmp64);
+ }
gen_storeq_reg(s, rn, rd, tmp64);
tcg_temp_free_i64(tmp64);
break;
+ default:
+ goto illegal_op;
}
} else {
rn = (insn >> 16) & 0xf;