commit
a854089fd1
|
@ -63,7 +63,6 @@ static void riscv013_fill_dmi_write_u64(struct target *target, char *buf, int a,
|
||||||
static void riscv013_fill_dmi_read_u64(struct target *target, char *buf, int a);
|
static void riscv013_fill_dmi_read_u64(struct target *target, char *buf, int a);
|
||||||
static int riscv013_dmi_write_u64_bits(struct target *target);
|
static int riscv013_dmi_write_u64_bits(struct target *target);
|
||||||
static void riscv013_fill_dmi_nop_u64(struct target *target, char *buf);
|
static void riscv013_fill_dmi_nop_u64(struct target *target, char *buf);
|
||||||
static void riscv013_reset_current_hart(struct target *target);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Since almost everything can be accomplish by scanning the dbus register, all
|
* Since almost everything can be accomplish by scanning the dbus register, all
|
||||||
|
@ -904,7 +903,6 @@ static int init_target(struct command_context *cmd_ctx,
|
||||||
generic_info->fill_dmi_read_u64 = &riscv013_fill_dmi_read_u64;
|
generic_info->fill_dmi_read_u64 = &riscv013_fill_dmi_read_u64;
|
||||||
generic_info->fill_dmi_nop_u64 = &riscv013_fill_dmi_nop_u64;
|
generic_info->fill_dmi_nop_u64 = &riscv013_fill_dmi_nop_u64;
|
||||||
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->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;
|
||||||
|
@ -1187,23 +1185,54 @@ static int examine(struct target *target)
|
||||||
|
|
||||||
static int assert_reset(struct target *target)
|
static int assert_reset(struct target *target)
|
||||||
{
|
{
|
||||||
/*FIXME -- this only works for single-hart.*/
|
|
||||||
RISCV_INFO(r);
|
RISCV_INFO(r);
|
||||||
assert(r->current_hartid == 0);
|
|
||||||
|
|
||||||
select_dmi(target);
|
select_dmi(target);
|
||||||
LOG_DEBUG("ASSERTING NDRESET");
|
|
||||||
uint32_t control = dmi_read(target, DMI_DMCONTROL);
|
uint32_t control_base = set_field(0, DMI_DMCONTROL_DMACTIVE, 1);
|
||||||
control = set_field(control, DMI_DMCONTROL_NDMRESET, 1);
|
|
||||||
if (target->reset_halt) {
|
if (target->rtos) {
|
||||||
LOG_DEBUG("TARGET RESET HALT SET, ensuring halt is set during reset.");
|
// There's only one target, and OpenOCD thinks each hart is a thread.
|
||||||
control = set_field(control, DMI_DMCONTROL_HALTREQ, 1);
|
// We must reset them all.
|
||||||
|
|
||||||
|
// TODO: Try to use hasel in dmcontrol
|
||||||
|
|
||||||
|
// Set haltreq/resumereq for each hart.
|
||||||
|
uint32_t control = control_base;
|
||||||
|
for (int i = 0; i < riscv_count_harts(target); ++i) {
|
||||||
|
if (!riscv_hart_enabled(target, i))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
control = set_field(control_base, DMI_DMCONTROL_HARTSEL, i);
|
||||||
|
control = set_field(control, DMI_DMCONTROL_HALTREQ,
|
||||||
|
target->reset_halt ? 1 : 0);
|
||||||
|
dmi_write(target, DMI_DMCONTROL, control);
|
||||||
|
}
|
||||||
|
// Assert ndmreset
|
||||||
|
control = set_field(control, DMI_DMCONTROL_NDMRESET, 1);
|
||||||
|
dmi_write(target, DMI_DMCONTROL, control);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
LOG_DEBUG("TARGET RESET HALT NOT SET");
|
// Reset just this hart.
|
||||||
control = set_field(control, DMI_DMCONTROL_HALTREQ, 0);
|
uint32_t control = set_field(control_base, DMI_DMCONTROL_HARTSEL,
|
||||||
|
r->current_hartid);
|
||||||
|
control = set_field(control, DMI_DMCONTROL_HALTREQ,
|
||||||
|
target->reset_halt ? 1 : 0);
|
||||||
|
control = set_field(control, DMI_DMCONTROL_HARTRESET, 1);
|
||||||
|
dmi_write(target, DMI_DMCONTROL, control);
|
||||||
|
|
||||||
|
// Read back to check if hartreset is supported.
|
||||||
|
uint32_t rb = dmi_read(target, DMI_DMCONTROL);
|
||||||
|
if (!get_field(rb, DMI_DMCONTROL_HARTRESET)) {
|
||||||
|
// Use ndmreset instead. That will reset the entire device, but
|
||||||
|
// that's probably what OpenOCD wants anyway.
|
||||||
|
control = set_field(control, DMI_DMCONTROL_HARTRESET, 0);
|
||||||
|
control = set_field(control, DMI_DMCONTROL_NDMRESET, 1);
|
||||||
|
dmi_write(target, DMI_DMCONTROL, control);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dmi_write(target, DMI_DMCONTROL, control);
|
target->state = TARGET_RESET;
|
||||||
|
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
@ -1214,38 +1243,55 @@ static int deassert_reset(struct target *target)
|
||||||
RISCV013_INFO(info);
|
RISCV013_INFO(info);
|
||||||
select_dmi(target);
|
select_dmi(target);
|
||||||
|
|
||||||
/*FIXME -- this only works for Single Hart*/
|
LOG_DEBUG("%d", r->current_hartid);
|
||||||
assert(r->current_hartid == 0);
|
|
||||||
|
|
||||||
/*FIXME -- is there bookkeeping we need to do here*/
|
|
||||||
|
|
||||||
uint32_t control = dmi_read(target, DMI_DMCONTROL);
|
|
||||||
|
|
||||||
// Clear the reset, but make sure haltreq is still set
|
// Clear the reset, but make sure haltreq is still set
|
||||||
if (target->reset_halt) {
|
uint32_t control = 0;
|
||||||
control = set_field(control, DMI_DMCONTROL_HALTREQ, 1);
|
control = set_field(control, DMI_DMCONTROL_HALTREQ, target->reset_halt ? 1 : 0);
|
||||||
}
|
control = set_field(control, DMI_DMCONTROL_HARTSEL, r->current_hartid);
|
||||||
|
control = set_field(control, DMI_DMCONTROL_DMACTIVE, 1);
|
||||||
control = set_field(control, DMI_DMCONTROL_NDMRESET, 0);
|
|
||||||
dmi_write(target, DMI_DMCONTROL, control);
|
dmi_write(target, DMI_DMCONTROL, control);
|
||||||
|
|
||||||
uint32_t status;
|
uint32_t dmstatus;
|
||||||
int dmi_busy_delay = info->dmi_busy_delay;
|
int dmi_busy_delay = info->dmi_busy_delay;
|
||||||
|
time_t start = time(NULL);
|
||||||
|
|
||||||
if (target->reset_halt) {
|
if (target->reset_halt) {
|
||||||
LOG_DEBUG("DEASSERTING RESET, waiting for hart to be halted.");
|
LOG_DEBUG("Waiting for hart to be halted.");
|
||||||
do {
|
do {
|
||||||
status = dmi_read(target, DMI_DMSTATUS);
|
dmstatus = dmi_read(target, DMI_DMSTATUS);
|
||||||
} while (get_field(status, DMI_DMSTATUS_ALLHALTED) == 0);
|
if (time(NULL) - start > riscv_reset_timeout_sec) {
|
||||||
} else {
|
LOG_ERROR("Hart didn't halt coming out of reset in %ds; "
|
||||||
LOG_DEBUG("DEASSERTING RESET, waiting for hart to be running.");
|
"dmstatus=0x%x; "
|
||||||
do {
|
"Increase the timeout with riscv set_reset_timeout_sec.",
|
||||||
status = dmi_read(target, DMI_DMSTATUS);
|
riscv_reset_timeout_sec, dmstatus);
|
||||||
if (get_field(status, DMI_DMSTATUS_ANYHALTED) ||
|
return ERROR_FAIL;
|
||||||
get_field(status, DMI_DMSTATUS_ANYUNAVAIL)) {
|
|
||||||
LOG_ERROR("Unexpected hart status during reset.");
|
|
||||||
abort();
|
|
||||||
}
|
}
|
||||||
} while (get_field(status, DMI_DMSTATUS_ALLRUNNING) == 0);
|
target->state = TARGET_HALTED;
|
||||||
|
} while (get_field(dmstatus, DMI_DMSTATUS_ALLHALTED) == 0);
|
||||||
|
|
||||||
|
control = set_field(control, DMI_DMCONTROL_HALTREQ, 0);
|
||||||
|
dmi_write(target, DMI_DMCONTROL, control);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
LOG_DEBUG("Waiting for hart to be running.");
|
||||||
|
do {
|
||||||
|
dmstatus = dmi_read(target, DMI_DMSTATUS);
|
||||||
|
if (get_field(dmstatus, DMI_DMSTATUS_ANYHALTED) ||
|
||||||
|
get_field(dmstatus, DMI_DMSTATUS_ANYUNAVAIL)) {
|
||||||
|
LOG_ERROR("Unexpected hart status during reset. dmstatus=0x%x",
|
||||||
|
dmstatus);
|
||||||
|
return ERROR_FAIL;
|
||||||
|
}
|
||||||
|
if (time(NULL) - start > riscv_reset_timeout_sec) {
|
||||||
|
LOG_ERROR("Hart didn't run coming out of reset in %ds; "
|
||||||
|
"dmstatus=0x%x; "
|
||||||
|
"Increase the timeout with riscv set_reset_timeout_sec.",
|
||||||
|
riscv_reset_timeout_sec, dmstatus);
|
||||||
|
return ERROR_FAIL;
|
||||||
|
}
|
||||||
|
} while (get_field(dmstatus, DMI_DMSTATUS_ALLRUNNING) == 0);
|
||||||
|
target->state = TARGET_RUNNING;
|
||||||
}
|
}
|
||||||
info->dmi_busy_delay = dmi_busy_delay;
|
info->dmi_busy_delay = dmi_busy_delay;
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
|
@ -1880,37 +1926,6 @@ int riscv013_dmi_write_u64_bits(struct target *target)
|
||||||
return info->abits + DTM_DMI_DATA_LENGTH + DTM_DMI_OP_LENGTH;
|
return info->abits + DTM_DMI_DATA_LENGTH + DTM_DMI_OP_LENGTH;
|
||||||
}
|
}
|
||||||
|
|
||||||
void riscv013_reset_current_hart(struct target *target)
|
|
||||||
{
|
|
||||||
select_dmi(target);
|
|
||||||
uint32_t control = dmi_read(target, DMI_DMCONTROL);
|
|
||||||
control = set_field(control, DMI_DMCONTROL_NDMRESET, 1);
|
|
||||||
control = set_field(control, DMI_DMCONTROL_HALTREQ, 1);
|
|
||||||
dmi_write(target, DMI_DMCONTROL, control);
|
|
||||||
|
|
||||||
control = set_field(control, DMI_DMCONTROL_NDMRESET, 0);
|
|
||||||
dmi_write(target, DMI_DMCONTROL, control);
|
|
||||||
|
|
||||||
time_t start = time(NULL);
|
|
||||||
|
|
||||||
while (1) {
|
|
||||||
uint32_t dmstatus = dmi_read(target, DMI_DMSTATUS);
|
|
||||||
if (get_field(dmstatus, DMI_DMSTATUS_ALLHALTED)) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (time(NULL) - start > riscv_reset_timeout_sec) {
|
|
||||||
LOG_ERROR("Hart didn't halt coming out of reset in %ds; "
|
|
||||||
"dmstatus=0x%x; "
|
|
||||||
"Increase the timeout with riscv set_reset_timeout_sec.",
|
|
||||||
riscv_reset_timeout_sec, dmstatus);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
control = set_field(control, DMI_DMCONTROL_HALTREQ, 0);
|
|
||||||
dmi_write(target, DMI_DMCONTROL, control);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Helper Functions. */
|
/* Helper Functions. */
|
||||||
static void riscv013_on_step_or_resume(struct target *target, bool step)
|
static void riscv013_on_step_or_resume(struct target *target, bool step)
|
||||||
{
|
{
|
||||||
|
|
|
@ -676,14 +676,13 @@ static int old_or_new_riscv_halt(struct target *target)
|
||||||
return riscv_openocd_halt(target);
|
return riscv_openocd_halt(target);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int oldriscv_assert_reset(struct target *target)
|
static int riscv_assert_reset(struct target *target)
|
||||||
{
|
{
|
||||||
LOG_DEBUG("RISCV ASSERT RESET");
|
|
||||||
struct target_type *tt = get_target_type(target);
|
struct target_type *tt = get_target_type(target);
|
||||||
return tt->assert_reset(target);
|
return tt->assert_reset(target);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int oldriscv_deassert_reset(struct target *target)
|
static int riscv_deassert_reset(struct target *target)
|
||||||
{
|
{
|
||||||
LOG_DEBUG("RISCV DEASSERT RESET");
|
LOG_DEBUG("RISCV DEASSERT RESET");
|
||||||
struct target_type *tt = get_target_type(target);
|
struct target_type *tt = get_target_type(target);
|
||||||
|
@ -691,24 +690,6 @@ static int oldriscv_deassert_reset(struct target *target)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int old_or_new_riscv_assert_reset(struct target *target)
|
|
||||||
{
|
|
||||||
RISCV_INFO(r);
|
|
||||||
if (r->is_halted == NULL)
|
|
||||||
return oldriscv_assert_reset(target);
|
|
||||||
else
|
|
||||||
return riscv_openocd_assert_reset(target);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int old_or_new_riscv_deassert_reset(struct target *target)
|
|
||||||
{
|
|
||||||
RISCV_INFO(r);
|
|
||||||
if (r->is_halted == NULL)
|
|
||||||
return oldriscv_deassert_reset(target);
|
|
||||||
else
|
|
||||||
return riscv_openocd_deassert_reset(target);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int oldriscv_resume(struct target *target, int current, uint32_t address,
|
static int oldriscv_resume(struct target *target, int current, uint32_t address,
|
||||||
int handle_breakpoints, int debug_execution)
|
int handle_breakpoints, int debug_execution)
|
||||||
{
|
{
|
||||||
|
@ -1115,29 +1096,6 @@ int riscv_openocd_step(
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
int riscv_openocd_assert_reset(struct target *target)
|
|
||||||
{
|
|
||||||
LOG_DEBUG("asserting reset for all harts");
|
|
||||||
int out = riscv_reset_all_harts(target);
|
|
||||||
if (out != ERROR_OK) {
|
|
||||||
LOG_ERROR("unable to reset all harts");
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
int riscv_openocd_deassert_reset(struct target *target)
|
|
||||||
{
|
|
||||||
LOG_DEBUG("deasserting reset for all harts");
|
|
||||||
if (target->reset_halt)
|
|
||||||
riscv_halt_all_harts(target);
|
|
||||||
else
|
|
||||||
riscv_resume_all_harts(target);
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Command Handlers */
|
/* Command Handlers */
|
||||||
COMMAND_HANDLER(riscv_set_command_timeout_sec) {
|
COMMAND_HANDLER(riscv_set_command_timeout_sec) {
|
||||||
|
|
||||||
|
@ -1217,8 +1175,8 @@ struct target_type riscv_target =
|
||||||
.resume = old_or_new_riscv_resume,
|
.resume = old_or_new_riscv_resume,
|
||||||
.step = old_or_new_riscv_step,
|
.step = old_or_new_riscv_step,
|
||||||
|
|
||||||
.assert_reset = old_or_new_riscv_assert_reset,
|
.assert_reset = riscv_assert_reset,
|
||||||
.deassert_reset = old_or_new_riscv_deassert_reset,
|
.deassert_reset = riscv_deassert_reset,
|
||||||
|
|
||||||
.read_memory = riscv_read_memory,
|
.read_memory = riscv_read_memory,
|
||||||
.write_memory = riscv_write_memory,
|
.write_memory = riscv_write_memory,
|
||||||
|
@ -1315,33 +1273,6 @@ int riscv_resume_one_hart(struct target *target, int hartid)
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int riscv_reset_all_harts(struct target *target)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < riscv_count_harts(target); ++i) {
|
|
||||||
if (!riscv_hart_enabled(target, i))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
riscv_reset_one_hart(target, i);
|
|
||||||
}
|
|
||||||
|
|
||||||
riscv_invalidate_register_cache(target);
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
int riscv_reset_one_hart(struct target *target, int hartid)
|
|
||||||
{
|
|
||||||
RISCV_INFO(r);
|
|
||||||
LOG_DEBUG("resetting hart %d", hartid);
|
|
||||||
riscv_halt_one_hart(target, hartid);
|
|
||||||
riscv_set_current_hartid(target, hartid);
|
|
||||||
r->reset_current_hart(target);
|
|
||||||
/* At this point the hart must be halted. On platforms that support
|
|
||||||
* "reset halt" exactly we expect the hart to have been halted before
|
|
||||||
* executing any instructions, while on older cores it'll just have
|
|
||||||
* halted quickly. */
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
int riscv_step_rtos_hart(struct target *target)
|
int riscv_step_rtos_hart(struct target *target)
|
||||||
{
|
{
|
||||||
RISCV_INFO(r);
|
RISCV_INFO(r);
|
||||||
|
|
|
@ -103,7 +103,6 @@ typedef struct {
|
||||||
void (*fill_dmi_write_u64)(struct target *target, char *buf, int a, uint64_t d);
|
void (*fill_dmi_write_u64)(struct target *target, char *buf, int a, uint64_t d);
|
||||||
void (*fill_dmi_read_u64)(struct target *target, char *buf, int a);
|
void (*fill_dmi_read_u64)(struct target *target, char *buf, int a);
|
||||||
void (*fill_dmi_nop_u64)(struct target *target, char *buf);
|
void (*fill_dmi_nop_u64)(struct target *target, char *buf);
|
||||||
void (*reset_current_hart)(struct target *target);
|
|
||||||
} riscv_info_t;
|
} riscv_info_t;
|
||||||
|
|
||||||
/* Wall-clock timeout for a command/access. Settable via RISC-V Target commands.*/
|
/* Wall-clock timeout for a command/access. Settable via RISC-V Target commands.*/
|
||||||
|
@ -161,8 +160,6 @@ int riscv_halt_all_harts(struct target *target);
|
||||||
int riscv_halt_one_hart(struct target *target, int hartid);
|
int riscv_halt_one_hart(struct target *target, int hartid);
|
||||||
int riscv_resume_all_harts(struct target *target);
|
int riscv_resume_all_harts(struct target *target);
|
||||||
int riscv_resume_one_hart(struct target *target, int hartid);
|
int riscv_resume_one_hart(struct target *target, int hartid);
|
||||||
int riscv_reset_all_harts(struct target *target);
|
|
||||||
int riscv_reset_one_hart(struct target *target, int hartid);
|
|
||||||
|
|
||||||
/* Steps the hart that's currently selected in the RTOS, or if there is no RTOS
|
/* Steps the hart that's currently selected in the RTOS, or if there is no RTOS
|
||||||
* then the only hart. */
|
* then the only hart. */
|
||||||
|
|
Loading…
Reference in New Issue