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, +}; --
