This is an automated email from Gerrit.

"liangzhen <[email protected]>" just uploaded a new patch set to Gerrit, 
which you can find at https://review.openocd.org/c/openocd/+/9215

-- gerrit

commit 72e793ff054c6cf561df063ab2d62c28375b9c3c
Author: liangzhen <[email protected]>
Date:   Wed Oct 29 19:38:57 2025 +0800

    target: Add RISC-V trace support
    
    Implement a basic framework for riscv trace where
    each type of riscv trace components only need to
    implement corresponding interfaces.
    
    Change-Id: I8eb19a73a86891d6816092d94fe3a7b8914ceedf
    Signed-off-by: liangzhen <[email protected]>

diff --git a/doc/openocd.texi b/doc/openocd.texi
index 91949d4089..2aee6f92b7 100644
--- a/doc/openocd.texi
+++ b/doc/openocd.texi
@@ -11676,6 +11676,87 @@ Displays all DSP registers' contents or get/set value 
by register name. Will dis
 an error if current CPU does not support DSP.
 @end deffn
 
+@section RISC-V Trace Drivers
+
+OpenOCD has limited support for RISC-V trace drivers using the @emph{rvtrace}
+group of commands.
+
+@deffn {Command} {rvtrace create} component_name type configparams...
+This command creates a rvtrace component instance @var{component_name}.
+@itemize
+@item @emph{component_name} ... is the name of the rvtrace component instance.
+This name is also used to create the rvtrace component object command, referred
+to here as $component_name, and in other places the component needs to be 
identified.
+@item @emph{type} ...  specifies the rvtrace component type.
+@item @emph{configparams} ... all parameters accepted by $component_name 
configure
+are permitted. You must set the @option{-dap} @emph{dap_name} @option{-ap-num} 
@emph{apn}
+or @option{-target} @emph{target_name} here.
+@end itemize
+@end deffn
+
+@deffn {Command} {rvtrace types}
+Lists all supported rvtrace component types. At this writing, the supported
+rvtrace component types are:
+@end deffn
+
+@deffn {Command} {rvtrace names}
+Lists the names of all current rvtrace components in the list.
+@end deffn
+
+@deffn {Command} {$component_name configure configparams...}
+The options accepted by this command may also be specified as parameters
+to @command{rvtrace create}. These values can later be queried one at a
+time by using the @command{$component_name cget} command.
+@itemize
+@item @option{-dap} @emph{dap_name} - names the DAP used to access this
+rvtrace component.
+@item @option{-ap-num} @emph{apn} - set DAP access port for the rvtrace
+component.
+On ADIv5 DAP ap number is the numeric index of the DAP AP the component
+is connected to. On ADIv6 DAP ap number is the base address of the DAP
+AP the component is connected to.
+@item @option{-target} @emph{target_name} - names the target used to
+access this rvtrace component.
+@item @option{-baseaddr} @emph{base_address} - base address of the
+component on the respective MEM-AP or target.
+@end itemize
+@end deffn
+
+@deffn {Command} {$component_name cget queryparm}
+Each configuration parameter accepted by @command{$component_name configure} 
can
+be individu ally queried, to return its current value. The queryparm is a 
parameter
+name accepted by that command, such as -baseaddr. There is a special cases:
+@itemize
+@item @option{-type} – returns the rvtrace component type. This is a special 
case
+because this is set using @command{rvtrace create} and can’t be changed using
+@command{$component_name configure}.
+@end itemize
+@end deffn
+
+@deffn {Command} {$component_name reset}
+Reset the rvtrace component.
+@end deffn
+
+@deffn {Command} {$component_name enable}
+Enable the rvtrace component.
+@end deffn
+
+@deffn {Command} {$component_name disable}
+Disable the rvtrace component.
+@end deffn
+
+@deffn {Command} {$component_name status}
+Show the rvtrace component status.
+@end deffn
+
+@deffn {Command} {$component_name write} @var{reg_name} @var{value}
+Write @var{value} to the rvtrace component register with the symbolic name 
@var{reg_name}.
+@end deffn
+
+@deffn {Command} {$component_name read} @var{reg_name}
+Print the value read from the rvtrace component register with the symbolic 
name @var{reg_name}.
+@end deffn
+
 @section RISC-V Architecture
 
 @uref{http://riscv.org/, RISC-V} is a free and open ISA. OpenOCD supports JTAG
diff --git a/src/openocd.c b/src/openocd.c
index 6e7018ce02..4dc800f6fc 100644
--- a/src/openocd.c
+++ b/src/openocd.c
@@ -28,6 +28,7 @@
 #include <target/arm_adi_v5.h>
 #include <target/arm_tpiu_swo.h>
 #include <target/coresight_trace.h>
+#include <target/riscv/riscv_trace.h>
 #include <rtt/rtt.h>
 
 #include <server/server.h>
@@ -168,6 +169,9 @@ COMMAND_HANDLER(handle_init_command)
        if (command_run_line(CMD_CTX, "tpiu init") != ERROR_OK)
                return ERROR_FAIL;
 
+       if (command_run_line(CMD_CTX, "rvtrace init") != ERROR_OK)
+               return ERROR_FAIL;
+
        jtag_poll_unmask(save_poll_mask);
 
        /* initialize telnet subsystem */
@@ -250,6 +254,7 @@ static int (* const command_registrants[])(struct 
command_context *cmd_ctx_value
        dap_register_commands,
        arm_tpiu_swo_register_commands,
        cstrace_register_commands,
+       rvtrace_register_commands,
 };
 
 static struct command_context *setup_command_handler(Jim_Interp *interp)
@@ -361,6 +366,8 @@ int openocd_main(int argc, char *argv[])
        unregister_all_commands(cmd_ctx, NULL);
        help_del_all_commands(cmd_ctx);
 
+       rvtrace_cleanup_all();
+
        /* free all DAP and CTI objects */
        cstrace_cleanup_all();
        arm_cti_cleanup_all();
diff --git a/src/target/riscv/Makefile.am b/src/target/riscv/Makefile.am
index 4b6a74f0b8..8d53da48ee 100644
--- a/src/target/riscv/Makefile.am
+++ b/src/target/riscv/Makefile.am
@@ -10,9 +10,11 @@ noinst_LTLIBRARIES += %D%/libriscv.la
        %D%/opcodes.h \
        %D%/program.h \
        %D%/riscv.h \
+       %D%/riscv_trace.h \
        %D%/batch.c \
        %D%/program.c \
        %D%/riscv-011.c \
        %D%/riscv-013.c \
        %D%/riscv.c \
-       %D%/riscv_semihosting.c
+       %D%/riscv_semihosting.c \
+       %D%/riscv_trace.c
diff --git a/src/target/riscv/riscv_trace.c b/src/target/riscv/riscv_trace.c
new file mode 100644
index 0000000000..88321e6d9b
--- /dev/null
+++ b/src/target/riscv/riscv_trace.c
@@ -0,0 +1,694 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/***************************************************************************
+ *   Copyright (C) 2025 by liangzhen                                       *
+ *   [email protected]                                               *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <helper/log.h>
+#include <helper/types.h>
+#include <helper/list.h>
+#include <helper/command.h>
+#include <helper/nvp.h>
+#include <helper/jim-nvp.h>
+#include <target/target.h>
+#include "riscv.h"
+#include "riscv_trace.h"
+
+static OOCD_LIST_HEAD(all_rvtrace_component);
+
+static struct rvtrace_type *rvtrace_type[] = {
+};
+
+int rvtrace_write_reg(const struct rvtrace_component *comp, unsigned int reg, 
uint32_t value)
+{
+       if (comp->rvtrace_ap->type == RVTRACE_AP_TYPE_TARGET)
+               return target_write_u32(comp->rvtrace_ap->ap, comp->spot.base + 
reg, value);
+
+       return mem_ap_write_atomic_u32(comp->rvtrace_ap->ap, comp->spot.base + 
reg, value);
+}
+
+int rvtrace_read_reg(const struct rvtrace_component *comp, unsigned int reg, 
uint32_t *value)
+{
+       if (!value)
+               return ERROR_COMMAND_ARGUMENT_INVALID;
+
+       if (comp->rvtrace_ap->type == RVTRACE_AP_TYPE_TARGET)
+               return target_read_u32(comp->rvtrace_ap->ap, comp->spot.base + 
reg, value);
+
+       return mem_ap_read_atomic_u32(comp->rvtrace_ap->ap, comp->spot.base + 
reg, value);
+}
+
+int rvtrace_read_buffer(const struct rvtrace_component *comp, target_addr_t 
address,
+               uint32_t size, uint8_t *buffer)
+{
+       if (comp->rvtrace_ap->type == RVTRACE_AP_TYPE_TARGET)
+               return target_read_buffer(comp->rvtrace_ap->ap, address, size, 
buffer);
+
+       return mem_ap_read_buf(comp->rvtrace_ap->ap, buffer, 4, size / 4, 
address);
+}
+
+int riscv_trace_timeout_sec = DEFAULT_RVTRACE_TIMEOUT_SEC;
+
+int rvtrace_poll_register(struct rvtrace_component *comp, unsigned int reg, 
uint32_t mask, uint32_t value)
+{
+       uint32_t regval;
+       time_t start = time(NULL);
+
+       while (1) {
+               if (rvtrace_read_reg(comp, reg, &regval) != ERROR_OK)
+                       return ERROR_FAIL;
+
+               if (get_field(regval, mask) == value)
+                       break;
+
+               if (time(NULL) - start > riscv_trace_timeout_sec) {
+                       LOG_ERROR("%s poll %x timeout", comp->name, reg);
+                       return ERROR_WAIT;
+               }
+       }
+
+       return ERROR_OK;
+}
+
+int rvtrace_enable_component(struct rvtrace_component *comp)
+{
+       uint32_t value;
+       if (rvtrace_read_reg(comp, RVTRACE_COMPONENT_CTRL, &value) != ERROR_OK)
+               return ERROR_FAIL;
+
+       value |= RVTRACE_COMPONENT_CTRL_ENABLE;
+       if (rvtrace_write_reg(comp, RVTRACE_COMPONENT_CTRL, value) != ERROR_OK)
+               return ERROR_FAIL;
+
+       return rvtrace_poll_register(comp, RVTRACE_COMPONENT_CTRL, 
RVTRACE_COMPONENT_CTRL_ENABLE, 0x1);
+}
+
+int rvtrace_disable_component(struct rvtrace_component *comp)
+{
+       uint32_t value;
+       if (rvtrace_read_reg(comp, RVTRACE_COMPONENT_CTRL, &value) != ERROR_OK)
+               return ERROR_FAIL;
+
+       value &= ~RVTRACE_COMPONENT_CTRL_ENABLE;
+       if (rvtrace_write_reg(comp, RVTRACE_COMPONENT_CTRL, value) != ERROR_OK)
+               return ERROR_FAIL;
+
+       return rvtrace_poll_register(comp, RVTRACE_COMPONENT_CTRL, 
RVTRACE_COMPONENT_CTRL_ENABLE, 0x0);
+}
+
+static int rvtrace_component_reset(struct rvtrace_component *comp)
+{
+       int ret;
+
+       if (rvtrace_write_reg(comp, RVTRACE_COMPONENT_CTRL, 0x0) != ERROR_OK)
+               return ERROR_FAIL;
+
+       ret = rvtrace_poll_register(comp, RVTRACE_COMPONENT_CTRL, 
RVTRACE_COMPONENT_CTRL_ACTIVE, 0x0);
+       if (ret != ERROR_OK)
+               return ret;
+
+       if (rvtrace_write_reg(comp, RVTRACE_COMPONENT_CTRL, 0x1) != ERROR_OK)
+               return ERROR_FAIL;
+
+       return rvtrace_poll_register(comp, RVTRACE_COMPONENT_CTRL, 
RVTRACE_COMPONENT_CTRL_ACTIVE, 0x1);
+}
+
+static int rvtrace_component_examine(struct rvtrace_component *comp)
+{
+       int ret;
+       uint32_t impl, type, major, minor, version;
+
+       ret = rvtrace_component_reset(comp);
+       if (ret != ERROR_OK)
+               return ret;
+
+       ret = rvtrace_read_reg(comp, RVTRACE_COMPONENT_IMPL, &impl);
+       if (ret != ERROR_OK)
+               return ret;
+
+       type = get_field(impl, RVTRACE_COMPONENT_IMPL_TYPE);
+       if (type != comp->type->id_type) {
+               LOG_ERROR("%s: 0x%x does not match expected %s type 
value(0x%x).", comp->name, type, comp->type->name, comp->type->id_type);
+               return ERROR_FAIL;
+       }
+
+       major = get_field(impl, RVTRACE_COMPONENT_IMPL_VERMAJOR);
+       minor = get_field(impl, RVTRACE_COMPONENT_IMPL_VERMINOR);
+       version = rvtrace_component_mkversion(major, minor);
+       if (version != comp->type->version) {
+               LOG_ERROR("%s: 0x%x does not match expected %s version 
value(0x%x).", comp->name, version, comp->type->name, comp->type->version);
+               return ERROR_FAIL;
+       }
+
+       LOG_INFO("[%s] type=0x%x, version=0x%x", comp->name, type, version);
+
+       if (comp->type->examine) {
+                ret = (*comp->type->examine)(comp);
+               if (ret != ERROR_OK)
+                       return ret;
+       }
+
+       return ERROR_OK;
+}
+
+int rvtrace_cleanup_all(void)
+{
+       struct rvtrace_component *obj, *tmp;
+       list_for_each_entry_safe(obj, tmp, &all_rvtrace_component, lh) {
+               rvtrace_disable_component(obj);
+               free(obj->component_info);
+               free(obj->private_config);
+               free(obj->rvtrace_ap);
+               free(obj->name);
+               free(obj->type);
+               free(obj);
+       }
+
+       return ERROR_OK;
+}
+
+COMMAND_HANDLER(handle_rvtrace_read)
+{
+       if (CMD_ARGC != 1)
+               return ERROR_COMMAND_SYNTAX_ERROR;
+
+       struct rvtrace_component *comp = CMD_DATA;
+
+       uint32_t value;
+       int retval = comp->type->read(comp, CMD_ARGV[0], &value);
+       if (retval != ERROR_OK) {
+               command_print(CMD, "failed to read register '%s'", CMD_ARGV[0]);
+               return retval;
+       }
+
+       command_print(CMD, "0x%08"PRIx32, value);
+
+       return retval;
+}
+
+COMMAND_HANDLER(handle_rvtrace_write)
+{
+       if (CMD_ARGC != 2)
+               return ERROR_COMMAND_SYNTAX_ERROR;
+
+       struct rvtrace_component *comp = CMD_DATA;
+
+       uint32_t value;
+       COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], value);
+
+       int retval = comp->type->write(comp, CMD_ARGV[0], value);
+       if (retval != ERROR_OK)
+               command_print(CMD, "failed to write '0x%x' to register '%s'", 
value, CMD_ARGV[0]);
+
+       return retval;
+}
+
+COMMAND_HANDLER(handle_rvtrace_status)
+{
+       if (CMD_ARGC != 0)
+               return ERROR_COMMAND_SYNTAX_ERROR;
+
+       struct rvtrace_component *comp = CMD_DATA;
+
+       int retval = comp->type->status(comp, CMD);
+       if (retval != ERROR_OK)
+               command_print(CMD, "failed to get '%s' status", comp->name);
+
+       return retval;
+}
+
+COMMAND_HANDLER(handle_rvtrace_disable)
+{
+       if (CMD_ARGC != 0)
+               return ERROR_COMMAND_SYNTAX_ERROR;
+
+       struct rvtrace_component *comp = CMD_DATA;
+
+       int retval = comp->type->disable(comp);
+
+       if (retval != ERROR_OK)
+               command_print(CMD, "failed to disable '%s'", comp->name);
+
+       return retval;
+}
+
+COMMAND_HANDLER(handle_rvtrace_enable)
+{
+       if (CMD_ARGC != 0)
+               return ERROR_COMMAND_SYNTAX_ERROR;
+
+       struct rvtrace_component *comp = CMD_DATA;
+
+       int retval = comp->type->enable(comp);
+       if (retval != ERROR_OK)
+               command_print(CMD, "failed to enable '%s'", comp->name);
+
+       return retval;
+}
+
+COMMAND_HANDLER(handle_rvtrace_reset)
+{
+       if (CMD_ARGC != 0)
+               return ERROR_COMMAND_SYNTAX_ERROR;
+
+       struct rvtrace_component *comp = CMD_DATA;
+
+       int retval = rvtrace_component_reset(comp);
+       if (retval != ERROR_OK)
+               command_print(CMD, "failed to reset '%s'", comp->name);
+
+       return retval;
+}
+
+enum rvtrace_cfg_opts {
+       RVTRACE_CFG_TYPE,
+       RVTRACE_CFG_TARGET,
+       RVTRACE_CFG_INVALID = -1
+};
+
+static struct nvp nvp_config_opts[] = {
+       { .name = "-type", .value = RVTRACE_CFG_TYPE },
+       { .name = "-target", .value = RVTRACE_CFG_TARGET },
+       { .name = NULL, .value = RVTRACE_CFG_INVALID },
+};
+
+static COMMAND_HELPER(rvtrace_component_configure, struct rvtrace_component* 
comp, unsigned int index, bool is_configure)
+{
+       const struct nvp *n;
+       struct jim_getopt_info goi;
+       const char *result;
+       int reslen;
+       int retval;
+       while (index < CMD_ARGC) {
+               if (comp->type->rvtrace_jim_configure) {
+                       jim_getopt_setup(&goi, CMD_CTX->interp, CMD_ARGC - 
index, CMD_JIMTCL_ARGV + index);
+                       goi.is_configure = is_configure;
+                       retval = (*comp->type->rvtrace_jim_configure)(comp, 
&goi);
+                       index = CMD_ARGC - goi.argc;
+
+                       result = Jim_GetString(Jim_GetResult(CMD_CTX->interp), 
&reslen);
+                       if (reslen > 0)
+                               command_print(CMD, "%s", result);
+
+                       if (retval == JIM_OK) {
+                               /* more? */
+                               continue;
+                       }
+                       if (retval == JIM_ERR) {
+                               /* An error */
+                               return ERROR_FAIL;
+                       }
+                       /* otherwise we 'continue' below */
+               }
+
+               jim_getopt_setup(&goi, CMD_CTX->interp, CMD_ARGC - index, 
CMD_JIMTCL_ARGV + index);
+               goi.is_configure = is_configure;
+               retval = adiv5_jim_mem_ap_spot_configure(&comp->spot, &goi);
+               index = CMD_ARGC - goi.argc;
+
+               result = Jim_GetString(Jim_GetResult(CMD_CTX->interp), &reslen);
+               if (reslen > 0)
+                       command_print(CMD, "%s", result);
+
+               if (retval == JIM_OK)
+                       continue;
+               if (retval == JIM_ERR)
+                       return retval;
+
+               n = nvp_name2value(nvp_config_opts, CMD_ARGV[index]);
+               if (!n->name) {
+                       nvp_unknown_command_print(CMD, nvp_config_opts, NULL, 
CMD_ARGV[index]);
+                       return ERROR_COMMAND_ARGUMENT_INVALID;
+               }
+               index++;
+               switch (n->value) {
+               case RVTRACE_CFG_TYPE:
+                       if (is_configure) {
+                               command_print(CMD, "not settable: %s", n->name);
+                               return ERROR_COMMAND_ARGUMENT_INVALID;
+                       }
+                       if (index != CMD_ARGC)
+                               return ERROR_COMMAND_SYNTAX_ERROR;
+                       command_print(CMD, "%s", comp->type->name);
+                       break;
+               case RVTRACE_CFG_TARGET:
+                       if (is_configure) {
+                               if (index == CMD_ARGC) {
+                                       command_print(CMD, "missing argument to 
%s", CMD_ARGV[index - 1]);
+                                       return ERROR_COMMAND_ARGUMENT_INVALID;
+                               }
+
+                               struct target *target = 
get_target(CMD_ARGV[index]);
+                               if (!target) {
+                                       command_print(CMD, "Target '%s' could 
not be found", CMD_ARGV[index]);
+                                       return ERROR_COMMAND_ARGUMENT_INVALID;
+                               }
+                               comp->rvtrace_ap->type = RVTRACE_AP_TYPE_TARGET;
+                               comp->rvtrace_ap->ap = target;
+                               index++;
+                       } else {
+                               if (index != CMD_ARGC)
+                                       return ERROR_COMMAND_SYNTAX_ERROR;
+                               if (comp->rvtrace_ap->type == 
RVTRACE_AP_TYPE_TARGET) {
+                                       struct target *target = 
comp->rvtrace_ap->ap;
+                                       command_print(CMD, "%s", 
target_name(target));
+                               } else {
+                                       command_print(CMD, "not target");
+                               }
+                       }
+                       break;
+               }
+       }
+
+       return ERROR_OK;
+}
+
+COMMAND_HANDLER(handle_rvtrace_configure)
+{
+       if (!CMD_ARGC)
+               return ERROR_COMMAND_SYNTAX_ERROR;
+
+       bool is_configure = !strcmp(CMD_NAME, "configure");
+
+       struct rvtrace_component *comp = CMD_DATA;
+
+       return CALL_COMMAND_HANDLER(rvtrace_component_configure, comp, 0, 
is_configure);
+}
+
+static const struct command_registration rvtrace_instance_command_handlers[] = 
{
+       {
+               .name = "configure",
+               .mode = COMMAND_ANY,
+               .handler = handle_rvtrace_configure,
+               .help  = "configure a new riscv trace component for use",
+               .usage = "[rvtrace_attribute ...]",
+       },
+       {
+               .name = "cget",
+               .mode = COMMAND_ANY,
+               .handler = handle_rvtrace_configure,
+               .help  = "returns the specified riscv trace component 
attribute",
+               .usage = "rvtrace_attribute",
+       },
+       {
+               .name = "reset",
+               .handler = handle_rvtrace_reset,
+               .mode  = COMMAND_EXEC,
+               .help = "reset the riscv trace component",
+               .usage = "",
+       },
+       {
+               .name = "enable",
+               .handler = handle_rvtrace_enable,
+               .mode  = COMMAND_EXEC,
+               .help = "enable the riscv trace component",
+               .usage = "",
+       },
+       {
+               .name = "disable",
+               .handler = handle_rvtrace_disable,
+               .mode  = COMMAND_EXEC,
+               .help = "disable the riscv trace component",
+               .usage = "",
+       },
+       {
+               .name  = "status",
+               .mode  = COMMAND_EXEC,
+               .handler = handle_rvtrace_status,
+               .help  = "show riscv trace component status",
+               .usage = "",
+       },
+       {
+               .name = "write",
+               .mode = COMMAND_EXEC,
+               .handler = handle_rvtrace_write,
+               .help = "write to a riscv trace component register",
+               .usage = "<register> <value>",
+       },
+       {
+               .name = "read",
+               .mode = COMMAND_EXEC,
+               .handler = handle_rvtrace_read,
+               .help = "read a riscv trace component register",
+               .usage = "<register>",
+       },
+       COMMAND_REGISTRATION_DONE
+};
+
+COMMAND_HANDLER(handle_rvtrace_create)
+{
+       int retval = ERROR_OK;
+       if (CMD_ARGC < 2)
+               return ERROR_COMMAND_SYNTAX_ERROR;
+
+       /* check if the riscv trace component name clashes with an existing 
command name */
+       Jim_Cmd *jimcmd = Jim_GetCommand(CMD_CTX->interp, CMD_JIMTCL_ARGV[0], 
JIM_NONE);
+       if (jimcmd) {
+               command_print(CMD, "Command: %s Exists", CMD_ARGV[0]);
+               return ERROR_FAIL;
+       }
+
+       /* does riscv trace component type exist */
+       const char *cp = CMD_ARGV[1];
+       size_t x;
+       for (x = 0; x < ARRAY_SIZE(rvtrace_type); x++) {
+               if (strcmp(cp, rvtrace_type[x]->name) == 0) {
+                       /* found */
+                       break;
+               }
+       }
+       if (x == ARRAY_SIZE(rvtrace_type)) {
+               char *all = NULL;
+               for (x = 0; x < ARRAY_SIZE(rvtrace_type); x++) {
+                       char *prev = all;
+                       if (all)
+                               all = alloc_printf("%s, %s", all, 
rvtrace_type[x]->name);
+                       else
+                               all = alloc_printf("%s", rvtrace_type[x]->name);
+                       free(prev);
+                       if (!all) {
+                               LOG_ERROR("Out of memory");
+                               return ERROR_FAIL;
+                       }
+               }
+               command_print(CMD, "Unknown coresight trace component type %s, 
try one of %s", cp, all);
+               free(all);
+               return ERROR_FAIL;
+       }
+
+       /* Create it */
+       struct rvtrace_component *comp = calloc(1, sizeof(struct 
rvtrace_component));
+       if (!comp) {
+               LOG_ERROR("Out of memory");
+               return ERROR_FAIL;
+       }
+
+       /* allocate memory for each unique rvtrace type */
+       comp->type = malloc(sizeof(struct rvtrace_type));
+       if (!comp->type) {
+               LOG_ERROR("Out of memory");
+               free(comp);
+               return ERROR_FAIL;
+       }
+
+       memcpy(comp->type, rvtrace_type[x], sizeof(struct rvtrace_type));
+
+       comp->name = strdup(CMD_ARGV[0]);
+       if (!comp->name) {
+               LOG_ERROR("Out of memory");
+               free(comp->type);
+               free(comp);
+               return ERROR_FAIL;
+       }
+
+       adiv5_mem_ap_spot_init(&comp->spot);
+
+       comp->rvtrace_ap = calloc(1, sizeof(struct rvtrace_ap));
+       if (!comp->rvtrace_ap) {
+               LOG_ERROR("Out of memory");
+               free(comp->name);
+               free(comp->type);
+               free(comp);
+               return ERROR_FAIL;
+       }
+
+       /* Do the rest as "configure" options */
+       bool is_configure = true;
+       retval = CALL_COMMAND_HANDLER(rvtrace_component_configure, comp, 2, 
is_configure);
+       if (retval == ERROR_OK) {
+               if (!comp->rvtrace_ap->ap && !comp->spot.dap) {
+                       command_print(CMD, "-target or -dap required when 
creating riscv trace component");
+                       retval = ERROR_COMMAND_ARGUMENT_INVALID;
+               }
+       }
+
+       if (retval != ERROR_OK) {
+               free(comp->rvtrace_ap);
+               free(comp->name);
+               free(comp->type);
+               free(comp);
+               return retval;
+       }
+
+       if (comp->type->rvtrace_create) {
+               retval = (*comp->type->rvtrace_create)(comp);
+               if (retval != ERROR_OK) {
+                       LOG_DEBUG("rvtrace_create failed");
+                       free(comp->private_config);
+                       free(comp->component_info);
+                       free(comp->rvtrace_ap);
+                       free(comp->name);
+                       free(comp->type);
+                       free(comp);
+                       return retval;
+               }
+       }
+
+       /* now - create the new rvtrace component name command */
+       const struct command_registration rvtrace_subcommands[] = {
+               {
+                       .chain = rvtrace_instance_command_handlers,
+               },
+               {
+                       .chain = comp->type->commands,
+               },
+               COMMAND_REGISTRATION_DONE
+       };
+       const struct command_registration rvtrace_commands[] = {
+               {
+                       .name = CMD_ARGV[0],
+                       .mode = COMMAND_ANY,
+                       .help = "coresight trace command group",
+                       .usage = "",
+                       .chain = rvtrace_subcommands,
+               },
+               COMMAND_REGISTRATION_DONE
+       };
+       retval = register_commands_with_data(CMD_CTX, NULL, rvtrace_commands, 
comp);
+       if (retval != ERROR_OK) {
+               free(comp->private_config);
+               free(comp->component_info);
+               free(comp->rvtrace_ap);
+               free(comp->name);
+               free(comp->type);
+               free(comp);
+               return retval;
+       }
+
+       if (!comp->rvtrace_ap->ap) {
+               comp->rvtrace_ap->ap = dap_get_ap(comp->spot.dap, 
comp->spot.ap_num);
+               comp->rvtrace_ap->type = RVTRACE_AP_TYPE_MEM_AP;
+       }
+
+       if (!comp->rvtrace_ap->ap) {
+               LOG_ERROR("riscv trace cannot get AP");
+               free(comp->private_config);
+               free(comp->component_info);
+               free(comp->rvtrace_ap);
+               free(comp->name);
+               free(comp->type);
+               free(comp);
+               return ERROR_FAIL;
+       }
+
+       list_add_tail(&comp->lh, &all_rvtrace_component);
+
+       return ERROR_OK;
+}
+
+COMMAND_HANDLER(handle_rvtrace_types)
+{
+       if (CMD_ARGC != 0)
+               return ERROR_COMMAND_SYNTAX_ERROR;
+
+       for (size_t x = 0; x < ARRAY_SIZE(rvtrace_type); x++)
+               command_print(CMD, "%s", rvtrace_type[x]->name);
+
+       return ERROR_OK;
+}
+
+COMMAND_HANDLER(handle_rvtrace_names)
+{
+       struct rvtrace_component *entry;
+
+       if (CMD_ARGC != 0)
+               return ERROR_COMMAND_SYNTAX_ERROR;
+
+       list_for_each_entry(entry, &all_rvtrace_component, lh)
+               command_print(CMD, "%s", entry->name);
+
+       return ERROR_OK;
+}
+
+COMMAND_HANDLER(handle_rvtrace_init)
+{
+       struct rvtrace_component *entry;
+
+       if (CMD_ARGC != 0)
+               return ERROR_COMMAND_SYNTAX_ERROR;
+
+       list_for_each_entry(entry, &all_rvtrace_component, lh) {
+               if (rvtrace_component_examine(entry) != ERROR_OK)
+                       return ERROR_FAIL;
+       }
+
+       return ERROR_OK;
+}
+
+static const struct command_registration rvtrace_subcommand_handlers[] = {
+       {
+               .name = "create",
+               .mode = COMMAND_ANY,
+               .handler = handle_rvtrace_create,
+               .usage = "name type [options ...]",
+               .help = "Creates a new riscv trace component",
+       },
+       {
+               .name = "types",
+               .mode = COMMAND_ANY,
+               .handler = handle_rvtrace_types,
+               .help = "Returns the available riscv trace component types as "
+                       "a list of strings",
+               .usage = "",
+       },
+       {
+               .name = "names",
+               .mode = COMMAND_ANY,
+               .handler = handle_rvtrace_names,
+               .help = "Returns the names of all riscv trace components as a "
+                       "list of strings",
+               .usage = "",
+       },
+       {
+               .name = "init",
+               .mode = COMMAND_ANY,
+               .handler = handle_rvtrace_init,
+               .help = "Initialize rvtrace component",
+               .usage = "",
+       },
+       COMMAND_REGISTRATION_DONE
+};
+
+static const struct command_registration rvtrace_command_handlers[] = {
+       {
+               .name = "rvtrace",
+               .mode = COMMAND_CONFIG,
+               .help = "configure riscv trace",
+               .chain = rvtrace_subcommand_handlers,
+               .usage = "",
+       },
+       COMMAND_REGISTRATION_DONE
+};
+
+int rvtrace_register_commands(struct command_context *cmd_ctx)
+{
+       return register_commands(cmd_ctx, NULL, rvtrace_command_handlers);
+}
diff --git a/src/target/riscv/riscv_trace.h b/src/target/riscv/riscv_trace.h
new file mode 100644
index 0000000000..0aea588258
--- /dev/null
+++ b/src/target/riscv/riscv_trace.h
@@ -0,0 +1,105 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/***************************************************************************
+ *   Copyright (C) 2025 by liangzhen                                       *
+ *   [email protected]                                               *
+ ***************************************************************************/
+
+#ifndef OPENOCD_TARGET_RISCV_RISCV_TRACE_H
+#define OPENOCD_TARGET_RISCV_RISCV_TRACE_H
+
+#include <target/arm_adi_v5.h>
+
+/* Control register common across all RISC-V trace components */
+#define RVTRACE_COMPONENT_CTRL             0x000
+#define RVTRACE_COMPONENT_CTRL_ACTIVE      0x1
+#define RVTRACE_COMPONENT_CTRL_ENABLE      0x2
+
+/* Implementation register common across all RISC-V trace components */
+#define RVTRACE_COMPONENT_IMPL             0x004
+#define RVTRACE_COMPONENT_IMPL_VERMAJOR            0xf
+#define RVTRACE_COMPONENT_IMPL_VERMINOR            0xf0
+#define RVTRACE_COMPONENT_IMPL_TYPE        0xf00
+
+#define DEFAULT_RVTRACE_TIMEOUT_SEC   10
+
+/* Possible component types defined by the RISC-V Trace Control Interface */
+enum rvtrace_component_type {
+       RVTRACE_COMPONENT_TYPE_RESV0,
+       RVTRACE_COMPONENT_TYPE_ENCODER, /* 0x1 */
+       RVTRACE_COMPONENT_TYPE_RESV2,
+       RVTRACE_COMPONENT_TYPE_RESV3,
+       RVTRACE_COMPONENT_TYPE_RESV4,
+       RVTRACE_COMPONENT_TYPE_RESV5,
+       RVTRACE_COMPONENT_TYPE_RESV6,
+       RVTRACE_COMPONENT_TYPE_RESV7,
+       RVTRACE_COMPONENT_TYPE_FUNNEL, /* 0x8 */
+       RVTRACE_COMPONENT_TYPE_RAMSINK, /* 0x9 */
+       RVTRACE_COMPONENT_TYPE_PIBSINK, /* 0xA */
+       RVTRACE_COMPONENT_TYPE_RESV11,
+       RVTRACE_COMPONENT_TYPE_RESV12,
+       RVTRACE_COMPONENT_TYPE_RESV13,
+       RVTRACE_COMPONENT_TYPE_ATBBRIDGE, /* 0xE */
+       RISCV_TRACE_COMPONENT_TYPE_RESV15,
+       RISCV_TRACE_COMPONENT_TYPE_MAX
+};
+
+enum rvtrace_ap_type {
+       RVTRACE_AP_TYPE_MEM_AP,
+       RVTRACE_AP_TYPE_TARGET,
+};
+
+struct rvtrace_ap {
+       enum rvtrace_ap_type type;
+       void *ap;
+};
+
+struct rvtrace_component {
+       struct list_head lh;
+       target_addr_t base;
+       char *name;
+       struct rvtrace_type *type;
+       struct adiv5_mem_ap_spot spot;
+       struct rvtrace_ap *rvtrace_ap;
+       void *component_info;
+       void *private_config;
+};
+
+struct rvtrace_type {
+       const char *name;
+       enum rvtrace_component_type id_type;
+       uint32_t version;
+       int (*rvtrace_create)(struct rvtrace_component *comp);
+       int (*rvtrace_jim_configure)(struct rvtrace_component *comp, struct 
jim_getopt_info *goi);
+       int (*rvtrace_jim_commands)(struct rvtrace_component *comp, struct 
jim_getopt_info *goi);
+
+       int (*examine)(struct rvtrace_component *comp);
+
+       int (*enable)(struct rvtrace_component *comp);
+       int (*disable)(struct rvtrace_component *comp);
+       int (*status)(struct rvtrace_component *comp, struct command_invocation 
*cmd);
+       int (*write)(struct rvtrace_component *comp, const char *reg_name, 
uint32_t value);
+       int (*read)(struct rvtrace_component *comp, const char *reg_name, 
uint32_t *value);
+
+       const struct command_registration *commands;
+};
+
+#define get_field(reg, mask) (((reg) & (mask)) / ((mask) & ~((mask) << 1)))
+#define set_field(reg, mask, val) (((reg) & ~(mask)) | (((val) * ((mask) & 
~((mask) << 1))) & (mask)))
+
+#define rvtrace_component_mkversion(major, minor) ((((major) & 0xf) << 4) | 
((minor) & 0xf))
+
+int rvtrace_write_reg(const struct rvtrace_component *comp, unsigned int reg, 
uint32_t value);
+int rvtrace_read_reg(const struct rvtrace_component *comp, unsigned int reg, 
uint32_t *value);
+int rvtrace_read_buffer(const struct rvtrace_component *comp, target_addr_t 
address, uint32_t size, uint8_t *buffer);
+
+int rvtrace_poll_register(struct rvtrace_component *comp, unsigned int reg, 
uint32_t mask, uint32_t value);
+
+int rvtrace_enable_component(struct rvtrace_component *comp);
+int rvtrace_disable_component(struct rvtrace_component *comp);
+
+int rvtrace_cleanup_all(void);
+
+int rvtrace_register_commands(struct command_context *cmd_ctx);
+
+#endif /* OPENOCD_TARGET_RISCV_RISCV_TRACE_H */

-- 

Reply via email to