Upstream tons of RISC-V changes.
These are all the changes from https://github.com/riscv/riscv-openocd
(approximately 91dc0c0c) made just to src/target/riscv/*. Some of the
new code is disabled because it requires some other target-independent
changes which I didn't want to include here.
Built like this, OpenOCD passes:
* All single-RV32 tests against spike.
* All single-RV64 tests against spike.
* Enough HiFive1 tests. (I suspect the failures are due to the test
suite rotting.)
* Many dual-RV32 (-rtos hwthread) against spike.
* Many dual-RV64 (-rtos hwthread) against spike.
I suspect this is an overall improvement compared to what's in mainline
right now, and it gets me a lot closer to getting all the riscv-openocd
work upstreamed.
Change-Id: Ide2f80c9397400780ff6780d78a206bc6a6e2f98
Signed-off-by: Tim Newsome <tim@sifive.com>
Reviewed-on: http://openocd.zylin.com/5821
Tested-by: jenkins
Reviewed-by: Jan Matyas <matyas@codasip.com>
Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com>
Reviewed-by: Karl Palsson <karlp@tweak.net.au>
This commit is contained in:
@@ -1,3 +1,5 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#ifndef RISCV_H
|
||||
#define RISCV_H
|
||||
|
||||
@@ -6,9 +8,11 @@ struct riscv_program;
|
||||
#include <stdint.h>
|
||||
#include "opcodes.h"
|
||||
#include "gdb_regs.h"
|
||||
#include "jtag/jtag.h"
|
||||
#include "target/register.h"
|
||||
|
||||
/* The register cache is statically allocated. */
|
||||
#define RISCV_MAX_HARTS 32
|
||||
#define RISCV_MAX_HARTS 1024
|
||||
#define RISCV_MAX_REGISTERS 5000
|
||||
#define RISCV_MAX_TRIGGERS 32
|
||||
#define RISCV_MAX_HWBPS 16
|
||||
@@ -16,6 +20,12 @@ struct riscv_program;
|
||||
#define DEFAULT_COMMAND_TIMEOUT_SEC 2
|
||||
#define DEFAULT_RESET_TIMEOUT_SEC 30
|
||||
|
||||
#define RISCV_SATP_MODE(xlen) ((xlen) == 32 ? SATP32_MODE : SATP64_MODE)
|
||||
#define RISCV_SATP_PPN(xlen) ((xlen) == 32 ? SATP32_PPN : SATP64_PPN)
|
||||
#define RISCV_PGSHIFT 12
|
||||
|
||||
# define PG_MAX_LEVEL 4
|
||||
|
||||
extern struct target_type riscv011_target;
|
||||
extern struct target_type riscv013_target;
|
||||
|
||||
@@ -32,6 +42,7 @@ enum riscv_halt_reason {
|
||||
RISCV_HALT_SINGLESTEP,
|
||||
RISCV_HALT_TRIGGER,
|
||||
RISCV_HALT_UNKNOWN,
|
||||
RISCV_HALT_GROUP,
|
||||
RISCV_HALT_ERROR
|
||||
};
|
||||
|
||||
@@ -46,9 +57,6 @@ typedef struct {
|
||||
struct command_context *cmd_ctx;
|
||||
void *version_specific;
|
||||
|
||||
/* The number of harts on this system. */
|
||||
int hart_count;
|
||||
|
||||
/* The hart that the RTOS thinks is currently being debugged. */
|
||||
int rtos_hartid;
|
||||
|
||||
@@ -58,11 +66,6 @@ typedef struct {
|
||||
* every function than an actual */
|
||||
int current_hartid;
|
||||
|
||||
/* Enough space to store all the registers we might need to save. */
|
||||
/* FIXME: This should probably be a bunch of register caches. */
|
||||
uint64_t saved_registers[RISCV_MAX_HARTS][RISCV_MAX_REGISTERS];
|
||||
bool valid_saved_registers[RISCV_MAX_HARTS][RISCV_MAX_REGISTERS];
|
||||
|
||||
/* OpenOCD's register cache points into here. This is not per-hart because
|
||||
* we just invalidate the entire cache when we change which hart is
|
||||
* selected. */
|
||||
@@ -75,6 +78,8 @@ typedef struct {
|
||||
/* It's possible that each core has a different supported ISA set. */
|
||||
int xlen[RISCV_MAX_HARTS];
|
||||
riscv_reg_t misa[RISCV_MAX_HARTS];
|
||||
/* Cached value of vlenb. 0 if vlenb is not readable for some reason. */
|
||||
unsigned vlenb[RISCV_MAX_HARTS];
|
||||
|
||||
/* The number of triggers per hart. */
|
||||
unsigned trigger_count[RISCV_MAX_HARTS];
|
||||
@@ -100,19 +105,33 @@ typedef struct {
|
||||
* delays, causing them to be relearned. Used for testing. */
|
||||
int reset_delays_wait;
|
||||
|
||||
/* This target has been prepped and is ready to step/resume. */
|
||||
bool prepped;
|
||||
/* This target was selected using hasel. */
|
||||
bool selected;
|
||||
|
||||
/* Helper functions that target the various RISC-V debug spec
|
||||
* implementations. */
|
||||
int (*get_register)(struct target *target,
|
||||
riscv_reg_t *value, int hid, int rid);
|
||||
int (*set_register)(struct target *target, int hartid, int regid,
|
||||
uint64_t value);
|
||||
int (*get_register_buf)(struct target *target, uint8_t *buf, int regno);
|
||||
int (*set_register_buf)(struct target *target, int regno,
|
||||
const uint8_t *buf);
|
||||
int (*select_current_hart)(struct target *target);
|
||||
bool (*is_halted)(struct target *target);
|
||||
int (*halt_current_hart)(struct target *target);
|
||||
int (*resume_current_hart)(struct target *target);
|
||||
/* Resume this target, as well as every other prepped target that can be
|
||||
* resumed near-simultaneously. Clear the prepped flag on any target that
|
||||
* was resumed. */
|
||||
int (*resume_go)(struct target *target);
|
||||
int (*step_current_hart)(struct target *target);
|
||||
int (*on_halt)(struct target *target);
|
||||
int (*on_resume)(struct target *target);
|
||||
/* Get this target as ready as possible to resume, without actually
|
||||
* resuming. */
|
||||
int (*resume_prep)(struct target *target);
|
||||
int (*halt_prep)(struct target *target);
|
||||
int (*halt_go)(struct target *target);
|
||||
int (*on_step)(struct target *target);
|
||||
enum riscv_halt_reason (*halt_reason)(struct target *target);
|
||||
int (*write_debug_buffer)(struct target *target, unsigned index,
|
||||
@@ -134,8 +153,52 @@ typedef struct {
|
||||
uint32_t num_words, target_addr_t illegal_address, bool run_sbbusyerror_test);
|
||||
|
||||
int (*test_compliance)(struct target *target);
|
||||
|
||||
int (*read_memory)(struct target *target, target_addr_t address,
|
||||
uint32_t size, uint32_t count, uint8_t *buffer, uint32_t increment);
|
||||
|
||||
/* How many harts are attached to the DM that this target is attached to? */
|
||||
int (*hart_count)(struct target *target);
|
||||
unsigned (*data_bits)(struct target *target);
|
||||
|
||||
/* Storage for vector register types. */
|
||||
struct reg_data_type_vector vector_uint8;
|
||||
struct reg_data_type_vector vector_uint16;
|
||||
struct reg_data_type_vector vector_uint32;
|
||||
struct reg_data_type_vector vector_uint64;
|
||||
struct reg_data_type_vector vector_uint128;
|
||||
struct reg_data_type type_uint8_vector;
|
||||
struct reg_data_type type_uint16_vector;
|
||||
struct reg_data_type type_uint32_vector;
|
||||
struct reg_data_type type_uint64_vector;
|
||||
struct reg_data_type type_uint128_vector;
|
||||
struct reg_data_type_union_field vector_fields[5];
|
||||
struct reg_data_type_union vector_union;
|
||||
struct reg_data_type type_vector;
|
||||
|
||||
/* Set when trigger registers are changed by the user. This indicates we eed
|
||||
* to beware that we may hit a trigger that we didn't realize had been set. */
|
||||
bool manual_hwbp_set;
|
||||
} riscv_info_t;
|
||||
|
||||
typedef struct {
|
||||
uint8_t tunneled_dr_width;
|
||||
struct scan_field tunneled_dr[4];
|
||||
} riscv_bscan_tunneled_scan_context_t;
|
||||
|
||||
typedef struct {
|
||||
const char *name;
|
||||
int level;
|
||||
unsigned va_bits;
|
||||
unsigned pte_shift;
|
||||
unsigned vpn_shift[PG_MAX_LEVEL];
|
||||
unsigned vpn_mask[PG_MAX_LEVEL];
|
||||
unsigned pte_ppn_shift[PG_MAX_LEVEL];
|
||||
unsigned pte_ppn_mask[PG_MAX_LEVEL];
|
||||
unsigned pa_ppn_shift[PG_MAX_LEVEL];
|
||||
unsigned pa_ppn_mask[PG_MAX_LEVEL];
|
||||
} virt2phys_info_t;
|
||||
|
||||
/* Wall-clock timeout for a command/access. Settable via RISC-V Target commands.*/
|
||||
extern int riscv_command_timeout_sec;
|
||||
|
||||
@@ -144,6 +207,11 @@ extern int riscv_reset_timeout_sec;
|
||||
|
||||
extern bool riscv_prefer_sba;
|
||||
|
||||
extern bool riscv_enable_virtual;
|
||||
extern bool riscv_ebreakm;
|
||||
extern bool riscv_ebreaks;
|
||||
extern bool riscv_ebreaku;
|
||||
|
||||
/* Everything needs the RISC-V specific info structure, so here's a nice macro
|
||||
* that provides that. */
|
||||
static inline riscv_info_t *riscv_info(const struct target *target) __attribute__((unused));
|
||||
@@ -158,17 +226,28 @@ extern struct scan_field select_dbus;
|
||||
extern uint8_t ir_idcode[4];
|
||||
extern struct scan_field select_idcode;
|
||||
|
||||
extern struct scan_field select_user4;
|
||||
extern struct scan_field *bscan_tunneled_select_dmi;
|
||||
extern uint32_t bscan_tunneled_select_dmi_num_fields;
|
||||
typedef enum { BSCAN_TUNNEL_NESTED_TAP, BSCAN_TUNNEL_DATA_REGISTER } bscan_tunnel_type_t;
|
||||
extern int bscan_tunnel_ir_width;
|
||||
extern bscan_tunnel_type_t bscan_tunnel_type;
|
||||
|
||||
uint32_t dtmcontrol_scan_via_bscan(struct target *target, uint32_t out);
|
||||
void select_dmi_via_bscan(struct target *target);
|
||||
|
||||
/*** OpenOCD Interface */
|
||||
int riscv_openocd_poll(struct target *target);
|
||||
|
||||
int riscv_openocd_halt(struct target *target);
|
||||
int riscv_halt(struct target *target);
|
||||
|
||||
int riscv_openocd_resume(
|
||||
int riscv_resume(
|
||||
struct target *target,
|
||||
int current,
|
||||
target_addr_t address,
|
||||
int handle_breakpoints,
|
||||
int debug_execution
|
||||
int debug_execution,
|
||||
bool single_hart
|
||||
);
|
||||
|
||||
int riscv_openocd_step(
|
||||
@@ -186,14 +265,6 @@ int riscv_openocd_deassert_reset(struct target *target);
|
||||
/* Initializes the shared RISC-V structure. */
|
||||
void riscv_info_init(struct target *target, riscv_info_t *r);
|
||||
|
||||
/* Run control, possibly for multiple harts. The _all_harts versions resume
|
||||
* all the enabled harts, which when running in RTOS mode is all the harts on
|
||||
* the system. */
|
||||
int riscv_halt_all_harts(struct target *target);
|
||||
int riscv_halt_one_hart(struct target *target, int hartid);
|
||||
int riscv_resume_all_harts(struct target *target);
|
||||
int riscv_resume_one_hart(struct target *target, int hartid);
|
||||
|
||||
/* Steps the hart that's currently selected in the RTOS, or if there is no RTOS
|
||||
* then the only hart. */
|
||||
int riscv_step_rtos_hart(struct target *target);
|
||||
@@ -201,7 +272,7 @@ int riscv_step_rtos_hart(struct target *target);
|
||||
bool riscv_supports_extension(struct target *target, int hartid, char letter);
|
||||
|
||||
/* Returns XLEN for the given (or current) hart. */
|
||||
int riscv_xlen(const struct target *target);
|
||||
unsigned riscv_xlen(const struct target *target);
|
||||
int riscv_xlen_of_hart(const struct target *target, int hartid);
|
||||
|
||||
bool riscv_rtos_enabled(const struct target *target);
|
||||
@@ -226,12 +297,14 @@ int riscv_count_harts(struct target *target);
|
||||
/* Returns TRUE if the target has the given register on the given hart. */
|
||||
bool riscv_has_register(struct target *target, int hartid, int regid);
|
||||
|
||||
/* Returns the value of the given register on the given hart. 32-bit registers
|
||||
* are zero extended to 64 bits. */
|
||||
/** Set register, updating the cache. */
|
||||
int riscv_set_register(struct target *target, enum gdb_regno i, riscv_reg_t v);
|
||||
/** Set register, updating the cache. */
|
||||
int riscv_set_register_on_hart(struct target *target, int hid, enum gdb_regno rid, uint64_t v);
|
||||
/** Get register, from the cache if it's in there. */
|
||||
int riscv_get_register(struct target *target, riscv_reg_t *value,
|
||||
enum gdb_regno r);
|
||||
/** Get register, from the cache if it's in there. */
|
||||
int riscv_get_register_on_hart(struct target *target, riscv_reg_t *value,
|
||||
int hartid, enum gdb_regno regid);
|
||||
|
||||
@@ -272,6 +345,15 @@ int riscv_hit_watchpoint(struct target *target, struct watchpoint **hit_wp_addre
|
||||
int riscv_init_registers(struct target *target);
|
||||
|
||||
void riscv_semihosting_init(struct target *target);
|
||||
int riscv_semihosting(struct target *target, int *retval);
|
||||
typedef enum {
|
||||
SEMI_NONE, /* Not halted for a semihosting call. */
|
||||
SEMI_HANDLED, /* Call handled, and target was resumed. */
|
||||
SEMI_WAITING, /* Call handled, target is halted waiting until we can resume. */
|
||||
SEMI_ERROR /* Something went wrong. */
|
||||
} semihosting_result_t;
|
||||
semihosting_result_t riscv_semihosting(struct target *target, int *retval);
|
||||
|
||||
void riscv_add_bscan_tunneled_scan(struct target *target, struct scan_field *field,
|
||||
riscv_bscan_tunneled_scan_context_t *ctxt);
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user