Properly track selecting multiple harts at once. (#743)
* Properly track selecting multiple harts at once. use_hasel is a bit of a hack. Change-Id: Ia589ebc16bca32038d915df9988361b88e940917 Signed-off-by: Tim Newsome <tim@sifive.com> * Clarifying comment. Co-authored-by: Jan Matyas <50193733+JanMatCodasip@users.noreply.github.com> Signed-off-by: Tim Newsome <tim@sifive.com> * Rename set_hartsel to set_dmcontrol_hartsel Change-Id: Iab28531281aa6fc604ec7d34974ed444ea9ea850 * Make set_dmcontrol_hartsel() more idiomatic. Change-Id: I56a885043c515359e33b9c8a03aed637c81d1486 * Use constant for multiple harts instead of -1. Change-Id: Iefeaf74202f2b4918d21f15f7ff7ca514175b8fb Signed-off-by: Tim Newsome <tim@sifive.com> Signed-off-by: Tim Newsome <tim@sifive.com> Co-authored-by: Jan Matyas <50193733+JanMatCodasip@users.noreply.github.com>
This commit is contained in:
parent
bed28d5ec7
commit
a50b280558
|
@ -31,7 +31,7 @@
|
||||||
|
|
||||||
static int riscv013_on_step_or_resume(struct target *target, bool step);
|
static int riscv013_on_step_or_resume(struct target *target, bool step);
|
||||||
static int riscv013_step_or_resume_current_hart(struct target *target,
|
static int riscv013_step_or_resume_current_hart(struct target *target,
|
||||||
bool step, bool use_hasel);
|
bool step);
|
||||||
static void riscv013_clear_abstract_error(struct target *target);
|
static void riscv013_clear_abstract_error(struct target *target);
|
||||||
|
|
||||||
/* Implementations of the functions in riscv_info_t. */
|
/* Implementations of the functions in riscv_info_t. */
|
||||||
|
@ -129,6 +129,8 @@ typedef enum {
|
||||||
YNM_NO
|
YNM_NO
|
||||||
} yes_no_maybe_t;
|
} yes_no_maybe_t;
|
||||||
|
|
||||||
|
#define HART_INDEX_MULTIPLE -1
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
struct list_head list;
|
struct list_head list;
|
||||||
int abs_chain_position;
|
int abs_chain_position;
|
||||||
|
@ -140,9 +142,7 @@ typedef struct {
|
||||||
/* Targets that are connected to this DM. */
|
/* Targets that are connected to this DM. */
|
||||||
struct list_head target_list;
|
struct list_head target_list;
|
||||||
/* Contains the ID of the hart that is currently selected by this DM.
|
/* Contains the ID of the hart that is currently selected by this DM.
|
||||||
* (If multiple harts are selected this is meaningless, and that corner case
|
* If multiple harts are selected this is HART_INDEX_MULTIPLE. */
|
||||||
* is not currently handled well.)
|
|
||||||
*/
|
|
||||||
int current_hartid;
|
int current_hartid;
|
||||||
|
|
||||||
bool hasel_supported;
|
bool hasel_supported;
|
||||||
|
@ -216,6 +216,9 @@ typedef struct {
|
||||||
|
|
||||||
/* DM that provides access to this target. */
|
/* DM that provides access to this target. */
|
||||||
dm013_info_t *dm;
|
dm013_info_t *dm;
|
||||||
|
|
||||||
|
/* This target was selected using hasel. */
|
||||||
|
bool selected;
|
||||||
} riscv013_info_t;
|
} riscv013_info_t;
|
||||||
|
|
||||||
LIST_HEAD(dm_list);
|
LIST_HEAD(dm_list);
|
||||||
|
@ -256,7 +259,7 @@ dm013_info_t *get_dm(struct target *target)
|
||||||
if (!dm)
|
if (!dm)
|
||||||
return NULL;
|
return NULL;
|
||||||
dm->abs_chain_position = abs_chain_position;
|
dm->abs_chain_position = abs_chain_position;
|
||||||
dm->current_hartid = -1;
|
dm->current_hartid = 0;
|
||||||
dm->hart_count = -1;
|
dm->hart_count = -1;
|
||||||
INIT_LIST_HEAD(&dm->target_list);
|
INIT_LIST_HEAD(&dm->target_list);
|
||||||
list_add(&dm->list, &dm_list);
|
list_add(&dm->list, &dm_list);
|
||||||
|
@ -279,16 +282,21 @@ dm013_info_t *get_dm(struct target *target)
|
||||||
return dm;
|
return dm;
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t set_hartsel(uint32_t initial, uint32_t index)
|
static uint32_t set_dmcontrol_hartsel(uint32_t initial, int hart_index)
|
||||||
{
|
{
|
||||||
initial &= ~DM_DMCONTROL_HARTSELLO;
|
if (hart_index >= 0) {
|
||||||
initial &= ~DM_DMCONTROL_HARTSELHI;
|
initial = set_field(initial, DM_DMCONTROL_HASEL, DM_DMCONTROL_HASEL_SINGLE);
|
||||||
|
uint32_t index_lo = hart_index & ((1 << DM_DMCONTROL_HARTSELLO_LENGTH) - 1);
|
||||||
uint32_t index_lo = index & ((1 << DM_DMCONTROL_HARTSELLO_LENGTH) - 1);
|
initial = set_field(initial, DM_DMCONTROL_HARTSELLO, index_lo);
|
||||||
initial |= index_lo << DM_DMCONTROL_HARTSELLO_OFFSET;
|
uint32_t index_hi = hart_index >> DM_DMCONTROL_HARTSELLO_LENGTH;
|
||||||
uint32_t index_hi = index >> DM_DMCONTROL_HARTSELLO_LENGTH;
|
assert(index_hi < (1 << DM_DMCONTROL_HARTSELHI_LENGTH));
|
||||||
assert(index_hi < 1 << DM_DMCONTROL_HARTSELHI_LENGTH);
|
initial = set_field(initial, DM_DMCONTROL_HARTSELHI, index_hi);
|
||||||
initial |= index_hi << DM_DMCONTROL_HARTSELHI_OFFSET;
|
} else if (hart_index == HART_INDEX_MULTIPLE) {
|
||||||
|
initial = set_field(initial, DM_DMCONTROL_HASEL, DM_DMCONTROL_HASEL_MULTIPLE);
|
||||||
|
/* TODO: https://github.com/riscv/riscv-openocd/issues/748 */
|
||||||
|
initial = set_field(initial, DM_DMCONTROL_HARTSELLO, 0);
|
||||||
|
initial = set_field(initial, DM_DMCONTROL_HARTSELHI, 0);
|
||||||
|
}
|
||||||
|
|
||||||
return initial;
|
return initial;
|
||||||
}
|
}
|
||||||
|
@ -1684,7 +1692,7 @@ static int examine(struct target *target)
|
||||||
|
|
||||||
if (get_field(s, DM_DMSTATUS_ANYHAVERESET))
|
if (get_field(s, DM_DMSTATUS_ANYHAVERESET))
|
||||||
dmi_write(target, DM_DMCONTROL,
|
dmi_write(target, DM_DMCONTROL,
|
||||||
set_hartsel(DM_DMCONTROL_DMACTIVE | DM_DMCONTROL_ACKHAVERESET, i));
|
set_dmcontrol_hartsel(DM_DMCONTROL_DMACTIVE | DM_DMCONTROL_ACKHAVERESET, i));
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG_DEBUG("Detected %d harts.", dm->hart_count);
|
LOG_DEBUG("Detected %d harts.", dm->hart_count);
|
||||||
|
@ -1703,6 +1711,7 @@ static int examine(struct target *target)
|
||||||
|
|
||||||
bool halted = riscv_is_halted(target);
|
bool halted = riscv_is_halted(target);
|
||||||
if (!halted) {
|
if (!halted) {
|
||||||
|
r->prepped = true;
|
||||||
if (riscv013_halt_go(target) != ERROR_OK) {
|
if (riscv013_halt_go(target) != ERROR_OK) {
|
||||||
LOG_TARGET_ERROR(target, "Fatal: Hart %d failed to halt during examine()",
|
LOG_TARGET_ERROR(target, "Fatal: Hart %d failed to halt during examine()",
|
||||||
info->index);
|
info->index);
|
||||||
|
@ -1761,7 +1770,7 @@ static int examine(struct target *target)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!halted)
|
if (!halted)
|
||||||
riscv013_step_or_resume_current_hart(target, false, false);
|
riscv013_step_or_resume_current_hart(target, false);
|
||||||
|
|
||||||
if (target->smp) {
|
if (target->smp) {
|
||||||
bool haltgroup_supported;
|
bool haltgroup_supported;
|
||||||
|
@ -2357,7 +2366,7 @@ static int assert_reset(struct target *target)
|
||||||
/* Set haltreq for each hart. */
|
/* Set haltreq for each hart. */
|
||||||
uint32_t control = control_base;
|
uint32_t control = control_base;
|
||||||
|
|
||||||
control = set_hartsel(control_base, info->index);
|
control = set_dmcontrol_hartsel(control_base, info->index);
|
||||||
control = set_field(control, DM_DMCONTROL_HALTREQ,
|
control = set_field(control, DM_DMCONTROL_HALTREQ,
|
||||||
target->reset_halt ? 1 : 0);
|
target->reset_halt ? 1 : 0);
|
||||||
dmi_write(target, DM_DMCONTROL, control);
|
dmi_write(target, DM_DMCONTROL, control);
|
||||||
|
@ -2368,7 +2377,7 @@ static int assert_reset(struct target *target)
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
/* Reset just this hart. */
|
/* Reset just this hart. */
|
||||||
uint32_t control = set_hartsel(control_base, info->index);
|
uint32_t control = set_dmcontrol_hartsel(control_base, info->index);
|
||||||
control = set_field(control, DM_DMCONTROL_HALTREQ,
|
control = set_field(control, DM_DMCONTROL_HALTREQ,
|
||||||
target->reset_halt ? 1 : 0);
|
target->reset_halt ? 1 : 0);
|
||||||
control = set_field(control, DM_DMCONTROL_NDMRESET, 1);
|
control = set_field(control, DM_DMCONTROL_NDMRESET, 1);
|
||||||
|
@ -2398,7 +2407,7 @@ static int deassert_reset(struct target *target)
|
||||||
uint32_t control = 0;
|
uint32_t control = 0;
|
||||||
control = set_field(control, DM_DMCONTROL_HALTREQ, target->reset_halt ? 1 : 0);
|
control = set_field(control, DM_DMCONTROL_HALTREQ, target->reset_halt ? 1 : 0);
|
||||||
control = set_field(control, DM_DMCONTROL_DMACTIVE, 1);
|
control = set_field(control, DM_DMCONTROL_DMACTIVE, 1);
|
||||||
dmi_write(target, DM_DMCONTROL, set_hartsel(control, info->index));
|
dmi_write(target, DM_DMCONTROL, set_dmcontrol_hartsel(control, info->index));
|
||||||
|
|
||||||
uint32_t dmstatus;
|
uint32_t dmstatus;
|
||||||
int dmi_busy_delay = info->dmi_busy_delay;
|
int dmi_busy_delay = info->dmi_busy_delay;
|
||||||
|
@ -2410,7 +2419,7 @@ static int deassert_reset(struct target *target)
|
||||||
if (index != info->index)
|
if (index != info->index)
|
||||||
continue;
|
continue;
|
||||||
dmi_write(target, DM_DMCONTROL,
|
dmi_write(target, DM_DMCONTROL,
|
||||||
set_hartsel(control, index));
|
set_dmcontrol_hartsel(control, index));
|
||||||
} else {
|
} else {
|
||||||
index = info->index;
|
index = info->index;
|
||||||
}
|
}
|
||||||
|
@ -2449,7 +2458,7 @@ static int deassert_reset(struct target *target)
|
||||||
if (get_field(dmstatus, DM_DMSTATUS_ALLHAVERESET)) {
|
if (get_field(dmstatus, DM_DMSTATUS_ALLHAVERESET)) {
|
||||||
/* Ack reset. */
|
/* Ack reset. */
|
||||||
dmi_write(target, DM_DMCONTROL,
|
dmi_write(target, DM_DMCONTROL,
|
||||||
set_hartsel(control, index) |
|
set_dmcontrol_hartsel(control, index) |
|
||||||
DM_DMCONTROL_ACKHAVERESET);
|
DM_DMCONTROL_ACKHAVERESET);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4122,7 +4131,7 @@ static int dm013_select_hart(struct target *target, int hart_index)
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
|
|
||||||
uint32_t dmcontrol = DM_DMCONTROL_DMACTIVE;
|
uint32_t dmcontrol = DM_DMCONTROL_DMACTIVE;
|
||||||
dmcontrol = set_hartsel(dmcontrol, hart_index);
|
dmcontrol = set_dmcontrol_hartsel(dmcontrol, hart_index);
|
||||||
if (dmi_write(target, DM_DMCONTROL, dmcontrol) != ERROR_OK) {
|
if (dmi_write(target, DM_DMCONTROL, dmcontrol) != ERROR_OK) {
|
||||||
/* Who knows what the state is? */
|
/* Who knows what the state is? */
|
||||||
dm->current_hartid = -2;
|
dm->current_hartid = -2;
|
||||||
|
@ -4134,15 +4143,14 @@ static int dm013_select_hart(struct target *target, int hart_index)
|
||||||
|
|
||||||
/* Select all harts that were prepped and that are selectable, clearing the
|
/* Select all harts that were prepped and that are selectable, clearing the
|
||||||
* prepped flag on the harts that actually were selected. */
|
* prepped flag on the harts that actually were selected. */
|
||||||
static int select_prepped_harts(struct target *target, bool *use_hasel)
|
static int select_prepped_harts(struct target *target)
|
||||||
{
|
{
|
||||||
|
RISCV_INFO(r);
|
||||||
dm013_info_t *dm = get_dm(target);
|
dm013_info_t *dm = get_dm(target);
|
||||||
if (!dm)
|
if (!dm)
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
if (!dm->hasel_supported) {
|
if (!dm->hasel_supported) {
|
||||||
RISCV_INFO(r);
|
|
||||||
r->prepped = false;
|
r->prepped = false;
|
||||||
*use_hasel = false;
|
|
||||||
dm013_select_target(target);
|
dm013_select_target(target);
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
@ -4155,27 +4163,33 @@ static int select_prepped_harts(struct target *target, bool *use_hasel)
|
||||||
|
|
||||||
target_list_t *entry;
|
target_list_t *entry;
|
||||||
unsigned total_selected = 0;
|
unsigned total_selected = 0;
|
||||||
|
unsigned int selected_index = 0;
|
||||||
list_for_each_entry(entry, &dm->target_list, list) {
|
list_for_each_entry(entry, &dm->target_list, list) {
|
||||||
struct target *t = entry->target;
|
struct target *t = entry->target;
|
||||||
riscv_info_t *r = riscv_info(t);
|
riscv_info_t *info = riscv_info(t);
|
||||||
riscv013_info_t *info = get_info(t);
|
riscv013_info_t *info_013 = get_info(t);
|
||||||
unsigned index = info->index;
|
unsigned index = info_013->index;
|
||||||
LOG_DEBUG("index=%d, coreid=%d, prepped=%d", index, t->coreid, r->prepped);
|
LOG_DEBUG("index=%d, coreid=%d, prepped=%d", index, t->coreid, info->prepped);
|
||||||
r->selected = r->prepped;
|
if (info->prepped) {
|
||||||
if (r->prepped) {
|
info_013->selected = true;
|
||||||
hawindow[index / 32] |= 1 << (index % 32);
|
hawindow[index / 32] |= 1 << (index % 32);
|
||||||
r->prepped = false;
|
info->prepped = false;
|
||||||
total_selected++;
|
total_selected++;
|
||||||
|
selected_index = index;
|
||||||
}
|
}
|
||||||
index++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (total_selected == 0) {
|
||||||
|
LOG_TARGET_ERROR(target, "No harts were prepped!");
|
||||||
|
return ERROR_FAIL;
|
||||||
|
} else if (total_selected == 1) {
|
||||||
/* Don't use hasel if we only need to talk to one hart. */
|
/* Don't use hasel if we only need to talk to one hart. */
|
||||||
if (total_selected <= 1) {
|
return dm013_select_hart(target, selected_index);
|
||||||
*use_hasel = false;
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (dm013_select_hart(target, HART_INDEX_MULTIPLE) != ERROR_OK)
|
||||||
|
return ERROR_FAIL;
|
||||||
|
|
||||||
for (unsigned i = 0; i < hawindow_count; i++) {
|
for (unsigned i = 0; i < hawindow_count; i++) {
|
||||||
if (dmi_write(target, DM_HAWINDOWSEL, i) != ERROR_OK)
|
if (dmi_write(target, DM_HAWINDOWSEL, i) != ERROR_OK)
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
|
@ -4183,7 +4197,6 @@ static int select_prepped_harts(struct target *target, bool *use_hasel)
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
*use_hasel = true;
|
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4194,19 +4207,18 @@ static int riscv013_halt_prep(struct target *target)
|
||||||
|
|
||||||
static int riscv013_halt_go(struct target *target)
|
static int riscv013_halt_go(struct target *target)
|
||||||
{
|
{
|
||||||
RISCV013_INFO(info);
|
dm013_info_t *dm = get_dm(target);
|
||||||
|
if (!dm)
|
||||||
|
return ERROR_FAIL;
|
||||||
|
|
||||||
bool use_hasel = false;
|
if (select_prepped_harts(target) != ERROR_OK)
|
||||||
if (select_prepped_harts(target, &use_hasel) != ERROR_OK)
|
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
|
|
||||||
LOG_TARGET_DEBUG(target, "halting hart");
|
LOG_TARGET_DEBUG(target, "halting hart");
|
||||||
|
|
||||||
/* Issue the halt command, and then wait for the current hart to halt. */
|
/* Issue the halt command, and then wait for the current hart to halt. */
|
||||||
uint32_t dmcontrol = DM_DMCONTROL_DMACTIVE | DM_DMCONTROL_HALTREQ;
|
uint32_t dmcontrol = DM_DMCONTROL_DMACTIVE | DM_DMCONTROL_HALTREQ;
|
||||||
if (use_hasel)
|
dmcontrol = set_dmcontrol_hartsel(dmcontrol, dm->current_hartid);
|
||||||
dmcontrol |= DM_DMCONTROL_HASEL;
|
|
||||||
dmcontrol = set_hartsel(dmcontrol, info->index);
|
|
||||||
dmi_write(target, DM_DMCONTROL, dmcontrol);
|
dmi_write(target, DM_DMCONTROL, dmcontrol);
|
||||||
uint32_t dmstatus;
|
uint32_t dmstatus;
|
||||||
for (size_t i = 0; i < 256; ++i) {
|
for (size_t i = 0; i < 256; ++i) {
|
||||||
|
@ -4232,11 +4244,8 @@ static int riscv013_halt_go(struct target *target)
|
||||||
dmcontrol = set_field(dmcontrol, DM_DMCONTROL_HALTREQ, 0);
|
dmcontrol = set_field(dmcontrol, DM_DMCONTROL_HALTREQ, 0);
|
||||||
dmi_write(target, DM_DMCONTROL, dmcontrol);
|
dmi_write(target, DM_DMCONTROL, dmcontrol);
|
||||||
|
|
||||||
if (use_hasel) {
|
if (dm->current_hartid == HART_INDEX_MULTIPLE) {
|
||||||
target_list_t *entry;
|
target_list_t *entry;
|
||||||
dm013_info_t *dm = get_dm(target);
|
|
||||||
if (!dm)
|
|
||||||
return ERROR_FAIL;
|
|
||||||
list_for_each_entry(entry, &dm->target_list, list) {
|
list_for_each_entry(entry, &dm->target_list, list) {
|
||||||
struct target *t = entry->target;
|
struct target *t = entry->target;
|
||||||
t->state = TARGET_HALTED;
|
t->state = TARGET_HALTED;
|
||||||
|
@ -4251,16 +4260,15 @@ static int riscv013_halt_go(struct target *target)
|
||||||
|
|
||||||
static int riscv013_resume_go(struct target *target)
|
static int riscv013_resume_go(struct target *target)
|
||||||
{
|
{
|
||||||
bool use_hasel = false;
|
if (select_prepped_harts(target) != ERROR_OK)
|
||||||
if (select_prepped_harts(target, &use_hasel) != ERROR_OK)
|
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
|
|
||||||
return riscv013_step_or_resume_current_hart(target, false, use_hasel);
|
return riscv013_step_or_resume_current_hart(target, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int riscv013_step_current_hart(struct target *target)
|
static int riscv013_step_current_hart(struct target *target)
|
||||||
{
|
{
|
||||||
return riscv013_step_or_resume_current_hart(target, true, false);
|
return riscv013_step_or_resume_current_hart(target, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int riscv013_resume_prep(struct target *target)
|
static int riscv013_resume_prep(struct target *target)
|
||||||
|
@ -4296,7 +4304,7 @@ static bool riscv013_is_halted(struct target *target)
|
||||||
/* TODO: Can we make this more obvious to eg. a gdb user? */
|
/* TODO: Can we make this more obvious to eg. a gdb user? */
|
||||||
uint32_t dmcontrol = DM_DMCONTROL_DMACTIVE |
|
uint32_t dmcontrol = DM_DMCONTROL_DMACTIVE |
|
||||||
DM_DMCONTROL_ACKHAVERESET;
|
DM_DMCONTROL_ACKHAVERESET;
|
||||||
dmcontrol = set_hartsel(dmcontrol, info->index);
|
dmcontrol = set_dmcontrol_hartsel(dmcontrol, info->index);
|
||||||
/* If we had been halted when we reset, request another halt. If we
|
/* If we had been halted when we reset, request another halt. If we
|
||||||
* ended up running out of reset, then the user will (hopefully) get a
|
* ended up running out of reset, then the user will (hopefully) get a
|
||||||
* message that a reset happened, that the target is running, and then
|
* message that a reset happened, that the target is running, and then
|
||||||
|
@ -4799,9 +4807,9 @@ static int riscv013_on_step_or_resume(struct target *target, bool step)
|
||||||
}
|
}
|
||||||
|
|
||||||
static int riscv013_step_or_resume_current_hart(struct target *target,
|
static int riscv013_step_or_resume_current_hart(struct target *target,
|
||||||
bool step, bool use_hasel)
|
bool step)
|
||||||
{
|
{
|
||||||
if (!riscv_is_halted(target)) {
|
if (target->state != TARGET_HALTED) {
|
||||||
LOG_TARGET_ERROR(target, "Hart is not halted!");
|
LOG_TARGET_ERROR(target, "Hart is not halted!");
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
}
|
}
|
||||||
|
@ -4813,12 +4821,9 @@ static int riscv013_step_or_resume_current_hart(struct target *target,
|
||||||
dm013_info_t *dm = get_dm(target);
|
dm013_info_t *dm = get_dm(target);
|
||||||
/* Issue the resume command, and then wait for the current hart to resume. */
|
/* Issue the resume command, and then wait for the current hart to resume. */
|
||||||
uint32_t dmcontrol = DM_DMCONTROL_DMACTIVE | DM_DMCONTROL_RESUMEREQ;
|
uint32_t dmcontrol = DM_DMCONTROL_DMACTIVE | DM_DMCONTROL_RESUMEREQ;
|
||||||
if (use_hasel)
|
dmcontrol = set_dmcontrol_hartsel(dmcontrol, dm->current_hartid);
|
||||||
dmcontrol |= DM_DMCONTROL_HASEL;
|
|
||||||
dmcontrol = set_hartsel(dmcontrol, dm->current_hartid);
|
|
||||||
dmi_write(target, DM_DMCONTROL, dmcontrol);
|
dmi_write(target, DM_DMCONTROL, dmcontrol);
|
||||||
|
|
||||||
dmcontrol = set_field(dmcontrol, DM_DMCONTROL_HASEL, 0);
|
|
||||||
dmcontrol = set_field(dmcontrol, DM_DMCONTROL_RESUMEREQ, 0);
|
dmcontrol = set_field(dmcontrol, DM_DMCONTROL_RESUMEREQ, 0);
|
||||||
|
|
||||||
uint32_t dmstatus;
|
uint32_t dmstatus;
|
||||||
|
|
Loading…
Reference in New Issue