aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/target/riscv/riscv-013.c126
1 files changed, 80 insertions, 46 deletions
diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c
index 183303c..2d34550 100644
--- a/src/target/riscv/riscv-013.c
+++ b/src/target/riscv/riscv-013.c
@@ -219,7 +219,7 @@ static riscv013_info_t *get_info(const struct target *target)
return (riscv013_info_t *) info->version_specific;
}
-bool extension_supported(struct target *target, char letter)
+bool supports_extension(struct target *target, char letter)
{
riscv013_info_t *info = get_info(target);
unsigned num;
@@ -769,43 +769,19 @@ static int abstract_write_register(struct target *target,
return ERROR_OK;
}
-/** Actually read registers from the target right now. */
-static int register_read_direct(struct target *target, uint64_t *value, uint32_t number)
+static int update_mstatus_actual(struct target *target)
{
- int result = abstract_read_register(target, value, number, xlen(target));
- if (result == ERROR_OK)
- return result;
-
- // Fall back to program buffer.
- if (number >= REG_FPR0 && number <= REG_FPR31) {
- program_t *program = program_new();
- if (extension_supported(target, 'D')) {
- program_add32(program, fmv_x_d(S0, number - REG_FPR0));
- } else {
- program_add32(program, fmv_x_s(S0, number - REG_FPR0));
- }
- program_add32(program, ebreak());
- program_set_read(program, S0);
- execute_program(target, program);
- program_delete(program);
- } else if (number >= REG_CSR0 && number <= REG_CSR4095) {
- program_t *program = program_new();
- program_add32(program, csrr(S0, number - REG_CSR0));
- program_add32(program, ebreak());
- program_set_read(program, S0);
- execute_program(target, program);
- program_delete(program);
- } else {
- return result;
+ struct reg *mstatus_reg = &target->reg_cache->reg_list[REG_MSTATUS];
+ if (mstatus_reg->valid) {
+ // We previously made it valid.
+ return ERROR_OK;
}
- result = register_read_direct(target, value, S0);
- if (result != ERROR_OK)
- return result;
-
- LOG_DEBUG("register 0x%x = 0x%" PRIx64, number, *value);
+ LOG_DEBUG("Reading mstatus");
- return ERROR_OK;
+ // Force reading the register. In that process mstatus_actual will be
+ // updated.
+ return register_get(&target->reg_cache->reg_list[REG_MSTATUS]);
}
static int register_write_direct(struct target *target, unsigned number,
@@ -824,8 +800,20 @@ static int register_write_direct(struct target *target, unsigned number,
// Fall back to program buffer.
if (number >= REG_FPR0 && number <= REG_FPR31) {
+ result = update_mstatus_actual(target);
+ if (result != ERROR_OK) {
+ return result;
+ }
+ if ((info->mstatus_actual & MSTATUS_FS) == 0) {
+ result = register_write_direct(target, REG_MSTATUS,
+ set_field(info->mstatus_actual, MSTATUS_FS, 1));
+ if (result != ERROR_OK)
+ return result;
+ }
+
program_t *program = program_new();
- if (extension_supported(target, 'D')) {
+ // TODO: Fully support D extension on RV32.
+ if (supports_extension(target, 'D') && xlen(target) >= 64) {
program_add32(program, fmv_d_x(number - REG_FPR0, S0));
} else {
program_add32(program, fmv_s_x(number - REG_FPR0, S0));
@@ -848,6 +836,61 @@ static int register_write_direct(struct target *target, unsigned number,
return result;
}
+/** Actually read registers from the target right now. */
+static int register_read_direct(struct target *target, uint64_t *value, uint32_t number)
+{
+ riscv013_info_t *info = get_info(target);
+ int result = abstract_read_register(target, value, number, xlen(target));
+ if (result == ERROR_OK)
+ return result;
+
+ // Fall back to program buffer.
+ if (number >= REG_FPR0 && number <= REG_FPR31) {
+ result = update_mstatus_actual(target);
+ if (result != ERROR_OK) {
+ return result;
+ }
+ if ((info->mstatus_actual & MSTATUS_FS) == 0) {
+ result = register_write_direct(target, REG_MSTATUS,
+ set_field(info->mstatus_actual, MSTATUS_FS, 1));
+ if (result != ERROR_OK)
+ return result;
+ }
+ LOG_DEBUG("mstatus_actual=0x%lx", info->mstatus_actual);
+
+ program_t *program = program_new();
+ if (supports_extension(target, 'D') && xlen(target) >= 64) {
+ program_add32(program, fmv_x_d(S0, number - REG_FPR0));
+ } else {
+ program_add32(program, fmv_x_s(S0, number - REG_FPR0));
+ }
+ program_add32(program, ebreak());
+ program_set_read(program, S0);
+ result = execute_program(target, program);
+ program_delete(program);
+ } else if (number >= REG_CSR0 && number <= REG_CSR4095) {
+ program_t *program = program_new();
+ program_add32(program, csrr(S0, number - REG_CSR0));
+ program_add32(program, ebreak());
+ program_set_read(program, S0);
+ result = execute_program(target, program);
+ program_delete(program);
+ } else {
+ return result;
+ }
+
+ if (result != ERROR_OK)
+ return result;
+
+ result = register_read_direct(target, value, S0);
+ if (result != ERROR_OK)
+ return result;
+
+ LOG_DEBUG("register 0x%x = 0x%" PRIx64, number, *value);
+
+ return ERROR_OK;
+}
+
static int maybe_read_tselect(struct target *target)
{
riscv013_info_t *info = get_info(target);
@@ -1067,21 +1110,12 @@ static int register_write(struct target *target, unsigned int number,
maybe_write_tselect(target);
- if (number <= REG_XPR31) {
- return abstract_write_register(target, number, xlen(target), value);
- } else if (number == REG_PC) {
+ if (number == REG_PC) {
info->dpc = value;
- return ERROR_OK;
- } else if (number >= REG_FPR0 && number <= REG_FPR31) {
- return abstract_write_register(target, number, xlen(target), value);
- } else if (number >= REG_CSR0 && number <= REG_CSR4095) {
- return register_write_direct(target, number, value);
} else if (number == REG_PRIV) {
info->dcsr = set_field(info->dcsr, DCSR_PRV, value);
- return ERROR_OK;
} else {
- LOG_ERROR("Don't know how to write register %d", number);
- return ERROR_FAIL;
+ return register_write_direct(target, number, value);
}
return ERROR_OK;