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


Reply via email to