Fix access FPU registers again.
Not a great fix. There's still a problem with accessing 64-bit floating point registers on 32-bit cores. 24 of the gdbserver.py tests pass now. Change-Id: I69a88ef5fd5581e2c7bf1d78057fd474ae86ff93
This commit is contained in:
parent
071f9a2916
commit
3173314f28
|
@ -219,7 +219,7 @@ static riscv013_info_t *get_info(const struct target *target)
|
||||||
return (riscv013_info_t *) info->version_specific;
|
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);
|
riscv013_info_t *info = get_info(target);
|
||||||
unsigned num;
|
unsigned num;
|
||||||
|
@ -769,43 +769,19 @@ static int abstract_write_register(struct target *target,
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Actually read registers from the target right now. */
|
static int update_mstatus_actual(struct target *target)
|
||||||
static int register_read_direct(struct target *target, uint64_t *value, uint32_t number)
|
|
||||||
{
|
{
|
||||||
int result = abstract_read_register(target, value, number, xlen(target));
|
struct reg *mstatus_reg = &target->reg_cache->reg_list[REG_MSTATUS];
|
||||||
if (result == ERROR_OK)
|
if (mstatus_reg->valid) {
|
||||||
return result;
|
// We previously made it valid.
|
||||||
|
|
||||||
// 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_DEBUG("Reading mstatus");
|
||||||
|
|
||||||
|
// 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,
|
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.
|
// Fall back to program buffer.
|
||||||
if (number >= REG_FPR0 && number <= REG_FPR31) {
|
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();
|
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));
|
program_add32(program, fmv_d_x(number - REG_FPR0, S0));
|
||||||
} else {
|
} else {
|
||||||
program_add32(program, fmv_s_x(number - REG_FPR0, S0));
|
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;
|
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)
|
static int maybe_read_tselect(struct target *target)
|
||||||
{
|
{
|
||||||
riscv013_info_t *info = get_info(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);
|
maybe_write_tselect(target);
|
||||||
|
|
||||||
if (number <= REG_XPR31) {
|
if (number == REG_PC) {
|
||||||
return abstract_write_register(target, number, xlen(target), value);
|
|
||||||
} else if (number == REG_PC) {
|
|
||||||
info->dpc = value;
|
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) {
|
} else if (number == REG_PRIV) {
|
||||||
info->dcsr = set_field(info->dcsr, DCSR_PRV, value);
|
info->dcsr = set_field(info->dcsr, DCSR_PRV, value);
|
||||||
return ERROR_OK;
|
|
||||||
} else {
|
} else {
|
||||||
LOG_ERROR("Don't know how to write register %d", number);
|
return register_write_direct(target, number, value);
|
||||||
return ERROR_FAIL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
|
|
Loading…
Reference in New Issue