Check busy before triggering another command.
This version was able to download code, and run to a breakpoint. Change-Id: I0ead8350579263d8e55f8df35e2b7af6c374ef21
This commit is contained in:
parent
ef3875a320
commit
88f14f4d5e
|
@ -131,6 +131,13 @@ typedef enum slot {
|
||||||
#define DMCONTROL_NDRESET (1<<1)
|
#define DMCONTROL_NDRESET (1<<1)
|
||||||
#define DMCONTROL_FULLRESET 1
|
#define DMCONTROL_FULLRESET 1
|
||||||
|
|
||||||
|
#define CMDERR_NONE 0
|
||||||
|
#define CMDERR_BUSY 1
|
||||||
|
#define CMDERR_NOT_SUPPORTED 2
|
||||||
|
#define CMDERR_EXCEPTION 3
|
||||||
|
#define CMDERR_HALT_RESUME 4
|
||||||
|
#define CMDERR_OTHER 7
|
||||||
|
|
||||||
/*** Info about the core being debugged. ***/
|
/*** Info about the core being debugged. ***/
|
||||||
|
|
||||||
#define DMI_ADDRESS_UNKNOWN 0xffff
|
#define DMI_ADDRESS_UNKNOWN 0xffff
|
||||||
|
@ -235,8 +242,6 @@ static int register_get(struct reg *reg);
|
||||||
|
|
||||||
/*** Utility functions. ***/
|
/*** Utility functions. ***/
|
||||||
|
|
||||||
#define DEBUG_LENGTH 264
|
|
||||||
|
|
||||||
static riscv013_info_t *get_info(const struct target *target)
|
static riscv013_info_t *get_info(const struct target *target)
|
||||||
{
|
{
|
||||||
riscv_info_t *info = (riscv_info_t *) target->arch_info;
|
riscv_info_t *info = (riscv_info_t *) target->arch_info;
|
||||||
|
@ -629,22 +634,31 @@ uint32_t abstract_register_size(unsigned width)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int wait_for_idle(struct target *target, uint32_t *abstractcs)
|
||||||
|
{
|
||||||
|
time_t start = time(NULL);
|
||||||
|
while (1) {
|
||||||
|
*abstractcs = dmi_read(target, DMI_ABSTRACTCS);
|
||||||
|
if (get_field(*abstractcs, DMI_ABSTRACTCS_BUSY) == 0) {
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
if (time(NULL) - start > WALL_CLOCK_TIMEOUT) {
|
||||||
|
LOG_ERROR("Timed out waiting for busy to go low. (abstractcs=0x%x)",
|
||||||
|
*abstractcs);
|
||||||
|
return ERROR_FAIL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static int execute_abstract_command(struct target *target, uint32_t command)
|
static int execute_abstract_command(struct target *target, uint32_t command)
|
||||||
{
|
{
|
||||||
dmi_write(target, DMI_COMMAND, command);
|
dmi_write(target, DMI_COMMAND, command);
|
||||||
|
|
||||||
uint32_t abstractcs;
|
uint32_t abstractcs;
|
||||||
for (unsigned i = 0; i < 256; i++) {
|
if (wait_for_idle(target, &abstractcs) != ERROR_OK)
|
||||||
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;
|
return ERROR_FAIL;
|
||||||
}
|
|
||||||
if (get_field(abstractcs, DMI_ABSTRACTCS_CMDERR)) {
|
if (get_field(abstractcs, DMI_ABSTRACTCS_CMDERR) != CMDERR_NONE) {
|
||||||
const char *errors[8] = {
|
const char *errors[8] = {
|
||||||
"none",
|
"none",
|
||||||
"busy",
|
"busy",
|
||||||
|
@ -775,22 +789,6 @@ static bits_t read_bits(struct target *target)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int wait_for_haltstatus(struct target *target, unsigned status)
|
|
||||||
{
|
|
||||||
time_t start = time(NULL);
|
|
||||||
while (1) {
|
|
||||||
uint32_t dmcontrol = dmi_read(target, DMI_DMCONTROL);
|
|
||||||
unsigned s = get_field(dmcontrol, DMI_DMCONTROL_HARTSTATUS);
|
|
||||||
if (s == status)
|
|
||||||
return ERROR_OK;
|
|
||||||
if (time(NULL) - start > WALL_CLOCK_TIMEOUT) {
|
|
||||||
LOG_ERROR("Timed out waiting for hart status to be %d (dmcontrol=0x%x)",
|
|
||||||
status, dmcontrol);
|
|
||||||
return ERROR_FAIL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static int wait_for_debugint_clear(struct target *target, bool ignore_first)
|
static int wait_for_debugint_clear(struct target *target, bool ignore_first)
|
||||||
{
|
{
|
||||||
time_t start = time(NULL);
|
time_t start = time(NULL);
|
||||||
|
@ -1218,6 +1216,15 @@ static int maybe_write_tselect(struct target *target)
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void reg_cache_set(struct target *target, unsigned int number,
|
||||||
|
uint64_t value)
|
||||||
|
{
|
||||||
|
struct reg *r = &target->reg_cache->reg_list[number];
|
||||||
|
LOG_DEBUG("%s <= 0x%" PRIx64, r->name, value);
|
||||||
|
r->valid = true;
|
||||||
|
buf_set_u64(r->value, 0, r->size, value);
|
||||||
|
}
|
||||||
|
|
||||||
static int execute_resume(struct target *target, bool step)
|
static int execute_resume(struct target *target, bool step)
|
||||||
{
|
{
|
||||||
riscv013_info_t *info = get_info(target);
|
riscv013_info_t *info = get_info(target);
|
||||||
|
@ -1266,12 +1273,9 @@ static int execute_resume(struct target *target, bool step)
|
||||||
dmi_write(target, DMI_DMCONTROL, DMI_DMCONTROL_DMACTIVE |
|
dmi_write(target, DMI_DMCONTROL, DMI_DMCONTROL_DMACTIVE |
|
||||||
DMI_DMCONTROL_RESUMEREQ);
|
DMI_DMCONTROL_RESUMEREQ);
|
||||||
|
|
||||||
if (wait_for_haltstatus(target, 1) != ERROR_OK) {
|
|
||||||
return ERROR_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
target->state = TARGET_RUNNING;
|
target->state = TARGET_RUNNING;
|
||||||
register_cache_invalidate(target->reg_cache);
|
register_cache_invalidate(target->reg_cache);
|
||||||
|
reg_cache_set(target, ZERO, 0);
|
||||||
|
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
@ -1307,15 +1311,6 @@ static int resume(struct target *target, int debug_execution, bool step)
|
||||||
return execute_resume(target, step);
|
return execute_resume(target, step);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void reg_cache_set(struct target *target, unsigned int number,
|
|
||||||
uint64_t value)
|
|
||||||
{
|
|
||||||
struct reg *r = &target->reg_cache->reg_list[number];
|
|
||||||
LOG_DEBUG("%s <= 0x%" PRIx64, r->name, value);
|
|
||||||
r->valid = true;
|
|
||||||
buf_set_u64(r->value, 0, r->size, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Update register sizes based on xlen. */
|
/** Update register sizes based on xlen. */
|
||||||
static void update_reg_list(struct target *target)
|
static void update_reg_list(struct target *target)
|
||||||
{
|
{
|
||||||
|
@ -1336,10 +1331,12 @@ static void update_reg_list(struct target *target)
|
||||||
} else {
|
} else {
|
||||||
r->size = xlen(target);
|
r->size = xlen(target);
|
||||||
}
|
}
|
||||||
r->valid = false;
|
if (i == ZERO) {
|
||||||
|
r->valid = true;
|
||||||
|
} else {
|
||||||
|
r->valid = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
reg_cache_set(target, ZERO, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint64_t reg_cache_get(struct target *target, unsigned int number)
|
static uint64_t reg_cache_get(struct target *target, unsigned int number)
|
||||||
|
@ -2331,7 +2328,7 @@ static int read_memory(struct target *target, uint32_t address,
|
||||||
execute_abstract_command(target,
|
execute_abstract_command(target,
|
||||||
AC_ACCESS_REGISTER_PREEXEC |
|
AC_ACCESS_REGISTER_PREEXEC |
|
||||||
abstract_register_size(xlen(target)) | reg_number_to_no(S1));
|
abstract_register_size(xlen(target)) | reg_number_to_no(S1));
|
||||||
dmi_write(target, DMI_ABSTRACTCS, DMI_ABSTRACTCS_AUTOEXEC0);
|
dmi_write(target, DMI_ABSTRACTCS, DMI_ABSTRACTCS_AUTOEXEC0 | DMI_ABSTRACTCS_CMDERR);
|
||||||
|
|
||||||
for (uint32_t i = 0; i < count; i++) {
|
for (uint32_t i = 0; i < count; i++) {
|
||||||
uint32_t value = dmi_read(target, DMI_DATA0);
|
uint32_t value = dmi_read(target, DMI_DATA0);
|
||||||
|
@ -2414,13 +2411,20 @@ static int write_memory(struct target *target, uint32_t address,
|
||||||
execute_abstract_command(target,
|
execute_abstract_command(target,
|
||||||
AC_ACCESS_REGISTER_WRITE | AC_ACCESS_REGISTER_POSTEXEC |
|
AC_ACCESS_REGISTER_WRITE | AC_ACCESS_REGISTER_POSTEXEC |
|
||||||
abstract_register_size(xlen(target)) | reg_number_to_no(S1));
|
abstract_register_size(xlen(target)) | reg_number_to_no(S1));
|
||||||
dmi_write(target, DMI_ABSTRACTCS, DMI_ABSTRACTCS_AUTOEXEC0);
|
dmi_write(target, DMI_ABSTRACTCS, DMI_ABSTRACTCS_AUTOEXEC0 | DMI_ABSTRACTCS_CMDERR);
|
||||||
|
} else {
|
||||||
|
uint32_t abstractcs;
|
||||||
|
if (wait_for_idle(target, &abstractcs) != ERROR_OK)
|
||||||
|
return ERROR_FAIL;
|
||||||
|
if (get_field(abstractcs, DMI_ABSTRACTCS_CMDERR) != CMDERR_NONE)
|
||||||
|
return ERROR_FAIL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
dmi_write(target, DMI_ABSTRACTCS, DMI_ABSTRACTCS_CMDERR);
|
dmi_write(target, DMI_ABSTRACTCS, DMI_ABSTRACTCS_CMDERR);
|
||||||
uint32_t abstractcs = dmi_read(target, DMI_ABSTRACTCS);
|
uint32_t abstractcs = dmi_read(target, DMI_ABSTRACTCS);
|
||||||
if (get_field(abstractcs, DMI_ABSTRACTCS_CMDERR)) {
|
if (get_field(abstractcs, DMI_ABSTRACTCS_CMDERR)) {
|
||||||
// TODO: retry with more delay?
|
// TODO: retry with more delay?
|
||||||
|
LOG_ERROR("cmderr=%d", get_field(abstractcs, DMI_ABSTRACTCS_CMDERR));
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue