aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/openocd.texi78
-rw-r--r--src/helper/log.h2
-rw-r--r--src/target/Makefile.am5
-rw-r--r--src/target/riscv/Makefile.am16
-rw-r--r--src/target/riscv/asm.h38
-rw-r--r--src/target/riscv/batch.c172
-rw-r--r--src/target/riscv/batch.h64
-rw-r--r--src/target/riscv/debug_defines.h1414
-rw-r--r--src/target/riscv/encoding.h1473
-rw-r--r--src/target/riscv/gdb_regs.h93
-rw-r--r--src/target/riscv/opcodes.h310
-rw-r--r--src/target/riscv/program.c162
-rw-r--r--src/target/riscv/program.h75
-rw-r--r--src/target/riscv/riscv-011.c2328
-rw-r--r--src/target/riscv/riscv-013.c3036
-rw-r--r--src/target/riscv/riscv.c2512
-rw-r--r--src/target/riscv/riscv.h262
-rw-r--r--src/target/riscv/riscv_semihosting.c194
-rw-r--r--src/target/target.c2
-rw-r--r--tcl/board/sifive-e31arty.cfg22
-rw-r--r--tcl/board/sifive-e51arty.cfg22
-rw-r--r--tcl/board/sifive-hifive1.cfg34
22 files changed, 12313 insertions, 1 deletions
diff --git a/doc/openocd.texi b/doc/openocd.texi
index 15cf7426..43ebf8cb 100644
--- a/doc/openocd.texi
+++ b/doc/openocd.texi
@@ -8946,6 +8946,84 @@ Display all registers in @emph{group}.
"timer" or any new group created with addreg command.
@end deffn
+@section RISC-V Architecture
+
+@uref{http://riscv.org/, RISC-V} is a free and open ISA. OpenOCD supports JTAG
+debug of targets that implement version 0.11 and 0.13 of the RISC-V Debug
+Specification.
+
+@subsection RISC-V Terminology
+
+A @emph{hart} is a hardware thread. A hart may share resources (eg. FPU) with
+another hart, or may be a separate core. RISC-V treats those the same, and
+OpenOCD exposes each hart as a separate core.
+
+@subsection RISC-V Debug Configuration Commands
+
+@deffn Command {riscv expose_csrs} n0[-m0][,n1[-m1]]...
+Configure a list of inclusive ranges for CSRs to expose in addition to the
+standard ones. This must be executed before `init`.
+
+By default OpenOCD attempts to expose only CSRs that are mentioned in a spec,
+and then only if the corresponding extension appears to be implemented. This
+command can be used if OpenOCD gets this wrong, or a target implements custom
+CSRs.
+@end deffn
+
+@deffn Command {riscv set_command_timeout_sec} [seconds]
+Set the wall-clock timeout (in seconds) for individual commands. The default
+should work fine for all but the slowest targets (eg. simulators).
+@end deffn
+
+@deffn Command {riscv set_reset_timeout_sec} [seconds]
+Set the maximum time to wait for a hart to come out of reset after reset is
+deasserted.
+@end deffn
+
+@deffn Command {riscv set_scratch_ram} none|[address]
+Set the address of 16 bytes of scratch RAM the debugger can use, or 'none'.
+This is used to access 64-bit floating point registers on 32-bit targets.
+@end deffn
+
+@deffn Command {riscv set_prefer_sba} on|off
+When on, prefer to use System Bus Access to access memory. When off, prefer to
+use the Program Buffer to access memory.
+@end deffn
+
+@subsection RISC-V Authentication Commands
+
+The following commands can be used to authenticate to a RISC-V system. Eg. a
+trivial challenge-response protocol could be implemented as follows in a
+configuration file, immediately following @command{init}:
+@example
+set challenge [ocd_riscv authdata_read]
+riscv authdata_write [expr $challenge + 1]
+@end example
+
+@deffn Command {riscv authdata_read}
+Return the 32-bit value read from authdata. Note that to get read value back in
+a TCL script, it needs to be invoked as @command{ocd_riscv authdata_read}.
+@end deffn
+
+@deffn Command {riscv authdata_write} value
+Write the 32-bit value to authdata.
+@end deffn
+
+@subsection RISC-V DMI Commands
+
+The following commands allow direct access to the Debug Module Interface, which
+can be used to interact with custom debug features.
+
+@deffn Command {riscv dmi_read}
+Perform a 32-bit DMI read at address, returning the value. Note that to get
+read value back in a TCL script, it needs to be invoked as @command{ocd_riscv
+dmi_read}.
+@end deffn
+
+@deffn Command {riscv dmi_write} address value
+Perform a 32-bit DMI write of value at address.
+@end deffn
+
@anchor{softwaredebugmessagesandtracing}
@section Software Debug Messages and Tracing
@cindex Linux-ARM DCC support
diff --git a/src/helper/log.h b/src/helper/log.h
index 512bcc51..d60587f7 100644
--- a/src/helper/log.h
+++ b/src/helper/log.h
@@ -149,6 +149,8 @@ extern int debug_level;
*/
#define ERROR_FAIL (-4)
#define ERROR_WAIT (-5)
+/* ERROR_TIMEOUT is already taken by winerror.h. */
+#define ERROR_TIMEOUT_REACHED (-6)
#endif /* OPENOCD_HELPER_LOG_H */
diff --git a/src/target/Makefile.am b/src/target/Makefile.am
index fcc23adb..b1119e7d 100644
--- a/src/target/Makefile.am
+++ b/src/target/Makefile.am
@@ -4,7 +4,9 @@ else
OOCD_TRACE_FILES =
endif
-%C%_libtarget_la_LIBADD = %D%/openrisc/libopenrisc.la
+%C%_libtarget_la_LIBADD = %D%/openrisc/libopenrisc.la \
+ %D%/riscv/libriscv.la
+
STARTUP_TCL_SRCS += %D%/startup.tcl
@@ -218,3 +220,4 @@ INTEL_IA32_SRC = \
%D%/arm_cti.h
include %D%/openrisc/Makefile.am
+include %D%/riscv/Makefile.am
diff --git a/src/target/riscv/Makefile.am b/src/target/riscv/Makefile.am
new file mode 100644
index 00000000..83f1a8ca
--- /dev/null
+++ b/src/target/riscv/Makefile.am
@@ -0,0 +1,16 @@
+noinst_LTLIBRARIES += %D%/libriscv.la
+%C%_libriscv_la_SOURCES = \
+ %D%/asm.h \
+ %D%/batch.h \
+ %D%/debug_defines.h \
+ %D%/encoding.h \
+ %D%/gdb_regs.h \
+ %D%/opcodes.h \
+ %D%/program.h \
+ %D%/riscv.h \
+ %D%/batch.c \
+ %D%/program.c \
+ %D%/riscv-011.c \
+ %D%/riscv-013.c \
+ %D%/riscv.c \
+ %D%/riscv_semihosting.c
diff --git a/src/target/riscv/asm.h b/src/target/riscv/asm.h
new file mode 100644
index 00000000..d81aa028
--- /dev/null
+++ b/src/target/riscv/asm.h
@@ -0,0 +1,38 @@
+#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
new file mode 100644
index 00000000..9327cb38
--- /dev/null
+++ b/src/target/riscv/batch.c
@@ -0,0 +1,172 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "batch.h"
+#include "debug_defines.h"
+#include "riscv.h"
+
+#define get_field(reg, mask) (((reg) & (mask)) / ((mask) & ~((mask) << 1)))
+#define set_field(reg, mask, val) (((reg) & ~(mask)) | (((val) * ((mask) & ~((mask) << 1))) & (mask)))
+
+static void dump_field(const struct scan_field *field);
+
+struct riscv_batch *riscv_batch_alloc(struct target *target, size_t scans, size_t idle)
+{
+ scans += 4;
+ struct riscv_batch *out = malloc(sizeof(*out));
+ memset(out, 0, sizeof(*out));
+ out->target = target;
+ out->allocated_scans = scans;
+ out->used_scans = 0;
+ out->idle_count = idle;
+ out->data_out = malloc(sizeof(*out->data_out) * (scans) * sizeof(uint64_t));
+ out->data_in = malloc(sizeof(*out->data_in) * (scans) * sizeof(uint64_t));
+ out->fields = malloc(sizeof(*out->fields) * (scans));
+ out->last_scan = RISCV_SCAN_TYPE_INVALID;
+ out->read_keys = malloc(sizeof(*out->read_keys) * (scans));
+ out->read_keys_used = 0;
+ return out;
+}
+
+void riscv_batch_free(struct riscv_batch *batch)
+{
+ free(batch->data_in);
+ free(batch->data_out);
+ free(batch->fields);
+ free(batch);
+}
+
+bool riscv_batch_full(struct riscv_batch *batch)
+{
+ return batch->used_scans > (batch->allocated_scans - 4);
+}
+
+int riscv_batch_run(struct riscv_batch *batch)
+{
+ if (batch->used_scans == 0) {
+ LOG_DEBUG("Ignoring empty batch.");
+ return ERROR_OK;
+ }
+
+ keep_alive();
+
+ LOG_DEBUG("running a batch of %ld scans", (long)batch->used_scans);
+ riscv_batch_add_nop(batch);
+
+ for (size_t i = 0; i < batch->used_scans; ++i) {
+ 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);
+ }
+
+ LOG_DEBUG("executing queue");
+ if (jtag_execute_queue() != ERROR_OK) {
+ LOG_ERROR("Unable to execute JTAG queue");
+ return ERROR_FAIL;
+ }
+
+ for (size_t i = 0; i < batch->used_scans; ++i)
+ dump_field(batch->fields + i);
+
+ return ERROR_OK;
+}
+
+void riscv_batch_add_dmi_write(struct riscv_batch *batch, unsigned address, uint64_t data)
+{
+ 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 * sizeof(uint64_t));
+ field->in_value = (void *)(batch->data_in + batch->used_scans * sizeof(uint64_t));
+ riscv_fill_dmi_write_u64(batch->target, (char *)field->out_value, address, data);
+ riscv_fill_dmi_nop_u64(batch->target, (char *)field->in_value);
+ batch->last_scan = RISCV_SCAN_TYPE_WRITE;
+ batch->used_scans++;
+}
+
+size_t riscv_batch_add_dmi_read(struct riscv_batch *batch, unsigned address)
+{
+ 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 * sizeof(uint64_t));
+ field->in_value = (void *)(batch->data_in + batch->used_scans * sizeof(uint64_t));
+ riscv_fill_dmi_read_u64(batch->target, (char *)field->out_value, address);
+ riscv_fill_dmi_nop_u64(batch->target, (char *)field->in_value);
+ batch->last_scan = RISCV_SCAN_TYPE_READ;
+ batch->used_scans++;
+
+ /* FIXME We get the read response back on the next scan. For now I'm
+ * just sticking a NOP in there, but this should be coelesced away. */
+ riscv_batch_add_nop(batch);
+
+ batch->read_keys[batch->read_keys_used] = batch->used_scans - 1;
+ LOG_DEBUG("read key %u for batch 0x%p is %u (0x%p)",
+ (unsigned) batch->read_keys_used, batch, (unsigned) (batch->used_scans - 1),
+ batch->data_in + sizeof(uint64_t) * (batch->used_scans + 1));
+ return batch->read_keys_used++;
+}
+
+uint64_t riscv_batch_get_dmi_read(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);
+ uint8_t *base = batch->data_in + 8 * index;
+ return base[0] |
+ ((uint64_t) base[1]) << 8 |
+ ((uint64_t) base[2]) << 16 |
+ ((uint64_t) base[3]) << 24 |
+ ((uint64_t) base[4]) << 32 |
+ ((uint64_t) base[5]) << 40 |
+ ((uint64_t) base[6]) << 48 |
+ ((uint64_t) base[7]) << 56;
+}
+
+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 * sizeof(uint64_t));
+ field->in_value = (void *)(batch->data_in + batch->used_scans * sizeof(uint64_t));
+ riscv_fill_dmi_nop_u64(batch->target, (char *)field->out_value);
+ riscv_fill_dmi_nop_u64(batch->target, (char *)field->in_value);
+ batch->last_scan = RISCV_SCAN_TYPE_NOP;
+ batch->used_scans++;
+ LOG_DEBUG(" added NOP with in_value=0x%p", field->in_value);
+}
+
+void dump_field(const struct scan_field *field)
+{
+ static const char * const op_string[] = {"-", "r", "w", "?"};
+ static const char * const status_string[] = {"+", "?", "F", "b"};
+
+ if (debug_level < LOG_LVL_DEBUG)
+ return;
+
+ assert(field->out_value != NULL);
+ 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__,
+ "%db %s %08x @%02x -> %s %08x @%02x",
+ field->num_bits,
+ op_string[out_op], out_data, out_address,
+ status_string[in_op], in_data, in_address);
+ } else {
+ log_printf_lf(LOG_LVL_DEBUG,
+ __FILE__, __LINE__, __PRETTY_FUNCTION__, "%db %s %08x @%02x -> ?",
+ field->num_bits, op_string[out_op], out_data, out_address);
+ }
+}
diff --git a/src/target/riscv/batch.h b/src/target/riscv/batch.h
new file mode 100644
index 00000000..70690a60
--- /dev/null
+++ b/src/target/riscv/batch.h
@@ -0,0 +1,64 @@
+#ifndef TARGET__RISCV__SCANS_H
+#define TARGET__RISCV__SCANS_H
+
+#include "target/target.h"
+#include "jtag/jtag.h"
+
+enum riscv_scan_type {
+ RISCV_SCAN_TYPE_INVALID,
+ RISCV_SCAN_TYPE_NOP,
+ RISCV_SCAN_TYPE_READ,
+ RISCV_SCAN_TYPE_WRITE,
+};
+
+/* 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
+ * fast. */
+struct riscv_batch {
+ struct target *target;
+
+ size_t allocated_scans;
+ size_t used_scans;
+
+ size_t idle_count;
+
+ uint8_t *data_out;
+ uint8_t *data_in;
+ struct scan_field *fields;
+
+ /* In JTAG we scan out the previous value's output when performing a
+ * scan. This is a pain for users, so we just provide them the
+ * illusion of not having to do this by eliding all but the last NOP.
+ * */
+ enum riscv_scan_type last_scan;
+
+ /* The read keys. */
+ size_t *read_keys;
+ size_t read_keys_used;
+};
+
+/* 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);
+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 address, uint64_t data);
+
+/* DMI reads must be handled in two parts: the first one schedules a read and
+ * provides a key, the second one actually obtains the value of that read .*/
+size_t riscv_batch_add_dmi_read(struct riscv_batch *batch, unsigned address);
+uint64_t riscv_batch_get_dmi_read(struct riscv_batch *batch, size_t key);
+
+/* Scans in a NOP. */
+void riscv_batch_add_nop(struct riscv_batch *batch);
+
+#endif
diff --git a/src/target/riscv/debug_defines.h b/src/target/riscv/debug_defines.h
new file mode 100644
index 00000000..d6ddd4ff
--- /dev/null
+++ b/src/target/riscv/debug_defines.h
@@ -0,0 +1,1414 @@
+#define DTM_IDCODE 0x01
+/*
+* Identifies the release version of this part.
+ */
+#define DTM_IDCODE_VERSION_OFFSET 28
+#define DTM_IDCODE_VERSION_LENGTH 4
+#define DTM_IDCODE_VERSION (0xfU << DTM_IDCODE_VERSION_OFFSET)
+/*
+* Identifies the designer's part number of this part.
+ */
+#define DTM_IDCODE_PARTNUMBER_OFFSET 12
+#define DTM_IDCODE_PARTNUMBER_LENGTH 16
+#define DTM_IDCODE_PARTNUMBER (0xffffU << DTM_IDCODE_PARTNUMBER_OFFSET)
+/*
+* Identifies the designer/manufacturer of this part. Bits 6:0 must be
+* bits 6:0 of the designer/manufacturer's Identification Code as
+* assigned by JEDEC Standard JEP106. Bits 10:7 contain the modulo-16
+* count of the number of continuation characters (0x7f) in that same
+* Identification Code.
+ */
+#define DTM_IDCODE_MANUFID_OFFSET 1
+#define DTM_IDCODE_MANUFID_LENGTH 11
+#define DTM_IDCODE_MANUFID (0x7ffU << DTM_IDCODE_MANUFID_OFFSET)
+#define DTM_IDCODE_1_OFFSET 0
+#define DTM_IDCODE_1_LENGTH 1
+#define DTM_IDCODE_1 (0x1U << DTM_IDCODE_1_OFFSET)
+#define DTM_DTMCS 0x10
+/*
+* Writing 1 to this bit does a hard reset of the DTM,
+* causing the DTM to forget about any outstanding DMI transactions.
+* In general this should only be used when the Debugger has
+* reason to expect that the outstanding DMI transaction will never
+* complete (e.g. a reset condition caused an inflight DMI transaction to
+* be cancelled).
+ */
+#define DTM_DTMCS_DMIHARDRESET_OFFSET 17
+#define DTM_DTMCS_DMIHARDRESET_LENGTH 1
+#define DTM_DTMCS_DMIHARDRESET (0x1U << DTM_DTMCS_DMIHARDRESET_OFFSET)
+/*
+* Writing 1 to this bit clears the sticky error state
+* and allows the DTM to retry or complete the previous
+* transaction.
+ */
+#define DTM_DTMCS_DMIRESET_OFFSET 16
+#define DTM_DTMCS_DMIRESET_LENGTH 1
+#define DTM_DTMCS_DMIRESET (0x1U << DTM_DTMCS_DMIRESET_OFFSET)
+/*
+* This is a hint to the debugger of the minimum number of
+* cycles a debugger should spend in
+* Run-Test/Idle after every DMI scan to avoid a `busy'
+* return code (\Fdmistat of 3). A debugger must still
+* check \Fdmistat when necessary.
+*
+* 0: It is not necessary to enter Run-Test/Idle at all.
+*
+* 1: Enter Run-Test/Idle and leave it immediately.
+*
+* 2: Enter Run-Test/Idle and stay there for 1 cycle before leaving.
+*
+* And so on.
+ */
+#define DTM_DTMCS_IDLE_OFFSET 12
+#define DTM_DTMCS_IDLE_LENGTH 3
+#define DTM_DTMCS_IDLE (0x7U << DTM_DTMCS_IDLE_OFFSET)
+/*
+* 0: No error.
+*
+* 1: Reserved. Interpret the same as 2.
+*
+* 2: An operation failed (resulted in \Fop of 2).
+*
+* 3: An operation was attempted while a DMI access was still in
+* progress (resulted in \Fop of 3).
+ */
+#define DTM_DTMCS_DMISTAT_OFFSET 10
+#define DTM_DTMCS_DMISTAT_LENGTH 2
+#define DTM_DTMCS_DMISTAT (0x3U << DTM_DTMCS_DMISTAT_OFFSET)
+/*
+* The size of \Faddress in \Rdmi.
+ */
+#define DTM_DTMCS_ABITS_OFFSET 4
+#define DTM_DTMCS_ABITS_LENGTH 6
+#define DTM_DTMCS_ABITS (0x3fU << DTM_DTMCS_ABITS_OFFSET)
+/*
+* 0: Version described in spec version 0.11.
+*
+* 1: Version described in spec version 0.13 (and later?), which
+* reduces the DMI data width to 32 bits.
+*
+* 15: Version not described in any available version of this spec.
+ */
+#define DTM_DTMCS_VERSION_OFFSET 0
+#define DTM_DTMCS_VERSION_LENGTH 4
+#define DTM_DTMCS_VERSION (0xfU << DTM_DTMCS_VERSION_OFFSET)
+#define DTM_DMI 0x11
+/*
+* Address used for DMI access. In Update-DR this value is used
+* to access the DM over the DMI.
+ */
+#define DTM_DMI_ADDRESS_OFFSET 34
+#define DTM_DMI_ADDRESS_LENGTH abits
+#define DTM_DMI_ADDRESS (((1L<<abits)-1) << DTM_DMI_ADDRESS_OFFSET)
+/*
+* The data to send to the DM over the DMI during Update-DR, and
+* the data returned from the DM as a result of the previous operation.
+ */
+#define DTM_DMI_DATA_OFFSET 2
+#define DTM_DMI_DATA_LENGTH 32
+#define DTM_DMI_DATA (0xffffffffULL << DTM_DMI_DATA_OFFSET)
+/*
+* When the debugger writes this field, it has the following meaning:
+*
+* 0: Ignore \Fdata and \Faddress. (nop)
+*
+* Don't send anything over the DMI during Update-DR.
+* This operation should never result in a busy or error response.
+* The address and data reported in the following Capture-DR
+* are undefined.
+*
+* 1: Read from \Faddress. (read)
+*
+* 2: Write \Fdata to \Faddress. (write)
+*
+* 3: Reserved.
+*
+* When the debugger reads this field, it means the following:
+*
+* 0: The previous operation completed successfully.
+*
+* 1: Reserved.
+*
+* 2: A previous operation failed. The data scanned into \Rdmi in
+* this access will be ignored. This status is sticky and can be
+* cleared by writing \Fdmireset in \Rdtmcs.
+*
+* This indicates that the DM itself responded with an error.
+* Note: there are no specified cases in which the DM would
+* respond with an error, and DMI is not required to support
+* returning errors.
+*
+* 3: An operation was attempted while a DMI request is still in
+* progress. The data scanned into \Rdmi in this access will be
+* ignored. This status is sticky and can be cleared by writing
+* \Fdmireset in \Rdtmcs. If a debugger sees this status, it
+* needs to give the target more TCK edges between Update-DR and
+* Capture-DR. The simplest way to do that is to add extra transitions
+* in Run-Test/Idle.
+*
+* (The DTM, DM, and/or component may be in different clock domains,
+* so synchronization may be required. Some relatively fixed number of
+* TCK ticks may be needed for the request to reach the DM, complete,
+* and for the response to be synchronized back into the TCK domain.)
+ */
+#define DTM_DMI_OP_OFFSET 0
+#define DTM_DMI_OP_LENGTH 2
+#define DTM_DMI_OP (0x3ULL << DTM_DMI_OP_OFFSET)
+#define CSR_DCSR 0x7b0
+/*
+* 0: There is no external debug support.
+*
+* 4: External debug support exists as it is described in this document.
+*
+* 15: There is external debug support, but it does not conform to any
+* available version of this spec.
+ */
+#define CSR_DCSR_XDEBUGVER_OFFSET 28
+#define CSR_DCSR_XDEBUGVER_LENGTH 4
+#define CSR_DCSR_XDEBUGVER (0xfU << CSR_DCSR_XDEBUGVER_OFFSET)
+/*
+* When 1, {\tt ebreak} instructions in Machine Mode enter Debug Mode.
+ */
+#define CSR_DCSR_EBREAKM_OFFSET 15
+#define CSR_DCSR_EBREAKM_LENGTH 1
+#define CSR_DCSR_EBREAKM (0x1U << CSR_DCSR_EBREAKM_OFFSET)
+/*
+* When 1, {\tt ebreak} instructions in Supervisor Mode enter Debug Mode.
+ */
+#define CSR_DCSR_EBREAKS_OFFSET 13
+#define CSR_DCSR_EBREAKS_LENGTH 1
+#define CSR_DCSR_EBREAKS (0x1U << CSR_DCSR_EBREAKS_OFFSET)
+/*
+* When 1, {\tt ebreak} instructions in User/Application Mode enter
+* Debug Mode.
+ */
+#define CSR_DCSR_EBREAKU_OFFSET 12
+#define CSR_DCSR_EBREAKU_LENGTH 1
+#define CSR_DCSR_EBREAKU (0x1U << CSR_DCSR_EBREAKU_OFFSET)
+/*
+* 0: Interrupts are disabled during single stepping.
+*
+* 1: Interrupts are enabled during single stepping.
+*
+* Implementations may hard wire this bit to 0.
+* The debugger must read back the value it
+* writes to check whether the feature is supported. If not
+* supported, interrupt behavior can be emulated by the debugger.
+ */
+#define CSR_DCSR_STEPIE_OFFSET 11
+#define CSR_DCSR_STEPIE_LENGTH 1
+#define CSR_DCSR_STEPIE (0x1U << CSR_DCSR_STEPIE_OFFSET)
+/*
+* 0: Increment counters as usual.
+*
+* 1: Don't increment any counters while in Debug Mode or on {\tt
+* ebreak} instructions that cause entry into Debug Mode. These
+* counters include the {\tt cycle} and {\tt instret} CSRs. This is
+* preferred for most debugging scenarios.
+*
+* An implementation may choose not to support writing to this bit.
+* The debugger must read back the value it writes to check whether
+* the feature is supported.
+ */
+#define CSR_DCSR_STOPCOUNT_OFFSET 10
+#define CSR_DCSR_STOPCOUNT_LENGTH 1
+#define CSR_DCSR_STOPCOUNT (0x1U << CSR_DCSR_STOPCOUNT_OFFSET)
+/*
+* 0: Increment timers as usual.
+*
+* 1: Don't increment any hart-local timers while in Debug Mode.
+*
+* An implementation may choose not to support writing to this bit.
+* The debugger must read back the value it writes to check whether
+* the feature is supported.
+ */
+#define CSR_DCSR_STOPTIME_OFFSET 9
+#define CSR_DCSR_STOPTIME_LENGTH 1
+#define CSR_DCSR_STOPTIME (0x1U << CSR_DCSR_STOPTIME_OFFSET)
+/*
+* Explains why Debug Mode was entered.
+*
+* When there are multiple reasons to enter Debug Mode in a single
+* cycle, hardware should set \Fcause to the cause with the highest
+* priority.
+*
+* 1: An {\tt ebreak} instruction was executed. (priority 3)
+*
+* 2: The Trigger Module caused a breakpoint exception. (priority 4)
+*
+* 3: The debugger requested entry to Debug Mode. (priority 2)
+*
+* 4: The hart single stepped because \Fstep was set. (priority 1)
+*
+* Other values are reserved for future use.
+ */
+#define CSR_DCSR_CAUSE_OFFSET 6
+#define CSR_DCSR_CAUSE_LENGTH 3
+#define CSR_DCSR_CAUSE (0x7U << CSR_DCSR_CAUSE_OFFSET)
+/*
+* When 1, \Fmprv in \Rmstatus takes effect during debug mode.
+* When 0, it is ignored during debug mode.
+* Implementing this bit is optional.
+* If not implemented it should be tied to 0.
+ */
+#define CSR_DCSR_MPRVEN_OFFSET 4
+#define CSR_DCSR_MPRVEN_LENGTH 1
+#define CSR_DCSR_MPRVEN (0x1U << CSR_DCSR_MPRVEN_OFFSET)
+/*
+* When set, there is a Non-Maskable-Interrupt (NMI) pending for the hart.
+*
+* Since an NMI can indicate a hardware error condition,
+* reliable debugging may no longer be possible once this bit becomes set.
+* This is implementation-dependent.
+ */
+#define CSR_DCSR_NMIP_OFFSET 3
+#define CSR_DCSR_NMIP_LENGTH 1
+#define CSR_DCSR_NMIP (0x1U << CSR_DCSR_NMIP_OFFSET)
+/*
+* When set and not in Debug Mode, the hart will only execute a single
+* instruction and then enter Debug Mode.
+* If the instruction does not complete due to an exception,
+* the hart will immediately enter Debug Mode before executing
+* the trap handler, with appropriate exception registers set.
+ */
+#define CSR_DCSR_STEP_OFFSET 2
+#define CSR_DCSR_STEP_LENGTH 1
+#define CSR_DCSR_STEP (0x1U << CSR_DCSR_STEP_OFFSET)
+/*
+* Contains the privilege level the hart was operating in when Debug
+* Mode was entered. The encoding is described in Table
+* \ref{tab:privlevel}. A debugger can change this value to change
+* the hart's privilege level when exiting Debug Mode.
+*
+* Not all privilege levels are supported on all harts. If the
+* encoding written is not supported or the debugger is not allowed to
+* change to it, the hart may change to any supported privilege level.
+ */
+#define CSR_DCSR_PRV_OFFSET 0
+#define CSR_DCSR_PRV_LENGTH 2
+#define CSR_DCSR_PRV (0x3U << CSR_DCSR_PRV_OFFSET)
+#define CSR_DPC 0x7b1
+#define CSR_DPC_DPC_OFFSET 0
+#define CSR_DPC_DPC_LENGTH MXLEN
+#define CSR_DPC_DPC (((1L<<MXLEN)-1) << CSR_DPC_DPC_OFFSET)
+#define CSR_DSCRATCH0 0x7b2
+#define CSR_DSCRATCH1 0x7b3
+#define CSR_TSELECT 0x7a0
+#define CSR_TSELECT_INDEX_OFFSET 0
+#define CSR_TSELECT_INDEX_LENGTH MXLEN
+#define CSR_TSELECT_INDEX (((1L<<MXLEN)-1) << CSR_TSELECT_INDEX_OFFSET)
+#define CSR_TDATA1 0x7a1
+/*
+* 0: There is no trigger at this \Rtselect.
+*
+* 1: The trigger is a legacy SiFive address match trigger. These
+* should not be implemented and aren't further documented here.
+*
+* 2: The trigger is an address/data match trigger. The remaining bits
+* in this register act as described in \Rmcontrol.
+*
+* 3: The trigger is an instruction count trigger. The remaining bits
+* in this register act as described in \Ricount.
+*
+* 4: The trigger is an interrupt trigger. The remaining bits
+* in this register act as described in \Ritrigger.
+*
+* 5: The trigger is an exception trigger. The remaining bits
+* in this register act as described in \Retrigger.
+*
+* 15: This trigger exists (so enumeration shouldn't terminate), but
+* is not currently available.
+*
+* Other values are reserved for future use.
+*
+* When this field is written to an unsupported value, it takes on its
+* reset value instead. The reset value is any one of the types
+* supported by the trigger selected by \Rtselect.
+ */
+#define CSR_TDATA1_TYPE_OFFSET (MXLEN-4)
+#define CSR_TDATA1_TYPE_LENGTH 4
+#define CSR_TDATA1_TYPE (0xfULL << CSR_TDATA1_TYPE_OFFSET)
+/*
+* 0: Both Debug and M Mode can write the {\tt tdata} registers at the
+* selected \Rtselect.
+*
+* 1: Only Debug Mode can write the {\tt tdata} registers at the
+* selected \Rtselect. Writes from other modes are ignored.
+*
+* This bit is only writable from Debug Mode.
+ */
+#define CSR_TDATA1_DMODE_OFFSET (MXLEN-5)
+#define CSR_TDATA1_DMODE_LENGTH 1
+#define CSR_TDATA1_DMODE (0x1ULL << CSR_TDATA1_DMODE_OFFSET)
+/*
+* Trigger-specific data.
+ */
+#define CSR_TDATA1_DATA_OFFSET 0
+#define CSR_TDATA1_DATA_LENGTH (MXLEN - 5)
+#define CSR_TDATA1_DATA (((1L<<MXLEN - 5)-1) << CSR_TDATA1_DATA_OFFSET)
+#define CSR_TDATA2 0x7a2
+#define CSR_TDATA2_DATA_OFFSET 0
+#define CSR_TDATA2_DATA_LENGTH MXLEN
+#define CSR_TDATA2_DATA (((1L<<MXLEN)-1) << CSR_TDATA2_DATA_OFFSET)
+#define CSR_TDATA3 0x7a3
+#define CSR_TDATA3_DATA_OFFSET 0
+#define CSR_TDATA3_DATA_LENGTH MXLEN
+#define CSR_TDATA3_DATA (((1L<<MXLEN)-1) << CSR_TDATA3_DATA_OFFSET)
+#define CSR_TINFO 0x7a4
+/*
+* One bit for each possible \Ftype enumerated in \Rtdataone. Bit N
+* corresponds to type N. If the bit is set, then that type is
+* supported by the currently selected trigger.
+*
+* If the currently selected trigger doesn't exist, this field
+* contains 1.
+*
+* If \Ftype is not writable, this register may be unimplemented, in
+* which case reading it causes an illegal instruction exception. In
+* this case the debugger can read the only supported type from
+* \Rtdataone.
+ */
+#define CSR_TINFO_INFO_OFFSET 0
+#define CSR_TINFO_INFO_LENGTH 16
+#define CSR_TINFO_INFO (0xffffULL << CSR_TINFO_INFO_OFFSET)
+#define CSR_MCONTROL 0x7a1
+#define CSR_MCONTROL_TYPE_OFFSET (MXLEN-4)
+#define CSR_MCONTROL_TYPE_LENGTH 4
+#define CSR_MCONTROL_TYPE (0xfULL << CSR_MCONTROL_TYPE_OFFSET)
+#define CSR_MCONTROL_DMODE_OFFSET (MXLEN-5)
+#define CSR_MCONTROL_DMODE_LENGTH 1
+#define CSR_MCONTROL_DMODE (0x1ULL << CSR_MCONTROL_DMODE_OFFSET)
+/*
+* Specifies the largest naturally aligned powers-of-two (NAPOT) range
+* supported by the hardware when \Fmatch is 1. The value is the
+* logarithm base 2 of the
+* number of bytes in that range. A value of 0 indicates that only
+* exact value matches are supported (one byte range). A value of 63
+* corresponds to the maximum NAPOT range, which is $2^{63}$ bytes in
+* size.
+ */
+#define CSR_MCONTROL_MASKMAX_OFFSET (MXLEN-11)
+#define CSR_MCONTROL_MASKMAX_LENGTH 6
+#define CSR_MCONTROL_MASKMAX (0x3fULL << CSR_MCONTROL_MASKMAX_OFFSET)
+/*
+* If this optional bit is implemented, the hardware sets it when this
+* trigger matches. The trigger's user can set or clear it at any
+* time. The trigger's user can use this bit to determine which
+* trigger(s) matched. If the bit is not implemented, it is always 0
+* and writing it has no effect.
+ */
+#define CSR_MCONTROL_HIT_OFFSET 20
+#define CSR_MCONTROL_HIT_LENGTH 1
+#define CSR_MCONTROL_HIT (0x1ULL << CSR_MCONTROL_HIT_OFFSET)
+/*
+* 0: Perform a match on the virtual address.
+*
+* 1: Perform a match on the data value loaded/stored, or the
+* instruction executed.
+ */
+#define CSR_MCONTROL_SELECT_OFFSET 19
+#define CSR_MCONTROL_SELECT_LENGTH 1
+#define CSR_MCONTROL_SELECT (0x1ULL << CSR_MCONTROL_SELECT_OFFSET)
+/*
+* 0: The action for this trigger will be taken just before the
+* instruction that triggered it is executed, but after all preceding
+* instructions are are committed.
+*
+* 1: The action for this trigger will be taken after the instruction
+* that triggered it is executed. It shoul