diff options
Diffstat (limited to 'src/target/riscv/riscv.h')
-rw-r--r-- | src/target/riscv/riscv.h | 262 |
1 files changed, 262 insertions, 0 deletions
diff --git a/src/target/riscv/riscv.h b/src/target/riscv/riscv.h new file mode 100644 index 00000000..31f3cf63 --- /dev/null +++ b/src/target/riscv/riscv.h @@ -0,0 +1,262 @@ +#ifndef RISCV_H +#define RISCV_H + +struct riscv_program; + +#include <stdint.h> +#include "opcodes.h" +#include "gdb_regs.h" + +/* The register cache is statically allocated. */ +#define RISCV_MAX_HARTS 32 +#define RISCV_MAX_REGISTERS 5000 +#define RISCV_MAX_TRIGGERS 32 +#define RISCV_MAX_HWBPS 16 + +#define DEFAULT_COMMAND_TIMEOUT_SEC 2 +#define DEFAULT_RESET_TIMEOUT_SEC 30 + +extern struct target_type riscv011_target; +extern struct target_type riscv013_target; + +/* + * Definitions shared by code supporting all RISC-V versions. + */ +typedef uint64_t riscv_reg_t; +typedef uint32_t riscv_insn_t; +typedef uint64_t riscv_addr_t; + +enum riscv_halt_reason { + RISCV_HALT_INTERRUPT, + RISCV_HALT_BREAKPOINT, + RISCV_HALT_SINGLESTEP, + RISCV_HALT_TRIGGER, + RISCV_HALT_UNKNOWN, + RISCV_HALT_ERROR +}; + +typedef struct { + unsigned dtm_version; + + 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; + + /* The hart that is currently being debugged. Note that this is + * different than the hartid that the RTOS is expected to use. This + * one will change all the time, it's more of a global argument to + * 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. */ + uint64_t reg_cache_values[RISCV_MAX_REGISTERS]; + + /* Single buffer that contains all register names, instead of calling + * malloc for each register. Needs to be freed when reg_list is freed. */ + char *reg_names; + + /* It's possible that each core has a different supported ISA set. */ + int xlen[RISCV_MAX_HARTS]; + riscv_reg_t misa[RISCV_MAX_HARTS]; + + /* The number of triggers per hart. */ + unsigned trigger_count[RISCV_MAX_HARTS]; + + /* For each physical trigger, contains -1 if the hwbp is available, or the + * unique_id of the breakpoint/watchpoint that is using it. + * Note that in RTOS mode the triggers are the same across all harts the + * target controls, while otherwise only a single hart is controlled. */ + int trigger_unique_id[RISCV_MAX_HWBPS]; + + /* The number of entries in the debug buffer. */ + int debug_buffer_size[RISCV_MAX_HARTS]; + + /* This avoids invalidating the register cache too often. */ + bool registers_initialized; + + /* This hart contains an implicit ebreak at the end of the program buffer. */ + bool impebreak; + + bool triggers_enumerated; + + /* 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 *, int hartid, int regid, + uint64_t value); + int (*select_current_hart)(struct target *); + bool (*is_halted)(struct target *target); + int (*halt_current_hart)(struct target *); + int (*resume_current_hart)(struct target *target); + int (*step_current_hart)(struct target *target); + int (*on_halt)(struct target *target); + int (*on_resume)(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, + riscv_insn_t d); + riscv_insn_t (*read_debug_buffer)(struct target *target, unsigned index); + int (*execute_debug_buffer)(struct target *target); + int (*dmi_write_u64_bits)(struct target *target); + void (*fill_dmi_write_u64)(struct target *target, char *buf, int a, uint64_t d); + void (*fill_dmi_read_u64)(struct target *target, char *buf, int a); + void (*fill_dmi_nop_u64)(struct target *target, char *buf); + + int (*authdata_read)(struct target *target, uint32_t *value); + int (*authdata_write)(struct target *target, uint32_t value); + + int (*dmi_read)(struct target *target, uint32_t *value, uint32_t address); + int (*dmi_write)(struct target *target, uint32_t address, uint32_t value); +} riscv_info_t; + +/* Wall-clock timeout for a command/access. Settable via RISC-V Target commands.*/ +extern int riscv_command_timeout_sec; + +/* Wall-clock timeout after reset. Settable via RISC-V Target commands.*/ +extern int riscv_reset_timeout_sec; + +extern bool riscv_prefer_sba; + +/* 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)); +static inline riscv_info_t *riscv_info(const struct target *target) +{ return target->arch_info; } +#define RISCV_INFO(R) riscv_info_t *R = riscv_info(target); + +extern uint8_t ir_dtmcontrol[1]; +extern struct scan_field select_dtmcontrol; +extern uint8_t ir_dbus[1]; +extern struct scan_field select_dbus; +extern uint8_t ir_idcode[1]; +extern struct scan_field select_idcode; + +/*** OpenOCD Interface */ +int riscv_openocd_poll(struct target *target); + +int riscv_openocd_halt(struct target *target); + +int riscv_openocd_resume( + struct target *target, + int current, + target_addr_t address, + int handle_breakpoints, + int debug_execution +); + +int riscv_openocd_step( + struct target *target, + int current, + target_addr_t address, + int handle_breakpoints +); + +int riscv_openocd_assert_reset(struct target *target); +int riscv_openocd_deassert_reset(struct target *target); + +/*** RISC-V Interface ***/ + +/* 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); + +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); +int riscv_xlen_of_hart(const struct target *target, int hartid); + +bool riscv_rtos_enabled(const struct target *target); + +/* Sets the current hart, which is the hart that will actually be used when + * issuing debug commands. */ +int riscv_set_current_hartid(struct target *target, int hartid); +int riscv_current_hartid(const struct target *target); + +/*** Support functions for the RISC-V 'RTOS', which provides multihart support + * without requiring multiple targets. */ + +/* When using the RTOS to debug, this selects the hart that is currently being + * debugged. This doesn't propogate to the hardware. */ +void riscv_set_all_rtos_harts(struct target *target); +void riscv_set_rtos_hartid(struct target *target, int hartid); + +/* Lists the number of harts in the system, which are assumed to be + * concecutive and start with mhartid=0. */ +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. */ +int riscv_set_register(struct target *target, enum gdb_regno i, riscv_reg_t v); +int riscv_set_register_on_hart(struct target *target, int hid, enum gdb_regno rid, uint64_t v); +int riscv_get_register(struct target *target, riscv_reg_t *value, + enum gdb_regno r); +int riscv_get_register_on_hart(struct target *target, riscv_reg_t *value, + int hartid, enum gdb_regno regid); + +/* Checks the state of the current hart -- "is_halted" checks the actual + * on-device register. */ +bool riscv_is_halted(struct target *target); +enum riscv_halt_reason riscv_halt_reason(struct target *target, int hartid); + +/* These helper functions let the generic program interface get target-specific + * information. */ +size_t riscv_debug_buffer_size(struct target *target); + +riscv_insn_t riscv_read_debug_buffer(struct target *target, int index); +int riscv_write_debug_buffer(struct target *target, int index, riscv_insn_t insn); +int riscv_execute_debug_buffer(struct target *target); + +void riscv_fill_dmi_nop_u64(struct target *target, char *buf); +void riscv_fill_dmi_write_u64(struct target *target, char *buf, int a, uint64_t d); +void riscv_fill_dmi_read_u64(struct target *target, char *buf, int a); +int riscv_dmi_write_u64_bits(struct target *target); + +/* Invalidates the register cache. */ +void riscv_invalidate_register_cache(struct target *target); + +/* Returns TRUE when a hart is enabled in this target. */ +bool riscv_hart_enabled(struct target *target, int hartid); + +int riscv_enumerate_triggers(struct target *target); + +int riscv_add_breakpoint(struct target *target, struct breakpoint *breakpoint); +int riscv_remove_breakpoint(struct target *target, + struct breakpoint *breakpoint); +int riscv_add_watchpoint(struct target *target, struct watchpoint *watchpoint); +int riscv_remove_watchpoint(struct target *target, + struct watchpoint *watchpoint); + +int riscv_init_registers(struct target *target); + +void riscv_semihosting_init(struct target *target); +int riscv_semihosting(struct target *target, int *retval); + +#endif |