qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
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 01/17] hw/riscv: Trace Encoder initial impl
Date: Thu, 20 Nov 2025 18:56:55 +0300	[thread overview]
Message-ID: <1ba7cae6-7683-4958-9c20-cef8fb0a8f46@syntacore.com> (raw)
In-Reply-To: <20251111114656.2285048-2-dbarboza@ventanamicro.com>



On 11/11/25 14:46, Daniel Henrique Barboza wrote:
> The Trace Encoder is a hardware module that interacts with a CPU,
> gathering execution information (a.k.a instruction delta trace), and
> send it downstream to other storage components such as a RAM Sink (a RAM
> storage). This trace info can then be read via software (e.g. perf) to
> reproduce the behavior of a given binary that ran in the CPU.
> 
> This implementation is based on the Efficient Trace for RISC-V [1] and
> RISC-V Trace Control Interface Specification [2]. It's not intended to
> implement all spec features: the idea is to provide a base where we can
> add extra features on demand.
> 
> We'll get back to the instruction delta trace and how we'll instrument
> TCG to produce it later. For now we'll set the minimal components to get
> the basic framework running.
> 
> This Trace Encoder impl has just the minimal bits specified in [2],
> section "Minimal Implementation". RO and RSVP bits are taken verbatim
> from [2] without considering what we're actually going to support. The
> base impl is heavily inspired by the XLNZ-ZDMA device w.r.t the usage of
> the RegisterInfo and register.h framework.
> 
> Discovery of the Trace Encoder will be made via fdt, a single entry per
> CPU. We'll connect each Trace Encoder to its CPU in the 'virt' board
> later.
> 
> [1] https://github.com/riscv-non-isa/riscv-trace-spec/releases/download/v2.0-20250616/riscv-trace-spec-asciidoc.pdf
> [2] https://github.com/riscv-non-isa/tg-nexus-trace/releases/download/1.0_Ratified/RISC-V-Trace-Control-Interface.pdf
> 
> Signed-off-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com>
> ---
>   hw/riscv/Kconfig         |   5 +
>   hw/riscv/meson.build     |   1 +
>   hw/riscv/trace-encoder.c | 216 +++++++++++++++++++++++++++++++++++++++
>   hw/riscv/trace-encoder.h |  42 ++++++++
>   hw/riscv/trace-events    |   4 +
>   5 files changed, 268 insertions(+)
>   create mode 100644 hw/riscv/trace-encoder.c
>   create mode 100644 hw/riscv/trace-encoder.h
> 
> diff --git a/hw/riscv/Kconfig b/hw/riscv/Kconfig
> index fc9c35bd98..2de0892496 100644
> --- a/hw/riscv/Kconfig
> +++ b/hw/riscv/Kconfig
> @@ -7,6 +7,10 @@ config RISCV_NUMA
>   config IBEX
>       bool
>   
> +config RISCV_TRACE
> +    bool
> +    select REGISTER
> +
>   # RISC-V machines in alphabetical order
>   
>   config MICROCHIP_PFSOC
> @@ -68,6 +72,7 @@ config RISCV_VIRT
>       select PLATFORM_BUS
>       select ACPI
>       select ACPI_PCI
> +    select RISCV_TRACE
>   
>   config SHAKTI_C
>       bool
> diff --git a/hw/riscv/meson.build b/hw/riscv/meson.build
> index 2a8d5b136c..b4a9988a62 100644
> --- a/hw/riscv/meson.build
> +++ b/hw/riscv/meson.build
> @@ -14,5 +14,6 @@ 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'))
>   
>   hw_arch += {'riscv': riscv_ss}
> diff --git a/hw/riscv/trace-encoder.c b/hw/riscv/trace-encoder.c
> new file mode 100644
> index 0000000000..21bf650a6a
> --- /dev/null
> +++ b/hw/riscv/trace-encoder.c
> @@ -0,0 +1,216 @@
> +/*
> + * Emulation of a RISC-V Trace Encoder
> + *
> + * Copyright (C) 2025 Ventana Micro Systems Inc.
> + *
> + * SPDX-License-Identifier: GPL-2.0-or-later
> + */
> +
> +#include "qemu/osdep.h"
> +
> +#include "trace-encoder.h"
> +#include "hw/irq.h"
> +#include "hw/qdev-properties.h"
> +#include "migration/vmstate.h"
> +#include "qemu/bitops.h"
> +#include "qemu/log.h"
> +#include "qemu/module.h"
> +#include "qapi/error.h"
> +#include "trace.h"
> +#include "system/device_tree.h"
> +#include "hw/register.h"
> +#include "cpu.h"
> +
> +/*
> + * trTeControl register fields
> + */
> +REG32(TR_TE_CONTROL, 0x0)
> +    FIELD(TR_TE_CONTROL, ACTIVE, 0, 1)
> +    FIELD(TR_TE_CONTROL, ENABLE, 1, 1)
> +    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, INST_SYNC_MODE, 16, 2)
> +    FIELD(TR_TE_CONTROL, FORMAT, 24, 3)
> +    /* reserved bits */
> +    FIELD(TR_TE_CONTROL, RSVP1, 7, 2)
> +    FIELD(TR_TE_CONTROL, RSVP2, 10, 1)
> +    FIELD(TR_TE_CONTROL, RSVP3, 14, 1)
> +    FIELD(TR_TE_CONTROL, RSVP4, 18, 2)
> +    FIELD(TR_TE_CONTROL, RSVP5, 27, 4)
RSVP5 should be 5 bits long, as it occupies bits [27:31]

> +
> +#define R_TR_TE_CONTROL_RSVP_BITS (MAKE_64BIT_MASK(32, 32) | \
> +                                   R_TR_TE_CONTROL_RSVP1_MASK | \
> +                                   R_TR_TE_CONTROL_RSVP2_MASK | \
> +                                   R_TR_TE_CONTROL_RSVP3_MASK | \
> +                                   R_TR_TE_CONTROL_RSVP4_MASK | \
> +                                   R_TR_TE_CONTROL_RSVP5_MASK)
> +
> +/* trTeControlEmpty is the only RO field and reset value */
> +#define R_TR_TE_CONTROL_RESET R_TR_TE_CONTROL_EMPTY_MASK
> +#define R_TR_TE_CONTROL_RO_BITS R_TR_TE_CONTROL_EMPTY_MASK
> +
> +/*
> + * trTeImpl register fields
> + */
> +REG32(TR_TE_IMPL, 0x4)
> +    FIELD(TR_TE_IMPL, VER_MAJOR, 0, 4)
> +    FIELD(TR_TE_IMPL, VER_MINOR, 4, 4)
> +    FIELD(TR_TE_IMPL, COMP_TYPE, 8, 4)
> +    FIELD(TR_TE_IMPL, PROTOCOL_MAJOR, 16, 4)
> +    FIELD(TR_TE_IMPL, PROTOCOL_MINOR, 20, 4)
> +    /* reserved bits */
> +    FIELD(TR_TE_IMPL, RSVP1, 12, 4)
> +    FIELD(TR_TE_IMPL, RSVP2, 24, 8)
> +
> +#define R_TR_TE_IMPL_RSVP_BITS (MAKE_64BIT_MASK(32, 32) | \
> +                                R_TR_TE_IMPL_RSVP1_MASK | \
> +                                R_TR_TE_IMPL_RSVP2_MASK)
> +
> +#define R_TR_TE_IMPL_RO_BITS (R_TR_TE_IMPL_VER_MAJOR_MASK | \
> +                              R_TR_TE_IMPL_VER_MINOR_MASK | \
> +                              R_TR_TE_IMPL_COMP_TYPE_MASK | \
> +                              R_TR_TE_IMPL_PROTOCOL_MAJOR_MASK | \
> +                              R_TR_TE_IMPL_PROTOCOL_MINOR_MASK)
> +
> +#define R_TR_TE_IMPL_RESET (BIT(0) | BIT(8))
> +
> +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,
> +    },
> +    {   .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,
> +    },
> +};
> +
> +static uint64_t trencoder_read(void *opaque, hwaddr addr, unsigned size)
> +{
> +    TraceEncoder *te = TRACE_ENCODER(opaque);
> +    RegisterInfo *r = &te->regs_info[addr / 4];
> +
> +    if (!r->data) {
> +        trace_trencoder_read_error(addr);
> +        return 0;
> +    }
> +
> +    return register_read(r, ~0, NULL, false);
> +}
> +
> +static void trencoder_write(void *opaque, hwaddr addr,
> +                            uint64_t value, unsigned size)
> +{
> +    TraceEncoder *te = TRACE_ENCODER(opaque);
> +    RegisterInfo *r = &te->regs_info[addr / 4];
> +
> +    if (!r->data) {
> +        trace_trencoder_write_error(addr, value);
> +        return;
> +    }
> +
> +    register_write(r, value, ~0, NULL, false);
> +}
> +
> +static const MemoryRegionOps trencoder_ops = {
> +    .read = trencoder_read,
> +    .write = trencoder_write,
> +    .endianness = DEVICE_LITTLE_ENDIAN,
> +    .valid = {
> +        .min_access_size = 4,
> +        .max_access_size = 4,
> +    },
> +};
> +
> +static void trencoder_reset(DeviceState *dev)
> +{
> +    TraceEncoder *te = TRACE_ENCODER(dev);
> +
> +    for (int i = 0; i < ARRAY_SIZE(te->regs_info); i++) {
> +        register_reset(&te->regs_info[i]);
> +    }
> +}
> +
> +static void trencoder_realize(DeviceState *dev, Error **errp)
> +{
> +    TraceEncoder *te = TRACE_ENCODER(dev);
> +
> +    memory_region_init_io(&te->reg_mem, OBJECT(dev),
> +                          &trencoder_ops, te,
> +                          TYPE_TRACE_ENCODER,
> +                          te->reg_mem_size);
> +    sysbus_init_mmio(SYS_BUS_DEVICE(dev), &te->reg_mem);
> +    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, te->baseaddr);
> +
> +    /* RegisterInfo init taken from hw/dma/xlnx-zdma.c */
> +    for (int i = 0; i < ARRAY_SIZE(trencoder_regs_info); i++) {
> +        uint32_t reg_idx = trencoder_regs_info[i].addr / 4;
> +        RegisterInfo *r = &te->regs_info[reg_idx];
> +
> +        *r = (RegisterInfo) {
> +            .data = (uint8_t *)&te->regs[reg_idx],
> +            .data_size = sizeof(uint32_t),
> +            .access = &trencoder_regs_info[i],
> +            .opaque = te,
> +        };
> +    }
> +}
> +
> +static const Property trencoder_props[] = {
> +    /*
> +     * We need a link to the associated CPU to
> +     * enable/disable tracing.
> +     */
> +    DEFINE_PROP_LINK("cpu", TraceEncoder, cpu, TYPE_RISCV_CPU, RISCVCPU *),
> +    DEFINE_PROP_UINT64("baseaddr", TraceEncoder, baseaddr, 0),
> +    DEFINE_PROP_UINT64("dest-baseaddr", TraceEncoder, dest_baseaddr, 0),
> +    DEFINE_PROP_UINT64("ramsink-ramstart", TraceEncoder,
> +                       ramsink_ramstart, 0),
> +    DEFINE_PROP_UINT64("ramsink-ramlimit", TraceEncoder,
> +                       ramsink_ramlimit, 0),
> +    DEFINE_PROP_UINT32("reg-mem-size", TraceEncoder,
> +                       reg_mem_size, TRACE_R_MAX * 4),
> +    DEFINE_PROP_INT32("cpu-id", TraceEncoder, cpu_id, 0),
> +};
> +
> +static const VMStateDescription vmstate_trencoder = {
> +    .name = TYPE_TRACE_ENCODER,
> +    .version_id = 1,
> +    .minimum_version_id = 1,
> +    .fields = (const VMStateField[]) {
> +        VMSTATE_UINT32_ARRAY(regs, TraceEncoder, TRACE_R_MAX),
> +        VMSTATE_UINT64(baseaddr, TraceEncoder),
> +        VMSTATE_UINT64(dest_baseaddr, TraceEncoder),
> +        VMSTATE_UINT64(ramsink_ramstart, TraceEncoder),
> +        VMSTATE_UINT64(ramsink_ramlimit, TraceEncoder),
> +        VMSTATE_INT32(cpu_id, TraceEncoder),
> +        VMSTATE_END_OF_LIST(),
> +    }
> +};
> +
> +static void trencoder_class_init(ObjectClass *klass, const void *data)
> +{
> +    DeviceClass *dc = DEVICE_CLASS(klass);
> +
> +    device_class_set_legacy_reset(dc, trencoder_reset);
> +    device_class_set_props(dc, trencoder_props);
> +    dc->realize = trencoder_realize;
> +    dc->vmsd = &vmstate_trencoder;
> +}
> +
> +static const TypeInfo trencoder_info = {
> +    .name          = TYPE_TRACE_ENCODER,
> +    .parent        = TYPE_SYS_BUS_DEVICE,
> +    .instance_size = sizeof(TraceEncoder),
> +    .class_init    = trencoder_class_init,
> +};
> +
> +static void trencoder_register_types(void)
> +{
> +    type_register_static(&trencoder_info);
> +}
> +
> +type_init(trencoder_register_types)
> diff --git a/hw/riscv/trace-encoder.h b/hw/riscv/trace-encoder.h
> new file mode 100644
> index 0000000000..71002f58a4
> --- /dev/null
> +++ b/hw/riscv/trace-encoder.h
> @@ -0,0 +1,42 @@
> +/*
> + * Emulation of a RISC-V Trace Encoder
> + *
> + * Copyright (C) 2025 Ventana Micro Systems Inc.
> + *
> + * SPDX-License-Identifier: GPL-2.0-or-later
> + */
> +
> +#ifndef RISCV_TRACE_ENCODER_H
> +#define RISCV_TRACE_ENCODER_H
> +
> +#include "hw/sysbus.h"
> +#include "hw/register.h"
> +#include "system/dma.h"
> +#include "qom/object.h"
> +#include "cpu.h"
> +
> +#define TRACE_R_MAX (0xFFF / 4)
> +
> +struct TraceEncoder {
> +    /*< private >*/
> +    SysBusDevice parent_obj;
> +
> +    RISCVCPU *cpu;
> +    int cpu_id;
> +
> +    MemoryRegion reg_mem;
> +    uint32_t reg_mem_size;
> +
> +    hwaddr baseaddr;
> +    hwaddr dest_baseaddr;
> +    hwaddr ramsink_ramstart;
> +    hwaddr ramsink_ramlimit;
> +    uint32_t regs[TRACE_R_MAX];
> +    RegisterInfo regs_info[TRACE_R_MAX];
> +};
> +
> +#define TYPE_TRACE_ENCODER "trace-encoder"
> +
> +OBJECT_DECLARE_SIMPLE_TYPE(TraceEncoder, TRACE_ENCODER)
> +
> +#endif
> diff --git a/hw/riscv/trace-events b/hw/riscv/trace-events
> index b50b14a654..0cbf6ffcb6 100644
> --- a/hw/riscv/trace-events
> +++ b/hw/riscv/trace-events
> @@ -24,3 +24,7 @@ riscv_iommu_hpm_incr_ctr(uint64_t cntr_val) "cntr_val 0x%"PRIx64
>   riscv_iommu_hpm_iocntinh_cy(bool prev_cy_inh) "prev_cy_inh %d"
>   riscv_iommu_hpm_cycle_write(uint32_t ovf, uint64_t val) "ovf 0x%x val 0x%"PRIx64
>   riscv_iommu_hpm_evt_write(uint32_t ctr_idx, uint32_t ovf, uint64_t val) "ctr_idx 0x%x ovf 0x%x val 0x%"PRIx64
> +
> +# trace-encoder.c
> +trencoder_read_error(uint64_t addr) "addr 0x%" PRIx64
> +trencoder_write_error(uint64_t addr, uint64_t value) "addr 0x%" PRIx64 " value 0x%" PRIx64



  reply	other threads:[~2025-11-20 15:58 UTC|newest]

Thread overview: 21+ 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 [this message]
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-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-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

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=1ba7cae6-7683-4958-9c20-cef8fb0a8f46@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).