[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
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.