diff options
-rw-r--r-- | doc/openocd.texi | 78 | ||||
-rw-r--r-- | src/helper/log.h | 2 | ||||
-rw-r--r-- | src/target/Makefile.am | 5 | ||||
-rw-r--r-- | src/target/riscv/Makefile.am | 16 | ||||
-rw-r--r-- | src/target/riscv/asm.h | 38 | ||||
-rw-r--r-- | src/target/riscv/batch.c | 172 | ||||
-rw-r--r-- | src/target/riscv/batch.h | 64 | ||||
-rw-r--r-- | src/target/riscv/debug_defines.h | 1414 | ||||
-rw-r--r-- | src/target/riscv/encoding.h | 1473 | ||||
-rw-r--r-- | src/target/riscv/gdb_regs.h | 93 | ||||
-rw-r--r-- | src/target/riscv/opcodes.h | 310 | ||||
-rw-r--r-- | src/target/riscv/program.c | 162 | ||||
-rw-r--r-- | src/target/riscv/program.h | 75 | ||||
-rw-r--r-- | src/target/riscv/riscv-011.c | 2328 | ||||
-rw-r--r-- | src/target/riscv/riscv-013.c | 3036 | ||||
-rw-r--r-- | src/target/riscv/riscv.c | 2512 | ||||
-rw-r--r-- | src/target/riscv/riscv.h | 262 | ||||
-rw-r--r-- | src/target/riscv/riscv_semihosting.c | 194 | ||||
-rw-r--r-- | src/target/target.c | 2 | ||||
-rw-r--r-- | tcl/board/sifive-e31arty.cfg | 22 | ||||
-rw-r--r-- | tcl/board/sifive-e51arty.cfg | 22 | ||||
-rw-r--r-- | tcl/board/sifive-hifive1.cfg | 34 |
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 |