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,6 +1537,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s) | ||
1537 | } | 1537 | } |
1538 | } else { | 1538 | } else { |
1539 | int address_offset; | 1539 | int address_offset; |
1540 | + int load; | ||
1540 | /* Misc load/store */ | 1541 | /* Misc load/store */ |
1541 | rn = (insn >> 16) & 0xf; | 1542 | rn = (insn >> 16) & 0xf; |
1542 | rd = (insn >> 12) & 0xf; | 1543 | rd = (insn >> 12) & 0xf; |
@@ -1558,7 +1559,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s) | @@ -1558,7 +1559,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s) | ||
1558 | gen_ldst(ldsw, s); | 1559 | gen_ldst(ldsw, s); |
1559 | break; | 1560 | break; |
1560 | } | 1561 | } |
1561 | - gen_movl_reg_T0(s, rd); | 1562 | + load = 1; |
1562 | } else if (sh & 2) { | 1563 | } else if (sh & 2) { |
1563 | /* doubleword */ | 1564 | /* doubleword */ |
1564 | if (sh & 1) { | 1565 | if (sh & 1) { |
@@ -1568,20 +1569,27 @@ static void disas_arm_insn(CPUState * env, DisasContext *s) | @@ -1568,20 +1569,27 @@ static void disas_arm_insn(CPUState * env, DisasContext *s) | ||
1568 | gen_op_addl_T1_im(4); | 1569 | gen_op_addl_T1_im(4); |
1569 | gen_movl_T0_reg(s, rd + 1); | 1570 | gen_movl_T0_reg(s, rd + 1); |
1570 | gen_ldst(stl, s); | 1571 | gen_ldst(stl, s); |
1572 | + load = 0; | ||
1571 | } else { | 1573 | } else { |
1572 | /* load */ | 1574 | /* load */ |
1573 | gen_ldst(ldl, s); | 1575 | gen_ldst(ldl, s); |
1574 | gen_movl_reg_T0(s, rd); | 1576 | gen_movl_reg_T0(s, rd); |
1575 | gen_op_addl_T1_im(4); | 1577 | gen_op_addl_T1_im(4); |
1576 | gen_ldst(ldl, s); | 1578 | gen_ldst(ldl, s); |
1577 | - gen_movl_reg_T0(s, rd + 1); | 1579 | + rd++; |
1580 | + load = 1; | ||
1578 | } | 1581 | } |
1579 | address_offset = -4; | 1582 | address_offset = -4; |
1580 | } else { | 1583 | } else { |
1581 | /* store */ | 1584 | /* store */ |
1582 | gen_movl_T0_reg(s, rd); | 1585 | gen_movl_T0_reg(s, rd); |
1583 | gen_ldst(stw, s); | 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 | if (!(insn & (1 << 24))) { | 1593 | if (!(insn & (1 << 24))) { |
1586 | gen_add_datah_offset(s, insn, address_offset); | 1594 | gen_add_datah_offset(s, insn, address_offset); |
1587 | gen_movl_reg_T1(s, rn); | 1595 | gen_movl_reg_T1(s, rn); |
@@ -1590,6 +1598,10 @@ static void disas_arm_insn(CPUState * env, DisasContext *s) | @@ -1590,6 +1598,10 @@ static void disas_arm_insn(CPUState * env, DisasContext *s) | ||
1590 | gen_op_addl_T1_im(address_offset); | 1598 | gen_op_addl_T1_im(address_offset); |
1591 | gen_movl_reg_T1(s, rn); | 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 | break; | 1606 | break; |
1595 | case 0x4: | 1607 | case 0x4: |
@@ -1633,10 +1645,6 @@ static void disas_arm_insn(CPUState * env, DisasContext *s) | @@ -1633,10 +1645,6 @@ static void disas_arm_insn(CPUState * env, DisasContext *s) | ||
1633 | gen_op_ldl_kernel(); | 1645 | gen_op_ldl_kernel(); |
1634 | } | 1646 | } |
1635 | #endif | 1647 | #endif |
1636 | - if (rd == 15) | ||
1637 | - gen_bx(s); | ||
1638 | - else | ||
1639 | - gen_movl_reg_T0(s, rd); | ||
1640 | } else { | 1648 | } else { |
1641 | /* store */ | 1649 | /* store */ |
1642 | gen_movl_T0_reg(s, rd); | 1650 | gen_movl_T0_reg(s, rd); |
@@ -1665,6 +1673,13 @@ static void disas_arm_insn(CPUState * env, DisasContext *s) | @@ -1665,6 +1673,13 @@ static void disas_arm_insn(CPUState * env, DisasContext *s) | ||
1665 | } else if (insn & (1 << 21)) | 1673 | } else if (insn & (1 << 21)) |
1666 | gen_movl_reg_T1(s, rn); { | 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 | break; | 1683 | break; |
1669 | case 0x08: | 1684 | case 0x08: |
1670 | case 0x09: | 1685 | case 0x09: |