From 6d357f4270f0be27cd93ff17af2fa456abd67380 Mon Sep 17 00:00:00 2001 From: Evgeniy Naydanov Date: Tue, 2 Jul 2024 17:01:51 +0300 Subject: [PATCH] target/riscv: reg cache entry is initialized before access * Register file examination is separated. * Allow to access registers through cache as early as possible to re-use general register access interface and propely track state of the register. * Reduces the number of operations: S0 and S1 are saved/restored only when needed (targets without abstract CSR access). Change-Id: I2e205ae4e88733a5c792f8a35cf30325c68d96b2 Signed-off-by: Evgeniy Naydanov --- src/target/riscv/riscv-011_reg.c | 4 +- src/target/riscv/riscv-013.c | 99 +++------------- src/target/riscv/riscv-013.h | 4 + src/target/riscv/riscv-013_reg.c | 186 ++++++++++++++++++++++++++++-- src/target/riscv/riscv-013_reg.h | 7 +- src/target/riscv/riscv_reg.c | 45 ++++---- src/target/riscv/riscv_reg_impl.h | 16 ++- 7 files changed, 239 insertions(+), 122 deletions(-) diff --git a/src/target/riscv/riscv-011_reg.c b/src/target/riscv/riscv-011_reg.c index 7f2906423..44ea1a49a 100644 --- a/src/target/riscv/riscv-011_reg.c +++ b/src/target/riscv/riscv-011_reg.c @@ -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) diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c index ae36a063d..63b13b86b 100644 --- a/src/target/riscv/riscv-013.c +++ b/src/target/riscv/riscv-013.c @@ -727,7 +727,7 @@ static int abstract_cmd_batch_check_and_clear_cmderr(struct target *target, 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) diff --git a/src/target/riscv/riscv-013.h b/src/target/riscv/riscv-013.h index f39393c07..ca2d4aefc 100644 --- a/src/target/riscv/riscv-013.h +++ b/src/target/riscv/riscv-013.h @@ -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 */ diff --git a/src/target/riscv/riscv-013_reg.c b/src/target/riscv/riscv-013_reg.c index a71a01c7b..ad1130d63 100644 --- a/src/target/riscv/riscv-013_reg.c +++ b/src/target/riscv/riscv-013_reg.c @@ -9,6 +9,7 @@ #include "riscv_reg.h" #include "riscv_reg_impl.h" #include "riscv-013.h" +#include "debug_defines.h" #include 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)); +} + +/** + * 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) +{ + return riscv_reg_impl_init_cache_entry(target, regno, + /* exist */ true, riscv013_gdb_regno_reg_type(regno)); } -int riscv013_reg_init_all(struct target *target) +static int examine_xlen(struct target *target) { - if (riscv_reg_impl_init_cache(target) != ERROR_OK) + 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); diff --git a/src/target/riscv/riscv-013_reg.h b/src/target/riscv/riscv-013_reg.h index e7a944747..e542a3501 100644 --- a/src/target/riscv/riscv-013_reg.h +++ b/src/target/riscv/riscv-013_reg.h @@ -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 diff --git a/src/target/riscv/riscv_reg.c b/src/target/riscv/riscv_reg.c index 6cf67dded..eefd4029a 100644 --- a/src/target/riscv/riscv_reg.c +++ b/src/target/riscv/riscv_reg.c @@ -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; diff --git a/src/target/riscv/riscv_reg_impl.h b/src/target/riscv/riscv_reg_impl.h index 906a5b6d5..9bfbbc93d 100644 --- a/src/target/riscv/riscv_reg_impl.h +++ b/src/target/riscv/riscv_reg_impl.h @@ -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 explisitly. + */ +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,