Read misa during examine(), using program buffer.
Change-Id: Icad5324d216b61207cb5f6024b2deab065658640
This commit is contained in:
parent
0fa8162a8c
commit
24033b53d8
File diff suppressed because it is too large
Load Diff
|
@ -649,6 +649,121 @@ static uint64_t scans_get_u64(scans_t *scans, unsigned int index,
|
||||||
|
|
||||||
/*** end of scans class ***/
|
/*** end of scans class ***/
|
||||||
|
|
||||||
|
/** Convert register number (internal OpenOCD number) to the number expected by
|
||||||
|
* the abstract command interface. */
|
||||||
|
static unsigned reg_number_to_no(unsigned reg_num)
|
||||||
|
{
|
||||||
|
if (reg_num <= REG_XPR31) {
|
||||||
|
return reg_num + 0x1000 - REG_XPR0;
|
||||||
|
} else if (reg_num >= REG_CSR0 && reg_num <= REG_CSR4095) {
|
||||||
|
return reg_num - REG_CSR0;
|
||||||
|
} else if (reg_num >= REG_FPR0 && reg_num <= REG_FPR31) {
|
||||||
|
return reg_num + 0x1020 - REG_FPR0;
|
||||||
|
} else {
|
||||||
|
return ~0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t abstract_register_size(unsigned width)
|
||||||
|
{
|
||||||
|
switch (width) {
|
||||||
|
case 32:
|
||||||
|
return set_field(0, AC_ACCESS_REGISTER_SIZE, 2);
|
||||||
|
case 64:
|
||||||
|
return set_field(0, AC_ACCESS_REGISTER_SIZE, 3);
|
||||||
|
break;
|
||||||
|
case 128:
|
||||||
|
return set_field(0, AC_ACCESS_REGISTER_SIZE, 4);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
LOG_ERROR("Unsupported register width: %d", width);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int execute_abstract_command(struct target *target, uint32_t command)
|
||||||
|
{
|
||||||
|
dmi_write(target, DMI_COMMAND, command);
|
||||||
|
|
||||||
|
uint32_t abstractcs;
|
||||||
|
for (unsigned i = 0; i < 256; i++) {
|
||||||
|
abstractcs = dmi_read(target, DMI_ABSTRACTCS);
|
||||||
|
if (get_field(abstractcs, DMI_ABSTRACTCS_BUSY) == 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (get_field(abstractcs, DMI_ABSTRACTCS_BUSY)) {
|
||||||
|
LOG_ERROR("Abstract command 0x%x never completed (abstractcs=0x%x)",
|
||||||
|
command, abstractcs);
|
||||||
|
return ERROR_FAIL;
|
||||||
|
}
|
||||||
|
if (get_field(abstractcs, DMI_ABSTRACTCS_CMDERR)) {
|
||||||
|
const char *errors[8] = {
|
||||||
|
"none",
|
||||||
|
"busy",
|
||||||
|
"not supported",
|
||||||
|
"exception",
|
||||||
|
"halt/resume",
|
||||||
|
"reserved",
|
||||||
|
"reserved",
|
||||||
|
"other" };
|
||||||
|
LOG_DEBUG("Abstract command 0x%x ended in error '%s' (abstractcs=0x%x)",
|
||||||
|
command, errors[get_field(abstractcs, DMI_ABSTRACTCS_CMDERR)],
|
||||||
|
abstractcs);
|
||||||
|
// Clear the error.
|
||||||
|
dmi_write(target, DMI_ABSTRACTCS, 0);
|
||||||
|
return ERROR_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*** program "class" ***/
|
||||||
|
/* This class allows a debug program to be built up piecemeal, and then be
|
||||||
|
* executed. If necessary, the program is split up to fit in the program
|
||||||
|
* buffer. */
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint8_t code[12 * 4];
|
||||||
|
unsigned length;
|
||||||
|
bool write;
|
||||||
|
unsigned regno;
|
||||||
|
uint64_t write_value;
|
||||||
|
} program_t;
|
||||||
|
|
||||||
|
static program_t *program_new(void)
|
||||||
|
{
|
||||||
|
program_t *program = malloc(sizeof(program_t));
|
||||||
|
if (program) {
|
||||||
|
program->length = 0;
|
||||||
|
// Default to read zero.
|
||||||
|
program->write = false;
|
||||||
|
program->regno = 0x1000;
|
||||||
|
}
|
||||||
|
return program;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void program_delete(program_t *program)
|
||||||
|
{
|
||||||
|
free(program);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void program_add32(program_t *program, uint32_t instruction)
|
||||||
|
{
|
||||||
|
assert(program->length + 4 < sizeof(program->code));
|
||||||
|
program->code[program->length++] = instruction & 0xff;
|
||||||
|
program->code[program->length++] = (instruction >> 8) & 0xff;
|
||||||
|
program->code[program->length++] = (instruction >> 16) & 0xff;
|
||||||
|
program->code[program->length++] = (instruction >> 24) & 0xff;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void program_set_read(program_t *program, unsigned reg_num)
|
||||||
|
{
|
||||||
|
program->write = false;
|
||||||
|
program->regno = reg_number_to_no(reg_num);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*** end of program class ***/
|
||||||
|
|
||||||
static uint32_t dram_read32(struct target *target, unsigned int index)
|
static uint32_t dram_read32(struct target *target, unsigned int index)
|
||||||
{
|
{
|
||||||
uint16_t address = dram_address(index);
|
uint16_t address = dram_address(index);
|
||||||
|
@ -979,15 +1094,80 @@ static int wait_for_state(struct target *target, enum target_state state)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int execute_program(struct target *target, const program_t *program)
|
||||||
|
{
|
||||||
|
riscv013_info_t *info = get_info(target);
|
||||||
|
|
||||||
|
assert(program->length <= info->progsize * 4);
|
||||||
|
for (unsigned i = 0; i < program->length; i += 4) {
|
||||||
|
uint32_t value =
|
||||||
|
program->code[i] |
|
||||||
|
((uint32_t) program->code[i+1] << 8) |
|
||||||
|
((uint32_t) program->code[i+2] << 16) |
|
||||||
|
((uint32_t) program->code[i+3] << 24);
|
||||||
|
dmi_write(target, DMI_IBUF0 + i / 4, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t command = 0;
|
||||||
|
if (program->write) {
|
||||||
|
command |= AC_ACCESS_REGISTER_WRITE | AC_ACCESS_REGISTER_POSTEXEC;
|
||||||
|
} else {
|
||||||
|
command |= AC_ACCESS_REGISTER_PREEXEC;
|
||||||
|
}
|
||||||
|
command |= abstract_register_size(xlen(target));
|
||||||
|
command |= program->regno;
|
||||||
|
|
||||||
|
return execute_abstract_command(target, command);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int abstract_read_register(struct target *target,
|
||||||
|
unsigned reg_number,
|
||||||
|
unsigned width,
|
||||||
|
uint64_t *value)
|
||||||
|
{
|
||||||
|
uint32_t command = abstract_register_size(width);
|
||||||
|
|
||||||
|
command |= reg_number_to_no(reg_number);
|
||||||
|
|
||||||
|
int result = execute_abstract_command(target, command);
|
||||||
|
if (result != ERROR_OK) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value) {
|
||||||
|
*value = 0;
|
||||||
|
switch (width) {
|
||||||
|
case 128:
|
||||||
|
LOG_WARNING("Ignoring top 64 bits from 128-bit register read.");
|
||||||
|
case 64:
|
||||||
|
*value |= ((uint64_t) dmi_read(target, DMI_DATA0)) << 32;
|
||||||
|
case 32:
|
||||||
|
*value |= dmi_read(target, DMI_DATA0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
static int read_csr(struct target *target, uint64_t *value, uint32_t csr)
|
static int read_csr(struct target *target, uint64_t *value, uint32_t csr)
|
||||||
{
|
{
|
||||||
cache_set32(target, 0, csrr(S0, csr));
|
int result = abstract_read_register(target, csr, xlen(target), value);
|
||||||
cache_set_store(target, 1, S0, SLOT0);
|
if (result == ERROR_OK)
|
||||||
cache_set_jump(target, 2);
|
return result;
|
||||||
if (cache_write(target, 4, true) != ERROR_OK) {
|
|
||||||
return ERROR_FAIL;
|
// Fall back to program buffer.
|
||||||
}
|
program_t *program = program_new();
|
||||||
*value = cache_get(target, SLOT0);
|
program_add32(program, csrr(S0, csr));
|
||||||
|
program_add32(program, ebreak());
|
||||||
|
program_set_read(program, S0);
|
||||||
|
execute_program(target, program);
|
||||||
|
program_delete(program);
|
||||||
|
|
||||||
|
result = abstract_read_register(target, S0, xlen(target), value);
|
||||||
|
if (result != ERROR_OK)
|
||||||
|
return result;
|
||||||
|
|
||||||
LOG_DEBUG("csr 0x%x = 0x%" PRIx64, csr, *value);
|
LOG_DEBUG("csr 0x%x = 0x%" PRIx64, csr, *value);
|
||||||
|
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
|
@ -1738,72 +1918,6 @@ static int step(struct target *target, int current, uint32_t address,
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int abstract_read_register(struct target *target,
|
|
||||||
unsigned reg_number,
|
|
||||||
unsigned width,
|
|
||||||
uint64_t *result)
|
|
||||||
{
|
|
||||||
uint32_t command = 0;
|
|
||||||
switch (width) {
|
|
||||||
case 32:
|
|
||||||
command = set_field(command, AC_ACCESS_REGISTER_SIZE, 2);
|
|
||||||
break;
|
|
||||||
case 64:
|
|
||||||
command = set_field(command, AC_ACCESS_REGISTER_SIZE, 3);
|
|
||||||
break;
|
|
||||||
case 128:
|
|
||||||
command = set_field(command, AC_ACCESS_REGISTER_SIZE, 4);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
LOG_ERROR("Unsupported register width: %d", width);
|
|
||||||
return ERROR_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (reg_number <= REG_XPR31) {
|
|
||||||
command |= reg_number + 0x1000 - REG_XPR0;
|
|
||||||
} else if (reg_number >= REG_CSR0 && reg_number <= REG_CSR4095) {
|
|
||||||
command |= reg_number - REG_CSR0;
|
|
||||||
} else if (reg_number >= REG_FPR0 && reg_number <= REG_FPR31) {
|
|
||||||
command |= reg_number + 0x1020 - REG_FPR0;
|
|
||||||
}
|
|
||||||
|
|
||||||
dmi_write(target, DMI_COMMAND, command);
|
|
||||||
|
|
||||||
uint32_t abstractcs;
|
|
||||||
for (unsigned i = 0; i < 256; i++) {
|
|
||||||
abstractcs = dmi_read(target, DMI_ABSTRACTCS);
|
|
||||||
if (get_field(abstractcs, DMI_ABSTRACTCS_BUSY) == 0)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (get_field(abstractcs, DMI_ABSTRACTCS_BUSY)) {
|
|
||||||
LOG_ERROR("Abstract command 0x%x never completed (abstractcs=0x%x)",
|
|
||||||
command, abstractcs);
|
|
||||||
return ERROR_FAIL;
|
|
||||||
}
|
|
||||||
if (get_field(abstractcs, DMI_ABSTRACTCS_CMDERR)) {
|
|
||||||
LOG_DEBUG("Abstract command 0x%x ended in error (abstractcs=0x%x)",
|
|
||||||
command, abstractcs);
|
|
||||||
// Clear the error.
|
|
||||||
dmi_write(target, DMI_ABSTRACTCS, 0);
|
|
||||||
return ERROR_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (result) {
|
|
||||||
*result = 0;
|
|
||||||
switch (width) {
|
|
||||||
case 128:
|
|
||||||
LOG_WARNING("Ignoring top 64 bits from 128-bit register read.");
|
|
||||||
case 64:
|
|
||||||
*result |= ((uint64_t) dmi_read(target, DMI_DATA0)) << 32;
|
|
||||||
case 32:
|
|
||||||
*result |= dmi_read(target, DMI_DATA0);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int examine(struct target *target)
|
static int examine(struct target *target)
|
||||||
{
|
{
|
||||||
// Don't need to select dbus, since the first thing we do is read dtmcontrol.
|
// Don't need to select dbus, since the first thing we do is read dtmcontrol.
|
||||||
|
|
Loading…
Reference in New Issue