SSR.SS enables a single-step debug event after each packet executed in user or guest mode.
Carry the state in a new SS_ACTIVE TB flag. When it is set, translate one packet per TB and raise HEX_EVENT_DEBUG w/PC at the next packet (which becomes ELR). Reviewed-by: Pierrick Bouvier <[email protected]> Signed-off-by: Brian Cain <[email protected]> --- target/hexagon/cpu.h | 1 + target/hexagon/translate.h | 1 + target/hexagon/cpu.c | 4 ++ target/hexagon/hexswi.c | 1 - target/hexagon/translate.c | 50 +++++++++++++++++++++++ tests/functional/hexagon/test_systests.py | 3 ++ 6 files changed, 59 insertions(+), 1 deletion(-) diff --git a/target/hexagon/cpu.h b/target/hexagon/cpu.h index c1a944920e8..15ae5d1d009 100644 --- a/target/hexagon/cpu.h +++ b/target/hexagon/cpu.h @@ -227,6 +227,7 @@ FIELD(TB_FLAGS, IS_TIGHT_LOOP, 0, 1) FIELD(TB_FLAGS, MMU_INDEX, 1, 3) FIELD(TB_FLAGS, HVX_COPROC_ENABLED, 5, 1) FIELD(TB_FLAGS, CPU_MODE, 6, 2) +FIELD(TB_FLAGS, SS_ACTIVE, 8, 1) G_NORETURN void hexagon_raise_exception_err(CPUHexagonState *env, uint32_t exception, diff --git a/target/hexagon/translate.h b/target/hexagon/translate.h index dc0c6b18bf1..98a5b39dd76 100644 --- a/target/hexagon/translate.h +++ b/target/hexagon/translate.h @@ -46,6 +46,7 @@ typedef struct DisasContext { bool implicit_usr_write; #ifndef CONFIG_USER_ONLY uint32_t cpu_mode; + bool ss_active; int greg_log[GREG_WRITES_MAX]; int greg_log_idx; DECLARE_BITMAP(gregs_written, NUM_GREGS); diff --git a/target/hexagon/cpu.c b/target/hexagon/cpu.c index ebd77e0f7dd..f383ffd88e6 100644 --- a/target/hexagon/cpu.c +++ b/target/hexagon/cpu.c @@ -388,6 +388,10 @@ static TCGTBCPUState hexagon_get_tb_cpu_state(CPUState *cs) GET_SSR_FIELD(SSR_XE, env->t_sreg[HEX_SREG_SSR])); hex_flags = FIELD_DP32(hex_flags, TB_FLAGS, CPU_MODE, get_cpu_mode(env)); + /* Single-step applies only to user and guest mode packets */ + hex_flags = FIELD_DP32(hex_flags, TB_FLAGS, SS_ACTIVE, + GET_SSR_FIELD(SSR_SS, env->t_sreg[HEX_SREG_SSR]) && + get_cpu_mode(env) != HEX_CPU_MODE_MONITOR); #else hex_flags = FIELD_DP32(hex_flags, TB_FLAGS, MMU_INDEX, MMU_USER_IDX); #endif diff --git a/target/hexagon/hexswi.c b/target/hexagon/hexswi.c index 19439658392..92506c26817 100644 --- a/target/hexagon/hexswi.c +++ b/target/hexagon/hexswi.c @@ -846,7 +846,6 @@ void hexagon_cpu_do_interrupt(CPUState *cs) case HEX_EVENT_DEBUG: hexagon_ssr_set_cause(env, env->cause_code); set_addresses(env, 0, cs->exception_index); - qemu_log_mask(LOG_UNIMP, "single-step exception is not handled\n"); break; case HEX_EVENT_PRECISE: diff --git a/target/hexagon/translate.c b/target/hexagon/translate.c index e2a5038a1a5..2f5e9f21098 100644 --- a/target/hexagon/translate.c +++ b/target/hexagon/translate.c @@ -175,10 +175,48 @@ static void gen_goto_tb(DisasContext *ctx, unsigned tb_slot_idx, } } +#ifndef CONFIG_USER_ONLY +/* + * Raise the single-step debug event once the packet has retired. PC + * already holds the address of the next packet, which becomes ELR. + */ +static void gen_singlestep_exception(DisasContext *ctx) +{ + tcg_gen_movi_i32(hex_cause_code, HEX_CAUSE_DEBUG_SINGLESTEP); + gen_helper_raise_exception(tcg_env, + tcg_constant_i32(HEX_EVENT_DEBUG), + hex_gpr[HEX_REG_PC]); + ctx->base.is_jmp = DISAS_NORETURN; +} + +static void gen_end_tb_singlestep(DisasContext *ctx) +{ + TCGv pc = hex_gpr[HEX_REG_PC]; + + if (ctx->branch_cond == TCG_COND_ALWAYS) { + tcg_gen_movi_tl(pc, ctx->branch_dest); + } else if (ctx->branch_cond != TCG_COND_NEVER) { + tcg_gen_movcond_tl(ctx->branch_cond, pc, ctx->branch_taken, + tcg_constant_tl(1), tcg_constant_tl(ctx->next_PC), + tcg_constant_tl(ctx->branch_dest)); + } else if (!ctx->pkt.pkt_has_cof) { + tcg_gen_movi_tl(pc, ctx->next_PC); + } + gen_singlestep_exception(ctx); +} +#endif + static void gen_end_tb(DisasContext *ctx) { gen_exec_counters(ctx); +#ifndef CONFIG_USER_ONLY + if (ctx->ss_active) { + gen_end_tb_singlestep(ctx); + return; + } +#endif + if (ctx->branch_cond != TCG_COND_NEVER) { if (ctx->branch_cond != TCG_COND_ALWAYS) { TCGLabel *skip = gen_new_label(); @@ -1336,6 +1374,12 @@ static void hexagon_tr_init_disas_context(DisasContextBase *dcbase, FIELD_EX32(hex_flags, TB_FLAGS, HVX_COPROC_ENABLED); ctx->hvx_check_emitted = false; ctx->cpu_mode = FIELD_EX32(hex_flags, TB_FLAGS, CPU_MODE); + ctx->ss_active = FIELD_EX32(hex_flags, TB_FLAGS, SS_ACTIVE); + if (ctx->ss_active) { + /* Step one packet, and let endloop0 branch within the packet */ + ctx->base.max_insns = 1; + ctx->is_tight_loop = false; + } #endif } @@ -1403,6 +1447,12 @@ static void hexagon_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu) case DISAS_TOO_MANY: gen_exec_counters(ctx); tcg_gen_movi_tl(hex_gpr[HEX_REG_PC], ctx->base.pc_next); +#ifndef CONFIG_USER_ONLY + if (ctx->ss_active) { + gen_singlestep_exception(ctx); + break; + } +#endif tcg_gen_exit_tb(NULL, 0); break; case DISAS_NORETURN: diff --git a/tests/functional/hexagon/test_systests.py b/tests/functional/hexagon/test_systests.py index 0489db0af91..1c1d5440bb6 100755 --- a/tests/functional/hexagon/test_systests.py +++ b/tests/functional/hexagon/test_systests.py @@ -111,5 +111,8 @@ def test_standalone_vec(self): def test_lock_verify(self): self.run_exit_zero("lock_verify") + def test_single_step(self): + self.run_exit_zero("single_step") + if __name__ == "__main__": QemuSystemTest.main() -- 2.34.1
