Check busy before triggering another command.

This version was able to download code, and run to a breakpoint.

Change-Id: I0ead8350579263d8e55f8df35e2b7af6c374ef21
__archive__
Tim Newsome 2017-02-16 14:16:18 -08:00
parent ef3875a320
commit 88f14f4d5e
1 changed files with 50 additions and 46 deletions

View File

@ -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);
} }
if (i == ZERO) {
r->valid = true;
} else {
r->valid = false; 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;
} }