Commit 5fd46862e5232d1840a9353c99b163f11b49a035

Authored by pbrook
1 parent 214201bd

ARM register index+writeback fix (Lauro Ramos Venancio).


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2481 c046a42c-6fe2-441c-8c8c-71466251a162
Showing 1 changed file with 21 additions and 6 deletions
target-arm/translate.c
... ... @@ -1537,6 +1537,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
1537 1537 }
1538 1538 } else {
1539 1539 int address_offset;
  1540 + int load;
1540 1541 /* Misc load/store */
1541 1542 rn = (insn >> 16) & 0xf;
1542 1543 rd = (insn >> 12) & 0xf;
... ... @@ -1558,7 +1559,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
1558 1559 gen_ldst(ldsw, s);
1559 1560 break;
1560 1561 }
1561   - gen_movl_reg_T0(s, rd);
  1562 + load = 1;
1562 1563 } else if (sh & 2) {
1563 1564 /* doubleword */
1564 1565 if (sh & 1) {
... ... @@ -1568,20 +1569,27 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
1568 1569 gen_op_addl_T1_im(4);
1569 1570 gen_movl_T0_reg(s, rd + 1);
1570 1571 gen_ldst(stl, s);
  1572 + load = 0;
1571 1573 } else {
1572 1574 /* load */
1573 1575 gen_ldst(ldl, s);
1574 1576 gen_movl_reg_T0(s, rd);
1575 1577 gen_op_addl_T1_im(4);
1576 1578 gen_ldst(ldl, s);
1577   - gen_movl_reg_T0(s, rd + 1);
  1579 + rd++;
  1580 + load = 1;
1578 1581 }
1579 1582 address_offset = -4;
1580 1583 } else {
1581 1584 /* store */
1582 1585 gen_movl_T0_reg(s, rd);
1583 1586 gen_ldst(stw, s);
  1587 + load = 0;
1584 1588 }
  1589 + /* Perform base writeback before the loaded value to
  1590 + ensure correct behavior with overlapping index registers.
  1591 + ldrd with base writeback is is undefined if the
  1592 + destination and index registers overlap. */
1585 1593 if (!(insn & (1 << 24))) {
1586 1594 gen_add_datah_offset(s, insn, address_offset);
1587 1595 gen_movl_reg_T1(s, rn);
... ... @@ -1590,6 +1598,10 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
1590 1598 gen_op_addl_T1_im(address_offset);
1591 1599 gen_movl_reg_T1(s, rn);
1592 1600 }
  1601 + if (load) {
  1602 + /* Complete the load. */
  1603 + gen_movl_reg_T0(s, rd);
  1604 + }
1593 1605 }
1594 1606 break;
1595 1607 case 0x4:
... ... @@ -1633,10 +1645,6 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
1633 1645 gen_op_ldl_kernel();
1634 1646 }
1635 1647 #endif
1636   - if (rd == 15)
1637   - gen_bx(s);
1638   - else
1639   - gen_movl_reg_T0(s, rd);
1640 1648 } else {
1641 1649 /* store */
1642 1650 gen_movl_T0_reg(s, rd);
... ... @@ -1665,6 +1673,13 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
1665 1673 } else if (insn & (1 << 21))
1666 1674 gen_movl_reg_T1(s, rn); {
1667 1675 }
  1676 + if (insn & (1 << 20)) {
  1677 + /* Complete the load. */
  1678 + if (rd == 15)
  1679 + gen_bx(s);
  1680 + else
  1681 + gen_movl_reg_T0(s, rd);
  1682 + }
1668 1683 break;
1669 1684 case 0x08:
1670 1685 case 0x09:
... ...