aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-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
18 files changed, 12157 insertions, 1 deletions
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 should be taken before the next
+* instruction is executed, but it is better to implement triggers and
+* not implement that suggestion than to not implement them at all.
+*
+* Most hardware will only implement one timing or the other, possibly
+* dependent on \Fselect, \Fexecute, \Fload, and \Fstore. This bit
+* primarily exists for the hardware to communicate to the debugger
+* what will happen. Hardware may implement the bit fully writable, in
+* which case the debugger has a little more control.
+*
+* Data load triggers with \Ftiming of 0 will result in the same load
+* happening again when the debugger lets the hart run. For data load
+* triggers, debuggers must first attempt to set the breakpoint with
+* \Ftiming of 1.
+*
+* A chain of triggers that don't all have the same \Ftiming value
+* will never fire (unless consecutive instructions match the
+* appropriate triggers).
+ */
+#define CSR_MCONTROL_TIMING_OFFSET 18
+#define CSR_MCONTROL_TIMING_LENGTH 1
+#define CSR_MCONTROL_TIMING (0x1ULL << CSR_MCONTROL_TIMING_OFFSET)
+/*
+* The action to take when the trigger fires. The values are explained
+* in Table~\ref{tab:action}.
+ */
+#define CSR_MCONTROL_ACTION_OFFSET 12
+#define CSR_MCONTROL_ACTION_LENGTH 6
+#define CSR_MCONTROL_ACTION (0x3fULL << CSR_MCONTROL_ACTION_OFFSET)
+/*
+* 0: When this trigger matches, the configured action is taken.
+*
+* 1: While this trigger does not match, it prevents the trigger with
+* the next index from matching.
+*
+* Because \Fchain affects the next trigger, hardware must zero it in
+* writes to \Rmcontrol that set \Fdmode to 0 if the next trigger has
+* \Fdmode of 1.
+* In addition hardware should ignore writes to \Rmcontrol that set
+* \Fdmode to 1 if the previous trigger has both \Fdmode of 0 and
+* \Fchain of 1. Debuggers must avoid the latter case by checking
+* \Fchain on the previous trigger if they're writing \Rmcontrol.
+*
+* Implementations that wish to limit the maximum length of a trigger
+* chain (eg. to meet timing requirements) may do so by zeroing
+* \Fchain in writes to \Rmcontrol that would make the chain too long.
+ */
+#define CSR_MCONTROL_CHAIN_OFFSET 11
+#define CSR_MCONTROL_CHAIN_LENGTH 1
+#define CSR_MCONTROL_CHAIN (0x1ULL << CSR_MCONTROL_CHAIN_OFFSET)
+/*
+* 0: Matches when the value equals \Rtdatatwo.
+*
+* 1: Matches when the top M bits of the value match the top M bits of
+* \Rtdatatwo. M is MXLEN-1 minus the index of the least-significant
+* bit containing 0 in \Rtdatatwo.
+*
+* 2: Matches when the value is greater than (unsigned) or equal to
+* \Rtdatatwo.
+*
+* 3: Matches when the value is less than (unsigned) \Rtdatatwo.
+*
+* 4: Matches when the lower half of the value equals the lower half
+* of \Rtdatatwo after the lower half of the value is ANDed with the
+* upper half of \Rtdatatwo.
+*
+* 5: Matches when the upper half of the value equals the lower half
+* of \Rtdatatwo after the upper half of the value is ANDed with the
+* upper half of \Rtdatatwo.
+*
+* Other values are reserved for future use.
+ */
+#define CSR_MCONTROL_MATCH_OFFSET 7
+#define CSR_MCONTROL_MATCH_LENGTH 4
+#define CSR_MCONTROL_MATCH (0xfULL << CSR_MCONTROL_MATCH_OFFSET)
+/*
+* When set, enable this trigger in M mode.
+ */
+#define CSR_MCONTROL_M_OFFSET 6
+#define CSR_MCONTROL_M_LENGTH 1
+#define CSR_MCONTROL_M (0x1ULL << CSR_MCONTROL_M_OFFSET)
+/*
+* When set, enable this trigger in S mode.
+ */
+#define CSR_MCONTROL_S_OFFSET 4
+#define CSR_MCONTROL_S_LENGTH 1
+#define CSR_MCONTROL_S (0x1ULL << CSR_MCONTROL_S_OFFSET)
+/*
+* When set, enable this trigger in U mode.
+ */
+#define CSR_MCONTROL_U_OFFSET 3
+#define CSR_MCONTROL_U_LENGTH 1
+#define CSR_MCONTROL_U (0x1ULL << CSR_MCONTROL_U_OFFSET)
+/*
+* When set, the trigger fires on the virtual address or opcode of an
+* instruction that is executed.
+ */
+#define CSR_MCONTROL_EXECUTE_OFFSET 2
+#define CSR_MCONTROL_EXECUTE_LENGTH 1
+#define CSR_MCONTROL_EXECUTE (0x1ULL << CSR_MCONTROL_EXECUTE_OFFSET)
+/*
+* When set, the trigger fires on the virtual address or data of a store.
+ */
+#define CSR_MCONTROL_STORE_OFFSET 1
+#define CSR_MCONTROL_STORE_LE