diff --git a/qemu/target-arm/translate.c b/qemu/target-arm/translate.c index 8e0eb5b8..4995edac 100644 --- a/qemu/target-arm/translate.c +++ b/qemu/target-arm/translate.c @@ -8532,34 +8532,29 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn) // qq } } else { int address_offset; - int load; + int load = insn & (1 << 20); + int wbit = insn & (1 << 21); + int pbit = insn & (1 << 24); + int doubleword = 0; /* Misc load/store */ rn = (insn >> 16) & 0xf; rd = (insn >> 12) & 0xf; + if (!load && (sh & 2)) { + /* doubleword */ + ARCH(5TE); + if (rd & 1) { + /* UNPREDICTABLE; we choose to UNDEF */ + goto illegal_op; + } + load = (sh & 1) == 0; + doubleword = 1; + } addr = load_reg(s, rn); - if (insn & (1 << 24)) + if (pbit) gen_add_datah_offset(s, insn, 0, addr); address_offset = 0; - if (insn & (1 << 20)) { - /* load */ - tmp = tcg_temp_new_i32(tcg_ctx); - switch(sh) { - case 1: - gen_aa32_ld16u(s, tmp, addr, get_mem_index(s)); - break; - case 2: - gen_aa32_ld8s(s, tmp, addr, get_mem_index(s)); - break; - default: - case 3: - gen_aa32_ld16s(s, tmp, addr, get_mem_index(s)); - break; - } - load = 1; - } else if (sh & 2) { - ARCH(5TE); - /* doubleword */ - if (sh & 1) { + if (doubleword) { + if (!load) { /* store */ tmp = load_reg(s, rd); gen_aa32_st32(s, tmp, addr, get_mem_index(s)); @@ -8568,7 +8563,6 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn) // qq tmp = load_reg(s, rd + 1); gen_aa32_st32(s, tmp, addr, get_mem_index(s)); tcg_temp_free_i32(tcg_ctx, tmp); - load = 0; } else { /* load */ tmp = tcg_temp_new_i32(tcg_ctx); @@ -8578,24 +8572,37 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn) // qq tmp = tcg_temp_new_i32(tcg_ctx); gen_aa32_ld32u(s, tmp, addr, get_mem_index(s)); rd++; - load = 1; } address_offset = -4; + } else if (load) { + /* load */ + tmp = tcg_temp_new_i32(tcg_ctx); + switch(sh) { + case 1: + gen_aa32_ld16u(s, tmp, addr, get_mem_index(s)); + break; + case 2: + gen_aa32_ld8s(s, tmp, addr, get_mem_index(s)); + break; + default: + case 3: + gen_aa32_ld16s(s, tmp, addr, get_mem_index(s)); + break; + } } else { /* store */ tmp = load_reg(s, rd); gen_aa32_st16(s, tmp, addr, get_mem_index(s)); tcg_temp_free_i32(tcg_ctx, tmp); - 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))) { + if (!pbit) { gen_add_datah_offset(s, insn, address_offset, addr); store_reg(s, rn, addr); - } else if (insn & (1 << 21)) { + } else if (wbit) { if (address_offset) tcg_gen_addi_i32(tcg_ctx, addr, addr, address_offset); store_reg(s, rn, addr);