Commit 5fd46862e5232d1840a9353c99b163f11b49a035
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: | ... | ... |