Merge branch 'riscv_timeout_commands' into riscv-compliance
This commit is contained in:
commit
6200d9a180
|
@ -910,7 +910,6 @@ static int init_target(struct command_context *cmd_ctx,
|
||||||
generic_info->dmi_write_u64_bits = &riscv013_dmi_write_u64_bits;
|
generic_info->dmi_write_u64_bits = &riscv013_dmi_write_u64_bits;
|
||||||
generic_info->reset_current_hart = &riscv013_reset_current_hart;
|
generic_info->reset_current_hart = &riscv013_reset_current_hart;
|
||||||
generic_info->test_compliance = &riscv013_test_compliance;
|
generic_info->test_compliance = &riscv013_test_compliance;
|
||||||
|
|
||||||
generic_info->version_specific = calloc(1, sizeof(riscv013_info_t));
|
generic_info->version_specific = calloc(1, sizeof(riscv013_info_t));
|
||||||
if (!generic_info->version_specific)
|
if (!generic_info->version_specific)
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
|
@ -1355,8 +1354,10 @@ static int read_memory(struct target *target, target_addr_t address,
|
||||||
riscv_addr_t fin_addr = address + (count * size);
|
riscv_addr_t fin_addr = address + (count * size);
|
||||||
riscv_addr_t prev_addr = ((riscv_addr_t) address) - size;
|
riscv_addr_t prev_addr = ((riscv_addr_t) address) - size;
|
||||||
bool first = true;
|
bool first = true;
|
||||||
LOG_DEBUG("writing until final address 0x%" PRIx64, fin_addr);
|
bool this_is_last_read = false;
|
||||||
while (count > 1 && (cur_addr = riscv_read_debug_buffer_x(target, d_addr)) < fin_addr) {
|
LOG_DEBUG("reading until final address 0x%" PRIx64, fin_addr);
|
||||||
|
while (count > 1 && !this_is_last_read) {
|
||||||
|
cur_addr = riscv_read_debug_buffer_x(target, d_addr);
|
||||||
LOG_DEBUG("transferring burst starting at address 0x%" TARGET_PRIxADDR
|
LOG_DEBUG("transferring burst starting at address 0x%" TARGET_PRIxADDR
|
||||||
" (previous burst was 0x%" TARGET_PRIxADDR ")", cur_addr,
|
" (previous burst was 0x%" TARGET_PRIxADDR ")", cur_addr,
|
||||||
prev_addr);
|
prev_addr);
|
||||||
|
@ -1373,11 +1374,22 @@ static int read_memory(struct target *target, target_addr_t address,
|
||||||
size_t reads = 0;
|
size_t reads = 0;
|
||||||
size_t rereads = reads;
|
size_t rereads = reads;
|
||||||
for (riscv_addr_t i = start; i < count; ++i) {
|
for (riscv_addr_t i = start; i < count; ++i) {
|
||||||
size_t index =
|
if (i == count - 1) {
|
||||||
riscv_batch_add_dmi_read(
|
// don't do actual read in this batch,
|
||||||
batch,
|
// we will do it later after we disable autoexec
|
||||||
riscv013_debug_buffer_register(target, r_data));
|
//
|
||||||
assert(index == reads);
|
// this is done to avoid reading more memory than requested
|
||||||
|
// which in some special cases(like reading stack located
|
||||||
|
// at the very top of RAM) may cause an exception
|
||||||
|
this_is_last_read = true;
|
||||||
|
} else {
|
||||||
|
size_t const index =
|
||||||
|
riscv_batch_add_dmi_read(
|
||||||
|
batch,
|
||||||
|
riscv013_debug_buffer_register(target, r_data));
|
||||||
|
assert(index == reads);
|
||||||
|
}
|
||||||
|
|
||||||
reads++;
|
reads++;
|
||||||
if (riscv_batch_full(batch))
|
if (riscv_batch_full(batch))
|
||||||
break;
|
break;
|
||||||
|
@ -1385,13 +1397,54 @@ static int read_memory(struct target *target, target_addr_t address,
|
||||||
|
|
||||||
riscv_batch_run(batch);
|
riscv_batch_run(batch);
|
||||||
|
|
||||||
|
// Note that if the scan resulted in a Busy DMI response, it
|
||||||
|
// is this read to abstractcs that will cause the dmi_busy_delay
|
||||||
|
// to be incremented if necessary. The loop condition above
|
||||||
|
// catches the case where no writes went through at all.
|
||||||
|
|
||||||
|
bool retry_batch_transaction = false;
|
||||||
|
uint32_t abstractcs = dmi_read(target, DMI_ABSTRACTCS);
|
||||||
|
while (get_field(abstractcs, DMI_ABSTRACTCS_BUSY))
|
||||||
|
abstractcs = dmi_read(target, DMI_ABSTRACTCS);
|
||||||
|
info->cmderr = get_field(abstractcs, DMI_ABSTRACTCS_CMDERR);
|
||||||
|
switch (info->cmderr) {
|
||||||
|
case CMDERR_NONE:
|
||||||
|
LOG_DEBUG("successful (partial?) memory write");
|
||||||
|
break;
|
||||||
|
case CMDERR_BUSY:
|
||||||
|
LOG_DEBUG("memory write resulted in busy response");
|
||||||
|
riscv013_clear_abstract_error(target);
|
||||||
|
increase_ac_busy_delay(target);
|
||||||
|
retry_batch_transaction = true;
|
||||||
|
riscv_batch_free(batch);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
LOG_ERROR("error when reading memory, abstractcs=0x%08lx", (long)abstractcs);
|
||||||
|
riscv013_set_autoexec(target, d_data, 0);
|
||||||
|
riscv_set_register(target, GDB_REGNO_S0, s0);
|
||||||
|
riscv_set_register(target, GDB_REGNO_S1, s1);
|
||||||
|
riscv013_clear_abstract_error(target);
|
||||||
|
riscv_batch_free(batch);
|
||||||
|
return ERROR_FAIL;
|
||||||
|
}
|
||||||
|
if (retry_batch_transaction) continue;
|
||||||
|
|
||||||
for (size_t i = start; i < start + reads; ++i) {
|
for (size_t i = start; i < start + reads; ++i) {
|
||||||
riscv_addr_t offset = size*i;
|
riscv_addr_t offset = size*i;
|
||||||
riscv_addr_t t_addr = address + offset;
|
riscv_addr_t t_addr = address + offset;
|
||||||
uint8_t *t_buffer = buffer + offset;
|
uint8_t *t_buffer = buffer + offset;
|
||||||
|
|
||||||
uint64_t dmi_out = riscv_batch_get_dmi_read(batch, rereads);
|
if (this_is_last_read && i == start + reads - 1) {
|
||||||
value = get_field(dmi_out, DTM_DMI_DATA);
|
riscv013_set_autoexec(target, d_data, 0);
|
||||||
|
|
||||||
|
// access debug buffer without executing a program - this address logic was taken from program.c
|
||||||
|
int const off = (r_data - riscv_debug_buffer_addr(program.target)) / sizeof(program.debug_buffer[0]);
|
||||||
|
value = riscv_read_debug_buffer(target, off);
|
||||||
|
} else {
|
||||||
|
uint64_t dmi_out = riscv_batch_get_dmi_read(batch, rereads);
|
||||||
|
value = get_field(dmi_out, DTM_DMI_DATA);
|
||||||
|
}
|
||||||
|
|
||||||
rereads++;
|
rereads++;
|
||||||
|
|
||||||
switch (size) {
|
switch (size) {
|
||||||
|
@ -1415,35 +1468,7 @@ static int read_memory(struct target *target, target_addr_t address,
|
||||||
|
|
||||||
LOG_DEBUG("M[0x%08lx] reads 0x%08lx", (long)t_addr, (long)value);
|
LOG_DEBUG("M[0x%08lx] reads 0x%08lx", (long)t_addr, (long)value);
|
||||||
}
|
}
|
||||||
|
|
||||||
riscv_batch_free(batch);
|
riscv_batch_free(batch);
|
||||||
|
|
||||||
// Note that if the scan resulted in a Busy DMI response, it
|
|
||||||
// is this read to abstractcs that will cause the dmi_busy_delay
|
|
||||||
// to be incremented if necessary. The loop condition above
|
|
||||||
// catches the case where no writes went through at all.
|
|
||||||
|
|
||||||
uint32_t abstractcs = dmi_read(target, DMI_ABSTRACTCS);
|
|
||||||
while (get_field(abstractcs, DMI_ABSTRACTCS_BUSY))
|
|
||||||
abstractcs = dmi_read(target, DMI_ABSTRACTCS);
|
|
||||||
info->cmderr = get_field(abstractcs, DMI_ABSTRACTCS_CMDERR);
|
|
||||||
switch (info->cmderr) {
|
|
||||||
case CMDERR_NONE:
|
|
||||||
LOG_DEBUG("successful (partial?) memory write");
|
|
||||||
break;
|
|
||||||
case CMDERR_BUSY:
|
|
||||||
LOG_DEBUG("memory write resulted in busy response");
|
|
||||||
riscv013_clear_abstract_error(target);
|
|
||||||
increase_ac_busy_delay(target);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
LOG_ERROR("error when writing memory, abstractcs=0x%08lx", (long)abstractcs);
|
|
||||||
riscv013_set_autoexec(target, d_data, 0);
|
|
||||||
riscv_set_register(target, GDB_REGNO_S0, s0);
|
|
||||||
riscv_set_register(target, GDB_REGNO_S1, s1);
|
|
||||||
riscv013_clear_abstract_error(target);
|
|
||||||
return ERROR_FAIL;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
riscv013_set_autoexec(target, d_data, 0);
|
riscv013_set_autoexec(target, d_data, 0);
|
||||||
|
|
|
@ -1137,8 +1137,96 @@ int riscv_openocd_deassert_reset(struct target *target)
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Declared below
|
/* Command Handlers */
|
||||||
const struct command_registration riscv_command_handlers[];
|
COMMAND_HANDLER(riscv_set_command_timeout_sec) {
|
||||||
|
|
||||||
|
if (CMD_ARGC != 1) {
|
||||||
|
LOG_ERROR("Command takes exactly 1 parameter");
|
||||||
|
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||||
|
}
|
||||||
|
int timeout = atoi(CMD_ARGV[0]);
|
||||||
|
if (timeout <= 0){
|
||||||
|
LOG_ERROR("%s is not a valid integer argument for command.", CMD_ARGV[0]);
|
||||||
|
return ERROR_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
riscv_command_timeout_sec = timeout;
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
COMMAND_HANDLER(riscv_set_reset_timeout_sec) {
|
||||||
|
|
||||||
|
if (CMD_ARGC != 1) {
|
||||||
|
LOG_ERROR("Command takes exactly 1 parameter");
|
||||||
|
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||||
|
}
|
||||||
|
int timeout = atoi(CMD_ARGV[0]);
|
||||||
|
if (timeout <= 0){
|
||||||
|
LOG_ERROR("%s is not a valid integer argument for command.", CMD_ARGV[0]);
|
||||||
|
return ERROR_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
riscv_reset_timeout_sec = timeout;
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
COMMAND_HANDLER(riscv_test_compliance) {
|
||||||
|
|
||||||
|
struct target *target = get_current_target(CMD_CTX);
|
||||||
|
|
||||||
|
RISCV_INFO(r);
|
||||||
|
|
||||||
|
if (CMD_ARGC > 0) {
|
||||||
|
LOG_ERROR("Command does not take any parameters.");
|
||||||
|
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (r->test_compliance) {
|
||||||
|
return r->test_compliance(target);
|
||||||
|
} else {
|
||||||
|
LOG_ERROR("This target does not support this command (may implement an older version of the spec).");
|
||||||
|
return ERROR_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static const struct command_registration riscv_exec_command_handlers[] = {
|
||||||
|
{
|
||||||
|
.name = "test_compliance",
|
||||||
|
.handler = riscv_test_compliance,
|
||||||
|
.mode = COMMAND_EXEC,
|
||||||
|
.usage = "riscv test_compliance",
|
||||||
|
.help = "Runs a basic compliance test suite against the RISC-V Debug Spec."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.name = "set_command_timeout_sec",
|
||||||
|
.handler = riscv_set_command_timeout_sec,
|
||||||
|
.mode = COMMAND_ANY,
|
||||||
|
.usage = "riscv set_command_timeout_sec [sec]",
|
||||||
|
.help = "Set the wall-clock timeout (in seconds) for individual commands"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.name = "set_reset_timeout_sec",
|
||||||
|
.handler = riscv_set_reset_timeout_sec,
|
||||||
|
.mode = COMMAND_ANY,
|
||||||
|
.usage = "riscv set_reset_timeout_sec [sec]",
|
||||||
|
.help = "Set the wall-clock timeout (in seconds) after reset is deasserted"
|
||||||
|
},
|
||||||
|
COMMAND_REGISTRATION_DONE
|
||||||
|
};
|
||||||
|
|
||||||
|
const struct command_registration riscv_command_handlers[] = {
|
||||||
|
{
|
||||||
|
.name = "riscv",
|
||||||
|
.mode = COMMAND_ANY,
|
||||||
|
.help = "RISC-V Command Group",
|
||||||
|
.usage = "",
|
||||||
|
.chain = riscv_exec_command_handlers
|
||||||
|
},
|
||||||
|
COMMAND_REGISTRATION_DONE
|
||||||
|
};
|
||||||
|
|
||||||
struct target_type riscv_target =
|
struct target_type riscv_target =
|
||||||
{
|
{
|
||||||
|
@ -1586,7 +1674,6 @@ int riscv_enumerate_triggers(struct target *target)
|
||||||
tselect_rb &= ~(1ULL << (riscv_xlen(target)-1));
|
tselect_rb &= ~(1ULL << (riscv_xlen(target)-1));
|
||||||
if (tselect_rb != t)
|
if (tselect_rb != t)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
uint64_t tdata1 = riscv_get_register_on_hart(target, hartid,
|
uint64_t tdata1 = riscv_get_register_on_hart(target, hartid,
|
||||||
GDB_REGNO_TDATA1);
|
GDB_REGNO_TDATA1);
|
||||||
int type = get_field(tdata1, MCONTROL_TYPE(riscv_xlen(target)));
|
int type = get_field(tdata1, MCONTROL_TYPE(riscv_xlen(target)));
|
||||||
|
@ -1612,98 +1699,6 @@ int riscv_enumerate_triggers(struct target *target)
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Command Handlers */
|
|
||||||
|
|
||||||
COMMAND_HANDLER(riscv_test_compliance) {
|
|
||||||
|
|
||||||
struct target *target = get_current_target(CMD_CTX);
|
|
||||||
|
|
||||||
RISCV_INFO(r);
|
|
||||||
|
|
||||||
if (CMD_ARGC > 0) {
|
|
||||||
LOG_ERROR("Command does not take any parameters.");
|
|
||||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (r->test_compliance) {
|
|
||||||
return r->test_compliance(target);
|
|
||||||
} else {
|
|
||||||
LOG_ERROR("This target does not support this command (may implement an older version of the spec).");
|
|
||||||
return ERROR_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
COMMAND_HANDLER(riscv_set_command_timeout_sec) {
|
|
||||||
|
|
||||||
if (CMD_ARGC != 1) {
|
|
||||||
LOG_ERROR("Command takes exactly 1 parameter");
|
|
||||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
|
||||||
}
|
|
||||||
int timeout = atoi(CMD_ARGV[0]);
|
|
||||||
if (timeout <= 0){
|
|
||||||
LOG_ERROR("%s is not a valid integer argument for command.", CMD_ARGV[0]);
|
|
||||||
return ERROR_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
riscv_command_timeout_sec = timeout;
|
|
||||||
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
COMMAND_HANDLER(riscv_set_reset_timeout_sec) {
|
|
||||||
|
|
||||||
if (CMD_ARGC != 1) {
|
|
||||||
LOG_ERROR("Command takes exactly 1 parameter");
|
|
||||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
|
||||||
}
|
|
||||||
int timeout = atoi(CMD_ARGV[0]);
|
|
||||||
if (timeout <= 0){
|
|
||||||
LOG_ERROR("%s is not a valid integer argument for command.", CMD_ARGV[0]);
|
|
||||||
return ERROR_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
riscv_reset_timeout_sec = timeout;
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static const struct command_registration riscv_exec_command_handlers[] = {
|
|
||||||
{
|
|
||||||
.name = "test_compliance",
|
|
||||||
.handler = riscv_test_compliance,
|
|
||||||
.mode = COMMAND_EXEC,
|
|
||||||
.usage = "riscv test_compliance",
|
|
||||||
.help = "Runs a basic compliance test suite against the RISC-V Debug Spec."
|
|
||||||
},
|
|
||||||
{
|
|
||||||
.name = "set_command_timeout_sec",
|
|
||||||
.handler = riscv_set_command_timeout_sec,
|
|
||||||
.mode = COMMAND_ANY,
|
|
||||||
.usage = "riscv set_command_timeout_sec [sec]",
|
|
||||||
.help = "Set the wall-clock timeout (in seconds) for individual commands"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
.name = "set_reset_timeout_sec",
|
|
||||||
.handler = riscv_set_reset_timeout_sec,
|
|
||||||
.mode = COMMAND_ANY,
|
|
||||||
.usage = "riscv set_reset_timeout_sec [sec]",
|
|
||||||
.help = "Set the wall-clock timeout (in seconds) after reset is deasserted"
|
|
||||||
},
|
|
||||||
COMMAND_REGISTRATION_DONE
|
|
||||||
};
|
|
||||||
|
|
||||||
const struct command_registration riscv_command_handlers[] = {
|
|
||||||
{
|
|
||||||
.name = "riscv",
|
|
||||||
.mode = COMMAND_ANY,
|
|
||||||
.help = "RISC-V Command Group",
|
|
||||||
.usage = "",
|
|
||||||
.chain = riscv_exec_command_handlers
|
|
||||||
},
|
|
||||||
COMMAND_REGISTRATION_DONE
|
|
||||||
};
|
|
||||||
|
|
||||||
const char *gdb_regno_name(enum gdb_regno regno)
|
const char *gdb_regno_name(enum gdb_regno regno)
|
||||||
{
|
{
|
||||||
static char buf[32];
|
static char buf[32];
|
||||||
|
|
Loading…
Reference in New Issue