From: Konstantin Semichastnov <k.semichastnov@syntacore.com>
To: Daniel Henrique Barboza <dbarboza@ventanamicro.com>,
<qemu-devel@nongnu.org>
Cc: <qemu-riscv@nongnu.org>, <alistair.francis@wdc.com>,
<liwei1518@gmail.com>, <zhiwei_liu@linux.alibaba.com>,
<palmer@dabbelt.com>
Subject: Re: [PATCH v2 06/17] hw/riscv: add e-trace message helpers
Date: Wed, 26 Nov 2025 12:03:59 +0300 [thread overview]
Message-ID: <cfde73ab-c9aa-4cef-a1ad-5a32d2a33261@syntacore.com> (raw)
In-Reply-To: <20251111114656.2285048-7-dbarboza@ventanamicro.com>
On 11/11/25 14:46, Daniel Henrique Barboza wrote:
> Before making the trace encoder writing into the RAM sink we need a way
> to encode the messages/packets. The encoding is LSB (least significant
> bit) based. The doc "Efficient Trace for RISC-V", Chapter 7, mentions:
>
> "The remainder of this section describes the contents of the payload
> portion which should be independent of the infrastructure. In each
> table, the fields are listed in transmission order: first field in
> the table is transmitted first, and multi-bit fields are transmitted
> LSB first."
>
> The "RISC-V Trace Control Interface Specification" docs, Chapter 7,
> states when talking about the Trace RAM Sink:
>
> "Trace data is placed in memory in LSB order (first byte of trace
> packet/data is placed on LSB)."
>
> This means that the LSB encoding must be used to write into the RAM Sink
> memory, which is our goal.
>
> The design we're going for is to have all these encoder helpers, along
> with the message formats, in a separated file. The trace encoder will
> make use of these helpers to blindly write a byte array with the packet
> desired, and then write it as is in the RAM Sink.
>
> We'll start by modeling the synchronisation packet first, adding more
> formats as we increment the Trace Encoder capabilities.
>
> Signed-off-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com>
> ---
> hw/riscv/meson.build | 3 +-
> hw/riscv/rv-trace-messages.c | 94 ++++++++++++++++++++++++++++++++++++
> hw/riscv/rv-trace-messages.h | 25 ++++++++++
> 3 files changed, 121 insertions(+), 1 deletion(-)
> create mode 100644 hw/riscv/rv-trace-messages.c
> create mode 100644 hw/riscv/rv-trace-messages.h
>
> diff --git a/hw/riscv/meson.build b/hw/riscv/meson.build
> index 2aadbe1e50..7d3576fcdf 100644
> --- a/hw/riscv/meson.build
> +++ b/hw/riscv/meson.build
> @@ -14,6 +14,7 @@ riscv_ss.add(when: 'CONFIG_RISCV_IOMMU', if_true: files(
> 'riscv-iommu.c', 'riscv-iommu-pci.c', 'riscv-iommu-sys.c', 'riscv-iommu-hpm.c'))
> riscv_ss.add(when: 'CONFIG_MICROBLAZE_V', if_true: files('microblaze-v-generic.c'))
> riscv_ss.add(when: 'CONFIG_XIANGSHAN_KUNMINGHU', if_true: files('xiangshan_kmh.c'))
> -riscv_ss.add(when: 'CONFIG_RISCV_TRACE', if_true: files('trace-encoder.c', 'trace-ram-sink.c'))
> +riscv_ss.add(when: 'CONFIG_RISCV_TRACE', if_true: files('trace-encoder.c',
> + 'trace-ram-sink.c', 'rv-trace-messages.c'))
>
> hw_arch += {'riscv': riscv_ss}
> diff --git a/hw/riscv/rv-trace-messages.c b/hw/riscv/rv-trace-messages.c
> new file mode 100644
> index 0000000000..215135dd47
> --- /dev/null
> +++ b/hw/riscv/rv-trace-messages.c
> @@ -0,0 +1,94 @@
> +/*
> + * Helpers for RISC-V Trace Messages
> + *
> + * Copyright (C) 2025 Ventana Micro Systems Inc.
> + *
> + * SPDX-License-Identifier: GPL-2.0-or-later
> + */
> +
> +#include "qemu/osdep.h"
> +
> +#include "rv-trace-messages.h"
> +#include "qemu/bitops.h"
> +#include "qemu/log.h"
> +#include "qemu/module.h"
> +#include "qapi/error.h"
> +#include "trace.h"
> +
> +typedef struct RVTraceMessageHeader {
> + uint8_t length:5;
> + uint8_t flow:2;
> + uint8_t extend:1;
> +} RVTraceMessageHeader;
> +#define HEADER_SIZE 1
I suggest to move all such size macros
to single enum to keep them all in one place:
typedef enum {
HEADER_SIZE = 1,
SYNC_PAYLOAD_SIZE_64BITS = 9,
/* and other */
} RVTraceMessagePayloadSize;
> +
> +/*
> + * Format 3 subformat 0 without 'time' and 'context' fields
> + */
> +typedef struct RVTraceSyncPayload {
> + uint8_t format:2;
> + uint8_t subformat:2;
> + uint8_t branch:1;
> + uint8_t privilege:3;
> + uint32_t addressLow;
> + uint32_t addressHigh;
> +} RVTraceSyncPayload;
> +#define SYNC_PAYLOAD_SIZE_64BITS 9
> +
> +static void rv_etrace_write_bits(uint8_t *bytes, uint32_t bit_pos,
> + uint32_t num_bits, uint32_t val)
Let's return num_bits here, so we could increment bit offset with return
value.
> +{
> + uint32_t pos, byte_index, byte_pos, byte_bits = 0;
> +
> + if (!num_bits || 32 < num_bits) {
> + return;
> + }
> +
> + for (pos = 0; pos < num_bits; pos += byte_bits) {
> + byte_index = (bit_pos + pos) >> 3;
> + byte_pos = (bit_pos + pos) & 0x7;
> + byte_bits = (8 - byte_pos) < (num_bits - pos) ?
> + (8 - byte_pos) : (num_bits - pos);
> + bytes[byte_index] &= ~(((1U << byte_bits) - 1) << byte_pos);
> + bytes[byte_index] |= ((val >> pos) & ((1U << byte_bits) - 1)) << byte_pos;
I suggest to break this down a bit, because it very overloaded,
and this is very unclear without comments or references to
specification.
1. Let's add a reference to chapter 7 of e-trace spec in comment.
2. Let's use arithmetic operations to compute byte_index
and byte_pos:
byte_index = (bit_pos + pos) / 8;
byte_pos = (bit_pos + pos) % 8;
Compiler will optimize it anyway, but it is more clear what does
division and reminder mean compared to bitwise "shift" and "and".
3. Let's use macro MIN to comute byte_bits:
byte_bits = MIN(8 - byte_pos, num_bits - pos);
4. Let's use extract32 and deposit32 to move bits from "val" to
"bytes" instead of manually shifting bits:
uint8_t chunk = extract32(val, pos, byte_bits);
bytes[byte_index] = deposit32(bytes[byte_index], byte_pos,
byte_bits, chunk);
> + }
> +}
> +
> +static void rv_etrace_write_header(uint8_t *buf, RVTraceMessageHeader header)
> +{
> + /* flow and extend are always zero, i.e just write length */
> + rv_etrace_write_bits(buf, 0, 5, header.length);
Flow and extend are, indeed, always zero, but we still need to write
them to buffer.
Also, let's keep it as generic as possible, and write all fields from
header, and not hardcoded zeroes.
uint8_t bit_pos = 0;
bit_pos += rv_etrace_write_bits(buf, bit_pos, 5, header.length);
bit_pos += rv_etrace_write_bits(buf, bit_pos, 2, header.flow);
bit_pos += rv_etrace_write_bits(buf, bit_pos, 1, header.extend);
> +}
> +
> +size_t rv_etrace_gen_encoded_sync_msg(uint8_t *buf, uint64_t pc,
> + TracePrivLevel priv_level)
> +{
> + RVTraceSyncPayload payload = {.format = 0b11,
> + .subformat = 0b00,
> + .branch = 1,
> + .privilege = priv_level};
Let's assign addressLow and addressHigh right away:
RVTraceSyncPayload payload = {.format = 0b11,
.subformat = 0b00,
.branch = 1,
.privilege = priv_level,
.addressLow = extract64(pc, 0, 32),
.addressHigh = extract64(pc, 32, 32)};
> + RVTraceMessageHeader header = {.flow = 0, .extend = 0,
> + .length = SYNC_PAYLOAD_SIZE_64BITS};
> + uint8_t bit_pos;
> +
> + payload.addressLow = extract64(pc, 0, 32);
> + payload.addressHigh = extract64(pc, 32, 32);
> +
> + rv_etrace_write_header(buf, header);
> + bit_pos = 8;
> +
> + rv_etrace_write_bits(buf, bit_pos, 2, payload.format);
> + bit_pos += 2;
> + rv_etrace_write_bits(buf, bit_pos, 2, payload.subformat);
> + bit_pos += 2;
> + rv_etrace_write_bits(buf, bit_pos, 1, payload.branch);
> + bit_pos += 1;
> + rv_etrace_write_bits(buf, bit_pos, 3, payload.privilege);
> + bit_pos += 3;
> +
> + rv_etrace_write_bits(buf, bit_pos, 32, payload.addressLow);
> + bit_pos += 32;
> + rv_etrace_write_bits(buf, bit_pos, 32, payload.addressHigh);
Let's return num_bits value from rv_etrace_write_bits(), so we could
just increment bit_pos with return value:
uint8_t bit_pos = 0;
bit_pos += rv_etrace_write_header(buf, header);
bit_pos += rv_etrace_write_bits(buf, bit_pos, 2, payload.format);
bit_pos += rv_etrace_write_bits(buf, bit_pos, 2, payload.subformat);
bit_pos += rv_etrace_write_bits(buf, bit_pos, 1, payload.branch);
bit_pos += rv_etrace_write_bits(buf, bit_pos, 3, payload.privilege);
bit_pos += rv_etrace_write_bits(buf, bit_pos, 32,
payload.addressLow);
bit_pos += rv_etrace_write_bits(buf, bit_pos, 32,
payload.addressHigh);
> +
> + return HEADER_SIZE + SYNC_PAYLOAD_SIZE_64BITS;
> +}
> diff --git a/hw/riscv/rv-trace-messages.h b/hw/riscv/rv-trace-messages.h
> new file mode 100644
> index 0000000000..aeafea8849
> --- /dev/null
> +++ b/hw/riscv/rv-trace-messages.h
> @@ -0,0 +1,25 @@
> +/*
> + * Helpers for RISC-V Trace Messages
> + *
> + * Copyright (C) 2025 Ventana Micro Systems Inc.
> + *
> + * SPDX-License-Identifier: GPL-2.0-or-later
> + */
> +
> +#ifndef RISCV_RV_TRACE_MESSAGES_H
> +#define RISCV_RV_TRACE_MESSAGES_H
> +
> +typedef enum {
> + U = 0,
> + S_HS = 1,
> + RESERVED = 2,
> + M = 3,
> + D = 4,
> + VU = 5,
> + VS = 6,
> +} TracePrivLevel;
> +
> +size_t rv_etrace_gen_encoded_sync_msg(uint8_t *buf, uint64_t pc,
> + TracePrivLevel priv_level);
> +
> +#endif
next prev parent reply other threads:[~2025-11-26 9:04 UTC|newest]
Thread overview: 24+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-11-11 11:46 [PATCH v2 00/17] hw/riscv, target/riscv: initial e-trace support Daniel Henrique Barboza
2025-11-11 11:46 ` [PATCH v2 01/17] hw/riscv: Trace Encoder initial impl Daniel Henrique Barboza
2025-11-20 15:56 ` Konstantin Semichastnov
2025-11-11 11:46 ` [PATCH v2 02/17] hw/riscv: Trace RAM Sink " Daniel Henrique Barboza
2025-11-20 18:03 ` Konstantin Semichastnov
2025-11-25 20:08 ` Daniel Henrique Barboza
2025-11-11 11:46 ` [PATCH v2 03/17] hw/riscv/trace-encoder: add trace start/stop logic Daniel Henrique Barboza
2025-11-11 11:46 ` [PATCH v2 04/17] hw/riscv/virt.c: add trace encoders and trace ram sinks Daniel Henrique Barboza
2025-11-11 11:46 ` [PATCH v2 05/17] hw/riscv/virt.c add trace encoder and ramsink fdt nodes Daniel Henrique Barboza
2025-11-11 11:46 ` [PATCH v2 06/17] hw/riscv: add e-trace message helpers Daniel Henrique Barboza
2025-11-26 9:03 ` Konstantin Semichastnov [this message]
2025-11-11 11:46 ` [PATCH v2 07/17] target/riscv: add initial trace instrumentation Daniel Henrique Barboza
2025-11-11 11:46 ` [PATCH v2 08/17] hw/riscv/trace-encoder: write e-trace packets to RAM sink Daniel Henrique Barboza
2025-11-11 11:46 ` [PATCH v2 09/17] test/qtest: add riscv-trace-test.c Daniel Henrique Barboza
2025-11-11 11:46 ` [PATCH v2 10/17] hw/riscv/rv-trace-messages.c: add encoded trap message Daniel Henrique Barboza
2025-11-11 11:46 ` [PATCH v2 11/17] hw/riscv, target/riscv: send trace trap messages Daniel Henrique Barboza
2025-11-11 11:46 ` [PATCH v2 12/17] target/riscv, hw/riscv: send trace ppccd packets Daniel Henrique Barboza
2025-11-11 11:46 ` [PATCH v2 13/17] hw/riscv/trace: add format2 msg helper Daniel Henrique Barboza
2025-11-11 11:46 ` [PATCH v2 14/17] hw/riscv, target/riscv: send resync updiscon trace packets Daniel Henrique Barboza
2025-11-11 11:46 ` [PATCH v2 15/17] hw/riscv/rv-trace-messages: add format 1 msgs with branch info Daniel Henrique Barboza
2025-11-11 11:46 ` [PATCH v2 16/17] hw/riscv/trace-encoder: send branches info Daniel Henrique Barboza
2025-11-11 11:46 ` [PATCH v2 17/17] hw/riscv/trace: update branch bit in sync messages Daniel Henrique Barboza
2025-11-20 12:14 ` [PATCH v2 00/17] hw/riscv, target/riscv: initial e-trace support Konstantin Semichastnov
2025-11-25 17:33 ` Daniel Henrique Barboza
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=cfde73ab-c9aa-4cef-a1ad-5a32d2a33261@syntacore.com \
--to=k.semichastnov@syntacore.com \
--cc=alistair.francis@wdc.com \
--cc=dbarboza@ventanamicro.com \
--cc=liwei1518@gmail.com \
--cc=palmer@dabbelt.com \
--cc=qemu-devel@nongnu.org \
--cc=qemu-riscv@nongnu.org \
--cc=zhiwei_liu@linux.alibaba.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).