Commit 358bf29e802e7f03d32dd4ba2064e1bba23a11fa

Authored by pbrook
1 parent cdbdb648

Thumb prefetch abort fix.


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1805 c046a42c-6fe2-441c-8c8c-71466251a162
Showing 1 changed file with 38 additions and 2 deletions
target-arm/translate.c
... ... @@ -2295,8 +2295,21 @@ static void disas_thumb_insn(DisasContext *s)
2295 2295  
2296 2296 case 14:
2297 2297 /* unconditional branch */
2298   - if (insn & (1 << 11))
2299   - goto undef; /* Second half of a blx */
  2298 + if (insn & (1 << 11)) {
  2299 + /* Second half of blx. */
  2300 + offset = ((insn & 0x7ff) << 1);
  2301 + gen_movl_T0_reg(s, 14);
  2302 + gen_op_movl_T1_im(offset);
  2303 + gen_op_addl_T0_T1();
  2304 + gen_op_movl_T1_im(0xfffffffc);
  2305 + gen_op_andl_T0_T1();
  2306 +
  2307 + val = (uint32_t)s->pc;
  2308 + gen_op_movl_T1_im(val | 1);
  2309 + gen_movl_reg_T1(s, 14);
  2310 + gen_bx(s);
  2311 + break;
  2312 + }
2300 2313 val = (uint32_t)s->pc;
2301 2314 offset = ((int32_t)insn << 21) >> 21;
2302 2315 val += (offset << 1) + 2;
... ... @@ -2305,6 +2318,29 @@ static void disas_thumb_insn(DisasContext *s)
2305 2318  
2306 2319 case 15:
2307 2320 /* branch and link [and switch to arm] */
  2321 + if ((s->pc & ~TARGET_PAGE_MASK) == 0) {
  2322 + /* Instruction spans a page boundary. Implement it as two
  2323 + 16-bit instructions in case the second half causes an
  2324 + prefetch abort. */
  2325 + offset = ((int32_t)insn << 21) >> 9;
  2326 + val = s->pc + 2 + offset;
  2327 + gen_op_movl_T0_im(val);
  2328 + gen_movl_reg_T0(s, 14);
  2329 + break;
  2330 + }
  2331 + if (insn & (1 << 11)) {
  2332 + /* Second half of bl. */
  2333 + offset = ((insn & 0x7ff) << 1) | 1;
  2334 + gen_movl_T0_reg(s, 14);
  2335 + gen_op_movl_T1_im(offset);
  2336 + gen_op_addl_T0_T1();
  2337 +
  2338 + val = (uint32_t)s->pc;
  2339 + gen_op_movl_T1_im(val | 1);
  2340 + gen_movl_reg_T1(s, 14);
  2341 + gen_bx(s);
  2342 + break;
  2343 + }
2308 2344 offset = ((int32_t)insn << 21) >> 10;
2309 2345 insn = lduw_code(s->pc);
2310 2346 offset |= insn & 0x7ff;
... ...