[PATCH 05/13] hw/riscv/trace_encoder, target/riscv: add trace pc history logic
Konstantin Semichastnov <[email protected]>
| Newsgroups | org.nongnu.qemu-riscv,org.nongnu.qemu-devel |
|---|---|
| Message-ID | <[email protected]> |
Add new fields to TraceEncoder struct, to be used when sending messages, that will be added in following commits: - last_addr_reported: a few N-Trace messages have field U-ADDR, that represents diff from last reported full pc address (F-ADDR field). This field tracks last reported full pc address (F-ADDR N-Trace field). - last_icnt_reset, icnt_accumulated: N-Trace requires to send I-CNT field in many messages, and this field represents number of retired instructions from last reported pc. We will track each executed branch and calculate pc-diff between previous branch to track I-CNT value. But there could be multiple branches before I-CNT report, so we will accumulate each pc-diff between consecutive branches in `icnt_accumulated` field. This pc-diff will be calculated as: `pc_before_branch + current_insn_len - last_icnt_reset` and we will update `last_icnt_reset` to `pc_after_branch` Signed-off-by: Konstantin Semichastnov <[email protected]> --- hw/riscv/trace-encoder.c | 19 +++++++++++++++++-- hw/riscv/trace-encoder.h | 14 +++++++++++++- target/riscv/helper.h | 4 ++-- target/riscv/insn_trans/trans_privileged.c.inc | 10 +++++----- target/riscv/insn_trans/trans_rvi.c.inc | 15 +++------------ target/riscv/trace_helper.c | 14 +++++++++----- target/riscv/translate.c | 19 +++++++++++++++++-- 7 files changed, 66 insertions(+), 29 deletions(-) diff --git a/hw/riscv/trace-encoder.c b/hw/riscv/trace-encoder.c index 703454c9b7..46501e4f03 100644 --- a/hw/riscv/trace-encoder.c +++ b/hw/riscv/trace-encoder.c @@ -262,6 +262,8 @@ static void trencoder_te_ctrl_postw(RegisterInfo *reg, uint64_t val) * using te->trace_next_insn */ trencoder_send_prog_trace_sync(OBJECT(te), env->pc); + te->last_icnt_reset = env->pc; + te->icnt_accumulated = 0; } else { te->trace_next_insn = true; } @@ -543,6 +545,7 @@ void trencoder_send_prog_trace_sync(Object *trencoder_obj, uint64_t pc) g_assert(trencoder->ntrace); + trencoder->last_addr_reported = pc; msg_size = rv_ntrace_gen_encoded_prog_trace_sync_msg(msg, faddr); trencoder_send_message_smem(trencoder, msg, msg_size); @@ -593,16 +596,28 @@ static void trencoder_send_branch_map(Object *trencoder_obj) trencoder_send_message_smem(te, msg, msg_size); } -void trencoder_report_branch(Object *trencoder_obj, uint64_t pc, bool taken) +void trencoder_report_branch(Object *trencoder_obj, uint64_t pc, + uint64_t insn_len, uint64_t offset, + TraceBranchRes taken) { TraceEncoder *te = TRACE_ENCODER(trencoder_obj); + if (te->ntrace && taken != BRANCH_NOT_TAKEN) { + te->icnt_accumulated += (pc + insn_len - te->last_icnt_reset) / 2; + te->last_icnt_reset = pc + offset; + } + + if (taken == BRANCH_TAKEN_UNCONDITIONAL) { + /* do not update branch map if branch is unconditional */ + return; + } + /* * Note: the e-trace spec determines the value '1' for a * branch *not* taken. The helper API is using taken = 1 * to be more intuitive when reading TCG code. */ - if (!taken) { + if (taken == BRANCH_NOT_TAKEN) { te->branch_map = deposit32(te->branch_map, te->branches, 1, 1); } diff --git a/hw/riscv/trace-encoder.h b/hw/riscv/trace-encoder.h index 96324d2b9a..6551ac77f9 100644 --- a/hw/riscv/trace-encoder.h +++ b/hw/riscv/trace-encoder.h @@ -46,8 +46,18 @@ struct TraceEncoder { bool trace_next_insn; bool ntrace; + uint64_t last_addr_reported; + uint64_t last_icnt_reset; + uint64_t icnt_accumulated; }; +typedef enum { + BRANCH_NOT_TAKEN = 0, + BRANCH_TAKEN_CONDITIONAL = 1, + BRANCH_TAKEN_UNCONDITIONAL = 2, +} TraceBranchRes; + + #define TYPE_TRACE_ENCODER "trace-encoder" OBJECT_DECLARE_SIMPLE_TYPE(TraceEncoder, TRACE_ENCODER) @@ -60,6 +70,8 @@ void trencoder_trace_trap_insn(Object *trencoder_obj, uint64_t tval); void trencoder_trace_ppccd(Object *trencoder_obj, uint64_t pc); void trencoder_report_updiscon(Object *trencoder_obj); -void trencoder_report_branch(Object *trencoder_obj, uint64_t pc, bool taken); +void trencoder_report_branch(Object *trencoder_obj, uint64_t pc, + uint64_t insn_len, uint64_t offset, + TraceBranchRes taken); #endif diff --git a/target/riscv/helper.h b/target/riscv/helper.h index b1de064e17..dcf2b74cb6 100644 --- a/target/riscv/helper.h +++ b/target/riscv/helper.h @@ -131,8 +131,8 @@ DEF_HELPER_6(csrrw_i128, tl, env, int, tl, tl, tl, tl) /* Trace helpers (should be put inside ifdef) */ DEF_HELPER_2(trace_insn, void, env, i64) -DEF_HELPER_1(trace_updiscon, void, env) -DEF_HELPER_3(trace_branch, void, env, tl, int) +DEF_HELPER_3(trace_updiscon, void, env, tl, tl) +DEF_HELPER_5(trace_branch, void, env, tl, tl, tl, int) #ifndef CONFIG_USER_ONLY DEF_HELPER_1(sret, tl, env) diff --git a/target/riscv/insn_trans/trans_privileged.c.inc b/target/riscv/insn_trans/trans_privileged.c.inc index 28089539d5..a3777b42e9 100644 --- a/target/riscv/insn_trans/trans_privileged.c.inc +++ b/target/riscv/insn_trans/trans_privileged.c.inc @@ -26,7 +26,7 @@ static bool trans_ecall(DisasContext *ctx, arg_ecall *a) { - gen_trace_updiscon(); + gen_trace_updiscon(ctx); /* always generates U-level ECALL, fixed in do_interrupt handler */ generate_exception(ctx, RISCV_EXCP_U_ECALL); @@ -42,7 +42,7 @@ static bool trans_ebreak(DisasContext *ctx, arg_ebreak *a) uint32_t ebreak = 0; uint32_t post = 0; - gen_trace_updiscon(); + gen_trace_updiscon(ctx); /* * The RISC-V semihosting spec specifies the following @@ -99,7 +99,7 @@ static bool trans_sret(DisasContext *ctx, arg_sret *a) { #ifndef CONFIG_USER_ONLY if (has_ext(ctx, RVS)) { - gen_trace_updiscon(); + gen_trace_updiscon(ctx); decode_save_opc(ctx, 0); translator_io_start(&ctx->base); @@ -119,7 +119,7 @@ static bool trans_sret(DisasContext *ctx, arg_sret *a) static bool trans_mret(DisasContext *ctx, arg_mret *a) { #ifndef CONFIG_USER_ONLY - gen_trace_updiscon(); + gen_trace_updiscon(ctx); decode_save_opc(ctx, 0); translator_io_start(&ctx->base); @@ -138,7 +138,7 @@ static bool trans_mnret(DisasContext *ctx, arg_mnret *a) #ifndef CONFIG_USER_ONLY REQUIRE_SMRNMI(ctx); - gen_trace_updiscon(); + gen_trace_updiscon(ctx); decode_save_opc(ctx, 0); gen_helper_mnret(cpu_pc, tcg_env); diff --git a/target/riscv/insn_trans/trans_rvi.c.inc b/target/riscv/insn_trans/trans_rvi.c.inc index ee29adbdeb..06fba108a8 100644 --- a/target/riscv/insn_trans/trans_rvi.c.inc +++ b/target/riscv/insn_trans/trans_rvi.c.inc @@ -183,7 +183,7 @@ static bool trans_jalr(DisasContext *ctx, arg_jalr *a) } } - gen_trace_updiscon(); + gen_trace_updiscon(ctx); lookup_and_goto_ptr(ctx); @@ -268,15 +268,6 @@ static void gen_setcond_i128(TCGv rl, TCGv rh, tcg_gen_movi_tl(rh, 0); } -static void gen_trace_branch(int taken) -{ - TCGLabel *skip = gen_new_label(); - - tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_trace_running, 0, skip); - gen_helper_trace_branch(tcg_env, cpu_pc, tcg_constant_i32(taken)); - gen_set_label(skip); -} - static bool gen_branch(DisasContext *ctx, arg_b *a, TCGCond cond) { TCGLabel *l = gen_new_label(); @@ -308,14 +299,14 @@ static bool gen_branch(DisasContext *ctx, arg_b *a, TCGCond cond) } #endif - gen_trace_branch(0); + gen_trace_branch(0, 0, 0); gen_goto_tb(ctx, 1, ctx->cur_insn_len); ctx->pc_save = orig_pc_save; gen_set_label(l); /* branch taken */ - gen_trace_branch(1); + gen_trace_branch(1, a->imm, ctx->cur_insn_len); if (!riscv_cpu_allow_16bit_insn(ctx->cfg_ptr, ctx->priv_ver, diff --git a/target/riscv/trace_helper.c b/target/riscv/trace_helper.c index 9b43aeac09..f6201e2fb9 100644 --- a/target/riscv/trace_helper.c +++ b/target/riscv/trace_helper.c @@ -29,7 +29,8 @@ void helper_trace_insn(CPURISCVState *env, uint64_t pc) } } -void helper_trace_updiscon(CPURISCVState *env) +void helper_trace_updiscon(CPURISCVState *env, target_ulong curr_pc, + target_ulong curr_inst_len) { RISCVCPU *cpu = env_archcpu(env); TraceEncoder *te = TRACE_ENCODER(cpu->trencoder); @@ -42,11 +43,12 @@ void helper_trace_updiscon(CPURISCVState *env) } } -void helper_trace_branch(CPURISCVState *env, target_ulong pc, int taken) +void helper_trace_branch(CPURISCVState *env, target_ulong pc, + target_ulong insn_len, target_ulong offset, int taken) { RISCVCPU *cpu = env_archcpu(env); - trencoder_report_branch(cpu->trencoder, pc, taken); + trencoder_report_branch(cpu->trencoder, pc, insn_len, offset, taken); } #else /* #ifndef CONFIG_USER_ONLY */ void helper_trace_insn(CPURISCVState *env, uint64_t pc) @@ -54,12 +56,14 @@ void helper_trace_insn(CPURISCVState *env, uint64_t pc) return; } -void helper_trace_updiscon(CPURISCVState *env) +void helper_trace_updiscon(CPURISCVState *env, target_ulong pc, + target_ulong curr_inst_len) { return; } -void helper_trace_branch(CPURISCVState *env, target_ulong pc, int taken) +void helper_trace_branch(CPURISCVState *env, target_ulong pc, + target_ulong insn_len, target_ulong offset, int taken) { return; } diff --git a/target/riscv/translate.c b/target/riscv/translate.c index 26c7678cb9..781068ad84 100644 --- a/target/riscv/translate.c +++ b/target/riscv/translate.c @@ -617,12 +617,25 @@ static void gen_ctr_jal(DisasContext *ctx, int rd, target_ulong imm) } #endif -static void gen_trace_updiscon(void) +static void gen_trace_updiscon(DisasContext *ctx) { TCGLabel *skip = gen_new_label(); + TCGv curr_pc = tcg_constant_tl(ctx->base.pc_next); + TCGv curr_inst_len = tcg_constant_tl(ctx->cur_insn_len); tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_trace_running, 0, skip); - gen_helper_trace_updiscon(tcg_env); + gen_helper_trace_updiscon(tcg_env, curr_pc, curr_inst_len); + gen_set_label(skip); +} + +static void gen_trace_branch(int taken, target_ulong imm, target_ulong cur_insn_len) +{ + TCGLabel *skip = gen_new_label(); + TCGv offset = tcg_constant_tl(imm); + TCGv insn_len = tcg_constant_tl(cur_insn_len); + + tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_trace_running, 0, skip); + gen_helper_trace_branch(tcg_env, cpu_pc, insn_len, offset, tcg_constant_i32(taken)); gen_set_label(skip); } @@ -647,6 +660,8 @@ static void gen_jal(DisasContext *ctx, int rd, target_ulong imm) gen_ctr_jal(ctx, rd, imm); } #endif + const int BRANCH_TAKEN_UNCONDITIONAL = 2; + gen_trace_branch(BRANCH_TAKEN_UNCONDITIONAL, imm, ctx->cur_insn_len); gen_pc_plus_diff(succ_pc, ctx, ctx->cur_insn_len); gen_set_gpr(ctx, rd, succ_pc); -- 2.43.0