From 358bf29e802e7f03d32dd4ba2064e1bba23a11fa Mon Sep 17 00:00:00 2001 From: pbrook Date: Sun, 9 Apr 2006 14:38:57 +0000 Subject: [PATCH] Thumb prefetch abort fix. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1805 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-arm/translate.c | 40 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 38 insertions(+), 2 deletions(-) diff --git a/target-arm/translate.c b/target-arm/translate.c index 1f8a4853bb..e6e8c6835a 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -2295,8 +2295,21 @@ static void disas_thumb_insn(DisasContext *s) case 14: /* unconditional branch */ - if (insn & (1 << 11)) - goto undef; /* Second half of a blx */ + if (insn & (1 << 11)) { + /* Second half of blx. */ + offset = ((insn & 0x7ff) << 1); + gen_movl_T0_reg(s, 14); + gen_op_movl_T1_im(offset); + gen_op_addl_T0_T1(); + gen_op_movl_T1_im(0xfffffffc); + gen_op_andl_T0_T1(); + + val = (uint32_t)s->pc; + gen_op_movl_T1_im(val | 1); + gen_movl_reg_T1(s, 14); + gen_bx(s); + break; + } val = (uint32_t)s->pc; offset = ((int32_t)insn << 21) >> 21; val += (offset << 1) + 2; @@ -2305,6 +2318,29 @@ static void disas_thumb_insn(DisasContext *s) case 15: /* branch and link [and switch to arm] */ + if ((s->pc & ~TARGET_PAGE_MASK) == 0) { + /* Instruction spans a page boundary. Implement it as two + 16-bit instructions in case the second half causes an + prefetch abort. */ + offset = ((int32_t)insn << 21) >> 9; + val = s->pc + 2 + offset; + gen_op_movl_T0_im(val); + gen_movl_reg_T0(s, 14); + break; + } + if (insn & (1 << 11)) { + /* Second half of bl. */ + offset = ((insn & 0x7ff) << 1) | 1; + gen_movl_T0_reg(s, 14); + gen_op_movl_T1_im(offset); + gen_op_addl_T0_T1(); + + val = (uint32_t)s->pc; + gen_op_movl_T1_im(val | 1); + gen_movl_reg_T1(s, 14); + gen_bx(s); + break; + } offset = ((int32_t)insn << 21) >> 10; insn = lduw_code(s->pc); offset |= insn & 0x7ff;