aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorTim Newsome <tim@sifive.com>2023-11-03 10:30:35 -0700
committerGitHub <noreply@github.com>2023-11-03 10:30:35 -0700
commitb75bfab0261aa06597ee68895884a62eabceec18 (patch)
tree8be5af962b0e99df64f96421d578e319d5d24f81 /src
parent2676f05f2f6e93b2d73d095393061afb4549d999 (diff)
parent805d394ff8c5e1d1d4f543956ed0393087306171 (diff)
downloadriscv-openocd-b75bfab0261aa06597ee68895884a62eabceec18.zip
riscv-openocd-b75bfab0261aa06597ee68895884a62eabceec18.tar.gz
riscv-openocd-b75bfab0261aa06597ee68895884a62eabceec18.tar.bz2
Merge pull request #896 from AnastasiyaChernikova/ac-sc2
target/riscv: Adding register tables to make register names consiste
Diffstat (limited to 'src')
-rw-r--r--src/target/riscv/gdb_regs.h2
-rw-r--r--src/target/riscv/riscv-011.c6
-rw-r--r--src/target/riscv/riscv-013.c24
-rw-r--r--src/target/riscv/riscv.c738
-rw-r--r--src/target/riscv/riscv.h10
5 files changed, 298 insertions, 482 deletions
diff --git a/src/target/riscv/gdb_regs.h b/src/target/riscv/gdb_regs.h
index ea0c014..570c508 100644
--- a/src/target/riscv/gdb_regs.h
+++ b/src/target/riscv/gdb_regs.h
@@ -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
diff --git a/src/target/riscv/riscv-011.c b/src/target/riscv/riscv-011.c
index dd7676e..c958c88 100644
--- a/src/target/riscv/riscv-011.c
+++ b/src/target/riscv/riscv-011.c
@@ -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;
}
diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c
index 04c39a1..5b84aadc 100644
--- a/src/target/riscv/riscv-013.c
+++ b/src/target/riscv/riscv-013.c
@@ -942,7 +942,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);
}
@@ -1178,7 +1178,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");
@@ -1198,7 +1198,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;
}
@@ -1487,7 +1487,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;
}
@@ -1633,7 +1633,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;
}
@@ -1645,7 +1645,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);
@@ -1663,7 +1663,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;
@@ -1673,7 +1673,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);
@@ -1692,7 +1692,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;
@@ -2372,7 +2372,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;
}
}
@@ -4671,7 +4671,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;
@@ -4688,7 +4688,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;
diff --git a/src/target/riscv/riscv.c b/src/target/riscv/riscv.c
index 7c72a66..3d605c1 100644
--- a/src/target/riscv/riscv.c
+++ b/src/target/riscv/riscv.c
@@ -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;
@@ -2678,7 +2693,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;
}
@@ -5019,7 +5035,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);
}
@@ -5114,7 +5130,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);
}
@@ -5151,7 +5167,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) &&
@@ -5330,7 +5346,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);
@@ -5389,188 +5405,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.
@@ -5670,14 +5672,54 @@ static struct reg_arch_type riscv_reg_arch_type = {
.set = register_set
};
-struct csr_info {
- unsigned number;
- const char *name;
-};
+static int init_custom_register_names(struct list_head *expose_custom,
+ struct reg_name_table *custom_register_names)
+{
+ 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;
-static int cmp_csr_info(const void *p1, const void *p2)
+ 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)
{
- return (int) (((struct csr_info *)p1)->number) - (int) (((struct csr_info *)p2)->number);
+ 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)
@@ -5687,32 +5729,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"
@@ -5844,152 +5881,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;
@@ -6003,119 +5933,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
@@ -6124,7 +5949,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:
@@ -6314,67 +6139,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) {
@@ -6383,12 +6201,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));
}
diff --git a/src/target/riscv/riscv.h b/src/target/riscv/riscv.h
index 38ef982..f2a9d68 100644
--- a/src/target/riscv/riscv.h
+++ b/src/target/riscv/riscv.h
@@ -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;