|
@@ -162,7 +162,7 @@ uint64_t asimd_imm_const(uint32_t imm, int cmode, int op)
|
|
|
void arm_gen_condlabel(DisasContext *s)
|
|
|
{
|
|
|
if (!s->condjmp) {
|
|
|
- s->condlabel = gen_new_label();
|
|
|
+ s->condlabel = gen_disas_label(s);
|
|
|
s->condjmp = 1;
|
|
|
}
|
|
|
}
|
|
@@ -260,17 +260,27 @@ static inline int get_a32_user_mem_index(DisasContext *s)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-/* The architectural value of PC. */
|
|
|
-static uint32_t read_pc(DisasContext *s)
|
|
|
+/* The pc_curr difference for an architectural jump. */
|
|
|
+static target_long jmp_diff(DisasContext *s, target_long diff)
|
|
|
{
|
|
|
- return s->pc_curr + (s->thumb ? 4 : 8);
|
|
|
+ return diff + (s->thumb ? 4 : 8);
|
|
|
+}
|
|
|
+
|
|
|
+static void gen_pc_plus_diff(DisasContext *s, TCGv_i32 var, target_long diff)
|
|
|
+{
|
|
|
+ assert(s->pc_save != -1);
|
|
|
+ if (TARGET_TB_PCREL) {
|
|
|
+ tcg_gen_addi_i32(var, cpu_R[15], (s->pc_curr - s->pc_save) + diff);
|
|
|
+ } else {
|
|
|
+ tcg_gen_movi_i32(var, s->pc_curr + diff);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
/* Set a variable to the value of a CPU register. */
|
|
|
void load_reg_var(DisasContext *s, TCGv_i32 var, int reg)
|
|
|
{
|
|
|
if (reg == 15) {
|
|
|
- tcg_gen_movi_i32(var, read_pc(s));
|
|
|
+ gen_pc_plus_diff(s, var, jmp_diff(s, 0));
|
|
|
} else {
|
|
|
tcg_gen_mov_i32(var, cpu_R[reg]);
|
|
|
}
|
|
@@ -286,7 +296,11 @@ TCGv_i32 add_reg_for_lit(DisasContext *s, int reg, int ofs)
|
|
|
TCGv_i32 tmp = tcg_temp_new_i32();
|
|
|
|
|
|
if (reg == 15) {
|
|
|
- tcg_gen_movi_i32(tmp, (read_pc(s) & ~3) + ofs);
|
|
|
+ /*
|
|
|
+ * This address is computed from an aligned PC:
|
|
|
+ * subtract off the low bits.
|
|
|
+ */
|
|
|
+ gen_pc_plus_diff(s, tmp, jmp_diff(s, ofs - (s->pc_curr & 3)));
|
|
|
} else {
|
|
|
tcg_gen_addi_i32(tmp, cpu_R[reg], ofs);
|
|
|
}
|
|
@@ -305,6 +319,7 @@ void store_reg(DisasContext *s, int reg, TCGv_i32 var)
|
|
|
*/
|
|
|
tcg_gen_andi_i32(var, var, s->thumb ? ~1 : ~3);
|
|
|
s->base.is_jmp = DISAS_JUMP;
|
|
|
+ s->pc_save = -1;
|
|
|
} else if (reg == 13 && arm_dc_feature(s, ARM_FEATURE_M)) {
|
|
|
/* For M-profile SP bits [1:0] are always zero */
|
|
|
tcg_gen_andi_i32(var, var, ~3);
|
|
@@ -768,9 +783,10 @@ void gen_set_condexec(DisasContext *s)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-void gen_set_pc_im(DisasContext *s, target_ulong val)
|
|
|
+void gen_update_pc(DisasContext *s, target_long diff)
|
|
|
{
|
|
|
- tcg_gen_movi_i32(cpu_R[15], val);
|
|
|
+ gen_pc_plus_diff(s, cpu_R[15], diff);
|
|
|
+ s->pc_save = s->pc_curr + diff;
|
|
|
}
|
|
|
|
|
|
/* Set PC and Thumb state from var. var is marked as dead. */
|
|
@@ -780,6 +796,7 @@ static inline void gen_bx(DisasContext *s, TCGv_i32 var)
|
|
|
tcg_gen_andi_i32(cpu_R[15], var, ~1);
|
|
|
tcg_gen_andi_i32(var, var, 1);
|
|
|
store_cpu_field(var, thumb);
|
|
|
+ s->pc_save = -1;
|
|
|
}
|
|
|
|
|
|
/*
|
|
@@ -821,7 +838,7 @@ static inline void gen_bx_excret(DisasContext *s, TCGv_i32 var)
|
|
|
static inline void gen_bx_excret_final_code(DisasContext *s)
|
|
|
{
|
|
|
/* Generate the code to finish possible exception return and end the TB */
|
|
|
- TCGLabel *excret_label = gen_new_label();
|
|
|
+ DisasLabel excret_label = gen_disas_label(s);
|
|
|
uint32_t min_magic;
|
|
|
|
|
|
if (arm_dc_feature(s, ARM_FEATURE_M_SECURITY)) {
|
|
@@ -833,14 +850,14 @@ static inline void gen_bx_excret_final_code(DisasContext *s)
|
|
|
}
|
|
|
|
|
|
/* Is the new PC value in the magic range indicating exception return? */
|
|
|
- tcg_gen_brcondi_i32(TCG_COND_GEU, cpu_R[15], min_magic, excret_label);
|
|
|
+ tcg_gen_brcondi_i32(TCG_COND_GEU, cpu_R[15], min_magic, excret_label.label);
|
|
|
/* No: end the TB as we would for a DISAS_JMP */
|
|
|
if (s->ss_active) {
|
|
|
gen_singlestep_exception(s);
|
|
|
} else {
|
|
|
tcg_gen_exit_tb(NULL, 0);
|
|
|
}
|
|
|
- gen_set_label(excret_label);
|
|
|
+ set_disas_label(s, excret_label);
|
|
|
/* Yes: this is an exception return.
|
|
|
* At this point in runtime env->regs[15] and env->thumb will hold
|
|
|
* the exception-return magic number, which do_v7m_exception_exit()
|
|
@@ -862,7 +879,7 @@ static inline void gen_bxns(DisasContext *s, int rm)
|
|
|
|
|
|
/* The bxns helper may raise an EXCEPTION_EXIT exception, so in theory
|
|
|
* we need to sync state before calling it, but:
|
|
|
- * - we don't need to do gen_set_pc_im() because the bxns helper will
|
|
|
+ * - we don't need to do gen_update_pc() because the bxns helper will
|
|
|
* always set the PC itself
|
|
|
* - we don't need to do gen_set_condexec() because BXNS is UNPREDICTABLE
|
|
|
* unless it's outside an IT block or the last insn in an IT block,
|
|
@@ -883,7 +900,7 @@ static inline void gen_blxns(DisasContext *s, int rm)
|
|
|
* We do however need to set the PC, because the blxns helper reads it.
|
|
|
* The blxns helper may throw an exception.
|
|
|
*/
|
|
|
- gen_set_pc_im(s, s->base.pc_next);
|
|
|
+ gen_update_pc(s, curr_insn_len(s));
|
|
|
gen_helper_v7m_blxns(cpu_env, var);
|
|
|
tcg_temp_free_i32(var);
|
|
|
s->base.is_jmp = DISAS_EXIT;
|
|
@@ -1051,7 +1068,7 @@ static inline void gen_hvc(DisasContext *s, int imm16)
|
|
|
* as an undefined insn by runtime configuration (ie before
|
|
|
* the insn really executes).
|
|
|
*/
|
|
|
- gen_set_pc_im(s, s->pc_curr);
|
|
|
+ gen_update_pc(s, 0);
|
|
|
gen_helper_pre_hvc(cpu_env);
|
|
|
/* Otherwise we will treat this as a real exception which
|
|
|
* happens after execution of the insn. (The distinction matters
|
|
@@ -1059,7 +1076,7 @@ static inline void gen_hvc(DisasContext *s, int imm16)
|
|
|
* for single stepping.)
|
|
|
*/
|
|
|
s->svc_imm = imm16;
|
|
|
- gen_set_pc_im(s, s->base.pc_next);
|
|
|
+ gen_update_pc(s, curr_insn_len(s));
|
|
|
s->base.is_jmp = DISAS_HVC;
|
|
|
}
|
|
|
|
|
@@ -1068,16 +1085,16 @@ static inline void gen_smc(DisasContext *s)
|
|
|
/* As with HVC, we may take an exception either before or after
|
|
|
* the insn executes.
|
|
|
*/
|
|
|
- gen_set_pc_im(s, s->pc_curr);
|
|
|
+ gen_update_pc(s, 0);
|
|
|
gen_helper_pre_smc(cpu_env, tcg_constant_i32(syn_aa32_smc()));
|
|
|
- gen_set_pc_im(s, s->base.pc_next);
|
|
|
+ gen_update_pc(s, curr_insn_len(s));
|
|
|
s->base.is_jmp = DISAS_SMC;
|
|
|
}
|
|
|
|
|
|
-static void gen_exception_internal_insn(DisasContext *s, uint32_t pc, int excp)
|
|
|
+static void gen_exception_internal_insn(DisasContext *s, int excp)
|
|
|
{
|
|
|
gen_set_condexec(s);
|
|
|
- gen_set_pc_im(s, pc);
|
|
|
+ gen_update_pc(s, 0);
|
|
|
gen_exception_internal(excp);
|
|
|
s->base.is_jmp = DISAS_NORETURN;
|
|
|
}
|
|
@@ -1099,32 +1116,34 @@ static void gen_exception(int excp, uint32_t syndrome)
|
|
|
tcg_constant_i32(syndrome));
|
|
|
}
|
|
|
|
|
|
-static void gen_exception_insn_el_v(DisasContext *s, uint64_t pc, int excp,
|
|
|
- uint32_t syn, TCGv_i32 tcg_el)
|
|
|
+static void gen_exception_insn_el_v(DisasContext *s, target_long pc_diff,
|
|
|
+ int excp, uint32_t syn, TCGv_i32 tcg_el)
|
|
|
{
|
|
|
if (s->aarch64) {
|
|
|
- gen_a64_set_pc_im(pc);
|
|
|
+ gen_a64_update_pc(s, pc_diff);
|
|
|
} else {
|
|
|
gen_set_condexec(s);
|
|
|
- gen_set_pc_im(s, pc);
|
|
|
+ gen_update_pc(s, pc_diff);
|
|
|
}
|
|
|
gen_exception_el_v(excp, syn, tcg_el);
|
|
|
s->base.is_jmp = DISAS_NORETURN;
|
|
|
}
|
|
|
|
|
|
-void gen_exception_insn_el(DisasContext *s, uint64_t pc, int excp,
|
|
|
+void gen_exception_insn_el(DisasContext *s, target_long pc_diff, int excp,
|
|
|
uint32_t syn, uint32_t target_el)
|
|
|
{
|
|
|
- gen_exception_insn_el_v(s, pc, excp, syn, tcg_constant_i32(target_el));
|
|
|
+ gen_exception_insn_el_v(s, pc_diff, excp, syn,
|
|
|
+ tcg_constant_i32(target_el));
|
|
|
}
|
|
|
|
|
|
-void gen_exception_insn(DisasContext *s, uint64_t pc, int excp, uint32_t syn)
|
|
|
+void gen_exception_insn(DisasContext *s, target_long pc_diff,
|
|
|
+ int excp, uint32_t syn)
|
|
|
{
|
|
|
if (s->aarch64) {
|
|
|
- gen_a64_set_pc_im(pc);
|
|
|
+ gen_a64_update_pc(s, pc_diff);
|
|
|
} else {
|
|
|
gen_set_condexec(s);
|
|
|
- gen_set_pc_im(s, pc);
|
|
|
+ gen_update_pc(s, pc_diff);
|
|
|
}
|
|
|
gen_exception(excp, syn);
|
|
|
s->base.is_jmp = DISAS_NORETURN;
|
|
@@ -1133,7 +1152,7 @@ void gen_exception_insn(DisasContext *s, uint64_t pc, int excp, uint32_t syn)
|
|
|
static void gen_exception_bkpt_insn(DisasContext *s, uint32_t syn)
|
|
|
{
|
|
|
gen_set_condexec(s);
|
|
|
- gen_set_pc_im(s, s->pc_curr);
|
|
|
+ gen_update_pc(s, 0);
|
|
|
gen_helper_exception_bkpt_insn(cpu_env, tcg_constant_i32(syn));
|
|
|
s->base.is_jmp = DISAS_NORETURN;
|
|
|
}
|
|
@@ -1141,13 +1160,13 @@ static void gen_exception_bkpt_insn(DisasContext *s, uint32_t syn)
|
|
|
void unallocated_encoding(DisasContext *s)
|
|
|
{
|
|
|
/* Unallocated and reserved encodings are uncategorized */
|
|
|
- gen_exception_insn(s, s->pc_curr, EXCP_UDEF, syn_uncategorized());
|
|
|
+ gen_exception_insn(s, 0, EXCP_UDEF, syn_uncategorized());
|
|
|
}
|
|
|
|
|
|
/* Force a TB lookup after an instruction that changes the CPU state. */
|
|
|
void gen_lookup_tb(DisasContext *s)
|
|
|
{
|
|
|
- tcg_gen_movi_i32(cpu_R[15], s->base.pc_next);
|
|
|
+ gen_pc_plus_diff(s, cpu_R[15], curr_insn_len(s));
|
|
|
s->base.is_jmp = DISAS_EXIT;
|
|
|
}
|
|
|
|
|
@@ -1167,7 +1186,7 @@ static inline void gen_hlt(DisasContext *s, int imm)
|
|
|
*/
|
|
|
if (semihosting_enabled(s->current_el != 0) &&
|
|
|
(imm == (s->thumb ? 0x3c : 0xf000))) {
|
|
|
- gen_exception_internal_insn(s, s->pc_curr, EXCP_SEMIHOST);
|
|
|
+ gen_exception_internal_insn(s, EXCP_SEMIHOST);
|
|
|
return;
|
|
|
}
|
|
|
|
|
@@ -2590,25 +2609,38 @@ static void gen_goto_ptr(void)
|
|
|
* cpu_loop_exec. Any live exit_requests will be processed as we
|
|
|
* enter the next TB.
|
|
|
*/
|
|
|
-static void gen_goto_tb(DisasContext *s, int n, target_ulong dest)
|
|
|
+static void gen_goto_tb(DisasContext *s, int n, target_long diff)
|
|
|
{
|
|
|
- if (translator_use_goto_tb(&s->base, dest)) {
|
|
|
- tcg_gen_goto_tb(n);
|
|
|
- gen_set_pc_im(s, dest);
|
|
|
+ if (translator_use_goto_tb(&s->base, s->pc_curr + diff)) {
|
|
|
+ /*
|
|
|
+ * For pcrel, the pc must always be up-to-date on entry to
|
|
|
+ * the linked TB, so that it can use simple additions for all
|
|
|
+ * further adjustments. For !pcrel, the linked TB is compiled
|
|
|
+ * to know its full virtual address, so we can delay the
|
|
|
+ * update to pc to the unlinked path. A long chain of links
|
|
|
+ * can thus avoid many updates to the PC.
|
|
|
+ */
|
|
|
+ if (TARGET_TB_PCREL) {
|
|
|
+ gen_update_pc(s, diff);
|
|
|
+ tcg_gen_goto_tb(n);
|
|
|
+ } else {
|
|
|
+ tcg_gen_goto_tb(n);
|
|
|
+ gen_update_pc(s, diff);
|
|
|
+ }
|
|
|
tcg_gen_exit_tb(s->base.tb, n);
|
|
|
} else {
|
|
|
- gen_set_pc_im(s, dest);
|
|
|
+ gen_update_pc(s, diff);
|
|
|
gen_goto_ptr();
|
|
|
}
|
|
|
s->base.is_jmp = DISAS_NORETURN;
|
|
|
}
|
|
|
|
|
|
/* Jump, specifying which TB number to use if we gen_goto_tb() */
|
|
|
-static inline void gen_jmp_tb(DisasContext *s, uint32_t dest, int tbno)
|
|
|
+static void gen_jmp_tb(DisasContext *s, target_long diff, int tbno)
|
|
|
{
|
|
|
if (unlikely(s->ss_active)) {
|
|
|
/* An indirect jump so that we still trigger the debug exception. */
|
|
|
- gen_set_pc_im(s, dest);
|
|
|
+ gen_update_pc(s, diff);
|
|
|
s->base.is_jmp = DISAS_JUMP;
|
|
|
return;
|
|
|
}
|
|
@@ -2625,7 +2657,7 @@ static inline void gen_jmp_tb(DisasContext *s, uint32_t dest, int tbno)
|
|
|
* gen_jmp();
|
|
|
* on the second call to gen_jmp().
|
|
|
*/
|
|
|
- gen_goto_tb(s, tbno, dest);
|
|
|
+ gen_goto_tb(s, tbno, diff);
|
|
|
break;
|
|
|
case DISAS_UPDATE_NOCHAIN:
|
|
|
case DISAS_UPDATE_EXIT:
|
|
@@ -2634,7 +2666,7 @@ static inline void gen_jmp_tb(DisasContext *s, uint32_t dest, int tbno)
|
|
|
* Avoid using goto_tb so we really do exit back to the main loop
|
|
|
* and don't chain to another TB.
|
|
|
*/
|
|
|
- gen_set_pc_im(s, dest);
|
|
|
+ gen_update_pc(s, diff);
|
|
|
gen_goto_ptr();
|
|
|
s->base.is_jmp = DISAS_NORETURN;
|
|
|
break;
|
|
@@ -2647,9 +2679,9 @@ static inline void gen_jmp_tb(DisasContext *s, uint32_t dest, int tbno)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-static inline void gen_jmp(DisasContext *s, uint32_t dest)
|
|
|
+static inline void gen_jmp(DisasContext *s, target_long diff)
|
|
|
{
|
|
|
- gen_jmp_tb(s, dest, 0);
|
|
|
+ gen_jmp_tb(s, diff, 0);
|
|
|
}
|
|
|
|
|
|
static inline void gen_mulxy(TCGv_i32 t0, TCGv_i32 t1, int x, int y)
|
|
@@ -2861,7 +2893,7 @@ static bool msr_banked_access_decode(DisasContext *s, int r, int sysm, int rn,
|
|
|
tcg_el = tcg_constant_i32(3);
|
|
|
}
|
|
|
|
|
|
- gen_exception_insn_el_v(s, s->pc_curr, EXCP_UDEF,
|
|
|
+ gen_exception_insn_el_v(s, 0, EXCP_UDEF,
|
|
|
syn_uncategorized(), tcg_el);
|
|
|
tcg_temp_free_i32(tcg_el);
|
|
|
return false;
|
|
@@ -2887,7 +2919,7 @@ static bool msr_banked_access_decode(DisasContext *s, int r, int sysm, int rn,
|
|
|
|
|
|
undef:
|
|
|
/* If we get here then some access check did not pass */
|
|
|
- gen_exception_insn(s, s->pc_curr, EXCP_UDEF, syn_uncategorized());
|
|
|
+ gen_exception_insn(s, 0, EXCP_UDEF, syn_uncategorized());
|
|
|
return false;
|
|
|
}
|
|
|
|
|
@@ -2902,7 +2934,7 @@ static void gen_msr_banked(DisasContext *s, int r, int sysm, int rn)
|
|
|
|
|
|
/* Sync state because msr_banked() can raise exceptions */
|
|
|
gen_set_condexec(s);
|
|
|
- gen_set_pc_im(s, s->pc_curr);
|
|
|
+ gen_update_pc(s, 0);
|
|
|
tcg_reg = load_reg(s, rn);
|
|
|
gen_helper_msr_banked(cpu_env, tcg_reg,
|
|
|
tcg_constant_i32(tgtmode),
|
|
@@ -2922,7 +2954,7 @@ static void gen_mrs_banked(DisasContext *s, int r, int sysm, int rn)
|
|
|
|
|
|
/* Sync state because mrs_banked() can raise exceptions */
|
|
|
gen_set_condexec(s);
|
|
|
- gen_set_pc_im(s, s->pc_curr);
|
|
|
+ gen_update_pc(s, 0);
|
|
|
tcg_reg = tcg_temp_new_i32();
|
|
|
gen_helper_mrs_banked(tcg_reg, cpu_env,
|
|
|
tcg_constant_i32(tgtmode),
|
|
@@ -4743,7 +4775,7 @@ static void do_coproc_insn(DisasContext *s, int cpnum, int is64,
|
|
|
}
|
|
|
|
|
|
gen_set_condexec(s);
|
|
|
- gen_set_pc_im(s, s->pc_curr);
|
|
|
+ gen_update_pc(s, 0);
|
|
|
gen_helper_access_check_cp_reg(cpu_env,
|
|
|
tcg_constant_ptr(ri),
|
|
|
tcg_constant_i32(syndrome),
|
|
@@ -4754,7 +4786,7 @@ static void do_coproc_insn(DisasContext *s, int cpnum, int is64,
|
|
|
* synchronize the CPU state in case it does.
|
|
|
*/
|
|
|
gen_set_condexec(s);
|
|
|
- gen_set_pc_im(s, s->pc_curr);
|
|
|
+ gen_update_pc(s, 0);
|
|
|
}
|
|
|
|
|
|
/* Handle special cases first */
|
|
@@ -4768,7 +4800,7 @@ static void do_coproc_insn(DisasContext *s, int cpnum, int is64,
|
|
|
unallocated_encoding(s);
|
|
|
return;
|
|
|
}
|
|
|
- gen_set_pc_im(s, s->base.pc_next);
|
|
|
+ gen_update_pc(s, curr_insn_len(s));
|
|
|
s->base.is_jmp = DISAS_WFI;
|
|
|
return;
|
|
|
default:
|
|
@@ -5111,8 +5143,7 @@ static void gen_srs(DisasContext *s,
|
|
|
* For the UNPREDICTABLE cases we choose to UNDEF.
|
|
|
*/
|
|
|
if (s->current_el == 1 && !s->ns && mode == ARM_CPU_MODE_MON) {
|
|
|
- gen_exception_insn_el(s, s->pc_curr, EXCP_UDEF,
|
|
|
- syn_uncategorized(), 3);
|
|
|
+ gen_exception_insn_el(s, 0, EXCP_UDEF, syn_uncategorized(), 3);
|
|
|
return;
|
|
|
}
|
|
|
|
|
@@ -5155,7 +5186,7 @@ static void gen_srs(DisasContext *s,
|
|
|
addr = tcg_temp_new_i32();
|
|
|
/* get_r13_banked() will raise an exception if called from System mode */
|
|
|
gen_set_condexec(s);
|
|
|
- gen_set_pc_im(s, s->pc_curr);
|
|
|
+ gen_update_pc(s, 0);
|
|
|
gen_helper_get_r13_banked(addr, cpu_env, tcg_constant_i32(mode));
|
|
|
switch (amode) {
|
|
|
case 0: /* DA */
|
|
@@ -5209,7 +5240,7 @@ static void gen_srs(DisasContext *s,
|
|
|
static void arm_skip_unless(DisasContext *s, uint32_t cond)
|
|
|
{
|
|
|
arm_gen_condlabel(s);
|
|
|
- arm_gen_test_cc(cond ^ 1, s->condlabel);
|
|
|
+ arm_gen_test_cc(cond ^ 1, s->condlabel.label);
|
|
|
}
|
|
|
|
|
|
|
|
@@ -6224,7 +6255,7 @@ static bool trans_YIELD(DisasContext *s, arg_YIELD *a)
|
|
|
* scheduling of other vCPUs.
|
|
|
*/
|
|
|
if (!(tb_cflags(s->base.tb) & CF_PARALLEL)) {
|
|
|
- gen_set_pc_im(s, s->base.pc_next);
|
|
|
+ gen_update_pc(s, curr_insn_len(s));
|
|
|
s->base.is_jmp = DISAS_YIELD;
|
|
|
}
|
|
|
return true;
|
|
@@ -6240,7 +6271,7 @@ static bool trans_WFE(DisasContext *s, arg_WFE *a)
|
|
|
* implemented so we can't sleep like WFI does.
|
|
|
*/
|
|
|
if (!(tb_cflags(s->base.tb) & CF_PARALLEL)) {
|
|
|
- gen_set_pc_im(s, s->base.pc_next);
|
|
|
+ gen_update_pc(s, curr_insn_len(s));
|
|
|
s->base.is_jmp = DISAS_WFE;
|
|
|
}
|
|
|
return true;
|
|
@@ -6249,7 +6280,7 @@ static bool trans_WFE(DisasContext *s, arg_WFE *a)
|
|
|
static bool trans_WFI(DisasContext *s, arg_WFI *a)
|
|
|
{
|
|
|
/* For WFI, halt the vCPU until an IRQ. */
|
|
|
- gen_set_pc_im(s, s->base.pc_next);
|
|
|
+ gen_update_pc(s, curr_insn_len(s));
|
|
|
s->base.is_jmp = DISAS_WFI;
|
|
|
return true;
|
|
|
}
|
|
@@ -6470,7 +6501,7 @@ static bool trans_BLX_r(DisasContext *s, arg_BLX_r *a)
|
|
|
return false;
|
|
|
}
|
|
|
tmp = load_reg(s, a->rm);
|
|
|
- tcg_gen_movi_i32(cpu_R[14], s->base.pc_next | s->thumb);
|
|
|
+ gen_pc_plus_diff(s, cpu_R[14], curr_insn_len(s) | s->thumb);
|
|
|
gen_bx(s, tmp);
|
|
|
return true;
|
|
|
}
|
|
@@ -6551,7 +6582,7 @@ static bool trans_BKPT(DisasContext *s, arg_BKPT *a)
|
|
|
if (arm_dc_feature(s, ARM_FEATURE_M) &&
|
|
|
semihosting_enabled(s->current_el == 0) &&
|
|
|
(a->imm == 0xab)) {
|
|
|
- gen_exception_internal_insn(s, s->pc_curr, EXCP_SEMIHOST);
|
|
|
+ gen_exception_internal_insn(s, EXCP_SEMIHOST);
|
|
|
} else {
|
|
|
gen_exception_bkpt_insn(s, syn_aa32_bkpt(a->imm, false));
|
|
|
}
|
|
@@ -6650,7 +6681,7 @@ static ISSInfo make_issinfo(DisasContext *s, int rd, bool p, bool w)
|
|
|
/* ISS not valid if writeback */
|
|
|
if (p && !w) {
|
|
|
ret = rd;
|
|
|
- if (s->base.pc_next - s->pc_curr == 2) {
|
|
|
+ if (curr_insn_len(s) == 2) {
|
|
|
ret |= ISSIs16Bit;
|
|
|
}
|
|
|
} else {
|
|
@@ -8317,7 +8348,7 @@ static bool trans_CLRM(DisasContext *s, arg_CLRM *a)
|
|
|
|
|
|
static bool trans_B(DisasContext *s, arg_i *a)
|
|
|
{
|
|
|
- gen_jmp(s, read_pc(s) + a->imm);
|
|
|
+ gen_jmp(s, jmp_diff(s, a->imm));
|
|
|
return true;
|
|
|
}
|
|
|
|
|
@@ -8332,14 +8363,14 @@ static bool trans_B_cond_thumb(DisasContext *s, arg_ci *a)
|
|
|
return true;
|
|
|
}
|
|
|
arm_skip_unless(s, a->cond);
|
|
|
- gen_jmp(s, read_pc(s) + a->imm);
|
|
|
+ gen_jmp(s, jmp_diff(s, a->imm));
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
static bool trans_BL(DisasContext *s, arg_i *a)
|
|
|
{
|
|
|
- tcg_gen_movi_i32(cpu_R[14], s->base.pc_next | s->thumb);
|
|
|
- gen_jmp(s, read_pc(s) + a->imm);
|
|
|
+ gen_pc_plus_diff(s, cpu_R[14], curr_insn_len(s) | s->thumb);
|
|
|
+ gen_jmp(s, jmp_diff(s, a->imm));
|
|
|
return true;
|
|
|
}
|
|
|
|
|
@@ -8357,16 +8388,17 @@ static bool trans_BLX_i(DisasContext *s, arg_BLX_i *a)
|
|
|
if (s->thumb && (a->imm & 2)) {
|
|
|
return false;
|
|
|
}
|
|
|
- tcg_gen_movi_i32(cpu_R[14], s->base.pc_next | s->thumb);
|
|
|
+ gen_pc_plus_diff(s, cpu_R[14], curr_insn_len(s) | s->thumb);
|
|
|
store_cpu_field_constant(!s->thumb, thumb);
|
|
|
- gen_jmp(s, (read_pc(s) & ~3) + a->imm);
|
|
|
+ /* This jump is computed from an aligned PC: subtract off the low bits. */
|
|
|
+ gen_jmp(s, jmp_diff(s, a->imm - (s->pc_curr & 3)));
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
static bool trans_BL_BLX_prefix(DisasContext *s, arg_BL_BLX_prefix *a)
|
|
|
{
|
|
|
assert(!arm_dc_feature(s, ARM_FEATURE_THUMB2));
|
|
|
- tcg_gen_movi_i32(cpu_R[14], read_pc(s) + (a->imm << 12));
|
|
|
+ gen_pc_plus_diff(s, cpu_R[14], jmp_diff(s, a->imm << 12));
|
|
|
return true;
|
|
|
}
|
|
|
|
|
@@ -8376,7 +8408,7 @@ static bool trans_BL_suffix(DisasContext *s, arg_BL_suffix *a)
|
|
|
|
|
|
assert(!arm_dc_feature(s, ARM_FEATURE_THUMB2));
|
|
|
tcg_gen_addi_i32(tmp, cpu_R[14], (a->imm << 1) | 1);
|
|
|
- tcg_gen_movi_i32(cpu_R[14], s->base.pc_next | 1);
|
|
|
+ gen_pc_plus_diff(s, cpu_R[14], curr_insn_len(s) | 1);
|
|
|
gen_bx(s, tmp);
|
|
|
return true;
|
|
|
}
|
|
@@ -8392,7 +8424,7 @@ static bool trans_BLX_suffix(DisasContext *s, arg_BLX_suffix *a)
|
|
|
tmp = tcg_temp_new_i32();
|
|
|
tcg_gen_addi_i32(tmp, cpu_R[14], a->imm << 1);
|
|
|
tcg_gen_andi_i32(tmp, tmp, 0xfffffffc);
|
|
|
- tcg_gen_movi_i32(cpu_R[14], s->base.pc_next | 1);
|
|
|
+ gen_pc_plus_diff(s, cpu_R[14], curr_insn_len(s) | 1);
|
|
|
gen_bx(s, tmp);
|
|
|
return true;
|
|
|
}
|
|
@@ -8459,7 +8491,7 @@ static bool trans_WLS(DisasContext *s, arg_WLS *a)
|
|
|
{
|
|
|
/* M-profile low-overhead while-loop start */
|
|
|
TCGv_i32 tmp;
|
|
|
- TCGLabel *nextlabel;
|
|
|
+ DisasLabel nextlabel;
|
|
|
|
|
|
if (!dc_isar_feature(aa32_lob, s)) {
|
|
|
return false;
|
|
@@ -8494,14 +8526,14 @@ static bool trans_WLS(DisasContext *s, arg_WLS *a)
|
|
|
* Do the check-and-raise-exception by hand.
|
|
|
*/
|
|
|
if (s->fp_excp_el) {
|
|
|
- gen_exception_insn_el(s, s->pc_curr, EXCP_NOCP,
|
|
|
+ gen_exception_insn_el(s, 0, EXCP_NOCP,
|
|
|
syn_uncategorized(), s->fp_excp_el);
|
|
|
return true;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- nextlabel = gen_new_label();
|
|
|
- tcg_gen_brcondi_i32(TCG_COND_EQ, cpu_R[a->rn], 0, nextlabel);
|
|
|
+ nextlabel = gen_disas_label(s);
|
|
|
+ tcg_gen_brcondi_i32(TCG_COND_EQ, cpu_R[a->rn], 0, nextlabel.label);
|
|
|
tmp = load_reg(s, a->rn);
|
|
|
store_reg(s, 14, tmp);
|
|
|
if (a->size != 4) {
|
|
@@ -8520,10 +8552,10 @@ static bool trans_WLS(DisasContext *s, arg_WLS *a)
|
|
|
* when we take this upcoming exit from this TB, so gen_jmp_tb() is OK.
|
|
|
*/
|
|
|
}
|
|
|
- gen_jmp_tb(s, s->base.pc_next, 1);
|
|
|
+ gen_jmp_tb(s, curr_insn_len(s), 1);
|
|
|
|
|
|
- gen_set_label(nextlabel);
|
|
|
- gen_jmp(s, read_pc(s) + a->imm);
|
|
|
+ set_disas_label(s, nextlabel);
|
|
|
+ gen_jmp(s, jmp_diff(s, a->imm));
|
|
|
return true;
|
|
|
}
|
|
|
|
|
@@ -8538,7 +8570,7 @@ static bool trans_LE(DisasContext *s, arg_LE *a)
|
|
|
* any faster.
|
|
|
*/
|
|
|
TCGv_i32 tmp;
|
|
|
- TCGLabel *loopend;
|
|
|
+ DisasLabel loopend;
|
|
|
bool fpu_active;
|
|
|
|
|
|
if (!dc_isar_feature(aa32_lob, s)) {
|
|
@@ -8593,17 +8625,17 @@ static bool trans_LE(DisasContext *s, arg_LE *a)
|
|
|
|
|
|
if (!a->tp && dc_isar_feature(aa32_mve, s) && fpu_active) {
|
|
|
/* Need to do a runtime check for LTPSIZE != 4 */
|
|
|
- TCGLabel *skipexc = gen_new_label();
|
|
|
+ DisasLabel skipexc = gen_disas_label(s);
|
|
|
tmp = load_cpu_field(v7m.ltpsize);
|
|
|
- tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 4, skipexc);
|
|
|
+ tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 4, skipexc.label);
|
|
|
tcg_temp_free_i32(tmp);
|
|
|
- gen_exception_insn(s, s->pc_curr, EXCP_INVSTATE, syn_uncategorized());
|
|
|
- gen_set_label(skipexc);
|
|
|
+ gen_exception_insn(s, 0, EXCP_INVSTATE, syn_uncategorized());
|
|
|
+ set_disas_label(s, skipexc);
|
|
|
}
|
|
|
|
|
|
if (a->f) {
|
|
|
/* Loop-forever: just jump back to the loop start */
|
|
|
- gen_jmp(s, read_pc(s) - a->imm);
|
|
|
+ gen_jmp(s, jmp_diff(s, -a->imm));
|
|
|
return true;
|
|
|
}
|
|
|
|
|
@@ -8613,9 +8645,9 @@ static bool trans_LE(DisasContext *s, arg_LE *a)
|
|
|
* loop decrement value is 1. For LETP we need to calculate the decrement
|
|
|
* value from LTPSIZE.
|
|
|
*/
|
|
|
- loopend = gen_new_label();
|
|
|
+ loopend = gen_disas_label(s);
|
|
|
if (!a->tp) {
|
|
|
- tcg_gen_brcondi_i32(TCG_COND_LEU, cpu_R[14], 1, loopend);
|
|
|
+ tcg_gen_brcondi_i32(TCG_COND_LEU, cpu_R[14], 1, loopend.label);
|
|
|
tcg_gen_addi_i32(cpu_R[14], cpu_R[14], -1);
|
|
|
} else {
|
|
|
/*
|
|
@@ -8628,21 +8660,21 @@ static bool trans_LE(DisasContext *s, arg_LE *a)
|
|
|
tcg_gen_shl_i32(decr, tcg_constant_i32(1), decr);
|
|
|
tcg_temp_free_i32(ltpsize);
|
|
|
|
|
|
- tcg_gen_brcond_i32(TCG_COND_LEU, cpu_R[14], decr, loopend);
|
|
|
+ tcg_gen_brcond_i32(TCG_COND_LEU, cpu_R[14], decr, loopend.label);
|
|
|
|
|
|
tcg_gen_sub_i32(cpu_R[14], cpu_R[14], decr);
|
|
|
tcg_temp_free_i32(decr);
|
|
|
}
|
|
|
/* Jump back to the loop start */
|
|
|
- gen_jmp(s, read_pc(s) - a->imm);
|
|
|
+ gen_jmp(s, jmp_diff(s, -a->imm));
|
|
|
|
|
|
- gen_set_label(loopend);
|
|
|
+ set_disas_label(s, loopend);
|
|
|
if (a->tp) {
|
|
|
/* Exits from tail-pred loops must reset LTPSIZE to 4 */
|
|
|
store_cpu_field(tcg_constant_i32(4), v7m.ltpsize);
|
|
|
}
|
|
|
/* End TB, continuing to following insn */
|
|
|
- gen_jmp_tb(s, s->base.pc_next, 1);
|
|
|
+ gen_jmp_tb(s, curr_insn_len(s), 1);
|
|
|
return true;
|
|
|
}
|
|
|
|
|
@@ -8715,10 +8747,11 @@ static bool op_tbranch(DisasContext *s, arg_tbranch *a, bool half)
|
|
|
tcg_gen_add_i32(addr, addr, tmp);
|
|
|
|
|
|
gen_aa32_ld_i32(s, tmp, addr, get_mem_index(s), half ? MO_UW : MO_UB);
|
|
|
- tcg_temp_free_i32(addr);
|
|
|
|
|
|
tcg_gen_add_i32(tmp, tmp, tmp);
|
|
|
- tcg_gen_addi_i32(tmp, tmp, read_pc(s));
|
|
|
+ gen_pc_plus_diff(s, addr, jmp_diff(s, 0));
|
|
|
+ tcg_gen_add_i32(tmp, tmp, addr);
|
|
|
+ tcg_temp_free_i32(addr);
|
|
|
store_reg(s, 15, tmp);
|
|
|
return true;
|
|
|
}
|
|
@@ -8739,9 +8772,9 @@ static bool trans_CBZ(DisasContext *s, arg_CBZ *a)
|
|
|
|
|
|
arm_gen_condlabel(s);
|
|
|
tcg_gen_brcondi_i32(a->nz ? TCG_COND_EQ : TCG_COND_NE,
|
|
|
- tmp, 0, s->condlabel);
|
|
|
+ tmp, 0, s->condlabel.label);
|
|
|
tcg_temp_free_i32(tmp);
|
|
|
- gen_jmp(s, read_pc(s) + a->imm);
|
|
|
+ gen_jmp(s, jmp_diff(s, a->imm));
|
|
|
return true;
|
|
|
}
|
|
|
|
|
@@ -8757,9 +8790,9 @@ static bool trans_SVC(DisasContext *s, arg_SVC *a)
|
|
|
if (!arm_dc_feature(s, ARM_FEATURE_M) &&
|
|
|
semihosting_enabled(s->current_el == 0) &&
|
|
|
(a->imm == semihost_imm)) {
|
|
|
- gen_exception_internal_insn(s, s->pc_curr, EXCP_SEMIHOST);
|
|
|
+ gen_exception_internal_insn(s, EXCP_SEMIHOST);
|
|
|
} else {
|
|
|
- gen_set_pc_im(s, s->base.pc_next);
|
|
|
+ gen_update_pc(s, curr_insn_len(s));
|
|
|
s->svc_imm = a->imm;
|
|
|
s->base.is_jmp = DISAS_SWI;
|
|
|
}
|
|
@@ -9065,7 +9098,7 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn)
|
|
|
* UsageFault exception.
|
|
|
*/
|
|
|
if (arm_dc_feature(s, ARM_FEATURE_M)) {
|
|
|
- gen_exception_insn(s, s->pc_curr, EXCP_INVSTATE, syn_uncategorized());
|
|
|
+ gen_exception_insn(s, 0, EXCP_INVSTATE, syn_uncategorized());
|
|
|
return;
|
|
|
}
|
|
|
|
|
@@ -9074,7 +9107,7 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn)
|
|
|
* Illegal execution state. This has priority over BTI
|
|
|
* exceptions, but comes after instruction abort exceptions.
|
|
|
*/
|
|
|
- gen_exception_insn(s, s->pc_curr, EXCP_UDEF, syn_illegalstate());
|
|
|
+ gen_exception_insn(s, 0, EXCP_UDEF, syn_illegalstate());
|
|
|
return;
|
|
|
}
|
|
|
|
|
@@ -9305,7 +9338,7 @@ static void arm_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
|
|
|
|
|
|
dc->isar = &cpu->isar;
|
|
|
dc->condjmp = 0;
|
|
|
-
|
|
|
+ dc->pc_save = dc->base.pc_first;
|
|
|
dc->aarch64 = false;
|
|
|
dc->thumb = EX_TBFLAG_AM32(tb_flags, THUMB);
|
|
|
dc->be_data = EX_TBFLAG_ANY(tb_flags, BE_DATA) ? MO_BE : MO_LE;
|
|
@@ -9323,7 +9356,6 @@ static void arm_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
|
|
|
*/
|
|
|
dc->eci = dc->condexec_mask = dc->condexec_cond = 0;
|
|
|
dc->eci_handled = false;
|
|
|
- dc->insn_eci_rewind = NULL;
|
|
|
if (condexec & 0xf) {
|
|
|
dc->condexec_mask = (condexec & 0xf) << 1;
|
|
|
dc->condexec_cond = condexec >> 4;
|
|
@@ -9459,13 +9491,17 @@ static void arm_tr_insn_start(DisasContextBase *dcbase, CPUState *cpu)
|
|
|
* fields here.
|
|
|
*/
|
|
|
uint32_t condexec_bits;
|
|
|
+ target_ulong pc_arg = dc->base.pc_next;
|
|
|
|
|
|
+ if (TARGET_TB_PCREL) {
|
|
|
+ pc_arg &= ~TARGET_PAGE_MASK;
|
|
|
+ }
|
|
|
if (dc->eci) {
|
|
|
condexec_bits = dc->eci << 4;
|
|
|
} else {
|
|
|
condexec_bits = (dc->condexec_cond << 4) | (dc->condexec_mask >> 1);
|
|
|
}
|
|
|
- tcg_gen_insn_start(dc->base.pc_next, condexec_bits, 0);
|
|
|
+ tcg_gen_insn_start(pc_arg, condexec_bits, 0);
|
|
|
dc->insn_start = tcg_last_op();
|
|
|
}
|
|
|
|
|
@@ -9508,8 +9544,11 @@ static bool arm_check_ss_active(DisasContext *dc)
|
|
|
|
|
|
static void arm_post_translate_insn(DisasContext *dc)
|
|
|
{
|
|
|
- if (dc->condjmp && !dc->base.is_jmp) {
|
|
|
- gen_set_label(dc->condlabel);
|
|
|
+ if (dc->condjmp && dc->base.is_jmp == DISAS_NEXT) {
|
|
|
+ if (dc->pc_save != dc->condlabel.pc_save) {
|
|
|
+ gen_update_pc(dc, dc->condlabel.pc_save - dc->pc_save);
|
|
|
+ }
|
|
|
+ gen_set_label(dc->condlabel.label);
|
|
|
dc->condjmp = 0;
|
|
|
}
|
|
|
translator_loop_temp_check(&dc->base);
|
|
@@ -9612,6 +9651,9 @@ static void thumb_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu)
|
|
|
uint32_t pc = dc->base.pc_next;
|
|
|
uint32_t insn;
|
|
|
bool is_16bit;
|
|
|
+ /* TCG op to rewind to if this turns out to be an invalid ECI state */
|
|
|
+ TCGOp *insn_eci_rewind = NULL;
|
|
|
+ target_ulong insn_eci_pc_save = -1;
|
|
|
|
|
|
/* Misaligned thumb PC is architecturally impossible. */
|
|
|
assert((dc->base.pc_next & 1) == 0);
|
|
@@ -9638,7 +9680,7 @@ static void thumb_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu)
|
|
|
* Illegal execution state. This has priority over BTI
|
|
|
* exceptions, but comes after instruction abort exceptions.
|
|
|
*/
|
|
|
- gen_exception_insn(dc, dc->pc_curr, EXCP_UDEF, syn_illegalstate());
|
|
|
+ gen_exception_insn(dc, 0, EXCP_UDEF, syn_illegalstate());
|
|
|
return;
|
|
|
}
|
|
|
|
|
@@ -9673,7 +9715,8 @@ static void thumb_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu)
|
|
|
* insn" case. We will rewind to the marker (ie throwing away
|
|
|
* all the generated code) and instead emit "take exception".
|
|
|
*/
|
|
|
- dc->insn_eci_rewind = tcg_last_op();
|
|
|
+ insn_eci_rewind = tcg_last_op();
|
|
|
+ insn_eci_pc_save = dc->pc_save;
|
|
|
}
|
|
|
|
|
|
if (dc->condexec_mask && !thumb_insn_is_unconditional(dc, insn)) {
|
|
@@ -9709,10 +9752,10 @@ static void thumb_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu)
|
|
|
* Insn wasn't valid for ECI/ICI at all: undo what we
|
|
|
* just generated and instead emit an exception
|
|
|
*/
|
|
|
- tcg_remove_ops_after(dc->insn_eci_rewind);
|
|
|
+ tcg_remove_ops_after(insn_eci_rewind);
|
|
|
+ dc->pc_save = insn_eci_pc_save;
|
|
|
dc->condjmp = 0;
|
|
|
- gen_exception_insn(dc, dc->pc_curr, EXCP_INVSTATE,
|
|
|
- syn_uncategorized());
|
|
|
+ gen_exception_insn(dc, 0, EXCP_INVSTATE, syn_uncategorized());
|
|
|
}
|
|
|
|
|
|
arm_post_translate_insn(dc);
|
|
@@ -9772,7 +9815,7 @@ static void arm_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu)
|
|
|
case DISAS_TOO_MANY:
|
|
|
case DISAS_UPDATE_EXIT:
|
|
|
case DISAS_UPDATE_NOCHAIN:
|
|
|
- gen_set_pc_im(dc, dc->base.pc_next);
|
|
|
+ gen_update_pc(dc, curr_insn_len(dc));
|
|
|
/* fall through */
|
|
|
default:
|
|
|
/* FIXME: Single stepping a WFI insn will not halt the CPU. */
|
|
@@ -9793,16 +9836,16 @@ static void arm_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu)
|
|
|
switch (dc->base.is_jmp) {
|
|
|
case DISAS_NEXT:
|
|
|
case DISAS_TOO_MANY:
|
|
|
- gen_goto_tb(dc, 1, dc->base.pc_next);
|
|
|
+ gen_goto_tb(dc, 1, curr_insn_len(dc));
|
|
|
break;
|
|
|
case DISAS_UPDATE_NOCHAIN:
|
|
|
- gen_set_pc_im(dc, dc->base.pc_next);
|
|
|
+ gen_update_pc(dc, curr_insn_len(dc));
|
|
|
/* fall through */
|
|
|
case DISAS_JUMP:
|
|
|
gen_goto_ptr();
|
|
|
break;
|
|
|
case DISAS_UPDATE_EXIT:
|
|
|
- gen_set_pc_im(dc, dc->base.pc_next);
|
|
|
+ gen_update_pc(dc, curr_insn_len(dc));
|
|
|
/* fall through */
|
|
|
default:
|
|
|
/* indicate that the hash table must be used to find the next TB */
|
|
@@ -9812,8 +9855,7 @@ static void arm_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu)
|
|
|
/* nothing more to generate */
|
|
|
break;
|
|
|
case DISAS_WFI:
|
|
|
- gen_helper_wfi(cpu_env,
|
|
|
- tcg_constant_i32(dc->base.pc_next - dc->pc_curr));
|
|
|
+ gen_helper_wfi(cpu_env, tcg_constant_i32(curr_insn_len(dc)));
|
|
|
/*
|
|
|
* The helper doesn't necessarily throw an exception, but we
|
|
|
* must go back to the main loop to check for interrupts anyway.
|
|
@@ -9840,13 +9882,13 @@ static void arm_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu)
|
|
|
|
|
|
if (dc->condjmp) {
|
|
|
/* "Condition failed" instruction codepath for the branch/trap insn */
|
|
|
- gen_set_label(dc->condlabel);
|
|
|
+ set_disas_label(dc, dc->condlabel);
|
|
|
gen_set_condexec(dc);
|
|
|
if (unlikely(dc->ss_active)) {
|
|
|
- gen_set_pc_im(dc, dc->base.pc_next);
|
|
|
+ gen_update_pc(dc, curr_insn_len(dc));
|
|
|
gen_singlestep_exception(dc);
|
|
|
} else {
|
|
|
- gen_goto_tb(dc, 1, dc->base.pc_next);
|
|
|
+ gen_goto_tb(dc, 1, curr_insn_len(dc));
|
|
|
}
|
|
|
}
|
|
|
}
|
|
@@ -9902,11 +9944,19 @@ void restore_state_to_opc(CPUARMState *env, TranslationBlock *tb,
|
|
|
target_ulong *data)
|
|
|
{
|
|
|
if (is_a64(env)) {
|
|
|
- env->pc = data[0];
|
|
|
+ if (TARGET_TB_PCREL) {
|
|
|
+ env->pc = (env->pc & TARGET_PAGE_MASK) | data[0];
|
|
|
+ } else {
|
|
|
+ env->pc = data[0];
|
|
|
+ }
|
|
|
env->condexec_bits = 0;
|
|
|
env->exception.syndrome = data[2] << ARM_INSN_START_WORD2_SHIFT;
|
|
|
} else {
|
|
|
- env->regs[15] = data[0];
|
|
|
+ if (TARGET_TB_PCREL) {
|
|
|
+ env->regs[15] = (env->regs[15] & TARGET_PAGE_MASK) | data[0];
|
|
|
+ } else {
|
|
|
+ env->regs[15] = data[0];
|
|
|
+ }
|
|
|
env->condexec_bits = data[1];
|
|
|
env->exception.syndrome = data[2] << ARM_INSN_START_WORD2_SHIFT;
|
|
|
}
|