|
From: openocd-gerrit <ope...@us...> - 2025-11-12 20:15:35
|
This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "Main OpenOCD repository".
The branch, master has been updated
via 5754aebc49450cc0da5c8a90ebd059160d21f256 (commit)
from ab22b0bf8f23924d8c76d3affd9e11528ba18438 (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commit 5754aebc49450cc0da5c8a90ebd059160d21f256
Author: Bernhard Rosenkränzer <be...@ba...>
Date: Tue May 6 01:20:22 2025 +0200
target: riscv: Sync with the RISC-V fork
Regenerate autogenerated debug_defines.{c,h} files from current
riscv-debug-spec, sync remaining RISC-V target files with the
RISC-V fork.
This is based on the work of (in alphabetic order):
Aleksey Lotosh <lo...@gm...>
Alexander Rumyantsev <cet...@gm...>
Anastasiya Chernikova <ana...@sy...>
Anatoly Parshintsev <114...@us...>
Bernhard Rosenkränzer <be...@ba...>
bluew <bl...@us...>
Carsten Gosvig <403...@us...>
cgsfv <cg...@us...>
Craig Blackmore <cra...@em...>
Dan Robertson <dan...@gm...>
Darius Rad <da...@bl...>
dave-estes-syzexion <537...@us...>
Dmitry Ryzhov <dmi...@cl...>
Dolu1990 <cha...@gm...>
Emmanuel Blot <emm...@fr...>
Ernie Edgar <431...@us...>
Evgeniy Naydanov <evg...@sy...>
Farid Khaydari <f.k...@sy...>
Gleb Gagarin <gl...@si...>
Greg Savin <431...@us...>
Hang Xu <xu...@es...>
Hsiangkai <Hsi...@gm...>
Jan Matyas <jan...@co...>
jhjung81 <489...@us...>
Jiuyang Liu <li...@ji...>
Kaspar Schleiser <ka...@sc...>
Khem Raj <raj...@gm...>
Kirill Radkin <kir...@sy...>
liangzhen <zhe...@sp...>
Liviu Ionescu <il...@li...>
Marc Schink <ope...@ma...>
Megan Wachs <me...@si...>
Nils Wistoff <gi...@wi...>
Palmer Dabbelt <pa...@da...>
panciyan <pan...@es...>
Parshintsev Anatoly <ana...@sy...>
Paul George <com...@gm...>
Pavel S. Smirnov <Pau...@gm...>
Philipp Wagner <ma...@ph...>
Ryan Macdonald <rm...@si...>
Samuel Obuch <sam...@gm...>
Tarek BOCHKATI <tar...@gm...>
Tim Newsome <ti...@ca...>
Tobias Kaiser <ma...@tb...>
Tom Hebb <tom...@gm...>
Tommy Murphy <tom...@ho...>
wxjstz <wx...@12...>
wzgpeter <wzg...@ou...>
Xiang W <wx...@12...>
zhusonghe <zhu...@es...>
Checkpatch-ignore MULTISTATEMENT_MACRO_USE_DO_WHILE is added to allow a
macro in riscv-013.c that can't use do/while because it expands to a
"case ...:" statement.
Checkpatch-ignore TRAILING_SEMICOLON is added to allow a construct in
riscv-013.c where a macro expands to either code (where it needs the
semicolon) or a member of an enum (where it needs a comma).
Checkpatch-ignore LONG_LINE_COMMENT and NEW_TYPEDEFS lines are added for
the sake of the autogenerated files from riscv-debug-spec.
All non-autogenerated files have been updated for checkpatch compliance.
Checkpatch-ignore: LONG_LINE_COMMENT
Checkpatch-ignore: NEW_TYPEDEFS
Checkpatch-ignore: MULTISTATEMENT_MACRO_USE_DO_WHILE
Checkpatch-ignore: TRAILING_SEMICOLON
Change-Id: Ie594915a4d6e6f9d9dad6016b176ab76409a099a
Signed-off-by: Bernhard Rosenkränzer <be...@ba...>
Reviewed-on: https://review.openocd.org/c/openocd/+/8893
Tested-by: jenkins
Reviewed-by: Evgeniy Naydanov <evg...@sy...>
Reviewed-by: Tomas Vanek <va...@fb...>
diff --git a/src/target/riscv/Makefile.am b/src/target/riscv/Makefile.am
index 4b6a74f0b..189edb3e6 100644
--- a/src/target/riscv/Makefile.am
+++ b/src/target/riscv/Makefile.am
@@ -2,17 +2,31 @@
noinst_LTLIBRARIES += %D%/libriscv.la
%C%_libriscv_la_SOURCES = \
- %D%/asm.h \
%D%/batch.h \
%D%/debug_defines.h \
+ %D%/debug_reg_printer.h \
%D%/encoding.h \
+ %D%/field_helpers.h \
%D%/gdb_regs.h \
%D%/opcodes.h \
%D%/program.h \
%D%/riscv.h \
+ %D%/riscv_reg_impl.h \
+ %D%/riscv_reg.h \
+ %D%/riscv-011.h \
+ %D%/riscv-011_reg.h \
+ %D%/riscv-013.h \
+ %D%/riscv-013_reg.h \
%D%/batch.c \
%D%/program.c \
%D%/riscv-011.c \
+ %D%/riscv-011_reg.c \
%D%/riscv-013.c \
+ %D%/riscv-013_reg.c \
%D%/riscv.c \
- %D%/riscv_semihosting.c
+ %D%/riscv_reg.c \
+ %D%/riscv_semihosting.c \
+ %D%/debug_defines.c \
+ %D%/debug_reg_printer.c
+
+STARTUP_TCL_SRCS += %D%/startup.tcl
diff --git a/src/target/riscv/asm.h b/src/target/riscv/asm.h
deleted file mode 100644
index 6ceb8c9bd..000000000
--- a/src/target/riscv/asm.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-
-#ifndef TARGET__RISCV__ASM_H
-#define TARGET__RISCV__ASM_H
-
-#include "riscv.h"
-
-/*** Version-independent functions that we don't want in the main address space. ***/
-
-static uint32_t load(const struct target *target, unsigned int rd,
- unsigned int base, uint16_t offset) __attribute__ ((unused));
-static uint32_t load(const struct target *target, unsigned int rd,
- unsigned int base, uint16_t offset)
-{
- switch (riscv_xlen(target)) {
- case 32:
- return lw(rd, base, offset);
- case 64:
- return ld(rd, base, offset);
- }
- assert(0);
- return 0; /* Silence -Werror=return-type */
-}
-
-static uint32_t store(const struct target *target, unsigned int src,
- unsigned int base, uint16_t offset) __attribute__ ((unused));
-static uint32_t store(const struct target *target, unsigned int src,
- unsigned int base, uint16_t offset)
-{
- switch (riscv_xlen(target)) {
- case 32:
- return sw(src, base, offset);
- case 64:
- return sd(src, base, offset);
- }
- assert(0);
- return 0; /* Silence -Werror=return-type */
-}
-
-#endif
diff --git a/src/target/riscv/batch.c b/src/target/riscv/batch.c
index e3f8ff3d4..ec68b3798 100644
--- a/src/target/riscv/batch.c
+++ b/src/target/riscv/batch.c
@@ -6,67 +6,90 @@
#include "batch.h"
#include "debug_defines.h"
+#include "debug_reg_printer.h"
#include "riscv.h"
+#include "field_helpers.h"
-#define get_field(reg, mask) (((reg) & (mask)) / ((mask) & ~((mask) << 1)))
-#define set_field(reg, mask, val) (((reg) & ~(mask)) | (((val) * ((mask) & ~((mask) << 1))) & (mask)))
-
+// TODO: DTM_DMI_MAX_ADDRESS_LENGTH should be reduced to 32 (per the debug spec)
#define DTM_DMI_MAX_ADDRESS_LENGTH ((1<<DTM_DTMCS_ABITS_LENGTH)-1)
#define DMI_SCAN_MAX_BIT_LENGTH (DTM_DMI_MAX_ADDRESS_LENGTH + DTM_DMI_DATA_LENGTH + DTM_DMI_OP_LENGTH)
+
#define DMI_SCAN_BUF_SIZE (DIV_ROUND_UP(DMI_SCAN_MAX_BIT_LENGTH, 8))
-static void dump_field(int idle, const struct scan_field *field);
+/* Reserve extra room in the batch (needed for the last NOP operation) */
+#define BATCH_RESERVED_SCANS 1
+
+static unsigned int get_dmi_scan_length(const struct target *target)
+{
+ const unsigned int abits = riscv_get_dmi_address_bits(target);
+ assert(abits > 0);
+ assert(abits <= DTM_DMI_MAX_ADDRESS_LENGTH);
+
+ return abits + DTM_DMI_DATA_LENGTH + DTM_DMI_OP_LENGTH;
+}
-struct riscv_batch *riscv_batch_alloc(struct target *target, size_t scans, size_t idle)
+struct riscv_batch *riscv_batch_alloc(struct target *target, size_t scans)
{
- scans += 4;
+ scans += BATCH_RESERVED_SCANS;
struct riscv_batch *out = calloc(1, sizeof(*out));
- if (!out)
- goto error0;
+ if (!out) {
+ LOG_ERROR("Failed to allocate struct riscv_batch");
+ return NULL;
+ }
+
out->target = target;
out->allocated_scans = scans;
- out->idle_count = idle;
- out->data_out = malloc(sizeof(*out->data_out) * (scans) * DMI_SCAN_BUF_SIZE);
+ out->last_scan = RISCV_SCAN_TYPE_INVALID;
+ out->was_run = false;
+ out->last_scan_delay = 0;
+
+ out->data_out = NULL;
+ out->data_in = NULL;
+ out->fields = NULL;
+ out->delay_classes = NULL;
+ out->bscan_ctxt = NULL;
+ out->read_keys = NULL;
+
+ /* FIXME: There is potential for memory usage reduction. We could allocate
+ * smaller buffers than DMI_SCAN_BUF_SIZE (that is, buffers that correspond to
+ * the real DR scan length on the given target) */
+ out->data_out = malloc(sizeof(*out->data_out) * scans * DMI_SCAN_BUF_SIZE);
if (!out->data_out) {
LOG_ERROR("Failed to allocate data_out in RISC-V batch.");
- goto error1;
+ goto alloc_error;
};
- out->data_in = malloc(sizeof(*out->data_in) * (scans) * DMI_SCAN_BUF_SIZE);
+ out->data_in = malloc(sizeof(*out->data_in) * scans * DMI_SCAN_BUF_SIZE);
if (!out->data_in) {
LOG_ERROR("Failed to allocate data_in in RISC-V batch.");
- goto error2;
+ goto alloc_error;
}
- out->fields = malloc(sizeof(*out->fields) * (scans));
+ out->fields = malloc(sizeof(*out->fields) * scans);
if (!out->fields) {
LOG_ERROR("Failed to allocate fields in RISC-V batch.");
- goto error3;
+ goto alloc_error;
+ }
+ out->delay_classes = malloc(sizeof(*out->delay_classes) * scans);
+ if (!out->delay_classes) {
+ LOG_ERROR("Failed to allocate delay_classes in RISC-V batch.");
+ goto alloc_error;
}
if (bscan_tunnel_ir_width != 0) {
- out->bscan_ctxt = malloc(sizeof(*out->bscan_ctxt) * (scans));
+ out->bscan_ctxt = malloc(sizeof(*out->bscan_ctxt) * scans);
if (!out->bscan_ctxt) {
LOG_ERROR("Failed to allocate bscan_ctxt in RISC-V batch.");
- goto error4;
+ goto alloc_error;
}
}
- out->last_scan = RISCV_SCAN_TYPE_INVALID;
- out->read_keys = malloc(sizeof(*out->read_keys) * (scans));
+ out->read_keys = malloc(sizeof(*out->read_keys) * scans);
if (!out->read_keys) {
LOG_ERROR("Failed to allocate read_keys in RISC-V batch.");
- goto error5;
+ goto alloc_error;
}
+
return out;
-error5:
- free(out->bscan_ctxt);
-error4:
- free(out->fields);
-error3:
- free(out->data_in);
-error2:
- free(out->data_out);
-error1:
- free(out);
-error0:
+alloc_error:
+ riscv_batch_free(out);
return NULL;
}
@@ -75,6 +98,7 @@ void riscv_batch_free(struct riscv_batch *batch)
free(batch->data_in);
free(batch->data_out);
free(batch->fields);
+ free(batch->delay_classes);
free(batch->bscan_ctxt);
free(batch->read_keys);
free(batch);
@@ -82,32 +106,209 @@ void riscv_batch_free(struct riscv_batch *batch)
bool riscv_batch_full(struct riscv_batch *batch)
{
- return batch->used_scans > (batch->allocated_scans - 4);
+ return riscv_batch_available_scans(batch) == 0;
+}
+
+static bool riscv_batch_was_scan_busy(const struct riscv_batch *batch,
+ size_t scan_idx)
+{
+ assert(batch->was_run);
+ assert(scan_idx < batch->used_scans);
+ const struct scan_field *field = batch->fields + scan_idx;
+ assert(field->in_value);
+ const uint64_t in = buf_get_u64(field->in_value, 0, field->num_bits);
+ return get_field(in, DTM_DMI_OP) == DTM_DMI_OP_BUSY;
}
-int riscv_batch_run(struct riscv_batch *batch)
+static void add_idle_before_batch(const struct riscv_batch *batch, size_t start_idx,
+ const struct riscv_scan_delays *delays)
{
- if (batch->used_scans == 0) {
- LOG_DEBUG("Ignoring empty batch.");
- return ERROR_OK;
+ if (!batch->was_run)
+ return;
+ /* Get the delay type of the scan that resulted in the busy response.
+ * Since DMI interactions always end with a NOP, if "start_idx" is zero
+ * the base delay value is used.
+ */
+ const enum riscv_scan_delay_class delay_class = start_idx > 0
+ ? batch->delay_classes[start_idx - 1]
+ : RISCV_DELAY_BASE;
+ const unsigned int new_delay = riscv_scan_get_delay(delays, delay_class);
+ if (new_delay <= batch->last_scan_delay)
+ return;
+ const unsigned int idle_change = new_delay - batch->last_scan_delay;
+ LOG_TARGET_DEBUG(batch->target, "Adding %u idle cycles before the batch.",
+ idle_change);
+ jtag_add_runtest(idle_change, TAP_IDLE);
+}
+
+static unsigned int get_delay(const struct riscv_batch *batch, size_t scan_idx,
+ const struct riscv_scan_delays *delays, bool resets_delays,
+ size_t reset_delays_after)
+{
+ assert(batch);
+ assert(scan_idx < batch->used_scans);
+ const bool delays_were_reset = resets_delays
+ && (scan_idx >= reset_delays_after);
+ const enum riscv_scan_delay_class delay_class =
+ batch->delay_classes[scan_idx];
+ const unsigned int delay = riscv_scan_get_delay(delays, delay_class);
+ return delays_were_reset ? 0 : delay;
+}
+
+static unsigned int decode_dmi(const struct riscv_batch *batch, char *text,
+ uint32_t address, uint32_t data)
+{
+ static const struct {
+ uint32_t address;
+ enum riscv_debug_reg_ordinal ordinal;
+ } description[] = {
+ {DM_DMCONTROL, DM_DMCONTROL_ORDINAL},
+ {DM_DMSTATUS, DM_DMSTATUS_ORDINAL},
+ {DM_ABSTRACTCS, DM_ABSTRACTCS_ORDINAL},
+ {DM_COMMAND, DM_COMMAND_ORDINAL},
+ {DM_SBCS, DM_SBCS_ORDINAL}
+ };
+
+ for (unsigned int i = 0; i < ARRAY_SIZE(description); i++) {
+ if (riscv_get_dmi_address(batch->target, description[i].address)
+ == address) {
+ const riscv_debug_reg_ctx_t context = {
+ .XLEN = { .value = 0, .is_set = false },
+ .DXLEN = { .value = 0, .is_set = false },
+ .abits = { .value = 0, .is_set = false },
+ };
+ return riscv_debug_reg_to_s(text, description[i].ordinal,
+ context, data, RISCV_DEBUG_REG_HIDE_ALL_0);
+ }
+ }
+ if (text)
+ text[0] = '\0';
+ return 0;
+}
+
+static void log_dmi_decoded(const struct riscv_batch *batch, bool write,
+ uint32_t address, uint32_t data)
+{
+ const size_t size = decode_dmi(batch, /* text */ NULL, address, data) + 1;
+ char * const decoded = malloc(size);
+ if (!decoded) {
+ LOG_ERROR("Not enough memory to allocate %zu bytes.", size);
+ return;
+ }
+ decode_dmi(batch, decoded, address, data);
+ LOG_DEBUG("%s: %s", write ? "write" : "read", decoded);
+ free(decoded);
+}
+
+static void log_batch(const struct riscv_batch *batch, size_t start_idx,
+ const struct riscv_scan_delays *delays, bool resets_delays,
+ size_t reset_delays_after)
+{
+ if (debug_level < LOG_LVL_DEBUG)
+ return;
+
+ const unsigned int abits = riscv_get_dmi_address_bits(batch->target);
+
+ /* Determine the "op" and "address" of the scan that preceded the first
+ * executed scan.
+ * FIXME: The code here assumes that there were no DMI operations between
+ * the last execution of the batch and the current one.
+ * Caching the info about the last executed DMI scan in "dm013_info_t"
+ * would be a more robust solution.
+ */
+ bool last_scan_was_read = false;
+ uint32_t last_scan_address = (uint32_t)(-1) /* to silence maybe-uninitialized */;
+ if (start_idx > 0) {
+ const struct scan_field * const field = &batch->fields[start_idx - 1];
+ assert(field->out_value);
+ last_scan_was_read = buf_get_u32(field->out_value, DTM_DMI_OP_OFFSET,
+ DTM_DMI_OP_LENGTH) == DTM_DMI_OP_READ;
+ last_scan_address = buf_get_u32(field->out_value,
+ DTM_DMI_ADDRESS_OFFSET, abits);
}
- riscv_batch_add_nop(batch);
+ /* Decode and log every executed scan */
+ for (size_t i = start_idx; i < batch->used_scans; ++i) {
+ static const char * const op_string[] = {"-", "r", "w", "?"};
+ const unsigned int delay = get_delay(batch, i, delays, resets_delays,
+ reset_delays_after);
+ const struct scan_field * const field = &batch->fields[i];
- for (size_t i = 0; i < batch->used_scans; ++i) {
+ assert(field->out_value);
+ const unsigned int out_op = buf_get_u32(field->out_value,
+ DTM_DMI_OP_OFFSET, DTM_DMI_OP_LENGTH);
+ const uint32_t out_data = buf_get_u32(field->out_value,
+ DTM_DMI_DATA_OFFSET, DTM_DMI_DATA_LENGTH);
+ const uint32_t out_address = buf_get_u32(field->out_value,
+ DTM_DMI_ADDRESS_OFFSET, abits);
+ if (field->in_value) {
+ static const char * const status_string[] = {
+ "+", "?", "F", "b"
+ };
+ const unsigned int in_op = buf_get_u32(field->in_value,
+ DTM_DMI_OP_OFFSET, DTM_DMI_OP_LENGTH);
+ const uint32_t in_data = buf_get_u32(field->in_value,
+ DTM_DMI_DATA_OFFSET, DTM_DMI_DATA_LENGTH);
+ const uint32_t in_address = buf_get_u32(field->in_value,
+ DTM_DMI_ADDRESS_OFFSET, abits);
+
+ LOG_DEBUG("%db %s %08" PRIx32 " @%02" PRIx32
+ " -> %s %08" PRIx32 " @%02" PRIx32 "; %ui",
+ field->num_bits, op_string[out_op], out_data, out_address,
+ status_string[in_op], in_data, in_address, delay);
+
+ if (last_scan_was_read && in_op == DTM_DMI_OP_SUCCESS)
+ log_dmi_decoded(batch, /*write*/ false,
+ last_scan_address, in_data);
+ } else {
+ LOG_DEBUG("%db %s %08" PRIx32 " @%02" PRIx32 " -> ?; %ui",
+ field->num_bits, op_string[out_op], out_data, out_address,
+ delay);
+ }
+
+ if (out_op == DTM_DMI_OP_WRITE)
+ log_dmi_decoded(batch, /*write*/ true, out_address,
+ out_data);
+
+ last_scan_was_read = out_op == DTM_DMI_OP_READ;
+ last_scan_address = out_address;
+ }
+}
+
+int riscv_batch_run_from(struct riscv_batch *batch, size_t start_idx,
+ const struct riscv_scan_delays *delays, bool resets_delays,
+ size_t reset_delays_after)
+{
+ assert(batch->used_scans);
+ assert(start_idx < batch->used_scans);
+ assert(batch->last_scan == RISCV_SCAN_TYPE_NOP);
+ assert(!batch->was_run || riscv_batch_was_scan_busy(batch, start_idx));
+ assert(start_idx == 0 || !riscv_batch_was_scan_busy(batch, start_idx - 1));
+
+ if (batch->was_run)
+ add_idle_before_batch(batch, start_idx, delays);
+
+ LOG_TARGET_DEBUG(batch->target, "Running batch of scans [%zu, %zu)",
+ start_idx, batch->used_scans);
+
+ unsigned int delay = 0 /* to silence maybe-uninitialized */;
+ for (size_t i = start_idx; i < batch->used_scans; ++i) {
if (bscan_tunnel_ir_width != 0)
- riscv_add_bscan_tunneled_scan(batch->target, batch->fields+i, batch->bscan_ctxt+i);
+ riscv_add_bscan_tunneled_scan(batch->target->tap, batch->fields + i,
+ batch->bscan_ctxt + i);
else
jtag_add_dr_scan(batch->target->tap, 1, batch->fields + i, TAP_IDLE);
- if (batch->idle_count > 0)
- jtag_add_runtest(batch->idle_count, TAP_IDLE);
+ delay = get_delay(batch, i, delays, resets_delays,
+ reset_delays_after);
+ if (delay > 0)
+ jtag_add_runtest(delay, TAP_IDLE);
}
keep_alive();
if (jtag_execute_queue() != ERROR_OK) {
- LOG_ERROR("Unable to execute JTAG queue");
+ LOG_TARGET_ERROR(batch->target, "Unable to execute JTAG queue");
return ERROR_FAIL;
}
@@ -115,40 +316,69 @@ int riscv_batch_run(struct riscv_batch *batch)
if (bscan_tunnel_ir_width != 0) {
/* need to right-shift "in" by one bit, because of clock skew between BSCAN TAP and DM TAP */
- for (size_t i = 0; i < batch->used_scans; ++i) {
+ for (size_t i = start_idx; i < batch->used_scans; ++i) {
if ((batch->fields + i)->in_value)
buffer_shr((batch->fields + i)->in_value, DMI_SCAN_BUF_SIZE, 1);
}
}
- for (size_t i = 0; i < batch->used_scans; ++i)
- dump_field(batch->idle_count, batch->fields + i);
-
+ log_batch(batch, start_idx, delays, resets_delays, reset_delays_after);
+ batch->was_run = true;
+ batch->last_scan_delay = delay;
return ERROR_OK;
}
-void riscv_batch_add_dmi_write(struct riscv_batch *batch, unsigned int address, uint64_t data)
+void riscv_batch_add_dmi_write(struct riscv_batch *batch, uint32_t address, uint32_t data,
+ bool read_back, enum riscv_scan_delay_class delay_class)
{
+ // TODO: Check that the bit width of "address" is no more than dtmcs.abits,
+ // otherwise return an error (during batch creation or when the batch is executed).
+
assert(batch->used_scans < batch->allocated_scans);
struct scan_field *field = batch->fields + batch->used_scans;
- field->num_bits = riscv_dmi_write_u64_bits(batch->target);
- field->out_value = (void *)(batch->data_out + batch->used_scans * DMI_SCAN_BUF_SIZE);
- field->in_value = (void *)(batch->data_in + batch->used_scans * DMI_SCAN_BUF_SIZE);
- riscv_fill_dmi_write_u64(batch->target, (char *)field->out_value, address, data);
- riscv_fill_dmi_nop_u64(batch->target, (char *)field->in_value);
+
+ field->num_bits = get_dmi_scan_length(batch->target);
+ assert(field->num_bits <= DMI_SCAN_MAX_BIT_LENGTH);
+
+ uint8_t *out_value = batch->data_out + batch->used_scans * DMI_SCAN_BUF_SIZE;
+ uint8_t *in_value = batch->data_in + batch->used_scans * DMI_SCAN_BUF_SIZE;
+
+ field->out_value = out_value;
+ riscv_fill_dmi_write(batch->target, out_value, address, data);
+
+ if (read_back) {
+ field->in_value = in_value;
+ riscv_fill_dm_nop(batch->target, in_value);
+ } else {
+ field->in_value = NULL;
+ }
+
+ batch->delay_classes[batch->used_scans] = delay_class;
batch->last_scan = RISCV_SCAN_TYPE_WRITE;
batch->used_scans++;
}
-size_t riscv_batch_add_dmi_read(struct riscv_batch *batch, unsigned int address)
+size_t riscv_batch_add_dmi_read(struct riscv_batch *batch, uint32_t address,
+ enum riscv_scan_delay_class delay_class)
{
+ // TODO: Check that the bit width of "address" is no more than dtmcs.abits,
+ // otherwise return an error (during batch creation or when the batch is executed).
+
assert(batch->used_scans < batch->allocated_scans);
struct scan_field *field = batch->fields + batch->used_scans;
- field->num_bits = riscv_dmi_write_u64_bits(batch->target);
- field->out_value = (void *)(batch->data_out + batch->used_scans * DMI_SCAN_BUF_SIZE);
- field->in_value = (void *)(batch->data_in + batch->used_scans * DMI_SCAN_BUF_SIZE);
- riscv_fill_dmi_read_u64(batch->target, (char *)field->out_value, address);
- riscv_fill_dmi_nop_u64(batch->target, (char *)field->in_value);
+
+ field->num_bits = get_dmi_scan_length(batch->target);
+ assert(field->num_bits <= DMI_SCAN_MAX_BIT_LENGTH);
+
+ uint8_t *out_value = batch->data_out + batch->used_scans * DMI_SCAN_BUF_SIZE;
+ uint8_t *in_value = batch->data_in + batch->used_scans * DMI_SCAN_BUF_SIZE;
+
+ field->out_value = out_value;
+ field->in_value = in_value;
+ riscv_fill_dmi_read(batch->target, out_value, address);
+ riscv_fill_dm_nop(batch->target, in_value);
+
+ batch->delay_classes[batch->used_scans] = delay_class;
batch->last_scan = RISCV_SCAN_TYPE_READ;
batch->used_scans++;
@@ -156,21 +386,21 @@ size_t riscv_batch_add_dmi_read(struct riscv_batch *batch, unsigned int address)
return batch->read_keys_used++;
}
-uint32_t riscv_batch_get_dmi_read_op(struct riscv_batch *batch, size_t key)
+uint32_t riscv_batch_get_dmi_read_op(const struct riscv_batch *batch, size_t key)
{
assert(key < batch->read_keys_used);
size_t index = batch->read_keys[key];
- assert(index <= batch->used_scans);
+ assert(index < batch->used_scans);
uint8_t *base = batch->data_in + DMI_SCAN_BUF_SIZE * index;
/* extract "op" field from the DMI read result */
return buf_get_u32(base, DTM_DMI_OP_OFFSET, DTM_DMI_OP_LENGTH);
}
-uint32_t riscv_batch_get_dmi_read_data(struct riscv_batch *batch, size_t key)
+uint32_t riscv_batch_get_dmi_read_data(const struct riscv_batch *batch, size_t key)
{
assert(key < batch->read_keys_used);
size_t index = batch->read_keys[key];
- assert(index <= batch->used_scans);
+ assert(index < batch->used_scans);
uint8_t *base = batch->data_in + DMI_SCAN_BUF_SIZE * index;
/* extract "data" field from the DMI read result */
return buf_get_u32(base, DTM_DMI_DATA_OFFSET, DTM_DMI_DATA_LENGTH);
@@ -180,48 +410,48 @@ void riscv_batch_add_nop(struct riscv_batch *batch)
{
assert(batch->used_scans < batch->allocated_scans);
struct scan_field *field = batch->fields + batch->used_scans;
- field->num_bits = riscv_dmi_write_u64_bits(batch->target);
- field->out_value = (void *)(batch->data_out + batch->used_scans * DMI_SCAN_BUF_SIZE);
- field->in_value = (void *)(batch->data_in + batch->used_scans * DMI_SCAN_BUF_SIZE);
- riscv_fill_dmi_nop_u64(batch->target, (char *)field->out_value);
- riscv_fill_dmi_nop_u64(batch->target, (char *)field->in_value);
+
+ field->num_bits = get_dmi_scan_length(batch->target);
+ assert(field->num_bits <= DMI_SCAN_MAX_BIT_LENGTH);
+
+ uint8_t *out_value = batch->data_out + batch->used_scans * DMI_SCAN_BUF_SIZE;
+ uint8_t *in_value = batch->data_in + batch->used_scans * DMI_SCAN_BUF_SIZE;
+
+ field->out_value = out_value;
+ field->in_value = in_value;
+ riscv_fill_dm_nop(batch->target, out_value);
+ riscv_fill_dm_nop(batch->target, in_value);
+
+ /* DMI NOP never triggers any debug module operation,
+ * so the shortest (base) delay can be used. */
+ batch->delay_classes[batch->used_scans] = RISCV_DELAY_BASE;
batch->last_scan = RISCV_SCAN_TYPE_NOP;
batch->used_scans++;
}
-void dump_field(int idle, const struct scan_field *field)
+size_t riscv_batch_available_scans(struct riscv_batch *batch)
{
- static const char * const op_string[] = {"-", "r", "w", "?"};
- static const char * const status_string[] = {"+", "?", "F", "b"};
-
- if (debug_level < LOG_LVL_DEBUG)
- return;
+ assert(batch->allocated_scans >= (batch->used_scans + BATCH_RESERVED_SCANS));
+ return batch->allocated_scans - batch->used_scans - BATCH_RESERVED_SCANS;
+}
- assert(field->out_value);
- uint64_t out = buf_get_u64(field->out_value, 0, field->num_bits);
- unsigned int out_op = get_field(out, DTM_DMI_OP);
- unsigned int out_data = get_field(out, DTM_DMI_DATA);
- unsigned int out_address = out >> DTM_DMI_ADDRESS_OFFSET;
-
- if (field->in_value) {
- uint64_t in = buf_get_u64(field->in_value, 0, field->num_bits);
- unsigned int in_op = get_field(in, DTM_DMI_OP);
- unsigned int in_data = get_field(in, DTM_DMI_DATA);
- unsigned int in_address = in >> DTM_DMI_ADDRESS_OFFSET;
-
- log_printf_lf(LOG_LVL_DEBUG,
- __FILE__, __LINE__, __PRETTY_FUNCTION__,
- "%ub %s %08x @%02x -> %s %08x @%02x; %di",
- field->num_bits, op_string[out_op], out_data, out_address,
- status_string[in_op], in_data, in_address, idle);
- } else {
- log_printf_lf(LOG_LVL_DEBUG,
- __FILE__, __LINE__, __PRETTY_FUNCTION__, "%ub %s %08x @%02x -> ?; %di",
- field->num_bits, op_string[out_op], out_data, out_address, idle);
- }
+bool riscv_batch_was_batch_busy(const struct riscv_batch *batch)
+{
+ assert(batch->was_run);
+ assert(batch->used_scans);
+ assert(batch->last_scan == RISCV_SCAN_TYPE_NOP);
+ return riscv_batch_was_scan_busy(batch, batch->used_scans - 1);
}
-size_t riscv_batch_available_scans(struct riscv_batch *batch)
+size_t riscv_batch_finished_scans(const struct riscv_batch *batch)
{
- return batch->allocated_scans - batch->used_scans - 4;
+ if (!riscv_batch_was_batch_busy(batch)) {
+ /* Whole batch succeeded. */
+ return batch->used_scans;
+ }
+ assert(batch->used_scans);
+ size_t first_busy = 0;
+ while (!riscv_batch_was_scan_busy(batch, first_busy))
+ ++first_busy;
+ return first_busy;
}
diff --git a/src/target/riscv/batch.h b/src/target/riscv/batch.h
index 537fa5923..5d8b57234 100644
--- a/src/target/riscv/batch.h
+++ b/src/target/riscv/batch.h
@@ -1,7 +1,7 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
-#ifndef TARGET__RISCV__SCANS_H
-#define TARGET__RISCV__SCANS_H
+#ifndef OPENOCD_TARGET_RISCV_BATCH_H
+#define OPENOCD_TARGET_RISCV_BATCH_H
#include "target/target.h"
#include "jtag/jtag.h"
@@ -14,6 +14,112 @@ enum riscv_scan_type {
RISCV_SCAN_TYPE_WRITE,
};
+/* These types are used to specify how many JTAG RTI cycles to add after a
+ * scan.
+ */
+enum riscv_scan_delay_class {
+ /* Delay needed for accessing debug module registers: */
+ RISCV_DELAY_BASE,
+ /* Delay for execution of an abstract command: */
+ RISCV_DELAY_ABSTRACT_COMMAND,
+ /* Delay for System Bus read operation: */
+ RISCV_DELAY_SYSBUS_READ,
+ /* Delay for System Bus write operation: */
+ RISCV_DELAY_SYSBUS_WRITE
+};
+
+static inline const char *
+riscv_scan_delay_class_name(enum riscv_scan_delay_class delay_class)
+{
+ switch (delay_class) {
+ case RISCV_DELAY_BASE:
+ return "DM access";
+ case RISCV_DELAY_ABSTRACT_COMMAND:
+ return "Abstract Command";
+ case RISCV_DELAY_SYSBUS_READ:
+ return "System Bus read";
+ case RISCV_DELAY_SYSBUS_WRITE:
+ return "System Bus write";
+ }
+ assert(0);
+ return NULL;
+}
+
+/* The scan delay values are passed to "jtag_add_runtest()", which accepts an
+ * "int". Therefore, the passed value should be no greater than "INT_MAX".
+ *
+ * Since the resulting delay value can be a sum of two individual delays,
+ * individual delays are limited to "INT_MAX / 2" to prevent overflow of the
+ * final sum.
+ */
+#define RISCV_SCAN_DELAY_MAX (INT_MAX / 2)
+
+struct riscv_scan_delays {
+ unsigned int base_delay;
+ unsigned int ac_delay;
+ unsigned int sb_read_delay;
+ unsigned int sb_write_delay;
+};
+
+static inline unsigned int
+riscv_scan_get_delay(const struct riscv_scan_delays *delays,
+ enum riscv_scan_delay_class delay_class)
+{
+ switch (delay_class) {
+ case RISCV_DELAY_BASE:
+ return delays->base_delay;
+ case RISCV_DELAY_ABSTRACT_COMMAND:
+ return delays->base_delay + delays->ac_delay;
+ case RISCV_DELAY_SYSBUS_READ:
+ return delays->base_delay + delays->sb_read_delay;
+ case RISCV_DELAY_SYSBUS_WRITE:
+ return delays->base_delay + delays->sb_write_delay;
+ }
+ assert(0);
+ return 0;
+}
+
+static inline void riscv_scan_set_delay(struct riscv_scan_delays *delays,
+ enum riscv_scan_delay_class delay_class, unsigned int delay)
+{
+ assert(delay <= RISCV_SCAN_DELAY_MAX);
+ LOG_DEBUG("%s delay is set to %u.",
+ riscv_scan_delay_class_name(delay_class), delay);
+ switch (delay_class) {
+ case RISCV_DELAY_BASE:
+ delays->base_delay = delay;
+ return;
+ case RISCV_DELAY_ABSTRACT_COMMAND:
+ delays->ac_delay = delay;
+ return;
+ case RISCV_DELAY_SYSBUS_READ:
+ delays->sb_read_delay = delay;
+ return;
+ case RISCV_DELAY_SYSBUS_WRITE:
+ delays->sb_write_delay = delay;
+ return;
+ }
+ assert(0);
+}
+
+static inline int riscv_scan_increase_delay(struct riscv_scan_delays *delays,
+ enum riscv_scan_delay_class delay_class)
+{
+ const unsigned int delay = riscv_scan_get_delay(delays, delay_class);
+ const unsigned int delay_step = delay / 10 + 1;
+ if (delay > RISCV_SCAN_DELAY_MAX - delay_step) {
+ /* It's not clear if this issue actually occurs in real
+ * use-cases, so stick with a simple solution until the
+ * first bug report.
+ */
+ LOG_ERROR("Delay for %s (%d) is not increased anymore (maximum was reached).",
+ riscv_scan_delay_class_name(delay_class), delay);
+ return ERROR_FAIL;
+ }
+ riscv_scan_set_delay(delays, delay_class, delay + delay_step);
+ return ERROR_OK;
+}
+
/* A batch of multiple JTAG scans, which are grouped together to avoid the
* overhead of some JTAG adapters when sending single commands. This is
* designed to support block copies, as that's what we actually need to go
@@ -24,11 +130,10 @@ struct riscv_batch {
size_t allocated_scans;
size_t used_scans;
- size_t idle_count;
-
uint8_t *data_out;
uint8_t *data_in;
struct scan_field *fields;
+ enum riscv_scan_delay_class *delay_classes;
/* If in BSCAN mode, this field will be allocated (one per scan),
and utilized to tunnel all the scans in the batch. If not in
@@ -44,29 +149,75 @@ struct riscv_batch {
/* The read keys. */
size_t *read_keys;
size_t read_keys_used;
+
+ /* Flag indicating that the last run of the batch finished without an error
+ * from the underlying JTAG layer of OpenOCD - all scans were performed.
+ * However, RISC-V DMI "busy" condition could still have occurred.
+ */
+ bool was_run;
+ /* Number of RTI cycles used by the last scan on the last run.
+ * Only valid when `was_run` is set.
+ */
+ unsigned int last_scan_delay;
};
/* Allocates (or frees) a new scan set. "scans" is the maximum number of JTAG
- * scans that can be issued to this object, and idle is the number of JTAG idle
- * cycles between every real scan. */
-struct riscv_batch *riscv_batch_alloc(struct target *target, size_t scans, size_t idle);
+ * scans that can be issued to this object. */
+struct riscv_batch *riscv_batch_alloc(struct target *target, size_t scans);
void riscv_batch_free(struct riscv_batch *batch);
/* Checks to see if this batch is full. */
bool riscv_batch_full(struct riscv_batch *batch);
-/* Executes this scan batch. */
-int riscv_batch_run(struct riscv_batch *batch);
-
-/* Adds a DMI write to this batch. */
-void riscv_batch_add_dmi_write(struct riscv_batch *batch, unsigned int address, uint64_t data);
-
-/* DMI reads must be handled in two parts: the first one schedules a read and
+/* Executes this batch of JTAG DTM DMI scans, starting form "start" scan.
+ *
+ * If batch is run for the first time, it is expected that "start" is zero.
+ * It is expected that the batch ends with a DMI NOP operation.
+ *
+ * "idle_counts" specifies the number of JTAG Run-Test-Idle cycles to add
+ * after each scan depending on the delay class of the scan.
+ *
+ * If "resets_delays" is true, the algorithm will stop inserting idle cycles
+ * (JTAG Run-Test-Idle) after "reset_delays_after" number of scans is
+ * performed. This is useful for stress-testing of RISC-V algorithms in
+ * OpenOCD that are based on batches.
+ */
+int riscv_batch_run_from(struct riscv_batch *batch, size_t start_idx,
+ const struct riscv_scan_delays *delays, bool resets_delays,
+ size_t reset_delays_after);
+
+/* Get the number of scans successfully executed form this batch. */
+size_t riscv_batch_finished_scans(const struct riscv_batch *batch);
+
+/* Adds a DM register write to this batch. */
+void riscv_batch_add_dmi_write(struct riscv_batch *batch, uint32_t address, uint32_t data,
+ bool read_back, enum riscv_scan_delay_class delay_class);
+
+static inline void
+riscv_batch_add_dm_write(struct riscv_batch *batch, uint32_t address, uint32_t data,
+ bool read_back, enum riscv_scan_delay_class delay_type)
+{
+ return riscv_batch_add_dmi_write(batch,
+ riscv_get_dmi_address(batch->target, address), data,
+ read_back, delay_type);
+}
+
+/* DM register reads must be handled in two parts: the first one schedules a read and
* provides a key, the second one actually obtains the result of the read -
* status (op) and the actual data. */
-size_t riscv_batch_add_dmi_read(struct riscv_batch *batch, unsigned int address);
-uint32_t riscv_batch_get_dmi_read_op(struct riscv_batch *batch, size_t key);
-uint32_t riscv_batch_get_dmi_read_data(struct riscv_batch *batch, size_t key);
+size_t riscv_batch_add_dmi_read(struct riscv_batch *batch, uint32_t address,
+ enum riscv_scan_delay_class delay_class);
+
+static inline size_t
+riscv_batch_add_dm_read(struct riscv_batch *batch, uint32_t address,
+ enum riscv_scan_delay_class delay_type)
+{
+ return riscv_batch_add_dmi_read(batch,
+ riscv_get_dmi_address(batch->target, address), delay_type);
+}
+
+uint32_t riscv_batch_get_dmi_read_op(const struct riscv_batch *batch, size_t key);
+uint32_t riscv_batch_get_dmi_read_data(const struct riscv_batch *batch, size_t key);
/* Scans in a NOP. */
void riscv_batch_add_nop(struct riscv_batch *batch);
@@ -74,4 +225,7 @@ void riscv_batch_add_nop(struct riscv_batch *batch);
/* Returns the number of available scans. */
size_t riscv_batch_available_scans(struct riscv_batch *batch);
-#endif
+/* Return true iff the last scan in the batch returned DMI_OP_BUSY. */
+bool riscv_batch_was_batch_busy(const struct riscv_batch *batch);
+
+#endif /* OPENOCD_TARGET_RISCV_BATCH_H */
diff --git a/src/target/riscv/debug_defines.c b/src/target/riscv/debug_defines.c
new file mode 100644
index 000000000..81644b2c2
--- /dev/null
+++ b/src/target/riscv/debug_defines.c
@@ -0,0 +1,3902 @@
+// SPDX-License-Identifier: BSD-2-Clause OR CC-BY-4.0
+/* This file was auto-generated by running 'make debug_defines' in https://github.com/riscv/riscv-debug-spec/ (22a7576) */
+
+#include "debug_defines.h"
+#include <stddef.h>
+#include <assert.h>
+static riscv_debug_reg_field_list_t dtm_idcode_get_version(riscv_debug_reg_ctx_t context)
+{
+ riscv_debug_reg_field_list_t result = {
+ .field = {
+ .name = "Version",
+ .lsb = 0x1c,
+ .msb = 0x1f,
+ .values = NULL
+ },
+ .get_next = NULL
+ };
+ return result;
+}
+
+static riscv_debug_reg_field_list_t dtm_idcode_get_partnumber(riscv_debug_reg_ctx_t context)
+{
+ riscv_debug_reg_field_list_t result = {
+ .field = {
+ .name = "PartNumber",
+ .lsb = 0xc,
+ .msb = 0x1b,
+ .values = NULL
+ },
+ .get_next = dtm_idcode_get_version
+ };
+ return result;
+}
+
+static riscv_debug_reg_field_list_t dtm_idcode_get_manufid(riscv_debug_reg_ctx_t context)
+{
+ riscv_debug_reg_field_list_t result = {
+ .field = {
+ .name = "ManufId",
+ .lsb = 1,
+ .msb = 0xb,
+ .values = NULL
+ },
+ .get_next = dtm_idcode_get_partnumber
+ };
+ return result;
+}
+
+static riscv_debug_reg_field_list_t dtm_idcode_get_1(riscv_debug_reg_ctx_t context)
+{
+ riscv_debug_reg_field_list_t result = {
+ .field = {
+ .name = "1",
+ .lsb = 0,
+ .msb = 0,
+ .values = NULL
+ },
+ .get_next = dtm_idcode_get_manufid
+ };
+ return result;
+}
+
+static const char *dtm_dtmcs_errinfo_values[8] = {
+ [0] = "not_implemented",
+ [1] = "dmi_error",
+ [2] = "communication_error",
+ [3] = "device_error",
+ [4] = "unknown"
+};
+static const char *dtm_dtmcs_version_values[16] = {
+ [0] = "0_11",
+ [1] = "1_0",
+ [15] = "custom"
+};
+static riscv_debug_reg_field_list_t dtm_dtmcs_get_abits(riscv_debug_reg_ctx_t context)
+{
+ riscv_debug_reg_field_list_t result = {
+ .field = {
+ .name = "abits",
+ .lsb = 4,
+ .msb = 9,
+ .values = NULL
+ },
+ .get_next = NULL
+ };
+ return result;
+}
+
+static riscv_debug_reg_field_list_t dtm_dtmcs_get_errinfo(riscv_debug_reg_ctx_t context)
+{
+ riscv_debug_reg_field_list_t result = {
+ .field = {
+ .name = "errinfo",
+ .lsb = 0x12,
+ .msb = 0x14,
+ .values = dtm_dtmcs_errinfo_values
+ },
+ .get_next = dtm_dtmcs_get_abits
+ };
+ return result;
+}
+
+static riscv_debug_reg_field_list_t dtm_dtmcs_get_dtmhardreset(riscv_debug_reg_ctx_t context)
+{
+ riscv_debug_reg_field_list_t result = {
+ .field = {
+ .name = "dtmhardreset",
+ .lsb = 0x11,
+ .msb = 0x11,
+ .values = NULL
+ },
+ .get_next = dtm_dtmcs_get_errinfo
+ };
+ return result;
+}
+
+static riscv_debug_reg_field_list_t dtm_dtmcs_get_dmireset(riscv_debug_reg_ctx_t context)
+{
+ riscv_debug_reg_field_list_t result = {
+ .field = {
+ .name = "dmireset",
+ .lsb = 0x10,
+ .msb = 0x10,
+ .values = NULL
+ },
+ .get_next = dtm_dtmcs_get_dtmhardreset
+ };
+ return result;
+}
+
+static riscv_debug_reg_field_list_t dtm_dtmcs_get_idle(riscv_debug_reg_ctx_t context)
+{
+ riscv_debug_reg_field_list_t result = {
+ .field = {
+ .name = "idle",
+ .lsb = 0xc,
+ .msb = 0xe,
+ .values = NULL
+ },
+ .get_next = dtm_dtmcs_get_dmireset
+ };
+ return result;
+}
+
+static riscv_debug_reg_field_list_t dtm_dtmcs_get_dmistat(riscv_debug_reg_ctx_t context)
+{
+ riscv_debug_reg_field_list_t result = {
+ .field = {
+ .name = "dmistat",
+ .lsb = 0xa,
+ .msb = 0xb,
+ .values = NULL
+ },
+ .get_next = dtm_dtmcs_get_idle
+ };
+ return result;
+}
+
+static riscv_debug_reg_field_list_t dtm_dtmcs_get_version(riscv_debug_reg_ctx_t context)
+{
+ riscv_debug_reg_field_list_t result = {
+ .field = {
+ .name = "version",
+ .lsb = 0,
+ .msb = 3,
+ .values = dtm_dtmcs_version_values
+ },
+ .get_next = dtm_dtmcs_get_dmistat
+ };
+ return result;
+}
+
+static const char *dtm_dmi_op_values[4] = {};
+static riscv_debug_reg_field_list_t dtm_dmi_get_address(riscv_debug_reg_ctx_t context)
+{
+ assert(context.abits.is_set);
+ riscv_debug_reg_field_list_t result = {
+ .field = {
+ .name = "address",
+ .lsb = 0x22,
+ .msb = (context.abits.value + 0x21),
+ .values = NULL
+ },
+ .get_next = NULL
+ };
+ return result;
+}
+
+static riscv_debug_reg_field_list_t dtm_dmi_get_data(riscv_debug_reg_ctx_t context)
+{
+ riscv_debug_reg_field_list_t result = {
+ .field = {
+ .name = "data",
+ .lsb = 2,
+ .msb = 0x21,
+ .values = NULL
+ },
+ .get_next = dtm_dmi_get_address
+ };
+ return result;
+}
+
+static riscv_debug_reg_field_list_t dtm_dmi_get_op(riscv_debug_reg_ctx_t context)
+{
+ riscv_debug_reg_field_list_t result = {
+ .field = {
+ .name = "op",
+ .lsb = 0,
+ .msb = 1,
+ .values = dtm_dmi_op_values
+ },
+ .get_next = dtm_dmi_get_data
+ };
+ return result;
+}
+
+
+static const char *csr_dcsr_debugver_values[16] = {
+ [0] = "none",
+ [4] = "1_0",
+ [15] = "custom"
+};
+static const char *csr_dcsr_extcause_values[8] = {
+ [0] = "critical_error"
+};
+static const char *csr_dcsr_cetrig_values[2] = {
+ [0] = "disabled",
+ [1] = "enabled"
+};
+static const char *csr_dcsr_pelp_values[2] = {
+ [0] = "NO_LP_EXPECTED",
+ [1] = "LP_EXPECTED"
+};
+static const char *csr_dcsr_ebreakvs_values[2] = {
+ [0] = "exception",
+ [1] = "debug_mode"
+};
+static const char *csr_dcsr_ebreakvu_values[2] = {
+ [0] = "exception",
+ [1] = "debug_mode"
+};
+static const char *csr_dcsr_ebreakm_values[2] = {
+ [0] = "exception",
+ [1] = "debug_mode"
+};
+static const char *csr_dcsr_ebreaks_values[2] = {
+ [0] = "exception",
+ [1] = "debug_mode"
+};
+static const char *csr_dcsr_ebreaku_values[2] = {
+ [0] = "exception",
+ [1] = "debug_mode"
+};
+static const char *csr_dcsr_stepie_values[2] = {
+ [0] = "interrupts_disabled",
+ [1] = "interrupts_enabled"
+};
+static const char *csr_dcsr_stopcount_values[2] = {
+ [0] = "normal",
+ [1] = "freeze"
+};
+static const char *csr_dcsr_stoptime_values[2] = {
+ [0] = "normal",
+ [1] = "freeze"
+};
+static const char *csr_dcsr_cause_values[8] = {
+ [1] = "ebreak",
+ [2] = "trigger",
+ [3] = "haltreq",
+ [4] = "step",
+ [5] = "resethaltreq",
+ [6] = "group",
+ [7] = "other"
+};
+static const char *csr_dcsr_mprven_values[2] = {
+ [0] = "disabled",
+ [1] = "enabled"
+};
+static riscv_debug_reg_field_list_t csr_dcsr_get_stoptime(riscv_debug_reg_ctx_t context)
+{
+ riscv_debug_reg_field_list_t result = {
+ .field = {
+ .name = "stoptime",
+ .lsb = 9,
+ .msb = 9,
+ .values = csr_dcsr_stoptime_values
+ },
+ .get_next = NULL
+ };
+ return result;
+}
+
+static riscv_debug_reg_field_list_t csr_dcsr_get_cause(riscv_debug_reg_ctx_t context)
+{
+ riscv_debug_reg_field_list_t result = {
+ .field = {
+ .name = "cause",
+ .lsb = 6,
+ .msb = 8,
+ .values = csr_dcsr_cause_values
+ },
+ .get_next = csr_dcsr_get_stoptime
+ };
+ return result;
+}
+
+static riscv_debug_reg_field_list_t csr_dcsr_get_v(riscv_debug_reg_ctx_t context)
+{
+ riscv_debug_reg_field_list_t result = {
+ .field = {
+ .name = "v",
+ .lsb = 5,
+ .msb = 5,
+ .values = NULL
+ },
+ .get_next = csr_dcsr_get_cause
+ };
+ return result;
+}
+
+static riscv_debug_reg_field_list_t csr_dcsr_get_mprven(riscv_debug_reg_ctx_t context)
+{
+ riscv_debug_reg_field_list_t result = {
+ .field = {
+ .name = "mprven",
+ .lsb = 4,
+ .msb = 4,
+ .values = csr_dcsr_mprven_values
+ },
+ .get_next = csr_dcsr_get_v
+ };
+ return result;
+}
+
+static riscv_debug_reg_field_list_t csr_dcsr_get_nmip(riscv_debug_reg_ctx_t context)
+{
+ riscv_debug_reg_field_list_t result = {
+ .field = {
+ .name = "nmip",
+ .lsb = 3,
+ .msb = 3,
+ .values = NULL
+ },
+ .get_next = csr_dcsr_get_mprven
+ };
+ return result;
+}
+
+static riscv_debug_reg_field_list_t csr_dcsr_get_debugver(riscv_debug_reg_ctx_t context)
+{
+ riscv_debug_reg_field_list_t result = {
+ .field = {
+ .name = "debugver",
+ .lsb = 0x1c,
+ .msb = 0x1f,
+ .values = csr_dcsr_debugver_values
+ },
+ .get_next = csr_dcsr_get_nmip
+ };
+ return result;
+}
+
+static riscv_debug_reg_field_list_t csr_dcsr_get_extcause(riscv_debug_reg_ctx_t context)
+{
+ riscv_debug_reg_field_list_t result = {
+ .field = {
+ .name = "extcause",
+ .lsb = 0x18,
+ .msb = 0x1a,
+ .values = csr_dcsr_extcause_values
+ },
+ .get_next = csr_dcsr_get_debugver
+ };
+ return result;
+}
+
+static riscv_debug_reg_field_list_t csr_dcsr_get_step(riscv_debug_reg_ctx_t context)
+{
+ riscv_debug_reg_field_list_t result = {
+ .field = {
+ .name = "step",
+ .lsb = 2,
+ .msb = 2,
+ .values = NULL
+ },
+ .get_next = csr_dcsr_get_extcause
+ };
+ return result;
+}
+
+static riscv_debug_reg_field_list_t csr_dcsr_get_cetrig(riscv_debug_reg_ctx_t context)
+{
+ riscv_debug_reg_field_list_t result = {
+ .field = {
+ .name = "cetrig",
+ .lsb = 0x13,
+ .msb = 0x13,
+ .values = csr_dcsr_cetrig_values
+ },
+ .get_next = csr_dcsr_get_step
+ };
+ return result;
+}
+
+static riscv_debug_reg_field_list_t csr_dcsr_get_pelp(riscv_debug_reg_ctx_t context)
+{
+ riscv_debug_reg_field_list_t result = {
+ .field = {
+ .name = "pelp",
+ .lsb = 0x12,
+ .msb = 0x12,
+ .values = csr_dcsr_pelp_values
+ },
+ .get_next = csr_dcsr_get_cetrig
+ };
+ return result;
+}
+
+static riscv_debug_reg_field_list_t csr_dcsr_get_ebreakvs(riscv_debug_reg_ctx_t context)
+{
+ riscv_debug_reg_field_list_t result = {
+ .field = {
+ .name = "ebreakvs",
+ .lsb = 0x11,
+ .msb = 0x11,
+ .values = csr_dcsr_ebreakvs_values
+ },
+ .get_next = csr_dcsr_get_pelp
+ };
+ return result;
+}
+
+static riscv_debug_reg_field_list_t csr_dcsr_get_ebreakvu(riscv_debug_reg_ctx_t context)
+{
+ riscv_debug_reg_field_list_t result = {
+ .field = {
+ .name = "ebreakvu",
+ .lsb = 0x10,
+ .msb = 0x10,
+ .values = csr_dcsr_ebreakvu_values
+ },
+ .get_next = csr_dcsr_get_ebreakvs
+ };
+ return result;
+}
+
+static riscv_debug_reg_field_list_t csr_dcsr_get_ebreakm(riscv_debug_reg_ctx_t context)
+{
+ riscv_debug_reg_field_list_t result = {
+ .field = {
+ .name = "ebreakm",
+ .lsb = 0xf,
+ .msb = 0xf,
+ .values = csr_dcsr_ebreakm_values
+ },
+ .get_next = csr_dcsr_get_ebreakvu
+ };
+ return result;
+}
+
+static riscv_debug_reg_field_list_t csr_dcsr_get_ebreaks(riscv_debug_reg_ctx_t context)
+{
+ riscv_debug_reg_field_list_t result = {
+ .field = {
+ .name = "ebreaks",
+ .lsb = 0xd,
+ .msb = 0xd,
+ .values = csr_dcsr_ebreaks_values
+ },
+ .get_next = csr_dcsr_get_ebreakm
+ };
+ return result;
+}
+
+static riscv_debug_reg_field_list_t csr_dcsr_get_ebreaku(riscv_debug_reg_ctx_t context)
+{
+ riscv_debug_reg_field_list_t result = {
+ .field = {
+ .name = "ebreaku",
+ .lsb = 0xc,
+ .msb = 0xc,
+ .values = csr_dcsr_ebreaku_values
+ },
+ .get_next = csr_dcsr_get_ebreaks
+ };
+ return result;
+}
+
+static riscv_debug_reg_field_list_t csr_dcsr_get_stepie(riscv_debug_reg_ctx_t context)
+{
+ riscv_debug_reg_field_list_t result = {
+ .field = {
+ .name = "stepie",
+ .lsb = 0xb,
+ .msb = 0xb,
+ .values = csr_dcsr_stepie_values
+ },
+ .get_next = csr_dcsr_get_ebreaku
+ };
+ return result;
+}
+
+static riscv_debug_reg_field_list_t csr_dcsr_get_stopcount(riscv_debug_reg_ctx_t context)
+{
+ riscv_debug_reg_field_list_t result = {
+ .field = {
+ .name = "stopcount",
+ .lsb = 0xa,
+ .msb = 0xa,
+ .values = csr_dcsr_stopcount_values
+ },
+ .get_next = csr_dcsr_get_stepie
+ };
+ return result;
+}
+
+static riscv_debug_reg_field_list_t csr_dcsr_get_prv(riscv_debug_reg_ctx_t context)
+{
+ riscv_debug_reg_field_list_t result = {
+ .field = {
+ .name = "prv",
+ .lsb = 0,
+ .msb = 1,
+ .values = NULL
+ },
+ .get_next = csr_dcsr_get_stopcount
+ };
+ return result;
+}
+
+static riscv_debug_reg_field_list_t csr_dpc_get_dpc(riscv_debug_reg_ctx_t context)
+{
+ assert(context.DXLEN.is_set);
+ riscv_debug_reg_field_list_t result = {
+ .field = {
+ .name = "dpc",
+ .lsb = 0,
+ .msb = (context.DXLEN.value + -1),
+ .values = NULL
+ },
+ .get_next = NULL
+ };
+ return result;
+}
+
+static riscv_debug_reg_field_list_t csr_dscratch0_get_dscratch0(riscv_debug_reg_ctx_t context)
+{
+ assert(context.DXLEN.is_set);
+ riscv_debug_reg_field_list_t result = {
+ .field = {
+ .name = "dscratch0",
+ .lsb = 0,
+ .msb = (context.DXLEN.value + -1),
+ .values = NULL
+ },
+ .get_next = NULL
+ };
+ return result;
+}
+
+static riscv_debug_reg_field_list_t csr_dscratch1_get_dscratch1(riscv_debug_reg_ctx_t context)
+{
+ assert(context.DXLEN.is_set);
+ riscv_debug_reg_field_list_t result = {
+ .field = {
+ .name = "dscratch1",
+ .lsb = 0,
+ .msb = (context.DXLEN.value + -1),
+ .values = NULL
+ },
+ .get_next = NULL
+ };
+ return result;
+}
+
+static riscv_debug_reg_field_list_t csr_tselect_get_index(riscv_debug_reg_ctx_t context)
+{
+ assert(context.XLEN.is_set);
+ riscv_debug_reg_field_list_t result = {
+ .field = {
+ .name = "index",
+ .lsb = 0,
+ .msb = (context.XLEN.value + -1),
+ .values = NULL
+ },
+ .get_next = NULL
+ };
+ return result;
+}
+
+static const char *csr_tdata1_type_values[16] = {
+ [0] = "none",
+ [1] = "legacy",
+ [2] = "mcontrol",
+ [3] = "icount",
+ [4] = "itrigger",
+ [5] = "etrigger",
+ [6] = "mcontrol6",
+ [7] = "tmexttrigger",
+ [15] = "disabled"
+};
+static const char *csr_tdata1_dmode_values[2] = {
+ [0] = "both",
+ [1] = "dmode"
+};
+static riscv_debug_reg_field_list_t csr_tdata1_get_dmode(riscv_debug_reg_ctx_t context)
+{
+ assert(context.XLEN.is_set);
+ riscv_debug_reg_field_list_t result = {
+ .field = {
+ .name = "dmode",
+ .lsb = (context.XLEN.value + -5),
+ .msb = (context.XLEN.value + -5),
+ .values = csr_tdata1_dmode_values
+ },
+ .get_next = NULL
+ };
+ return result;
+}
+
+static riscv_debug_reg_field_list_t csr_tdata1_get_type(riscv_debug_reg_ctx_t context)
+{
+ assert(context.XLEN.is_set);
+ riscv_debug_reg_field_list_t result = {
+ .field = {
+ .name = "type",
+ .lsb = (context.XLEN.value + -4),
+ .msb = (context.XLEN.value + -1),
+ .values = csr_tdata1_type_values
+ },
+ .get_next = csr_tdata1_get_dmode
+ };
+ return result;
+}
+
+static riscv_debug_reg_field_list_t csr_tdata1_get_data(riscv_debug_reg_ctx_t context)
+{
+ assert(context.XLEN.is_set);
+ riscv_debug_reg_field_list_t result = {
+ .field = {
+ .name = "data",
+ .lsb = 0,
+ .msb = (context.XLEN.value + -6),
+ .values = NULL
+ },
+ .get_next = csr_tdata1_get_type
+ };
+ return result;
+}
+
+static riscv_debug_reg_field_list_t csr_tdata2_get_data(riscv_debug_reg_ctx_t context)
+{
+ assert(context.XLEN.is_set);
+ riscv_debug_reg_field_list_t result = {
+ .field = {
+ .name = "data",
+ .lsb = 0,
+ .msb = (context.XLEN.value + -1),
+ .values = NULL
+ },
+ .get_next = NULL
+ };
+ return result;
+}
+
+static riscv_debug_reg_field_list_t csr_tdata3_get_data(riscv_debug_reg_ctx_t context)
+{
+ assert(context.XLEN.is_set);
+ riscv_debug_reg_field_list_t result = {
+ .field = {
+ .name = "data",
+ .lsb = 0,
+ .msb = (context.XLEN.value + -1),
+ .values = NULL
+ },
+ .get_next = NULL
+ };
+ return result;
+}
+
+static const char *csr_tinfo_version_values[256] = {
+ [0] = "0",
+ [1] = "1"
+};
+static riscv_debug_reg_field_list_t csr_tinfo_get_version(riscv_debug_reg_ctx_t context)
+{
+ riscv_debug_reg_field_list_t result = {
+ .field = {
+ .name = "version",
+ .lsb = 0x18,
+ .msb = 0x1f,
+ .values = csr_tinfo_version_values
+ },
+ .get_next = NULL
+ };
+ return result;
+}
+
+static riscv_debug_reg_field_list_t csr_tinfo_get_info(riscv_debug_reg_ctx_t context)
+{
+ riscv_debug_reg_field_list_t result = {
+ .field = {
+ .name = "info",
+ .lsb = 0,
+ .msb = 0xf,
+ .values = NULL
+ },
+ .get_next = csr_tinfo_get_version
+ };
+ return result;
+}
+
+static const char *csr_tcontrol_mte_values[2] = {
+ [0] = "disabled",
+ [1] = "enabled"
+};
+static riscv_debug_reg_field_list_t csr_tcontrol_get_mpte(riscv_debug_reg_ctx_t context)
+{
+ riscv_debug_reg_field_list_t result = {
+ .field = {
+ .name = "mpte",
+ .lsb = 7,
+ .msb = 7,
+ .values = NULL
+ },
+ .get_next = NULL
+ };
+ return result;
+}
+
+static riscv_debug_reg_field_list_t csr_tcontrol_get_mte(riscv_debug_reg_ctx_t context)
+{
+ riscv_debug_reg_field_list_t result = {
+ .field = {
+ .name = "mte",
+ .lsb = 3,
+ .msb = 3,
+ .values = csr_tcontrol_mte_values
+ },
+ .get_next = csr_tcontrol_get_mpte
+ };
+ return result;
+}
+
+static riscv_debug_reg_field_list_t csr_scontext_get_data(riscv_debug_reg_ctx_t context)
+{
+ riscv_debug_reg_field_list_t result = {
+ .field = {
+ .name = "data",
+ .lsb = 0,
+ .msb = 0x1f,
+ .values = NULL
+ },
+ .get_next = NULL
+ };
+ return result;
+}
+
+static riscv_debug_reg_field_list_t csr_mcontext_get_hcontext(riscv_debug_reg_ctx_t context)
+{
+ riscv_debug_reg_field_list_t result = {
+ .field = {
+ .name = "hcontext",
+ .lsb = 0,
+ .msb = 0xd,
+ .values = NULL
+ },
+ .get_next = NULL
+ };
+ return result;
+}
+
+static const char *csr_mcontrol_select_values[2] = {
+ [0] = "address",
+ [1] = "data"
+};
+static const char *csr_mcontrol_timing_values[2] = {
+ [0] = "before",
+ [1] = "after"
+};
+static const char *csr_mcontrol_sizelo_values[4] = {};
+static const char *csr_mcontrol_action_values[16] = {
+ [0] = "breakpoint",
+ [1] = "debug_mode",
+ [2] = "trace_on",
+ [3] = "trace_off",
+ [4] = "trace_notify",
+ [8] = "external0",
+ [9] = "external1"
+};
+static const char *csr_mcontrol_chain_values[2] = {
+ [0] = "disabled",
+ [1] = "enabled"
+};
+static const char *csr_mcontrol_match_values[16] = {
+ [0] = "equal",
+ [1] = "napot",
+ [2] = "ge",
+ [3] = "lt",
+ [4] = "mask_low",
+ [5] = "mask_high",
+ [8] = "not_equal",
+ [9] = "not_napot",
+ [12] = "not_mask_low",
+ [13] = "not_mask_high"
+};
+static riscv_debug_reg_field_list_t csr_mcontrol_get_dmode(riscv_debug_reg_ctx_t context)
+{
+ assert(context.XLEN.is_set);
+ riscv_debug_reg_field_list_t result = {
+ .field = {
+ .name = "dmode",
+ .lsb = (context.XLEN.value + -5),
+ .msb = (context.XLEN.value + -5),
+ .values = NULL
+ },
+ .get_next = NULL
+ };
+ return result;
+}
+
+static riscv_debug_reg_field_list_t csr_mcontrol_get_type(riscv_debug_reg_ctx_t context)
+{
+ assert(context.XLEN.is_set);
+ riscv_debug_reg_field_list_t result = {
+ .field = {
+ .name = "type",
+ .lsb = (context.XLEN.value + -4),
+ .msb = (context.XLEN.value + -1),
+ .values = NULL
+ },
+ .get_next = csr_mcontrol_get_dmode
+ };
+ return result;
+}
+
+static riscv_debug_reg_field_list_t csr_mcontrol_get_maskmax(riscv_debug_reg_ctx_t context)
+{
+ assert(context.XLEN.is_set);
+ riscv_debug_reg_field_list_t result = {
+ .field = {
+ .name = "maskmax",
+ .lsb = (context.XLEN.value + -0xb),
+ .msb = (context.XLEN.value + -6),
+ .values = NULL
+ },
+ .get_next = csr_mcontrol_get_type
+ };
+ return result;
+}
+
+static riscv_debug_reg_field_list_t csr_mcontrol_get_match(riscv_debug_reg_ctx_t context)
+{
+ riscv_debug_reg_field_list_t result = {
+ .field = {
+ .name = "match",
+ .lsb = 7,
+ .msb = 0xa,
+ .values = csr_mcontrol_match_values
+ },
+ .get_next = csr_mcontrol_get_maskmax
+ };
+ return result;
+}
+
+static riscv_debug_reg_field_list_t csr_mcontrol_get_m(riscv_debug_reg_ctx_t context)
+{
+ riscv_debug_reg_field_list_t result = {
+ .field = {
+ .name = "m",
+ .lsb = 6,
+ .msb = 6,
+ .values = NULL
+ },
+ .get_next = csr_mcontrol_get_match
+ };
+ return result;
+}
+
+static riscv_debug_reg_field_list_t csr_mcontrol_get_s(riscv_debug_reg_ctx_t context)
+{
+ riscv_debug_reg_field_list_t result = {
+ .field = {
+ .name = "s",
+ .lsb = 4,
+ .msb = 4,
+ .values = NULL
+ },
+ .get_next = csr_mcontrol_get_m
+ };
+ return result;
+}
+
+static riscv_debug_reg_field_list_t csr_mcontrol_get_u(riscv_debug_reg_ctx_t context)
+{
+ riscv_debug_reg_field_list_t result = {
+ .field = {
+ .name = "u",
+ .lsb = 3,
+ .msb = 3,
+ .values = NULL
+ },
+ .get_next = csr_mcontrol_get_s
+ };
+ return result;
+}
+
+static riscv_debug_reg_field_list_t csr_mcontrol_get_sizehi(riscv_debug_reg_ctx_t context)
+{
+ riscv_debug_reg_field_list_t result = {
+ .field = {
+ .name = "sizehi",
+ .lsb = 0x15,
+ .msb = 0x16,
+ .values = NULL
+ },
+ .get_next = csr_mcontrol_get_u
+ };
+ return result;
+}
+
+static riscv_debug_reg_field_list_t csr_mcontrol_get_hit(riscv_debug_reg_ctx_t context)
+{
+ riscv_debug_reg_field_list_t result = {
+ .field = {
+ .name = "hit",
+ .lsb = 0x14,
+ .msb = 0x14,
+ .values = NULL
+ },
+ .get_next = csr_mcontrol_get_sizehi
+ };
+ return result;
+}
+
+static riscv_debug_reg_field_list_t csr_mcontrol_get_execute(riscv_debug_reg_ctx_t context)
+{
+ riscv_debug_reg_field_list_t result = {
+ .field = {
+ .name = "execute",
+ .lsb = 2,
+ .msb = 2,
+ .values = NULL
+ },
+ .get_next = csr_mcontrol_get_hit
+ };
+ return result;
+}
+
+static riscv_debug_reg_field_list_t csr_mcontrol_get_select(riscv_debug_reg_ctx_t context)
+{
+ riscv_debug_reg_field_list_t result = {
+ .field = {
+ .name = "select",
+ .lsb = 0x13,
+ .msb = 0x13,
+ .values = csr_mcontrol_select_values
+ },
+ .get_next = csr_mcontrol_get_execute
+ };
+ return result;
+}
+
+static riscv_debug_reg_field_list_t csr_mcontrol_get_timing(riscv_debug_reg_ctx_t context)
+{
+ riscv_debug_reg_field_list_t result = {
+ .field = {
+ .name = "timing",
+ .lsb = 0x12,
+ .msb = 0x12,
+ .values = csr_mcontrol_timing_values
+ },
+ .get_next = csr_mcontrol_get_select
+ };
+ return result;
+}
+
+static riscv_debug_reg_field_list_t csr_mcontrol_get_sizelo(riscv_debug_reg_ctx_t context)
+{
+ riscv_debug_reg_field_list_t result = {
+ .field = {
+ .name = "sizelo",
+ .lsb = 0x10,
+ .msb = 0x11,
+ .values = csr_mcontrol_sizelo_values
+ },
+ .get_next = csr_mcontrol_get_timing
+ };
+ return result;
+}
+
+static riscv_debug_reg_field_list_t csr_mcontrol_get_action(riscv_debug_reg_ctx_t context)
+{
+ riscv_debug_reg_field_list_t result = {
+ .field = {
+ .name = "action",
+ .lsb = 0xc,
+ .msb = 0xf,
+ .values = csr_mcontrol_action_values
+ },
+ .get_next = csr_mcontrol_get_sizelo
+ };
+ return result;
+}
+
+static riscv_debug_reg_field_list_t csr_mcontrol_get_chain(riscv_debug_reg_ctx_t context)
+{
+ riscv_debug_reg_field_list_t result = {
+ .field = {
+ .name = "chain",
+ .lsb = 0xb,
+ .msb = 0xb,
+ .values = csr_mcontrol_chain_values
+ },
+ .get_next = csr_mcontrol_get_action
+ };
+ return result;
+}
+
+static riscv_debug_reg_field_list_t csr_mcontrol_get_store(riscv_debug_reg_ctx_t context)
+{
+ riscv_debug_reg_field_list_t result = {
+ .field = {
+ .name = "store",
+ .lsb = 1,
+ .msb = 1,
+ .values = NULL
+ },
+ .get_next = csr_mcontrol_get_chain
+ };
+ return result;
+}
+
+static riscv_debug_reg_field_list_t csr_mcontrol_get_load(riscv_debug_reg_ctx_t context)
+{
+ riscv_debug_reg_field_list_t result = {
+ .field = {
+ .name = "load",
+ .lsb = 0,
+ .msb = 0,
+ .values = NULL
+ },
+ .get_next = csr_mcontrol_get_store
+ };
+ return result;
+}
+
+static const char *csr_mcontrol6_uncertain_values[2] = {
+ [0] = "certain",
+ [1] = "uncertain"
+};
+static const char *csr_mcontrol6_hit0_values[2] = {};
+static const char *csr_mcontrol6_select_values[2] = {
+ [0] = "address",
+ [1] = "data"
+};
+static const char *csr_mcontrol6_size_values[8] = {
+ [0] = "any",
+ [1] = "8bit",
+ [2] = "16bit",
+ [3] = "32bit",
+ [4] = "48bit",
+ [5] = "64bit",
+ [6] = "128bit"
+};
+static const char *csr_mcontrol6_action_values[16] = {
+ [0] = "breakpoint",
+ [1] = "debug_mode",
+ [2] = "trace_on",
+ [3] = "trace_off",
+ [4] = "trace_notify",
+ [8] = "external0",
+ [9] = "external1"
+};
+static const char *csr_mcontrol6_chain_values[2] = {
+ [0] = "disabled",
+ [1] = "enabled"
+};
+static const char *csr_mcontrol6_match_values[16] = {
+ [0] = "equal",
+ [1] = "napot",
+ [2] = "ge",
+ [3] = "lt",
+ [4] = "mask_low",
+ [5] = "mask_high",
+ [8] = "not_equal",
+ [9] = "not_napot",
+ [12] = "not_mask_low",
+ [13] = "not_mask_high"
+};
+static const char *csr_mcontrol6_uncertainen_values[2] = {
+ [0] = "disabled",
+ [1] = "enabled"
+};
+static riscv_debug_reg_field_list_t csr_mcontrol6_get_dmode(riscv_debug_reg_ctx_t context)
+{
+ assert(context.XLEN.is_set);
+ riscv_debug_reg_field_list_t result = {
+ .field = {
+ .name = "dmode",
+ .lsb = (context.XLEN.value + -5),
+ .msb = (context.XLEN.value + -5),
+ .values = NULL
+ },
+ .get_next = NULL
+ };
+ return result;
+}
+
+static riscv_debug_reg_field_list_t csr_mcontrol6_get_type(riscv_debug_reg_ctx_t context)
+{
+ assert(context.XLEN.is_set);
+ riscv_debug_reg_field_list_t result = {
+ .field = {
+ .name = "type",
+ .lsb = (context.XLEN.value + -4),
+ .msb = (context.XLEN.value + -1),
+ .values = NULL
+ },
+ .get_next = csr_mcontrol6_get_dmode
+ };
+ return result;
+}
+
+static riscv_debug_reg_field_list_t csr_mcontrol6_get_match(riscv_debug_reg_ctx_t context)
+{
+ riscv_debug_reg_field_list_t result = {
+ .field = {...
[truncated message content] |