Branch info is reported via the TCG helpers, updating the trace encoder
internal branch map.
Branch packets are sent in two circunstances:
- when the branch map is full;
- when an updiscon packet is about to be sent and the branch map
isn't empty.
The former will trigger a Format 1 no-addr packet, the latter a Format 1
with the updiscon address.
Signed-off-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com>
---
hw/riscv/trace-encoder.c | 52 ++++++++++++++++++++++++-
hw/riscv/trace-encoder.h | 4 ++
target/riscv/helper.h | 1 +
target/riscv/insn_trans/trans_rvi.c.inc | 13 +++++++
target/riscv/trace_helper.c | 12 ++++++
5 files changed, 81 insertions(+), 1 deletion(-)
diff --git a/hw/riscv/trace-encoder.c b/hw/riscv/trace-encoder.c
index 5572483d26..5b8f773b11 100644
--- a/hw/riscv/trace-encoder.c
+++ b/hw/riscv/trace-encoder.c
@@ -29,6 +29,8 @@
*/
#define TRACE_MSG_MAX_SIZE 32
+#define TRACE_MAX_BRANCHES 31
+
static TracePrivLevel trencoder_get_curr_priv_level(TraceEncoder *te)
{
CPURISCVState *env = &te->cpu->env;
@@ -313,6 +315,9 @@ static void trencoder_reset(DeviceState *dev)
te->trace_running = false;
te->trace_next_insn = false;
env->trace_running = false;
+
+ te->branch_map = 0;
+ te->branches = 0;
}
static void trencoder_realize(DeviceState *dev, Error **errp)
@@ -410,9 +415,20 @@ static void trencoder_send_updiscon(TraceEncoder *trencoder, uint64_t pc)
bool updiscon = !notify;
uint8_t msg_size;
- msg_size = rv_etrace_gen_encoded_format2_msg(format2_msg, pc,
+ if (trencoder->branches > 0) {
+ msg_size = rv_etrace_gen_encoded_format1(format2_msg,
+ trencoder->branches,
+ trencoder->branch_map,
+ pc,
notify,
updiscon);
+ trencoder->branches = 0;
+ } else {
+ msg_size = rv_etrace_gen_encoded_format2_msg(format2_msg, pc,
+ notify,
+ updiscon);
+ }
+
trencoder_send_message_smem(trencoder, format2_msg, msg_size);
trencoder->updiscon_pending = false;
@@ -457,6 +473,40 @@ void trencoder_trace_trap_insn(Object *trencoder_obj,
trencoder_send_message_smem(trencoder, msg, msg_size);
}
+static void trencoder_send_branch_map(Object *trencoder_obj)
+{
+ TraceEncoder *te = TRACE_ENCODER(trencoder_obj);
+ g_autofree uint8_t *msg = g_malloc0(TRACE_MSG_MAX_SIZE);
+ uint8_t msg_size;
+
+ msg_size = rv_etrace_gen_encoded_format1_noaddr(msg,
+ te->branches,
+ te->branch_map);
+ trencoder_send_message_smem(te, msg, msg_size);
+}
+
+void trencoder_report_branch(Object *trencoder_obj, uint64_t pc, bool taken)
+{
+ TraceEncoder *te = TRACE_ENCODER(trencoder_obj);
+
+ /*
+ * 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) {
+ te->branch_map = deposit32(te->branch_map, te->branches, 1, 1);
+ }
+
+ te->last_branch_pc = pc;
+ te->branches++;
+
+ if (te->branches == TRACE_MAX_BRANCHES) {
+ trencoder_send_branch_map(trencoder_obj);
+ te->branches = 0;
+ }
+}
+
void trencoder_trace_ppccd(Object *trencoder_obj, uint64_t pc)
{
TraceEncoder *trencoder = TRACE_ENCODER(trencoder_obj);
diff --git a/hw/riscv/trace-encoder.h b/hw/riscv/trace-encoder.h
index 0c44092ccb..854f8a9ad6 100644
--- a/hw/riscv/trace-encoder.h
+++ b/hw/riscv/trace-encoder.h
@@ -28,6 +28,9 @@ struct TraceEncoder {
uint32_t reg_mem_size;
uint64_t first_pc;
+ uint64_t last_branch_pc;
+ uint32_t branch_map;
+ uint8_t branches;
hwaddr baseaddr;
hwaddr dest_baseaddr;
@@ -54,5 +57,6 @@ 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);
#endif
diff --git a/target/riscv/helper.h b/target/riscv/helper.h
index f27ff319e9..b1de064e17 100644
--- a/target/riscv/helper.h
+++ b/target/riscv/helper.h
@@ -132,6 +132,7 @@ 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)
#ifndef CONFIG_USER_ONLY
DEF_HELPER_1(sret, tl, env)
diff --git a/target/riscv/insn_trans/trans_rvi.c.inc b/target/riscv/insn_trans/trans_rvi.c.inc
index ac00cbc802..ee29adbdeb 100644
--- a/target/riscv/insn_trans/trans_rvi.c.inc
+++ b/target/riscv/insn_trans/trans_rvi.c.inc
@@ -268,6 +268,15 @@ 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();
@@ -299,11 +308,15 @@ static bool gen_branch(DisasContext *ctx, arg_b *a, TCGCond cond)
}
#endif
+ gen_trace_branch(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);
+
if (!riscv_cpu_allow_16bit_insn(ctx->cfg_ptr,
ctx->priv_ver,
ctx->misa_ext) &&
diff --git a/target/riscv/trace_helper.c b/target/riscv/trace_helper.c
index 4b2b645f04..b48b89e0db 100644
--- a/target/riscv/trace_helper.c
+++ b/target/riscv/trace_helper.c
@@ -37,6 +37,13 @@ void helper_trace_updiscon(CPURISCVState *env)
te->updiscon_pending = true;
te->trace_next_insn = true;
}
+
+void helper_trace_branch(CPURISCVState *env, target_ulong pc, int taken)
+{
+ RISCVCPU *cpu = env_archcpu(env);
+
+ trencoder_report_branch(cpu->trencoder, pc, taken);
+}
#else /* #ifndef CONFIG_USER_ONLY */
void helper_trace_insn(CPURISCVState *env, uint64_t pc)
{
@@ -47,4 +54,9 @@ void helper_trace_updiscon(CPURISCVState *env)
{
return;
}
+
+void helper_trace_branch(CPURISCVState *env, target_ulong pc, int taken)
+{
+ return;
+}
#endif /* #ifndef CONFIG_USER_ONLY*/
--
2.51.1