diff options
author | Peter Maydell <peter.maydell@linaro.org> | 2011-07-22 00:51:19 +0000 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2011-07-26 14:30:54 +0000 |
commit | 934814f1984346af3e95306648cf20195269b098 (patch) | |
tree | 28b34718b3b869c47370589501f16edeecdda4ea /target-arm/translate.c | |
parent | 87f19eb2a5a3ffda5db4ab3bc0c326f2fcd3bcce (diff) | |
download | hqemu-934814f1984346af3e95306648cf20195269b098.zip hqemu-934814f1984346af3e95306648cf20195269b098.tar.gz |
target-arm: Handle UNDEF and UNPREDICTABLE cases for VLDM, VSTM
Handle the UNDEF and UNPREDICTABLE cases for VLDM and VSTM. In
particular, we now generate an undef exception for overlarge imm8
values rather than generating 1000+ TCG ops and hitting an assertion.
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'target-arm/translate.c')
-rw-r--r-- | target-arm/translate.c | 38 |
1 files changed, 31 insertions, 7 deletions
diff --git a/target-arm/translate.c b/target-arm/translate.c index c7961b8..7acb498 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -3397,17 +3397,18 @@ static int disas_vfp_insn(CPUState * env, DisasContext *s, uint32_t insn) VFP_DREG_D(rd, insn); else rd = VFP_SREG_D(insn); - if (s->thumb && rn == 15) { - addr = tcg_temp_new_i32(); - tcg_gen_movi_i32(addr, s->pc & ~2); - } else { - addr = load_reg(s, rn); - } if ((insn & 0x01200000) == 0x01000000) { /* Single load/store */ offset = (insn & 0xff) << 2; if ((insn & (1 << 23)) == 0) offset = -offset; + if (s->thumb && rn == 15) { + /* This is actually UNPREDICTABLE */ + addr = tcg_temp_new_i32(); + tcg_gen_movi_i32(addr, s->pc & ~2); + } else { + addr = load_reg(s, rn); + } tcg_gen_addi_i32(addr, addr, offset); if (insn & (1 << 20)) { gen_vfp_ld(s, dp, addr); @@ -3419,11 +3420,34 @@ static int disas_vfp_insn(CPUState * env, DisasContext *s, uint32_t insn) tcg_temp_free_i32(addr); } else { /* load/store multiple */ + int w = insn & (1 << 21); if (dp) n = (insn >> 1) & 0x7f; else n = insn & 0xff; + if (w && !(((insn >> 23) ^ (insn >> 24)) & 1)) { + /* P == U , W == 1 => UNDEF */ + return 1; + } + if (n == 0 || (rd + n) > 32 || (dp && n > 16)) { + /* UNPREDICTABLE cases for bad immediates: we choose to + * UNDEF to avoid generating huge numbers of TCG ops + */ + return 1; + } + if (rn == 15 && w) { + /* writeback to PC is UNPREDICTABLE, we choose to UNDEF */ + return 1; + } + + if (s->thumb && rn == 15) { + /* This is actually UNPREDICTABLE */ + addr = tcg_temp_new_i32(); + tcg_gen_movi_i32(addr, s->pc & ~2); + } else { + addr = load_reg(s, rn); + } if (insn & (1 << 24)) /* pre-decrement */ tcg_gen_addi_i32(addr, addr, -((insn & 0xff) << 2)); @@ -3443,7 +3467,7 @@ static int disas_vfp_insn(CPUState * env, DisasContext *s, uint32_t insn) } tcg_gen_addi_i32(addr, addr, offset); } - if (insn & (1 << 21)) { + if (w) { /* writeback */ if (insn & (1 << 24)) offset = -offset * n; |