diff --git a/qemu/target/arm/translate.c b/qemu/target/arm/translate.c index 495cc4c3..080ebb01 100644 --- a/qemu/target/arm/translate.c +++ b/qemu/target/arm/translate.c @@ -193,18 +193,18 @@ static inline void store_cpu_offset(DisasContext *s, TCGv_i32 var, int offset) #define store_cpu_field(s, var, name) \ store_cpu_offset(s, var, offsetof(CPUARMState, name)) +/* The architectural value of PC. */ +static uint32_t read_pc(DisasContext *s) +{ + return s->pc_curr + (s->thumb ? 4 : 8); +} + /* Set a variable to the value of a CPU register. */ static void load_reg_var(DisasContext *s, TCGv_i32 var, int reg) { TCGContext *tcg_ctx = s->uc->tcg_ctx; if (reg == 15) { - uint32_t addr; - /* normally, since we updated PC, we need only to add one insn */ - if (s->thumb) - addr = (long)s->pc + 2; - else - addr = (long)s->pc + 4; - tcg_gen_movi_i32(tcg_ctx, var, addr); + tcg_gen_movi_i32(tcg_ctx, var, read_pc(s)); } else { tcg_gen_mov_i32(tcg_ctx, var, tcg_ctx->cpu_R[reg]); } @@ -8036,16 +8036,14 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn) /* branch link and change to thumb (blx ) */ int32_t offset; - val = (uint32_t)s->pc; tmp = tcg_temp_new_i32(tcg_ctx); - tcg_gen_movi_i32(tcg_ctx, tmp, val); + tcg_gen_movi_i32(tcg_ctx, tmp, s->pc); store_reg(s, 14, tmp); /* Sign-extend the 24-bit offset */ offset = (((int32_t)insn) << 8) >> 8; + val = read_pc(s); /* offset * 4 + bit24 * 2 + (thumb bit) */ val += (offset << 2) | ((insn >> 23) & 2) | 1; - /* pipeline offset */ - val += 4; /* protected by ARCH(5); above, near the start of uncond block */ gen_bx_im(s, val); return; @@ -9321,10 +9319,8 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn) } else { /* store */ if (i == 15) { - /* special case: r15 = PC + 8 */ - val = (long)s->pc + 4; tmp = tcg_temp_new_i32(tcg_ctx); - tcg_gen_movi_i32(tcg_ctx, tmp, val); + tcg_gen_movi_i32(tcg_ctx, tmp, read_pc(s)); } else if (user) { tmp = tcg_temp_new_i32(tcg_ctx); tmp2 = tcg_const_i32(tcg_ctx, i); @@ -9384,15 +9380,13 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn) int32_t offset; /* branch (and link) */ - val = (int32_t)s->pc; if (insn & (1 << 24)) { tmp = tcg_temp_new_i32(tcg_ctx); - tcg_gen_movi_i32(tcg_ctx, tmp, val); + tcg_gen_movi_i32(tcg_ctx, tmp, s->pc); store_reg(s, 14, tmp); } offset = sextract32(insn << 2, 0, 26); - val += offset + 4; - gen_jmp(s, val); + gen_jmp(s, read_pc(s) + offset); } break; case 0xc: @@ -9752,12 +9746,7 @@ static void disas_thumb2_insn(DisasContext *s, uint32_t insn) tcg_temp_free_i32(tcg_ctx, addr); } else if ((insn & (7 << 5)) == 0) { /* Table Branch. */ - if (rn == 15) { - addr = tcg_temp_new_i32(tcg_ctx); - tcg_gen_movi_i32(tcg_ctx, addr, s->pc); - } else { - addr = load_reg(s, rn); - } + addr = load_reg(s, rn); tmp = load_reg(s, rm); tcg_gen_add_i32(tcg_ctx, addr, addr, tmp); if (insn & (1 << 4)) { @@ -9773,7 +9762,7 @@ static void disas_thumb2_insn(DisasContext *s, uint32_t insn) } tcg_temp_free_i32(tcg_ctx, addr); tcg_gen_shli_i32(tcg_ctx, tmp, tmp, 1); - tcg_gen_addi_i32(tcg_ctx, tmp, tmp, s->pc); + tcg_gen_addi_i32(tcg_ctx, tmp, tmp, read_pc(s)); store_reg(s, 15, tmp); } else { bool is_lasr = false; @@ -10506,7 +10495,7 @@ static void disas_thumb2_insn(DisasContext *s, uint32_t insn) tcg_gen_movi_i32(tcg_ctx, tcg_ctx->cpu_R[14], s->pc | 1); } - offset += s->pc; + offset += read_pc(s); if (insn & (1 << 12)) { /* b/bl */ gen_jmp(s, offset); @@ -10747,7 +10736,7 @@ static void disas_thumb2_insn(DisasContext *s, uint32_t insn) offset |= (insn & (1 << 11)) << 8; /* jump to the offset */ - gen_jmp(s, s->pc + offset); + gen_jmp(s, read_pc(s) + offset); } } else { /* @@ -11242,7 +11231,7 @@ static void disas_thumb_insn(DisasContext *s, uint32_t insn) if (insn & (1 << 11)) { rd = (insn >> 8) & 7; /* load pc-relative. Bit 1 of PC is ignored. */ - val = s->pc + 2 + ((insn & 0xff) * 4); + val = read_pc(s) + 2 + ((insn & 0xff) * 4); val &= ~(uint32_t)2; addr = tcg_temp_new_i32(tcg_ctx); tcg_gen_movi_i32(tcg_ctx, addr, val); @@ -11629,7 +11618,7 @@ static void disas_thumb_insn(DisasContext *s, uint32_t insn) } else { /* PC. bit 1 is ignored. */ tmp = tcg_temp_new_i32(tcg_ctx); - tcg_gen_movi_i32(tcg_ctx, tmp, (s->pc + 2) & ~(uint32_t)2); + tcg_gen_movi_i32(tcg_ctx, tmp, read_pc(s) & ~(uint32_t)2); } val = (insn & 0xff) * 4; tcg_gen_addi_i32(tcg_ctx, tmp, tmp, val); @@ -11749,9 +11738,7 @@ static void disas_thumb_insn(DisasContext *s, uint32_t insn) tcg_gen_brcondi_i32(tcg_ctx, TCG_COND_NE, tmp, 0, s->condlabel); tcg_temp_free_i32(tcg_ctx, tmp); offset = ((insn & 0xf8) >> 2) | (insn & 0x200) >> 3; - val = (uint32_t)s->pc + 2; - val += offset; - gen_jmp(s, val); + gen_jmp(s, read_pc(s) + offset); break; case 15: /* IT, nop-hint. */ @@ -11915,7 +11902,7 @@ static void disas_thumb_insn(DisasContext *s, uint32_t insn) arm_skip_unless(s, cond); /* jump to the offset */ - val = (uint32_t)s->pc + 2; + val = read_pc(s); offset = ((int32_t)insn << 24) >> 24; val += offset << 1; gen_jmp(s, val); @@ -11941,9 +11928,9 @@ static void disas_thumb_insn(DisasContext *s, uint32_t insn) break; } /* unconditional branch */ - val = (uint32_t)s->pc; + val = read_pc(s); offset = ((int32_t)insn << 21) >> 21; - val += (offset << 1) + 2; + val += offset << 1; gen_jmp(s, val); break; @@ -11967,7 +11954,7 @@ static void disas_thumb_insn(DisasContext *s, uint32_t insn) /* 0b1111_0xxx_xxxx_xxxx : BL/BLX prefix */ uint32_t uoffset = ((int32_t)insn << 21) >> 9; - tcg_gen_movi_i32(tcg_ctx, tcg_ctx->cpu_R[14], s->pc + 2 + uoffset); + tcg_gen_movi_i32(tcg_ctx, tcg_ctx->cpu_R[14], read_pc(s) + uoffset); } break; }