From 5fd46862e5232d1840a9353c99b163f11b49a035 Mon Sep 17 00:00:00 2001 From: pbrook Date: Sat, 17 Mar 2007 01:43:01 +0000 Subject: [PATCH] ARM register index+writeback fix (Lauro Ramos Venancio). git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2481 c046a42c-6fe2-441c-8c8c-71466251a162 --- target-arm/translate.c | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/target-arm/translate.c b/target-arm/translate.c index 055ccfa..4cb9142 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -1537,6 +1537,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s) } } else { int address_offset; + int load; /* Misc load/store */ rn = (insn >> 16) & 0xf; rd = (insn >> 12) & 0xf; @@ -1558,7 +1559,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s) gen_ldst(ldsw, s); break; } - gen_movl_reg_T0(s, rd); + load = 1; } else if (sh & 2) { /* doubleword */ if (sh & 1) { @@ -1568,20 +1569,27 @@ static void disas_arm_insn(CPUState * env, DisasContext *s) gen_op_addl_T1_im(4); gen_movl_T0_reg(s, rd + 1); gen_ldst(stl, s); + load = 0; } else { /* load */ gen_ldst(ldl, s); gen_movl_reg_T0(s, rd); gen_op_addl_T1_im(4); gen_ldst(ldl, s); - gen_movl_reg_T0(s, rd + 1); + rd++; + load = 1; } address_offset = -4; } else { /* store */ gen_movl_T0_reg(s, rd); gen_ldst(stw, s); + load = 0; } + /* Perform base writeback before the loaded value to + ensure correct behavior with overlapping index registers. + ldrd with base writeback is is undefined if the + destination and index registers overlap. */ if (!(insn & (1 << 24))) { gen_add_datah_offset(s, insn, address_offset); gen_movl_reg_T1(s, rn); @@ -1590,6 +1598,10 @@ static void disas_arm_insn(CPUState * env, DisasContext *s) gen_op_addl_T1_im(address_offset); gen_movl_reg_T1(s, rn); } + if (load) { + /* Complete the load. */ + gen_movl_reg_T0(s, rd); + } } break; case 0x4: @@ -1633,10 +1645,6 @@ static void disas_arm_insn(CPUState * env, DisasContext *s) gen_op_ldl_kernel(); } #endif - if (rd == 15) - gen_bx(s); - else - gen_movl_reg_T0(s, rd); } else { /* store */ gen_movl_T0_reg(s, rd); @@ -1665,6 +1673,13 @@ static void disas_arm_insn(CPUState * env, DisasContext *s) } else if (insn & (1 << 21)) gen_movl_reg_T1(s, rn); { } + if (insn & (1 << 20)) { + /* Complete the load. */ + if (rd == 15) + gen_bx(s); + else + gen_movl_reg_T0(s, rd); + } break; case 0x08: case 0x09: -- 2.7.4