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/+/9217

-- gerrit

commit ea4613e4a46848d3f924e78d2ed530f34c6ec9fe
Author: liangzhen <[email protected]>
Date:   Fri Oct 31 15:23:04 2025 +0800

    target/riscv: rvtrace: Add trace funnel support
    
    Add support for the trace funnel component.
    
    Change-Id: Ie2e5cb4a3563e3fc6039d4f9791bc6312b4b3317
    Signed-off-by: liangzhen <[email protected]>

diff --git a/doc/openocd.texi b/doc/openocd.texi
index 9ebec22821..5ca8baffbb 100644
--- a/doc/openocd.texi
+++ b/doc/openocd.texi
@@ -11699,6 +11699,7 @@ Lists all supported rvtrace component types. At this 
writing, the supported
 rvtrace component types are:
 @itemize
 @item @code{encoder} - this a rvtrace encoder component.
+@item @code{funnel} - this a rvtrace funnel component.
 @end itemize
 @end deffn
 
@@ -11809,6 +11810,14 @@ The commands specific to the @code{encoder} are:
 @item @command{component_name encoder stop} - stop instruction trace.
 @end itemize
 
+@subsection Funnel Component
+When the rvtrace component is a @code{funnel} type, the configure configparams
+specific to the @code{funnel} are:
+@itemize
+@item @option{-ports} @emph{ports_mask} - funnel ports opened or closed by
+@command{component_name enable} and @command{component_name disable}.
+@end itemize
+
 @section RISC-V Architecture
 
 @uref{http://riscv.org/, RISC-V} is a free and open ISA. OpenOCD supports JTAG
diff --git a/src/target/riscv/Makefile.am b/src/target/riscv/Makefile.am
index 541ab38386..8a102b423a 100644
--- a/src/target/riscv/Makefile.am
+++ b/src/target/riscv/Makefile.am
@@ -18,4 +18,5 @@ noinst_LTLIBRARIES += %D%/libriscv.la
        %D%/riscv.c \
        %D%/riscv_semihosting.c \
        %D%/riscv_trace.c \
-       %D%/trace_encoder.c
+       %D%/trace_encoder.c \
+       %D%/trace_funnel.c
diff --git a/src/target/riscv/riscv_trace.c b/src/target/riscv/riscv_trace.c
index c3fc36a00a..c50c585daf 100644
--- a/src/target/riscv/riscv_trace.c
+++ b/src/target/riscv/riscv_trace.c
@@ -26,6 +26,7 @@ static OOCD_LIST_HEAD(all_rvtrace_component);
 
 static struct rvtrace_type *rvtrace_type[] = {
        &rvtrace_encoder,
+       &rvtrace_funnel,
 };
 
 int rvtrace_write_reg(const struct rvtrace_component *comp, unsigned int reg, 
uint32_t value)
diff --git a/src/target/riscv/riscv_trace.h b/src/target/riscv/riscv_trace.h
index 5d039f836a..b182a81fc1 100644
--- a/src/target/riscv/riscv_trace.h
+++ b/src/target/riscv/riscv_trace.h
@@ -103,5 +103,6 @@ int rvtrace_cleanup_all(void);
 int rvtrace_register_commands(struct command_context *cmd_ctx);
 
 extern struct rvtrace_type rvtrace_encoder;
+extern struct rvtrace_type rvtrace_funnel;
 
 #endif /* OPENOCD_TARGET_RISCV_RISCV_TRACE_H */
diff --git a/src/target/riscv/trace_funnel.c b/src/target/riscv/trace_funnel.c
new file mode 100644
index 0000000000..afce53330b
--- /dev/null
+++ b/src/target/riscv/trace_funnel.c
@@ -0,0 +1,280 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/***************************************************************************
+ *   Copyright (C) 2025 by liangzhen                                       *
+ *   [email protected]                                               *
+ ***************************************************************************/
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <helper/log.h>
+#include <helper/types.h>
+#include <helper/command.h>
+#include <helper/jim-nvp.h>
+#include "riscv_trace.h"
+
+#define RVTRACE_FUNNEL_CTRL                    0x000
+#define RVTRACE_FUNNEL_IMPL                    0x004
+#define RVTRACE_FUNNEL_DISINPUT                        0x008
+
+/* register description */
+/* trFunnelControl */
+#define RVTRACE_FUNNEL_CTRL_ACTIVE             0x1
+#define RVTRACE_FUNNEL_CTRL_ENABLE             0x2
+#define RVTRACE_FUNNEL_CTRL_EMPTY              0x8
+/* trFunnelDisInput */
+#define RVTRACE_FUNNEL_DISINPUT_DISINPUT       0xffff
+
+#define RVTRACE_FUNNEL_DISINPUT_MAX            15
+
+struct rv_funnel_info {
+       bool was_enabled;
+       uint32_t disinput_lenb;
+};
+
+struct rv_funnel_private_config {
+       uint32_t ports;
+};
+
+static inline struct rv_funnel_info *rv_funnel_info(struct rvtrace_component 
*comp)
+{
+       assert(comp->component_info);
+       return comp->component_info;
+}
+
+static inline struct rv_funnel_private_config *rv_funnel_private_config(struct 
rvtrace_component *comp)
+{
+       assert(comp->private_config);
+       return comp->private_config;
+}
+
+#define RV_FUNNEL_INFO(R) struct rv_funnel_info *R = rv_funnel_info(comp);
+
+static struct rv_funnel_private_config 
*alloc_default_rv_funnel_private_config(void)
+{
+       struct rv_funnel_private_config *config =  malloc(sizeof(struct 
rv_funnel_private_config));
+       if (!config) {
+               LOG_ERROR("Out of memory!");
+               return NULL;
+       }
+
+       config->ports = RVTRACE_FUNNEL_DISINPUT_DISINPUT;
+
+       return config;
+}
+
+static const struct {
+       uint32_t offset;
+       const char *label;
+} funnel_names[] = {
+       { RVTRACE_FUNNEL_CTRL, "CONTROL" },
+       { RVTRACE_FUNNEL_IMPL, "IMPL" },
+       { RVTRACE_FUNNEL_DISINPUT, "DISINPUT" },
+};
+
+static int funnel_find_reg_offset(const char *name)
+{
+       for (size_t i = 0; i < ARRAY_SIZE(funnel_names); i++) {
+               if (!strcasecmp(name, funnel_names[i].label))
+                       return funnel_names[i].offset;
+       }
+
+       LOG_ERROR("unknown rvtrace funnel register %s", name);
+       return -1;
+}
+
+static int funnel_create(struct rvtrace_component *comp)
+{
+       LOG_DEBUG("funnel_create()");
+       struct rv_funnel_private_config *config = comp->private_config;
+       if (!config) {
+               config = alloc_default_rv_funnel_private_config();
+               if (!config)
+                       return ERROR_FAIL;
+               comp->private_config = config;
+       }
+       comp->component_info = calloc(1, sizeof(struct rv_funnel_info));
+       if (!comp->component_info) {
+               LOG_ERROR("Failed to allocate funnel info structure.");
+               return ERROR_FAIL;
+       }
+       return ERROR_OK;
+}
+
+enum rv_funnel_cfg_opts {
+       CS_FUNNEL_CFG_PORTS,
+};
+
+static struct jim_nvp nvp_config_opts[] = {
+       { .name = "-ports", .value = CS_FUNNEL_CFG_PORTS },
+       { .name = NULL, .value = -1 }
+};
+
+static int funnel_jim_configure(struct rvtrace_component *comp, struct 
jim_getopt_info *goi)
+{
+       struct rv_funnel_private_config *config = comp->private_config;
+       if (!config) {
+               config = alloc_default_rv_funnel_private_config();
+               if (!config)
+                       return JIM_ERR;
+               comp->private_config = config;
+       }
+
+       if (!goi->argc)
+               return JIM_OK;
+
+       struct jim_nvp *n;
+       int e = jim_nvp_name2value_obj(goi->interp, nvp_config_opts, 
goi->argv[0], &n);
+
+       if (e != JIM_OK)
+               return JIM_CONTINUE;
+
+       e = jim_getopt_obj(goi, NULL);
+       if (e != JIM_OK)
+               return e;
+
+       if (!goi->is_configure && goi->argc > 0) {
+               /*no arguments */
+               Jim_WrongNumArgs(goi->interp, 2, goi->argv - 2, "");
+               return JIM_ERR;
+       }
+
+       switch (n->value) {
+       case CS_FUNNEL_CFG_PORTS:
+               if (goi->is_configure) {
+                       jim_wide w;
+                       e = jim_getopt_wide(goi, &w);
+                       if (e != JIM_OK)
+                               return e;
+                       if (w < 1 && w > RVTRACE_FUNNEL_DISINPUT_DISINPUT) {
+                               Jim_SetResultString(goi->interp, "Invalid 
ports!", -1);
+                               return JIM_ERR;
+                       }
+                       config->ports = (uint32_t)w;
+               } else {
+                       Jim_SetResult(goi->interp, Jim_NewIntObj(goi->interp, 
config->ports));
+               }
+               break;
+       }
+       return JIM_OK;
+}
+
+static int funnel_examine(struct rvtrace_component *comp)
+{
+       RV_FUNNEL_INFO(info);
+
+       uint32_t disinput_lenb = 0;
+       /* set 0xffff to detect which inputs may be disabled in that trace 
funnel. */
+       uint32_t disinput = RVTRACE_FUNNEL_DISINPUT_DISINPUT;
+
+       if (rvtrace_write_reg(comp, RVTRACE_FUNNEL_DISINPUT, disinput) != 
ERROR_OK)
+               return ERROR_FAIL;
+
+       if (rvtrace_read_reg(comp, RVTRACE_FUNNEL_DISINPUT, &disinput) != 
ERROR_OK)
+               return ERROR_FAIL;
+
+       disinput = get_field(disinput, RVTRACE_FUNNEL_DISINPUT_DISINPUT);
+       while (disinput) {
+               disinput_lenb += disinput & 1;
+               disinput >>= 1;
+       }
+
+       info->disinput_lenb = disinput_lenb;
+
+       if (!info->disinput_lenb)
+               LOG_INFO("[%s] all inputs are always enabled", comp->name);
+
+       return ERROR_OK;
+}
+
+static int funnel_enable(struct rvtrace_component *comp)
+{
+       RV_FUNNEL_INFO(info);
+       if (info->was_enabled)
+               return ERROR_OK;
+
+       struct rv_funnel_private_config *config = 
rv_funnel_private_config(comp);
+
+       uint32_t disinput = set_field(0, RVTRACE_FUNNEL_DISINPUT_DISINPUT, 
~config->ports);
+       if (rvtrace_write_reg(comp, RVTRACE_FUNNEL_DISINPUT, disinput) != 
ERROR_OK)
+               return ERROR_FAIL;
+
+       if (rvtrace_enable_component(comp) != ERROR_OK)
+               return ERROR_FAIL;
+
+       info->was_enabled = true;
+
+       return ERROR_OK;
+}
+
+static int funnel_disable(struct rvtrace_component *comp)
+{
+       RV_FUNNEL_INFO(info);
+
+       if (!info->was_enabled)
+               return ERROR_OK;
+
+       if (rvtrace_disable_component(comp) != ERROR_OK)
+               return ERROR_FAIL;
+
+       if (rvtrace_poll_register(comp, RVTRACE_FUNNEL_CTRL, 
RVTRACE_FUNNEL_CTRL_EMPTY, 1) != ERROR_OK)
+               return ERROR_FAIL;
+
+       info->was_enabled = false;
+
+       return ERROR_OK;
+}
+
+static int funnel_status(struct rvtrace_component *comp,struct 
command_invocation *cmd)
+{
+       uint32_t ctrl, disinput;
+
+       if (rvtrace_read_reg(comp, RVTRACE_FUNNEL_CTRL, &ctrl) != ERROR_OK)
+               return ERROR_FAIL;
+
+       if (rvtrace_read_reg(comp, RVTRACE_FUNNEL_DISINPUT, &disinput) != 
ERROR_OK)
+               return ERROR_FAIL;      
+
+       command_print(cmd, "Control: %s",
+                       get_field(ctrl, RVTRACE_FUNNEL_CTRL_ENABLE) ? "enabled" 
: "disabled");
+       command_print(cmd, "Empty: %d", get_field(ctrl, 
RVTRACE_FUNNEL_CTRL_EMPTY));
+       command_print(cmd, "Disinput: 0x%x", get_field(disinput, 
RVTRACE_FUNNEL_DISINPUT_DISINPUT));
+
+       return ERROR_OK;
+}
+
+static int funnel_write(struct rvtrace_component *comp, const char *reg_name, 
uint32_t value)
+{
+       int offset = funnel_find_reg_offset(reg_name);
+       if (offset < 0)
+               return ERROR_FAIL;
+
+       return rvtrace_write_reg(comp, offset, value);
+}
+
+static int funnel_read(struct rvtrace_component *comp, const char *reg_name, 
uint32_t *value)
+{
+       int offset = funnel_find_reg_offset(reg_name);
+       if (offset < 0)
+               return ERROR_FAIL;
+
+       return rvtrace_read_reg(comp, offset, value);
+}
+
+struct rvtrace_type rvtrace_funnel = {
+       .name = "funnel",
+       .id_type = RVTRACE_COMPONENT_TYPE_FUNNEL,
+       .version = rvtrace_component_mkversion(1, 0),
+
+       .rvtrace_create = funnel_create,
+       .rvtrace_jim_configure = funnel_jim_configure,
+
+       .examine = funnel_examine,
+
+       .enable = funnel_enable,
+       .disable = funnel_disable,
+       .status = funnel_status,
+       .write = funnel_write,
+       .read = funnel_read,
+};

-- 

Reply via email to