Starting/stopping a trace session will rely on two flags:
- trace_next_insn: this flag will be used to signal the translation that
the encoder wants to know the PC of the current insn. The translation
helper (to be added) will clear this flag after sending the current
insn to the encoder;
- trace_running: shows that we're running a trace session and certain
insns classes (traps, certain jumps and branches) need to report to
the trace encoder.
These flags are controlled by the trTeInstTracing bit. This bit requires
other two bits to be set beforehand (ACTIVE and ENABLE). We'll revisit
these bits in the future as more features are implemented.
While we're at it, add hardwire bits to indicate which features we're
(not) implementing at this time.
Signed-off-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com>
---
hw/riscv/trace-encoder.c | 107 +++++++++++++++++++++++++++++++++++++++
hw/riscv/trace-encoder.h | 4 ++
2 files changed, 111 insertions(+)
diff --git a/hw/riscv/trace-encoder.c b/hw/riscv/trace-encoder.c
index 21bf650a6a..d45e45d17e 100644
--- a/hw/riscv/trace-encoder.c
+++ b/hw/riscv/trace-encoder.c
@@ -30,7 +30,11 @@ REG32(TR_TE_CONTROL, 0x0)
FIELD(TR_TE_CONTROL, INST_TRACING, 2, 1)
FIELD(TR_TE_CONTROL, EMPTY, 3, 1)
FIELD(TR_TE_CONTROL, INST_MODE, 4, 3)
+ FIELD(TR_TE_CONTROL, CONTEXT, 9, 1)
+ FIELD(TR_TE_CONTROL, INST_STALL_ENA, 13, 1)
+ FIELD(TR_TE_CONTROL, INHIBIT_SRC, 15, 1)
FIELD(TR_TE_CONTROL, INST_SYNC_MODE, 16, 2)
+ FIELD(TR_TE_CONTROL, INST_SYNC_MAX, 20, 4)
FIELD(TR_TE_CONTROL, FORMAT, 24, 3)
/* reserved bits */
FIELD(TR_TE_CONTROL, RSVP1, 7, 2)
@@ -75,17 +79,116 @@ REG32(TR_TE_IMPL, 0x4)
#define R_TR_TE_IMPL_RESET (BIT(0) | BIT(8))
+REG32(TR_TE_INST_FEATURES, 0x8)
+ FIELD(TR_TE_INST_FEATURES, NO_ADDR_DIFF, 0, 1)
+
+static uint64_t trencoder_te_ctrl_set_hardwire_vals(uint64_t input)
+{
+ input = FIELD_DP32(input, TR_TE_CONTROL, INST_MODE, 0x6);
+ input = FIELD_DP32(input, TR_TE_CONTROL, CONTEXT, 0);
+ input = FIELD_DP32(input, TR_TE_CONTROL, INST_STALL_ENA, 0);
+ input = FIELD_DP32(input, TR_TE_CONTROL, INHIBIT_SRC, 1);
+ input = FIELD_DP32(input, TR_TE_CONTROL, FORMAT, 0);
+
+ /* SYNC_MODE and SYNC_MAX will be revisited */
+ input = FIELD_DP32(input, TR_TE_CONTROL, INST_SYNC_MODE, 0);
+ input = FIELD_DP32(input, TR_TE_CONTROL, INST_SYNC_MAX, 0);
+
+ return input;
+}
+
+static uint64_t trencoder_te_ctrl_prew(RegisterInfo *reg, uint64_t val)
+{
+ TraceEncoder *te = TRACE_ENCODER(reg->opaque);
+ uint32_t trTeActive = ARRAY_FIELD_EX32(te->regs, TR_TE_CONTROL, ACTIVE);
+ uint32_t trTeInstTracing = ARRAY_FIELD_EX32(te->regs, TR_TE_CONTROL,
+ INST_TRACING);
+ uint32_t temp;
+
+ val = trencoder_te_ctrl_set_hardwire_vals(val);
+
+ if (!trTeActive) {
+ /*
+ * 11.2 Reset and discovery, table 58, trTeControl = 0x1
+ * means "Release from reset and set all defaults." Do
+ * that only if trTeActive is 0.
+ */
+ if (val == 0x1) {
+ val = FIELD_DP32(val, TR_TE_CONTROL, EMPTY, 1);
+
+ return val;
+ }
+
+ /*
+ * 11.3 Enabling and Disabling hints that the device must
+ * be activated first (trTeActive = 1), then enabled.
+ * Do not enable the device if it's not active
+ * beforehand.
+ */
+ temp = FIELD_EX32(val, TR_TE_CONTROL, ENABLE);
+ if (temp) {
+ val = FIELD_DP32(val, TR_TE_CONTROL, ENABLE, 0);
+ }
+ }
+
+ /*
+ * Do not allow inst tracing to start if the device isn't
+ * already enabled. Do not allow enabling the devince and
+ * and enable tracing at the same time.
+ */
+ if (!te->enabled && trTeInstTracing) {
+ val = FIELD_DP32(val, TR_TE_CONTROL, INST_TRACING, 0);
+ }
+
+ return val;
+}
+
+static void trencoder_te_ctrl_postw(RegisterInfo *reg, uint64_t val)
+{
+ TraceEncoder *te = TRACE_ENCODER(reg->opaque);
+ uint32_t trTeActive = ARRAY_FIELD_EX32(te->regs, TR_TE_CONTROL, ACTIVE);
+ uint32_t trTeEnable = ARRAY_FIELD_EX32(te->regs, TR_TE_CONTROL, ENABLE);
+ uint32_t trTeInstTracing = ARRAY_FIELD_EX32(te->regs, TR_TE_CONTROL,
+ INST_TRACING);
+
+ if (!trTeActive) {
+ te->enabled = false;
+ te->trace_running = false;
+ te->trace_next_insn = false;
+ return;
+ }
+
+ if (te->enabled && !trTeEnable) {
+ /* TODO: this should cause a pending trace data flush. */
+ }
+
+ te->enabled = trTeEnable ? true : false;
+
+ if (!te->trace_running && trTeInstTracing) {
+ /* Starting trace. Ask the CPU for the first trace insn */
+ te->trace_next_insn = true;
+ }
+
+ te->trace_running = trTeInstTracing ? true : false;
+}
+
static RegisterAccessInfo trencoder_regs_info[] = {
{ .name = "TR_TE_CONTROL", .addr = A_TR_TE_CONTROL,
.rsvd = R_TR_TE_CONTROL_RSVP_BITS,
.reset = R_TR_TE_CONTROL_RESET,
.ro = R_TR_TE_CONTROL_RO_BITS,
+ .pre_write = &trencoder_te_ctrl_prew,
+ .post_write = &trencoder_te_ctrl_postw,
},
{ .name = "TR_TE_IMPL", .addr = A_TR_TE_IMPL,
.rsvd = R_TR_TE_IMPL_RSVP_BITS,
.reset = R_TR_TE_IMPL_RESET,
.ro = R_TR_TE_IMPL_RO_BITS,
},
+ { .name = "TR_TE_INST_FEATURES", .addr = A_TR_TE_INST_FEATURES,
+ .reset = R_TR_TE_INST_FEATURES_NO_ADDR_DIFF_MASK,
+ .ro = ~0,
+ },
};
static uint64_t trencoder_read(void *opaque, hwaddr addr, unsigned size)
@@ -132,6 +235,10 @@ static void trencoder_reset(DeviceState *dev)
for (int i = 0; i < ARRAY_SIZE(te->regs_info); i++) {
register_reset(&te->regs_info[i]);
}
+
+ te->enabled = false;
+ te->trace_running = false;
+ te->trace_next_insn = false;
}
static void trencoder_realize(DeviceState *dev, Error **errp)
diff --git a/hw/riscv/trace-encoder.h b/hw/riscv/trace-encoder.h
index 71002f58a4..001d872514 100644
--- a/hw/riscv/trace-encoder.h
+++ b/hw/riscv/trace-encoder.h
@@ -33,6 +33,10 @@ struct TraceEncoder {
hwaddr ramsink_ramlimit;
uint32_t regs[TRACE_R_MAX];
RegisterInfo regs_info[TRACE_R_MAX];
+
+ bool enabled;
+ bool trace_running;
+ bool trace_next_insn;
};
#define TYPE_TRACE_ENCODER "trace-encoder"
--
2.51.1