target/riscv: Adding register tables to make register names consistent

Added the ability to enter dimensionless registers

Change-Id: I1b781959ce4690ec65304142bd9a7c6f540b3e86
Signed-off-by: Anastasiya Chernikova <anastasiya.chernikova@syntacore.com>
This commit is contained in:
Anastasiya Chernikova 2023-10-12 11:29:08 +03:00
parent aad90d8989
commit 805d394ff8
5 changed files with 299 additions and 483 deletions

View File

@ -120,6 +120,6 @@ enum gdb_regno {
GDB_REGNO_COUNT
};
const char *gdb_regno_name(enum gdb_regno regno);
const char *gdb_regno_name(struct target *target, enum gdb_regno regno);
#endif

View File

@ -1045,7 +1045,7 @@ static int read_remote_csr(struct target *target, uint64_t *value, uint32_t csr)
uint32_t exception = cache_get32(target, info->dramsize-1);
if (exception) {
LOG_WARNING("Got exception 0x%x when reading %s", exception,
gdb_regno_name(GDB_REGNO_CSR0 + csr));
gdb_regno_name(target, GDB_REGNO_CSR0 + csr));
*value = ~0;
return ERROR_FAIL;
}
@ -1247,7 +1247,7 @@ static int register_read(struct target *target, riscv_reg_t *value, int regnum)
uint32_t exception = cache_get32(target, info->dramsize-1);
if (exception) {
LOG_WARNING("Got exception 0x%x when reading %s", exception, gdb_regno_name(regnum));
LOG_WARNING("Got exception 0x%x when reading %s", exception, gdb_regno_name(target, regnum));
*value = ~0;
return ERROR_FAIL;
}
@ -1322,7 +1322,7 @@ static int register_write(struct target *target, unsigned int number,
uint32_t exception = cache_get32(target, info->dramsize-1);
if (exception) {
LOG_WARNING("Got exception 0x%x when writing %s", exception,
gdb_regno_name(number));
gdb_regno_name(target, number));
return ERROR_FAIL;
}

View File

@ -937,7 +937,7 @@ static uint32_t access_register_command(struct target *target, uint32_t number,
break;
default:
LOG_TARGET_ERROR(target, "%d-bit register %s not supported.",
size, gdb_regno_name(number));
size, gdb_regno_name(target, number));
assert(0);
}
@ -1173,7 +1173,7 @@ static int prep_for_register_access(struct target *target,
return ERROR_OK;
LOG_TARGET_DEBUG(target, "Preparing mstatus to access %s",
gdb_regno_name(regno));
gdb_regno_name(target, regno));
assert(target->state == TARGET_HALTED &&
"The target must be halted to modify and then restore mstatus");
@ -1193,7 +1193,7 @@ static int prep_for_register_access(struct target *target,
return ERROR_FAIL;
LOG_TARGET_DEBUG(target, "Prepared to access %s (mstatus=0x%" PRIx64 ")",
gdb_regno_name(regno), new_mstatus);
gdb_regno_name(target, regno), new_mstatus);
return ERROR_OK;
}
@ -1482,7 +1482,7 @@ static int register_read_progbuf(struct target *target, uint64_t *value,
return csr_read_progbuf(target, value, number);
LOG_TARGET_ERROR(target, "Unexpected read of %s via program buffer.",
gdb_regno_name(number));
gdb_regno_name(target, number));
return ERROR_FAIL;
}
@ -1628,7 +1628,7 @@ static int register_write_progbuf(struct target *target, enum gdb_regno number,
return csr_write_progbuf(target, number, value);
LOG_TARGET_ERROR(target, "Unexpected write to %s via program buffer.",
gdb_regno_name(number));
gdb_regno_name(target, number));
return ERROR_FAIL;
}
@ -1640,7 +1640,7 @@ static int register_write_direct(struct target *target, enum gdb_regno number,
riscv_reg_t value)
{
LOG_TARGET_DEBUG(target, "Writing 0x%" PRIx64 " to %s", value,
gdb_regno_name(number));
gdb_regno_name(target, number));
if (target->state != TARGET_HALTED)
return register_write_abstract(target, number, value);
@ -1658,7 +1658,7 @@ static int register_write_direct(struct target *target, enum gdb_regno number,
return ERROR_FAIL;
if (result == ERROR_OK)
LOG_TARGET_DEBUG(target, "%s <- 0x%" PRIx64, gdb_regno_name(number),
LOG_TARGET_DEBUG(target, "%s <- 0x%" PRIx64, gdb_regno_name(target, number),
value);
return result;
@ -1668,7 +1668,7 @@ static int register_write_direct(struct target *target, enum gdb_regno number,
static int register_read_direct(struct target *target, riscv_reg_t *value,
enum gdb_regno number)
{
LOG_TARGET_DEBUG(target, "Reading %s", gdb_regno_name(number));
LOG_TARGET_DEBUG(target, "Reading %s", gdb_regno_name(target, number));
if (target->state != TARGET_HALTED)
return register_read_abstract(target, value, number);
@ -1687,7 +1687,7 @@ static int register_read_direct(struct target *target, riscv_reg_t *value,
return ERROR_FAIL;
if (result == ERROR_OK)
LOG_TARGET_DEBUG(target, "%s = 0x%" PRIx64, gdb_regno_name(number),
LOG_TARGET_DEBUG(target, "%s = 0x%" PRIx64, gdb_regno_name(target, number),
*value);
return result;
@ -2367,7 +2367,7 @@ static int riscv013_get_register_buf(struct target *target,
} else {
LOG_TARGET_ERROR(target,
"Failed to execute vmv/vslide1down while reading %s",
gdb_regno_name(regno));
gdb_regno_name(target, regno));
break;
}
}
@ -4666,7 +4666,7 @@ struct target_type riscv013_target = {
static int riscv013_get_register(struct target *target,
riscv_reg_t *value, enum gdb_regno rid)
{
LOG_TARGET_DEBUG(target, "reading register %s", gdb_regno_name(rid));
LOG_TARGET_DEBUG(target, "reading register %s", gdb_regno_name(target, rid));
if (dm013_select_target(target) != ERROR_OK)
return ERROR_FAIL;
@ -4683,7 +4683,7 @@ static int riscv013_set_register(struct target *target, enum gdb_regno rid,
riscv_reg_t value)
{
LOG_TARGET_DEBUG(target, "writing 0x%" PRIx64 " to register %s",
value, gdb_regno_name(rid));
value, gdb_regno_name(target, rid));
if (dm013_select_target(target) != ERROR_OK)
return ERROR_FAIL;

View File

@ -488,6 +488,21 @@ static void riscv_free_registers(struct target *target)
}
}
static void free_reg_names(struct target *target);
static void free_custom_register_names(struct target *target)
{
RISCV_INFO(info);
if (!info->custom_register_names.reg_names)
return;
for (unsigned int i = 0; i < info->custom_register_names.num_entries; i++)
free(info->custom_register_names.reg_names[i]);
free(info->custom_register_names.reg_names);
info->custom_register_names.reg_names = NULL;
}
static void riscv_deinit_target(struct target *target)
{
LOG_TARGET_DEBUG(target, "riscv_deinit_target()");
@ -524,7 +539,7 @@ static void riscv_deinit_target(struct target *target)
free(entry);
}
free(info->reg_names);
free_reg_names(target);
free(target->arch_info);
target->arch_info = NULL;
@ -2670,7 +2685,8 @@ static int riscv_run_algorithm(struct target *target, int num_mem_params,
riscv_reg_t reg_value;
if (riscv_get_register(target, &reg_value, regno) != ERROR_OK)
break;
LOG_TARGET_ERROR(target, "%s = 0x%" PRIx64, gdb_regno_name(regno), reg_value);
LOG_TARGET_ERROR(target, "%s = 0x%" PRIx64, gdb_regno_name(target, regno), reg_value);
}
return ERROR_TARGET_TIMEOUT;
}
@ -5011,7 +5027,7 @@ static int riscv_set_or_write_register(struct target *target,
assert(!target_was_examined(target));
LOG_TARGET_DEBUG(target,
"No cache, writing to target: %s <- 0x%" PRIx64,
gdb_regno_name(regid), value);
gdb_regno_name(target, regid), value);
return r->set_register(target, regid, value);
}
@ -5106,7 +5122,7 @@ int riscv_get_register(struct target *target, riscv_reg_t *value,
if (!target->reg_cache) {
assert(!target_was_examined(target));
LOG_TARGET_DEBUG(target, "No cache, reading %s from target",
gdb_regno_name(regid));
gdb_regno_name(target, regid));
return r->get_register(target, value, regid);
}
@ -5143,7 +5159,7 @@ int riscv_save_register(struct target *target, enum gdb_regno regid)
{
if (target->state != TARGET_HALTED) {
LOG_TARGET_ERROR(target, "Can't save register %s on a hart that is not halted.",
gdb_regno_name(regid));
gdb_regno_name(target, regid));
return ERROR_FAIL;
}
assert(gdb_regno_cacheable(regid, /* is write? */ false) &&
@ -5322,7 +5338,7 @@ static int disable_trigger_if_dmode(struct target *target, riscv_reg_t tdata1)
* something.
* Disable any hardware triggers that have dmode set. We can't have set them
* ourselves. Maybe they're left over from some killed debug session.
* */
*/
int riscv_enumerate_triggers(struct target *target)
{
RISCV_INFO(r);
@ -5381,188 +5397,174 @@ int riscv_enumerate_triggers(struct target *target)
return ERROR_OK;
}
const char *gdb_regno_name(enum gdb_regno regno)
static char *init_reg_name(const char *name)
{
static char buf[32];
const int size_buf = strlen(name) + 1;
switch (regno) {
case GDB_REGNO_ZERO:
return "zero";
case GDB_REGNO_RA:
return "ra";
case GDB_REGNO_SP:
return "sp";
case GDB_REGNO_GP:
return "gp";
case GDB_REGNO_TP:
return "tp";
case GDB_REGNO_T0:
return "t0";
case GDB_REGNO_T1:
return "t1";
case GDB_REGNO_T2:
return "t2";
case GDB_REGNO_S0:
return "s0";
case GDB_REGNO_S1:
return "s1";
case GDB_REGNO_A0:
return "a0";
case GDB_REGNO_A1:
return "a1";
case GDB_REGNO_A2:
return "a2";
case GDB_REGNO_A3:
return "a3";
case GDB_REGNO_A4:
return "a4";
case GDB_REGNO_A5:
return "a5";
case GDB_REGNO_A6:
return "a6";
case GDB_REGNO_A7:
return "a7";
case GDB_REGNO_S2:
return "s2";
case GDB_REGNO_S3:
return "s3";
case GDB_REGNO_S4:
return "s4";
case GDB_REGNO_S5:
return "s5";
case GDB_REGNO_S6:
return "s6";
case GDB_REGNO_S7:
return "s7";
case GDB_REGNO_S8:
return "s8";
case GDB_REGNO_S9:
return "s9";
case GDB_REGNO_S10:
return "s10";
case GDB_REGNO_S11:
return "s11";
case GDB_REGNO_T3:
return "t3";
case GDB_REGNO_T4:
return "t4";
case GDB_REGNO_T5:
return "t5";
case GDB_REGNO_T6:
return "t6";
case GDB_REGNO_PC:
return "pc";
case GDB_REGNO_FPR0:
return "fpr0";
case GDB_REGNO_FPR31:
return "fpr31";
case GDB_REGNO_CSR0:
return "csr0";
case GDB_REGNO_TSELECT:
return "tselect";
case GDB_REGNO_TDATA1:
return "tdata1";
case GDB_REGNO_TDATA2:
return "tdata2";
case GDB_REGNO_MISA:
return "misa";
case GDB_REGNO_DPC:
return "dpc";
case GDB_REGNO_DCSR:
return "dcsr";
case GDB_REGNO_DSCRATCH0:
return "dscratch0";
case GDB_REGNO_MSTATUS:
return "mstatus";
case GDB_REGNO_MEPC:
return "mepc";
case GDB_REGNO_MCAUSE:
return "mcause";
case GDB_REGNO_PRIV:
return "priv";
case GDB_REGNO_SATP:
return "satp";
case GDB_REGNO_VTYPE:
return "vtype";
case GDB_REGNO_VL:
return "vl";
case GDB_REGNO_V0:
return "v0";
case GDB_REGNO_V1:
return "v1";
case GDB_REGNO_V2:
return "v2";
case GDB_REGNO_V3:
return "v3";
case GDB_REGNO_V4:
return "v4";
case GDB_REGNO_V5:
return "v5";
case GDB_REGNO_V6:
return "v6";
case GDB_REGNO_V7:
return "v7";
case GDB_REGNO_V8:
return "v8";
case GDB_REGNO_V9:
return "v9";
case GDB_REGNO_V10:
return "v10";
case GDB_REGNO_V11:
return "v11";
case GDB_REGNO_V12:
return "v12";
case GDB_REGNO_V13:
return "v13";
case GDB_REGNO_V14:
return "v14";
case GDB_REGNO_V15:
return "v15";
case GDB_REGNO_V16:
return "v16";
case GDB_REGNO_V17:
return "v17";
case GDB_REGNO_V18:
return "v18";
case GDB_REGNO_V19:
return "v19";
case GDB_REGNO_V20:
return "v20";
case GDB_REGNO_V21:
return "v21";
case GDB_REGNO_V22:
return "v22";
case GDB_REGNO_V23:
return "v23";
case GDB_REGNO_V24:
return "v24";
case GDB_REGNO_V25:
return "v25";
case GDB_REGNO_V26:
return "v26";
case GDB_REGNO_V27:
return "v27";
case GDB_REGNO_V28:
return "v28";
case GDB_REGNO_V29:
return "v29";
case GDB_REGNO_V30:
return "v30";
case GDB_REGNO_V31:
return "v31";
default:
if (regno <= GDB_REGNO_XPR31)
sprintf(buf, "x%d", regno - GDB_REGNO_ZERO);
else if (regno >= GDB_REGNO_CSR0 && regno <= GDB_REGNO_CSR4095)
sprintf(buf, "csr%d", regno - GDB_REGNO_CSR0);
else if (regno >= GDB_REGNO_FPR0 && regno <= GDB_REGNO_FPR31)
sprintf(buf, "f%d", regno - GDB_REGNO_FPR0);
else
sprintf(buf, "gdb_regno_%d", regno);
return buf;
char * const buf = calloc(size_buf, sizeof(char));
if (!buf) {
LOG_ERROR("Failed to allocate memory for a register name.");
return NULL;
}
strcpy(buf, name);
return buf;
}
static char *init_reg_name_with_prefix(const char *name_prefix,
unsigned int num)
{
const int size_buf = snprintf(NULL, 0, "%s%d", name_prefix, num) + 1;
char * const buf = calloc(size_buf, sizeof(char));
if (!buf) {
LOG_ERROR("Failed to allocate memory for a register name.");
return NULL;
}
int result = snprintf(buf, size_buf, "%s%d", name_prefix, num);
assert(result > 0 && result <= (size_buf - 1));
return buf;
}
static const char * const default_reg_names[GDB_REGNO_COUNT] = {
[GDB_REGNO_ZERO] = "zero",
[GDB_REGNO_RA] = "ra",
[GDB_REGNO_SP] = "sp",
[GDB_REGNO_GP] = "gp",
[GDB_REGNO_TP] = "tp",
[GDB_REGNO_T0] = "t0",
[GDB_REGNO_T1] = "t1",
[GDB_REGNO_T2] = "t2",
[GDB_REGNO_FP] = "fp",
[GDB_REGNO_S1] = "s1",
[GDB_REGNO_A0] = "a0",
[GDB_REGNO_A1] = "a1",
[GDB_REGNO_A2] = "a2",
[GDB_REGNO_A3] = "a3",
[GDB_REGNO_A4] = "a4",
[GDB_REGNO_A5] = "a5",
[GDB_REGNO_A6] = "a6",
[GDB_REGNO_A7] = "a7",
[GDB_REGNO_S2] = "s2",
[GDB_REGNO_S3] = "s3",
[GDB_REGNO_S4] = "s4",
[GDB_REGNO_S5] = "s5",
[GDB_REGNO_S6] = "s6",
[GDB_REGNO_S7] = "s7",
[GDB_REGNO_S8] = "s8",
[GDB_REGNO_S9] = "s9",
[GDB_REGNO_S10] = "s10",
[GDB_REGNO_S11] = "s11",
[GDB_REGNO_T3] = "t3",
[GDB_REGNO_T4] = "t4",
[GDB_REGNO_T5] = "t5",
[GDB_REGNO_T6] = "t6",
[GDB_REGNO_PC] = "pc",
[GDB_REGNO_CSR0] = "csr0",
[GDB_REGNO_PRIV] = "priv",
[GDB_REGNO_FT0] = "ft0",
[GDB_REGNO_FT1] = "ft1",
[GDB_REGNO_FT2] = "ft2",
[GDB_REGNO_FT3] = "ft3",
[GDB_REGNO_FT4] = "ft4",
[GDB_REGNO_FT5] = "ft5",
[GDB_REGNO_FT6] = "ft6",
[GDB_REGNO_FT7] = "ft7",
[GDB_REGNO_FS0] = "fs0",
[GDB_REGNO_FS1] = "fs1",
[GDB_REGNO_FA0] = "fa0",
[GDB_REGNO_FA1] = "fa1",
[GDB_REGNO_FA2] = "fa2",
[GDB_REGNO_FA3] = "fa3",
[GDB_REGNO_FA4] = "fa4",
[GDB_REGNO_FA5] = "fa5",
[GDB_REGNO_FA6] = "fa6",
[GDB_REGNO_FA7] = "fa7",
[GDB_REGNO_FS2] = "fs2",
[GDB_REGNO_FS3] = "fs3",
[GDB_REGNO_FS4] = "fs4",
[GDB_REGNO_FS5] = "fs5",
[GDB_REGNO_FS6] = "fs6",
[GDB_REGNO_FS7] = "fs7",
[GDB_REGNO_FS8] = "fs8",
[GDB_REGNO_FS9] = "fs9",
[GDB_REGNO_FS10] = "fs10",
[GDB_REGNO_FS11] = "fs11",
[GDB_REGNO_FT8] = "ft8",
[GDB_REGNO_FT9] = "ft9",
[GDB_REGNO_FT10] = "ft10",
[GDB_REGNO_FT11] = "ft11",
#define DECLARE_CSR(csr_name, number)[(number) + GDB_REGNO_CSR0] = #csr_name,
#include "encoding.h"
#undef DECLARE_CSR
};
static void free_reg_names(struct target *target)
{
RISCV_INFO(info);
if (!info->reg_names)
return;
for (unsigned int i = 0; i < GDB_REGNO_COUNT; ++i)
free(info->reg_names[i]);
free(info->reg_names);
info->reg_names = NULL;
free_custom_register_names(target);
}
static void init_custom_csr_names(struct target *target)
{
RISCV_INFO(info);
range_list_t *entry;
list_for_each_entry(entry, &info->expose_csr, list) {
if (!entry->name)
continue;
assert(entry->low == entry->high);
const unsigned int regno = entry->low + GDB_REGNO_CSR0;
assert(regno <= GDB_REGNO_CSR4095);
if (info->reg_names[regno])
return;
info->reg_names[regno] = init_reg_name(entry->name);
}
}
const char *gdb_regno_name(struct target *target, unsigned int regno)
{
RISCV_INFO(info);
if (regno >= GDB_REGNO_COUNT) {
assert(info->custom_register_names.reg_names);
assert(regno - GDB_REGNO_COUNT <= info->custom_register_names.num_entries);
return info->custom_register_names.reg_names[regno - GDB_REGNO_COUNT];
}
if (!info->reg_names)
info->reg_names = calloc(GDB_REGNO_COUNT, sizeof(char *));
if (info->reg_names[regno])
return info->reg_names[regno];
if (default_reg_names[regno])
return default_reg_names[regno];
if (regno <= GDB_REGNO_XPR31) {
info->reg_names[regno] = init_reg_name_with_prefix("x", regno - GDB_REGNO_ZERO);
return info->reg_names[regno];
}
if (regno <= GDB_REGNO_V31 && regno >= GDB_REGNO_V0) {
info->reg_names[regno] = init_reg_name_with_prefix("v", regno - GDB_REGNO_V0);
return info->reg_names[regno];
}
if (regno >= GDB_REGNO_CSR0 && regno <= GDB_REGNO_CSR4095) {
init_custom_csr_names(target);
info->reg_names[regno] = init_reg_name_with_prefix("csr", regno - GDB_REGNO_CSR0);
return info->reg_names[regno];
}
assert(!"Encountered uninitialized entry in reg_names table");
return NULL;
}
/**
* This function is the handler of user's request to read a register.
@ -5662,14 +5664,54 @@ static struct reg_arch_type riscv_reg_arch_type = {
.set = register_set
};
struct csr_info {
unsigned number;
const char *name;
};
static int cmp_csr_info(const void *p1, const void *p2)
static int init_custom_register_names(struct list_head *expose_custom,
struct reg_name_table *custom_register_names)
{
return (int) (((struct csr_info *)p1)->number) - (int) (((struct csr_info *)p2)->number);
unsigned int custom_regs_num = 0;
if (!list_empty(expose_custom)) {
range_list_t *entry;
list_for_each_entry(entry, expose_custom, list)
custom_regs_num += entry->high - entry->low + 1;
}
if (!custom_regs_num)
return ERROR_OK;
custom_register_names->reg_names = calloc(custom_regs_num, sizeof(char *));
if (!custom_register_names->reg_names) {
LOG_ERROR("Failed to allocate memory for custom_register_names->reg_names");
return ERROR_FAIL;
}
custom_register_names->num_entries = custom_regs_num;
char **reg_names = custom_register_names->reg_names;
range_list_t *range;
unsigned int next_custom_reg_index = 0;
list_for_each_entry(range, expose_custom, list) {
for (unsigned int custom_number = range->low; custom_number <= range->high; ++custom_number) {
if (range->name)
reg_names[next_custom_reg_index] = init_reg_name(range->name);
else
reg_names[next_custom_reg_index] =
init_reg_name_with_prefix("custom", custom_number);
if (!reg_names[next_custom_reg_index])
return ERROR_FAIL;
++next_custom_reg_index;
}
}
return ERROR_OK;
}
static bool is_known_standard_csr(unsigned int csr_num)
{
static const bool is_csr_in_buf[GDB_REGNO_CSR4095 - GDB_REGNO_CSR0 + 1] = {
#define DECLARE_CSR(csr_name, number)[number] = true,
#include "encoding.h"
#undef DECLARE_CSR
};
assert(csr_num < ARRAY_SIZE(is_csr_in_buf));
return is_csr_in_buf[csr_num];
}
int riscv_init_registers(struct target *target)
@ -5679,32 +5721,27 @@ int riscv_init_registers(struct target *target)
riscv_free_registers(target);
target->reg_cache = calloc(1, sizeof(*target->reg_cache));
if (!target->reg_cache)
if (!target->reg_cache) {
LOG_TARGET_ERROR(target, "Failed to allocate memory for target->reg_cache");
return ERROR_FAIL;
}
target->reg_cache->name = "RISC-V Registers";
target->reg_cache->num_regs = GDB_REGNO_COUNT;
if (!list_empty(&info->expose_custom)) {
range_list_t *entry;
list_for_each_entry(entry, &info->expose_custom, list)
target->reg_cache->num_regs += entry->high - entry->low + 1;
if (init_custom_register_names(&info->expose_custom, &info->custom_register_names) != ERROR_OK) {
LOG_TARGET_ERROR(target, "init_custom_register_names failed");
return ERROR_FAIL;
}
target->reg_cache->num_regs = GDB_REGNO_COUNT + info->custom_register_names.num_entries;
LOG_TARGET_DEBUG(target, "create register cache for %d registers",
target->reg_cache->num_regs);
target->reg_cache->reg_list =
calloc(target->reg_cache->num_regs, sizeof(struct reg));
if (!target->reg_cache->reg_list)
if (!target->reg_cache->reg_list) {
LOG_TARGET_ERROR(target, "Failed to allocate memory for target->reg_cache->reg_list");
return ERROR_FAIL;
const unsigned int max_reg_name_len = 12;
free(info->reg_names);
info->reg_names =
calloc(target->reg_cache->num_regs, max_reg_name_len);
if (!info->reg_names)
return ERROR_FAIL;
char *reg_name = info->reg_names;
}
static struct reg_feature feature_cpu = {
.name = "org.gnu.gdb.riscv.cpu"
@ -5836,152 +5873,45 @@ int riscv_init_registers(struct target *target)
info->type_vector.type_class = REG_TYPE_CLASS_UNION;
info->type_vector.reg_type_union = &info->vector_union;
struct csr_info csr_info[] = {
#define DECLARE_CSR(name, number) { number, #name },
#include "encoding.h"
#undef DECLARE_CSR
};
/* encoding.h does not contain the registers in sorted order. */
qsort(csr_info, ARRAY_SIZE(csr_info), sizeof(*csr_info), cmp_csr_info);
unsigned csr_info_index = 0;
int custom_within_range = 0;
riscv_reg_info_t *shared_reg_info = calloc(1, sizeof(riscv_reg_info_t));
if (!shared_reg_info)
return ERROR_FAIL;
shared_reg_info->target = target;
int custom_within_range = 0;
/* When gdb requests register N, gdb_get_register_packet() assumes that this
* is register at index N in reg_list. So if there are certain registers
* that don't exist, we need to leave holes in the list (or renumber, but
* it would be nice not to have yet another set of numbers to translate
* between). */
for (uint32_t number = 0; number < target->reg_cache->num_regs; number++) {
struct reg *r = &target->reg_cache->reg_list[number];
for (uint32_t reg_num = 0; reg_num < target->reg_cache->num_regs; reg_num++) {
struct reg *r = &target->reg_cache->reg_list[reg_num];
r->dirty = false;
r->valid = false;
r->exist = true;
r->type = &riscv_reg_arch_type;
r->arch_info = shared_reg_info;
r->number = number;
r->number = reg_num;
r->size = riscv_xlen(target);
/* r->size is set in riscv_invalidate_register_cache, maybe because the
* target is in theory allowed to change XLEN on us. But I expect a lot
* of other things to break in that case as well. */
if (number <= GDB_REGNO_XPR31) {
r->exist = number <= GDB_REGNO_XPR15 ||
r->name = gdb_regno_name(target, reg_num);
if (reg_num <= GDB_REGNO_XPR31) {
r->exist = reg_num <= GDB_REGNO_XPR15 ||
!riscv_supports_extension(target, 'E');
/* TODO: For now we fake that all GPRs exist because otherwise gdb
* doesn't work. */
r->exist = true;
r->caller_save = true;
switch (number) {
case GDB_REGNO_ZERO:
r->name = "zero";
break;
case GDB_REGNO_RA:
r->name = "ra";
break;
case GDB_REGNO_SP:
r->name = "sp";
break;
case GDB_REGNO_GP:
r->name = "gp";
break;
case GDB_REGNO_TP:
r->name = "tp";
break;
case GDB_REGNO_T0:
r->name = "t0";
break;
case GDB_REGNO_T1:
r->name = "t1";
break;
case GDB_REGNO_T2:
r->name = "t2";
break;
case GDB_REGNO_FP:
r->name = "fp";
break;
case GDB_REGNO_S1:
r->name = "s1";
break;
case GDB_REGNO_A0:
r->name = "a0";
break;
case GDB_REGNO_A1:
r->name = "a1";
break;
case GDB_REGNO_A2:
r->name = "a2";
break;
case GDB_REGNO_A3:
r->name = "a3";
break;
case GDB_REGNO_A4:
r->name = "a4";
break;
case GDB_REGNO_A5:
r->name = "a5";
break;
case GDB_REGNO_A6:
r->name = "a6";
break;
case GDB_REGNO_A7:
r->name = "a7";
break;
case GDB_REGNO_S2:
r->name = "s2";
break;
case GDB_REGNO_S3:
r->name = "s3";
break;
case GDB_REGNO_S4:
r->name = "s4";
break;
case GDB_REGNO_S5:
r->name = "s5";
break;
case GDB_REGNO_S6:
r->name = "s6";
break;
case GDB_REGNO_S7:
r->name = "s7";
break;
case GDB_REGNO_S8:
r->name = "s8";
break;
case GDB_REGNO_S9:
r->name = "s9";
break;
case GDB_REGNO_S10:
r->name = "s10";
break;
case GDB_REGNO_S11:
r->name = "s11";
break;
case GDB_REGNO_T3:
r->name = "t3";
break;
case GDB_REGNO_T4:
r->name = "t4";
break;
case GDB_REGNO_T5:
r->name = "t5";
break;
case GDB_REGNO_T6:
r->name = "t6";
break;
}
r->group = "general";
r->feature = &feature_cpu;
} else if (number == GDB_REGNO_PC) {
} else if (reg_num == GDB_REGNO_PC) {
r->caller_save = true;
sprintf(reg_name, "pc");
r->group = "general";
r->feature = &feature_cpu;
} else if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31) {
} else if (reg_num >= GDB_REGNO_FPR0 && reg_num <= GDB_REGNO_FPR31) {
r->caller_save = true;
if (riscv_supports_extension(target, 'D')) {
r->size = 64;
@ -5995,119 +5925,14 @@ int riscv_init_registers(struct target *target)
} else {
r->exist = false;
}
switch (number) {
case GDB_REGNO_FT0:
r->name = "ft0";
break;
case GDB_REGNO_FT1:
r->name = "ft1";
break;
case GDB_REGNO_FT2:
r->name = "ft2";
break;
case GDB_REGNO_FT3:
r->name = "ft3";
break;
case GDB_REGNO_FT4:
r->name = "ft4";
break;
case GDB_REGNO_FT5:
r->name = "ft5";
break;
case GDB_REGNO_FT6:
r->name = "ft6";
break;
case GDB_REGNO_FT7:
r->name = "ft7";
break;
case GDB_REGNO_FS0:
r->name = "fs0";
break;
case GDB_REGNO_FS1:
r->name = "fs1";
break;
case GDB_REGNO_FA0:
r->name = "fa0";
break;
case GDB_REGNO_FA1:
r->name = "fa1";
break;
case GDB_REGNO_FA2:
r->name = "fa2";
break;
case GDB_REGNO_FA3:
r->name = "fa3";
break;
case GDB_REGNO_FA4:
r->name = "fa4";
break;
case GDB_REGNO_FA5:
r->name = "fa5";
break;
case GDB_REGNO_FA6:
r->name = "fa6";
break;
case GDB_REGNO_FA7:
r->name = "fa7";
break;
case GDB_REGNO_FS2:
r->name = "fs2";
break;
case GDB_REGNO_FS3:
r->name = "fs3";
break;
case GDB_REGNO_FS4:
r->name = "fs4";
break;
case GDB_REGNO_FS5:
r->name = "fs5";
break;
case GDB_REGNO_FS6:
r->name = "fs6";
break;
case GDB_REGNO_FS7:
r->name = "fs7";
break;
case GDB_REGNO_FS8:
r->name = "fs8";
break;
case GDB_REGNO_FS9:
r->name = "fs9";
break;
case GDB_REGNO_FS10:
r->name = "fs10";
break;
case GDB_REGNO_FS11:
r->name = "fs11";
break;
case GDB_REGNO_FT8:
r->name = "ft8";
break;
case GDB_REGNO_FT9:
r->name = "ft9";
break;
case GDB_REGNO_FT10:
r->name = "ft10";
break;
case GDB_REGNO_FT11:
r->name = "ft11";
break;
}
r->group = "float";
r->feature = &feature_fpu;
} else if (number >= GDB_REGNO_CSR0 && number <= GDB_REGNO_CSR4095) {
} else if (reg_num >= GDB_REGNO_CSR0 && reg_num <= GDB_REGNO_CSR4095) {
r->group = "csr";
r->feature = &feature_csr;
unsigned csr_number = number - GDB_REGNO_CSR0;
const unsigned int csr_num = reg_num - GDB_REGNO_CSR0;
while (csr_info[csr_info_index].number < csr_number &&
csr_info_index < ARRAY_SIZE(csr_info) - 1) {
csr_info_index++;
}
if (csr_info[csr_info_index].number == csr_number) {
r->name = csr_info[csr_info_index].name;
} else {
sprintf(reg_name, "csr%d", csr_number);
if (!is_known_standard_csr(csr_num)) {
/* Assume unnamed registers don't exist, unless we have some
* configuration that tells us otherwise. That's important
* because eg. Eclipse crashes if a target has too many
@ -6116,7 +5941,7 @@ int riscv_init_registers(struct target *target)
r->exist = false;
}
switch (csr_number) {
switch (csr_num) {
case CSR_DCSR:
case CSR_MVENDORID:
case CSR_MCOUNTINHIBIT:
@ -6306,67 +6131,60 @@ int riscv_init_registers(struct target *target)
if (!r->exist && !list_empty(&info->expose_csr)) {
range_list_t *entry;
list_for_each_entry(entry, &info->expose_csr, list)
if ((entry->low <= csr_number) && (csr_number <= entry->high)) {
if (entry->name) {
*reg_name = 0;
r->name = entry->name;
}
LOG_TARGET_DEBUG(target, "Exposing additional CSR %d (name=%s).",
csr_number, entry->name ? entry->name : reg_name);
if (entry->low <= csr_num && csr_num <= entry->high) {
LOG_TARGET_DEBUG(target, "Exposing additional CSR %d (name=%s)",
csr_num, r->name);
r->exist = true;
break;
}
} else if (r->exist && !list_empty(&info->hide_csr)) {
range_list_t *entry;
list_for_each_entry(entry, &info->hide_csr, list)
if (entry->low <= csr_number && csr_number <= entry->high) {
LOG_TARGET_DEBUG(target, "Hiding CSR %d (name=%s).", csr_number, r->name);
if (entry->low <= csr_num && csr_num <= entry->high) {
LOG_TARGET_DEBUG(target, "Hiding CSR %d (name=%s).", csr_num, r->name);
r->hidden = true;
break;
}
}
} else if (number == GDB_REGNO_PRIV) {
sprintf(reg_name, "priv");
} else if (reg_num == GDB_REGNO_PRIV) {
r->group = "general";
r->feature = &feature_virtual;
r->size = 8;
} else if (number >= GDB_REGNO_V0 && number <= GDB_REGNO_V31) {
} else if (reg_num >= GDB_REGNO_V0 && reg_num <= GDB_REGNO_V31) {
r->caller_save = false;
r->exist = (info->vlenb > 0);
r->size = info->vlenb * 8;
sprintf(reg_name, "v%d", number - GDB_REGNO_V0);
r->group = "vector";
r->feature = &feature_vector;
r->reg_data_type = &info->type_vector;
} else if (number >= GDB_REGNO_COUNT) {
} else if (reg_num >= GDB_REGNO_COUNT) {
/* Custom registers. */
const unsigned int custom_reg_index = reg_num - GDB_REGNO_COUNT;
assert(!list_empty(&info->expose_custom));
assert(custom_reg_index < info->custom_register_names.num_entries);
range_list_t *range = list_first_entry(&info->expose_custom, range_list_t, list);
unsigned custom_number = range->low + custom_within_range;
const unsigned int custom_number = range->low + custom_within_range;
r->group = "custom";
r->feature = &feature_custom;
r->arch_info = calloc(1, sizeof(riscv_reg_info_t));
if (!r->arch_info)
if (!r->arch_info) {
LOG_ERROR("Failed to allocate memory for r->arch_info");
return ERROR_FAIL;
((riscv_reg_info_t *) r->arch_info)->target = target;
((riscv_reg_info_t *) r->arch_info)->custom_number = custom_number;
sprintf(reg_name, "custom%d", custom_number);
if (range->name) {
*reg_name = 0;
r->name = range->name;
}
((riscv_reg_info_t *)r->arch_info)->target = target;
((riscv_reg_info_t *)r->arch_info)->custom_number = custom_number;
LOG_TARGET_DEBUG(target, "Exposing additional custom register %d (name=%s).",
number, range->name ? range->name : reg_name);
char **reg_names = info->custom_register_names.reg_names;
r->name = reg_names[custom_reg_index];
LOG_TARGET_DEBUG(target, "Exposing additional custom register %d (name=%s)", reg_num, r->name);
custom_within_range++;
if (custom_within_range > range->high - range->low) {
@ -6375,12 +6193,6 @@ int riscv_init_registers(struct target *target)
}
}
if (reg_name[0]) {
r->name = reg_name;
reg_name += strlen(reg_name) + 1;
assert(reg_name < info->reg_names + target->reg_cache->num_regs *
max_reg_name_len);
}
r->value = calloc(1, DIV_ROUND_UP(r->size, 8));
}

View File

@ -113,6 +113,11 @@ typedef struct {
#define DTM_DTMCS_VERSION_UNKNOWN ((unsigned int)-1)
struct reg_name_table {
unsigned int num_entries;
char **reg_names;
};
struct riscv_info {
unsigned int common_magic;
@ -121,9 +126,8 @@ struct riscv_info {
struct command_context *cmd_ctx;
void *version_specific;
/* 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;
struct reg_name_table custom_register_names;
char **reg_names;
/* It's possible that each core has a different supported ISA set. */
int xlen;