Merge pull request #1101 from en-sc/en-sc/ref-reg-examine
target/riscv: reg cache entry is initialized before access
This commit is contained in:
commit
e4d6885eb5
|
@ -38,7 +38,9 @@ static const struct reg_arch_type *riscv011_gdb_regno_reg_type(uint32_t regno)
|
|||
|
||||
static int riscv011_init_reg(struct target *target, uint32_t regno)
|
||||
{
|
||||
return riscv_reg_impl_init_one(target, regno, riscv011_gdb_regno_reg_type(regno));
|
||||
return riscv_reg_impl_init_cache_entry(target, regno,
|
||||
riscv_reg_impl_gdb_regno_exist(target, regno),
|
||||
riscv011_gdb_regno_reg_type(regno));
|
||||
}
|
||||
|
||||
int riscv011_reg_init_all(struct target *target)
|
||||
|
|
|
@ -727,7 +727,7 @@ clear_cmderr:
|
|||
return res;
|
||||
}
|
||||
|
||||
static int execute_abstract_command(struct target *target, uint32_t command,
|
||||
int riscv013_execute_abstract_command(struct target *target, uint32_t command,
|
||||
uint32_t *cmderr)
|
||||
{
|
||||
assert(cmderr);
|
||||
|
@ -863,7 +863,7 @@ static int write_abstract_arg(struct target *target, unsigned index,
|
|||
/**
|
||||
* @par size in bits
|
||||
*/
|
||||
static uint32_t access_register_command(struct target *target, uint32_t number,
|
||||
uint32_t riscv013_access_register_command(struct target *target, uint32_t number,
|
||||
unsigned size, uint32_t flags)
|
||||
{
|
||||
uint32_t command = set_field(0, DM_COMMAND_CMDTYPE, 0);
|
||||
|
@ -920,11 +920,11 @@ static int register_read_abstract_with_size(struct target *target,
|
|||
if (number >= GDB_REGNO_V0 && number <= GDB_REGNO_V31)
|
||||
return ERROR_FAIL;
|
||||
|
||||
uint32_t command = access_register_command(target, number, size,
|
||||
uint32_t command = riscv013_access_register_command(target, number, size,
|
||||
AC_ACCESS_REGISTER_TRANSFER);
|
||||
|
||||
uint32_t cmderr;
|
||||
int result = execute_abstract_command(target, command, &cmderr);
|
||||
int result = riscv013_execute_abstract_command(target, command, &cmderr);
|
||||
if (result != ERROR_OK) {
|
||||
if (cmderr == CMDERR_NOT_SUPPORTED) {
|
||||
if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31) {
|
||||
|
@ -969,7 +969,7 @@ static int register_write_abstract(struct target *target, enum gdb_regno number,
|
|||
return ERROR_FAIL;
|
||||
|
||||
const unsigned int size_bits = register_size(target, number);
|
||||
const uint32_t command = access_register_command(target, number, size_bits,
|
||||
const uint32_t command = riscv013_access_register_command(target, number, size_bits,
|
||||
AC_ACCESS_REGISTER_TRANSFER |
|
||||
AC_ACCESS_REGISTER_WRITE);
|
||||
LOG_DEBUG_REG(target, AC_ACCESS_REGISTER, command);
|
||||
|
@ -2112,70 +2112,9 @@ static int examine(struct target *target)
|
|||
* program buffer. */
|
||||
r->progbuf_size = info->progbufsize;
|
||||
|
||||
result = register_read_abstract_with_size(target, NULL, GDB_REGNO_S0, 64);
|
||||
if (result == ERROR_OK)
|
||||
r->xlen = 64;
|
||||
else
|
||||
r->xlen = 32;
|
||||
|
||||
/* Save s0 and s1. The register cache hasn't be initialized yet so we
|
||||
* need to take care of this manually. */
|
||||
uint64_t s0, s1;
|
||||
if (register_read_abstract(target, &s0, GDB_REGNO_S0) != ERROR_OK) {
|
||||
LOG_TARGET_ERROR(target, "Fatal: Failed to read s0.");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
if (register_read_abstract(target, &s1, GDB_REGNO_S1) != ERROR_OK) {
|
||||
LOG_TARGET_ERROR(target, "Fatal: Failed to read s1.");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
if (register_read_direct(target, &r->misa, GDB_REGNO_MISA)) {
|
||||
LOG_TARGET_ERROR(target, "Fatal: Failed to read MISA.");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
uint64_t value;
|
||||
if (register_read_direct(target, &value, GDB_REGNO_VLENB) != ERROR_OK) {
|
||||
if (riscv_supports_extension(target, 'V'))
|
||||
LOG_TARGET_WARNING(target, "Couldn't read vlenb; vector register access won't work.");
|
||||
r->vlenb = 0;
|
||||
} else {
|
||||
r->vlenb = value;
|
||||
LOG_TARGET_INFO(target, "Vector support with vlenb=%d", r->vlenb);
|
||||
}
|
||||
|
||||
if (register_read_direct(target, &value, GDB_REGNO_MTOPI) == ERROR_OK) {
|
||||
r->mtopi_readable = true;
|
||||
|
||||
if (register_read_direct(target, &value, GDB_REGNO_MTOPEI) == ERROR_OK) {
|
||||
LOG_TARGET_INFO(target, "S?aia detected with IMSIC");
|
||||
r->mtopei_readable = true;
|
||||
} else {
|
||||
r->mtopei_readable = false;
|
||||
LOG_TARGET_INFO(target, "S?aia detected without IMSIC");
|
||||
}
|
||||
} else {
|
||||
r->mtopi_readable = false;
|
||||
}
|
||||
|
||||
/* Display this as early as possible to help people who are using
|
||||
* really slow simulators. */
|
||||
LOG_TARGET_DEBUG(target, " XLEN=%d, misa=0x%" PRIx64, r->xlen, r->misa);
|
||||
|
||||
/* Restore s0 and s1. */
|
||||
if (register_write_direct(target, GDB_REGNO_S0, s0) != ERROR_OK) {
|
||||
LOG_TARGET_ERROR(target, "Fatal: Failed to write back s0.");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
if (register_write_direct(target, GDB_REGNO_S1, s1) != ERROR_OK) {
|
||||
LOG_TARGET_ERROR(target, "Fatal: Failed to write back s1.");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
/* Now init registers based on what we discovered. */
|
||||
if (riscv013_reg_init_all(target) != ERROR_OK)
|
||||
return ERROR_FAIL;
|
||||
result = riscv013_reg_examine_all(target);
|
||||
if (result != ERROR_OK)
|
||||
return result;
|
||||
|
||||
if (set_dcsr_ebreak(target, false) != ERROR_OK)
|
||||
return ERROR_FAIL;
|
||||
|
@ -3651,7 +3590,7 @@ static int read_memory_abstract(struct target *target, target_addr_t address,
|
|||
|
||||
/* Execute the command */
|
||||
uint32_t cmderr;
|
||||
result = execute_abstract_command(target, command, &cmderr);
|
||||
result = riscv013_execute_abstract_command(target, command, &cmderr);
|
||||
|
||||
/* TODO: we need to modify error handling here. */
|
||||
/* NOTE: in case of timeout cmderr is set to CMDERR_NONE */
|
||||
|
@ -3673,7 +3612,7 @@ static int read_memory_abstract(struct target *target, target_addr_t address,
|
|||
} else {
|
||||
/* Try the same access but with postincrement disabled. */
|
||||
command = access_memory_command(target, false, width, false, false);
|
||||
result = execute_abstract_command(target, command, &cmderr);
|
||||
result = riscv013_execute_abstract_command(target, command, &cmderr);
|
||||
if (result == ERROR_OK) {
|
||||
LOG_TARGET_DEBUG(target, "aampostincrement is not supported on this target.");
|
||||
info->has_aampostincrement = YNM_NO;
|
||||
|
@ -3744,7 +3683,7 @@ static int write_memory_abstract(struct target *target, target_addr_t address,
|
|||
|
||||
/* Execute the command */
|
||||
uint32_t cmderr;
|
||||
result = execute_abstract_command(target, command, &cmderr);
|
||||
result = riscv013_execute_abstract_command(target, command, &cmderr);
|
||||
|
||||
/* TODO: we need to modify error handling here. */
|
||||
/* NOTE: in case of timeout cmderr is set to CMDERR_NONE */
|
||||
|
@ -3766,7 +3705,7 @@ static int write_memory_abstract(struct target *target, target_addr_t address,
|
|||
} else {
|
||||
/* Try the same access but with postincrement disabled. */
|
||||
command = access_memory_command(target, false, width, false, true);
|
||||
result = execute_abstract_command(target, command, &cmderr);
|
||||
result = riscv013_execute_abstract_command(target, command, &cmderr);
|
||||
if (result == ERROR_OK) {
|
||||
LOG_TARGET_DEBUG(target, "aampostincrement is not supported on this target.");
|
||||
info->has_aampostincrement = YNM_NO;
|
||||
|
@ -3812,11 +3751,11 @@ static int read_memory_progbuf_inner_startup(struct target *target,
|
|||
/* AC_ACCESS_REGISTER_POSTEXEC is used to trigger first stage of the
|
||||
* pipeline (memory -> s1) whenever this command is executed.
|
||||
*/
|
||||
const uint32_t startup_command = access_register_command(target,
|
||||
const uint32_t startup_command = riscv013_access_register_command(target,
|
||||
GDB_REGNO_S1, riscv_xlen(target),
|
||||
AC_ACCESS_REGISTER_TRANSFER | AC_ACCESS_REGISTER_POSTEXEC);
|
||||
uint32_t cmderr;
|
||||
if (execute_abstract_command(target, startup_command, &cmderr) != ERROR_OK)
|
||||
if (riscv013_execute_abstract_command(target, startup_command, &cmderr) != ERROR_OK)
|
||||
return ERROR_FAIL;
|
||||
/* TODO: we need to modify error handling here. */
|
||||
/* NOTE: in case of timeout cmderr is set to CMDERR_NONE */
|
||||
|
@ -4299,11 +4238,11 @@ static int read_memory_progbuf_inner_one(struct target *target,
|
|||
if (write_abstract_arg(target, 0, access.target_address, riscv_xlen(target))
|
||||
!= ERROR_OK)
|
||||
return ERROR_FAIL;
|
||||
uint32_t command = access_register_command(target, GDB_REGNO_S1,
|
||||
uint32_t command = riscv013_access_register_command(target, GDB_REGNO_S1,
|
||||
riscv_xlen(target), AC_ACCESS_REGISTER_WRITE |
|
||||
AC_ACCESS_REGISTER_TRANSFER | AC_ACCESS_REGISTER_POSTEXEC);
|
||||
uint32_t cmderr;
|
||||
if (execute_abstract_command(target, command, &cmderr) != ERROR_OK)
|
||||
if (riscv013_execute_abstract_command(target, command, &cmderr) != ERROR_OK)
|
||||
return ERROR_FAIL;
|
||||
|
||||
return read_word_from_s1(target, access, 0);
|
||||
|
@ -4642,14 +4581,14 @@ static int write_memory_progbuf_startup(struct target *target, target_addr_t *ad
|
|||
|
||||
/* Write and execute command that moves the value from data0 [, data1]
|
||||
* into S1 and executes program buffer. */
|
||||
uint32_t command = access_register_command(target,
|
||||
uint32_t command = riscv013_access_register_command(target,
|
||||
GDB_REGNO_S1, riscv_xlen(target),
|
||||
AC_ACCESS_REGISTER_POSTEXEC |
|
||||
AC_ACCESS_REGISTER_TRANSFER |
|
||||
AC_ACCESS_REGISTER_WRITE);
|
||||
|
||||
uint32_t cmderr;
|
||||
if (execute_abstract_command(target, command, &cmderr) != ERROR_OK)
|
||||
if (riscv013_execute_abstract_command(target, command, &cmderr) != ERROR_OK)
|
||||
return ERROR_FAIL;
|
||||
|
||||
log_memory_access64(*address_p, value, size, /*is_read*/ false);
|
||||
|
@ -5320,7 +5259,7 @@ static int riscv013_execute_progbuf(struct target *target, uint32_t *cmderr)
|
|||
run_program = set_field(run_program, AC_ACCESS_REGISTER_TRANSFER, 0);
|
||||
run_program = set_field(run_program, AC_ACCESS_REGISTER_REGNO, 0x1000);
|
||||
|
||||
return execute_abstract_command(target, run_program, cmderr);
|
||||
return riscv013_execute_abstract_command(target, run_program, cmderr);
|
||||
}
|
||||
|
||||
static void riscv013_fill_dmi_write(struct target *target, char *buf, uint64_t a, uint32_t d)
|
||||
|
|
|
@ -19,5 +19,9 @@ int riscv013_set_register(struct target *target, enum gdb_regno rid,
|
|||
riscv_reg_t value);
|
||||
int riscv013_set_register_buf(struct target *target, enum gdb_regno regno,
|
||||
const uint8_t *value);
|
||||
uint32_t riscv013_access_register_command(struct target *target, uint32_t number,
|
||||
unsigned int size, uint32_t flags);
|
||||
int riscv013_execute_abstract_command(struct target *target, uint32_t command,
|
||||
uint32_t *cmderr);
|
||||
|
||||
#endif /* OPENOCD_TARGET_RISCV_RISCV_013_H */
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include "riscv_reg.h"
|
||||
#include "riscv_reg_impl.h"
|
||||
#include "riscv-013.h"
|
||||
#include "debug_defines.h"
|
||||
#include <helper/time_support.h>
|
||||
|
||||
static int riscv013_reg_get(struct reg *reg)
|
||||
|
@ -85,33 +86,196 @@ static int riscv013_reg_set(struct reg *reg, uint8_t *buf)
|
|||
|
||||
static const struct reg_arch_type *riscv013_gdb_regno_reg_type(uint32_t regno)
|
||||
{
|
||||
static const struct reg_arch_type riscv011_reg_type = {
|
||||
static const struct reg_arch_type riscv013_reg_type = {
|
||||
.get = riscv013_reg_get,
|
||||
.set = riscv013_reg_set
|
||||
};
|
||||
return &riscv011_reg_type;
|
||||
return &riscv013_reg_type;
|
||||
}
|
||||
|
||||
static int riscv013_init_reg(struct target *target, uint32_t regno)
|
||||
static int init_cache_entry(struct target *target, uint32_t regno)
|
||||
{
|
||||
return riscv_reg_impl_init_one(target, regno, riscv013_gdb_regno_reg_type(regno));
|
||||
struct reg * const reg = riscv_reg_impl_cache_entry(target, regno);
|
||||
if (riscv_reg_impl_is_initialized(reg))
|
||||
return ERROR_OK;
|
||||
return riscv_reg_impl_init_cache_entry(target, regno,
|
||||
riscv_reg_impl_gdb_regno_exist(target, regno),
|
||||
riscv013_gdb_regno_reg_type(regno));
|
||||
}
|
||||
|
||||
int riscv013_reg_init_all(struct target *target)
|
||||
/**
|
||||
* Some registers are optional (e.g. "misa"). For such registers it is first
|
||||
* assumed they exist (via "assume_reg_exist()"), then the read is attempted
|
||||
* (via the usual "riscv_reg_get()") and if the read fails, the register is
|
||||
* marked as non-existing (via "riscv_reg_impl_set_exist()").
|
||||
*/
|
||||
static int assume_reg_exist(struct target *target, uint32_t regno)
|
||||
{
|
||||
if (riscv_reg_impl_init_cache(target) != ERROR_OK)
|
||||
return riscv_reg_impl_init_cache_entry(target, regno,
|
||||
/* exist */ true, riscv013_gdb_regno_reg_type(regno));
|
||||
}
|
||||
|
||||
static int examine_xlen(struct target *target)
|
||||
{
|
||||
RISCV_INFO(r);
|
||||
unsigned int cmderr;
|
||||
|
||||
const uint32_t command = riscv013_access_register_command(target,
|
||||
GDB_REGNO_S0, /* size */ 64, AC_ACCESS_REGISTER_TRANSFER);
|
||||
int res = riscv013_execute_abstract_command(target, command, &cmderr);
|
||||
if (res == ERROR_OK) {
|
||||
r->xlen = 64;
|
||||
return ERROR_OK;
|
||||
}
|
||||
if (res == ERROR_TIMEOUT_REACHED)
|
||||
return ERROR_FAIL;
|
||||
r->xlen = 32;
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int examine_vlenb(struct target *target)
|
||||
{
|
||||
RISCV_INFO(r);
|
||||
|
||||
/* Reading "vlenb" requires "mstatus.vs" to be set, so "mstatus" should
|
||||
* be accessible.*/
|
||||
int res = init_cache_entry(target, GDB_REGNO_MSTATUS);
|
||||
if (res != ERROR_OK)
|
||||
return res;
|
||||
|
||||
res = assume_reg_exist(target, GDB_REGNO_VLENB);
|
||||
if (res != ERROR_OK)
|
||||
return res;
|
||||
|
||||
riscv_reg_t vlenb_val;
|
||||
if (riscv_reg_get(target, &vlenb_val, GDB_REGNO_VLENB) != ERROR_OK) {
|
||||
if (riscv_supports_extension(target, 'V'))
|
||||
LOG_TARGET_WARNING(target, "Couldn't read vlenb; vector register access won't work.");
|
||||
r->vlenb = 0;
|
||||
return riscv_reg_impl_set_exist(target, GDB_REGNO_VLENB, false);
|
||||
}
|
||||
/* As defined by RISC-V V extension specification:
|
||||
* https://github.com/riscv/riscv-v-spec/blob/2f68ef7256d6ec53e4d2bd7cb12862f406d64e34/v-spec.adoc?plain=1#L67-L72 */
|
||||
const unsigned int vlen_max = 65536;
|
||||
const unsigned int vlenb_max = vlen_max / 8;
|
||||
if (vlenb_val > vlenb_max) {
|
||||
LOG_TARGET_WARNING(target, "'vlenb == %" PRIu64
|
||||
"' is greater than maximum allowed by specification (%u); vector register access won't work.",
|
||||
vlenb_val, vlenb_max);
|
||||
r->vlenb = 0;
|
||||
return ERROR_OK;
|
||||
}
|
||||
assert(vlenb_max <= UINT_MAX);
|
||||
r->vlenb = (unsigned int)vlenb_val;
|
||||
|
||||
LOG_TARGET_INFO(target, "Vector support with vlenb=%u", r->vlenb);
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int examine_misa(struct target *target)
|
||||
{
|
||||
RISCV_INFO(r);
|
||||
|
||||
int res = init_cache_entry(target, GDB_REGNO_MISA);
|
||||
if (res != ERROR_OK)
|
||||
return res;
|
||||
|
||||
res = riscv_reg_get(target, &r->misa, GDB_REGNO_MISA);
|
||||
if (res != ERROR_OK)
|
||||
return res;
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int examine_mtopi(struct target *target)
|
||||
{
|
||||
RISCV_INFO(r);
|
||||
|
||||
/* Assume the registers exist */
|
||||
r->mtopi_readable = true;
|
||||
r->mtopei_readable = true;
|
||||
|
||||
int res = assume_reg_exist(target, GDB_REGNO_MTOPI);
|
||||
if (res != ERROR_OK)
|
||||
return res;
|
||||
res = assume_reg_exist(target, GDB_REGNO_MTOPEI);
|
||||
if (res != ERROR_OK)
|
||||
return res;
|
||||
|
||||
riscv_reg_t value;
|
||||
if (riscv_reg_get(target, &value, GDB_REGNO_MTOPI) != ERROR_OK) {
|
||||
r->mtopi_readable = false;
|
||||
r->mtopei_readable = false;
|
||||
} else if (riscv_reg_get(target, &value, GDB_REGNO_MTOPEI) != ERROR_OK) {
|
||||
LOG_TARGET_INFO(target, "S?aia detected without IMSIC");
|
||||
r->mtopei_readable = false;
|
||||
} else {
|
||||
LOG_TARGET_INFO(target, "S?aia detected with IMSIC");
|
||||
}
|
||||
res = riscv_reg_impl_set_exist(target, GDB_REGNO_MTOPI, r->mtopi_readable);
|
||||
if (res != ERROR_OK)
|
||||
return res;
|
||||
|
||||
return riscv_reg_impl_set_exist(target, GDB_REGNO_MTOPEI, r->mtopei_readable);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function assumes target's DM to be initialized (target is able to
|
||||
* access DMs registers, execute program buffer, etc.)
|
||||
*/
|
||||
int riscv013_reg_examine_all(struct target *target)
|
||||
{
|
||||
RISCV_INFO(r);
|
||||
|
||||
int res = riscv_reg_impl_init_cache(target);
|
||||
if (res != ERROR_OK)
|
||||
return res;
|
||||
|
||||
init_shared_reg_info(target);
|
||||
|
||||
assert(target->state == TARGET_HALTED);
|
||||
|
||||
res = examine_xlen(target);
|
||||
if (res != ERROR_OK)
|
||||
return res;
|
||||
|
||||
/* Reading CSRs may clobber "s0", "s1", so it should be possible to
|
||||
* save them in cache. */
|
||||
res = init_cache_entry(target, GDB_REGNO_S0);
|
||||
if (res != ERROR_OK)
|
||||
return res;
|
||||
res = init_cache_entry(target, GDB_REGNO_S1);
|
||||
if (res != ERROR_OK)
|
||||
return res;
|
||||
|
||||
res = examine_misa(target);
|
||||
if (res != ERROR_OK)
|
||||
return res;
|
||||
|
||||
/* Display this as early as possible to help people who are using
|
||||
* really slow simulators. */
|
||||
LOG_TARGET_DEBUG(target, " XLEN=%d, misa=0x%" PRIx64, riscv_xlen(target), r->misa);
|
||||
|
||||
res = examine_vlenb(target);
|
||||
if (res != ERROR_OK)
|
||||
return res;
|
||||
|
||||
riscv_reg_impl_init_vector_reg_type(target);
|
||||
|
||||
for (uint32_t regno = 0; regno < target->reg_cache->num_regs; ++regno)
|
||||
if (riscv013_init_reg(target, regno) != ERROR_OK)
|
||||
return ERROR_FAIL;
|
||||
res = examine_mtopi(target);
|
||||
if (res != ERROR_OK)
|
||||
return res;
|
||||
|
||||
if (riscv_reg_impl_expose_csrs(target) != ERROR_OK)
|
||||
return ERROR_FAIL;
|
||||
for (uint32_t regno = 0; regno < target->reg_cache->num_regs; ++regno) {
|
||||
res = init_cache_entry(target, regno);
|
||||
if (res != ERROR_OK)
|
||||
return res;
|
||||
}
|
||||
|
||||
res = riscv_reg_impl_expose_csrs(target);
|
||||
if (res != ERROR_OK)
|
||||
return res;
|
||||
|
||||
riscv_reg_impl_hide_csrs(target);
|
||||
|
||||
|
|
|
@ -13,10 +13,11 @@
|
|||
*/
|
||||
|
||||
/**
|
||||
* Init initialize register cache. After this function all registers can be
|
||||
* safely accessed via functions described here and in `riscv_reg.h`.
|
||||
* This function assumes target is halted.
|
||||
* After this function all registers can be safely accessed via functions
|
||||
* described here and in `riscv_reg.h`.
|
||||
*/
|
||||
int riscv013_reg_init_all(struct target *target);
|
||||
int riscv013_reg_examine_all(struct target *target);
|
||||
|
||||
/**
|
||||
* This function is used to save the value of a register in cache. The register
|
||||
|
|
|
@ -376,8 +376,19 @@ static bool is_known_standard_csr(unsigned int csr_num)
|
|||
return is_csr_in_buf[csr_num];
|
||||
}
|
||||
|
||||
static bool gdb_regno_exist(const struct target *target, uint32_t regno)
|
||||
bool riscv_reg_impl_gdb_regno_exist(const struct target *target, uint32_t regno)
|
||||
{
|
||||
switch (regno) {
|
||||
case GDB_REGNO_VLENB:
|
||||
case GDB_REGNO_MTOPI:
|
||||
case GDB_REGNO_MTOPEI:
|
||||
assert(false
|
||||
&& "Existence of other registers is determined "
|
||||
"depending on existence of these ones, so "
|
||||
"whether these register exist or not should be "
|
||||
"set explicitly.");
|
||||
};
|
||||
|
||||
if (regno <= GDB_REGNO_XPR15 ||
|
||||
regno == GDB_REGNO_PC ||
|
||||
regno == GDB_REGNO_PRIV)
|
||||
|
@ -403,7 +414,6 @@ static bool gdb_regno_exist(const struct target *target, uint32_t regno)
|
|||
case CSR_VL:
|
||||
case CSR_VCSR:
|
||||
case CSR_VTYPE:
|
||||
case CSR_VLENB:
|
||||
return vlenb_exists(target);
|
||||
case CSR_SCOUNTEREN:
|
||||
case CSR_SSTATUS:
|
||||
|
@ -599,14 +609,15 @@ static int resize_reg(const struct target *target, uint32_t regno, bool exist,
|
|||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int set_reg_exist(const struct target *target, uint32_t regno, bool exist)
|
||||
int riscv_reg_impl_set_exist(const struct target *target, uint32_t regno, bool exist)
|
||||
{
|
||||
const struct reg *reg = riscv_reg_impl_cache_entry(target, regno);
|
||||
assert(riscv_reg_impl_is_initialized(reg));
|
||||
return resize_reg(target, regno, exist, reg->size);
|
||||
}
|
||||
|
||||
int riscv_reg_impl_init_one(struct target *target, uint32_t regno, const struct reg_arch_type *reg_type)
|
||||
int riscv_reg_impl_init_cache_entry(struct target *target, uint32_t regno,
|
||||
bool exist, const struct reg_arch_type *reg_type)
|
||||
{
|
||||
struct reg * const reg = riscv_reg_impl_cache_entry(target, regno);
|
||||
if (riscv_reg_impl_is_initialized(reg))
|
||||
|
@ -634,8 +645,7 @@ int riscv_reg_impl_init_one(struct target *target, uint32_t regno, const struct
|
|||
reg_arch_info->target = target;
|
||||
reg_arch_info->custom_number = gdb_regno_custom_number(target, regno);
|
||||
}
|
||||
return resize_reg(target, regno, gdb_regno_exist(target, regno),
|
||||
gdb_regno_size(target, regno));
|
||||
return resize_reg(target, regno, exist, gdb_regno_size(target, regno));
|
||||
}
|
||||
|
||||
static int init_custom_register_names(struct list_head *expose_custom,
|
||||
|
@ -725,7 +735,7 @@ int riscv_reg_impl_expose_csrs(const struct target *target)
|
|||
csr_number);
|
||||
continue;
|
||||
}
|
||||
if (set_reg_exist(target, regno, /*exist*/ true) != ERROR_OK)
|
||||
if (riscv_reg_impl_set_exist(target, regno, /*exist*/ true) != ERROR_OK)
|
||||
return ERROR_FAIL;
|
||||
LOG_TARGET_DEBUG(target, "Exposing additional CSR %d (name=%s)",
|
||||
csr_number, reg->name);
|
||||
|
@ -834,15 +844,8 @@ static int riscv_set_or_write_register(struct target *target,
|
|||
return riscv_set_or_write_register(target, GDB_REGNO_DCSR, dcsr, write_through);
|
||||
}
|
||||
|
||||
if (!target->reg_cache) {
|
||||
assert(!target_was_examined(target));
|
||||
LOG_TARGET_DEBUG(target,
|
||||
"No cache, writing to target: %s <- 0x%" PRIx64,
|
||||
riscv_reg_gdb_regno_name(target, regid), value);
|
||||
return riscv013_set_register(target, regid, value);
|
||||
}
|
||||
|
||||
struct reg *reg = riscv_reg_impl_cache_entry(target, regid);
|
||||
assert(riscv_reg_impl_is_initialized(reg));
|
||||
|
||||
if (!reg->exist) {
|
||||
LOG_TARGET_DEBUG(target, "Register %s does not exist.", reg->name);
|
||||
|
@ -935,21 +938,15 @@ int riscv_reg_get(struct target *target, riscv_reg_t *value,
|
|||
RISCV_INFO(r);
|
||||
assert(r);
|
||||
if (r->dtm_version == DTM_DTMCS_VERSION_0_11)
|
||||
return riscv013_get_register(target, value, regid);
|
||||
return riscv011_get_register(target, value, regid);
|
||||
|
||||
keep_alive();
|
||||
|
||||
if (regid == GDB_REGNO_PC)
|
||||
return riscv_reg_get(target, value, GDB_REGNO_DPC);
|
||||
|
||||
if (!target->reg_cache) {
|
||||
assert(!target_was_examined(target));
|
||||
LOG_TARGET_DEBUG(target, "No cache, reading %s from target",
|
||||
riscv_reg_gdb_regno_name(target, regid));
|
||||
return riscv013_get_register(target, value, regid);
|
||||
}
|
||||
|
||||
struct reg *reg = riscv_reg_impl_cache_entry(target, regid);
|
||||
assert(riscv_reg_impl_is_initialized(reg));
|
||||
if (!reg->exist) {
|
||||
LOG_TARGET_DEBUG(target, "Register %s does not exist.", reg->name);
|
||||
return ERROR_FAIL;
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
* This file describes the helpers to use during register cache initialization
|
||||
* of a RISC-V target. Each cache entry proceedes through the following stages:
|
||||
* - not allocated before `riscv_reg_impl_init_cache()`
|
||||
* - not initialized before the call to `riscv_reg_impl_init_one()` with appropriate regno.
|
||||
* - not initialized before the call to `riscv_reg_impl_init_cache_entry()` with appropriate regno.
|
||||
* - initialized until `riscv_reg_free_all()` is called.
|
||||
*/
|
||||
static inline bool riscv_reg_impl_is_initialized(const struct reg *reg)
|
||||
|
@ -37,8 +37,18 @@ static inline bool riscv_reg_impl_is_initialized(const struct reg *reg)
|
|||
int riscv_reg_impl_init_cache(struct target *target);
|
||||
|
||||
/** Initialize register. */
|
||||
int riscv_reg_impl_init_one(struct target *target, uint32_t regno,
|
||||
const struct reg_arch_type *reg_type);
|
||||
int riscv_reg_impl_init_cache_entry(struct target *target, uint32_t regno,
|
||||
bool exist, const struct reg_arch_type *reg_type);
|
||||
|
||||
/**
|
||||
* For most registers, returns whether they exist or not.
|
||||
* For some registers the "exist" bit should be set explicitly.
|
||||
*/
|
||||
bool riscv_reg_impl_gdb_regno_exist(const struct target *target, uint32_t regno);
|
||||
|
||||
/** Mark register as existing or not. */
|
||||
int riscv_reg_impl_set_exist(const struct target *target,
|
||||
uint32_t regno, bool exist);
|
||||
|
||||
/** Return the entry in the register cache of the target. */
|
||||
struct reg *riscv_reg_impl_cache_entry(const struct target *target,
|
||||
|
|
Loading…
Reference in New Issue