Remove riscv_info_t.current_hartid

This was used to track which hart a given operation must apply to. But
we already have a target associated with each operation, and from there
we can find the desired hart id. dm013_info_t already tracks
current_hartid (meaning which hart ID is currently selected by the DM).

This makes the code simpler to understand. Also it turns out we don't
need to make sure the correct hart ID is currently selected because
there are only a few real entry points.

Change-Id: Ibe8d5e156523397f245edd6ec0a5df3239b717bf
Signed-off-by: Tim Newsome <tim@sifive.com>
This commit is contained in:
Tim Newsome 2022-09-23 11:32:42 -07:00
parent 550a66e720
commit 84365e65e5
4 changed files with 79 additions and 121 deletions

View File

@ -1590,7 +1590,6 @@ static int examine(struct target *target)
return result;
target_set_examined(target);
riscv_set_current_hartid(target, 0);
for (size_t i = 0; i < 32; ++i)
reg_cache_set(target, i, -1);
LOG_INFO("Examined RISCV core; XLEN=%d, misa=0x%" PRIx64,

View File

@ -38,7 +38,7 @@ static void riscv013_clear_abstract_error(struct target *target);
static int riscv013_get_register(struct target *target,
riscv_reg_t *value, int rid);
static int riscv013_set_register(struct target *target, int regid, uint64_t value);
static int riscv013_select_current_hart(struct target *target);
static int dm013_select_hart(struct target *target, int hart_index);
static int riscv013_halt_prep(struct target *target);
static int riscv013_halt_go(struct target *target);
static int riscv013_resume_go(struct target *target);
@ -139,8 +139,12 @@ typedef struct {
bool was_reset;
/* Targets that are connected to this DM. */
struct list_head target_list;
/* The currently selected hartid on 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
* is not currently handled well.)
*/
int current_hartid;
bool hasel_supported;
/* The program buffer stores executable code. 0 is an illegal instruction,
@ -758,6 +762,12 @@ static int wait_for_idle(struct target *target, uint32_t *abstractcs)
}
}
static int dm013_select_target(struct target *target)
{
riscv013_info_t *info = get_info(target);
return dm013_select_hart(target, info->index);
}
static int execute_abstract_command(struct target *target, uint32_t command)
{
RISCV013_INFO(info);
@ -1384,6 +1394,9 @@ static int register_write_direct(struct target *target, unsigned number,
/** Actually read registers from the target right now. */
static int register_read_direct(struct target *target, uint64_t *value, uint32_t number)
{
if (dm013_select_target(target) != ERROR_OK)
return ERROR_FAIL;
int result = register_read_abstract(target, value, number,
register_size(target, number));
@ -1659,8 +1672,7 @@ static int examine(struct target *target)
/* Before doing anything else we must first enumerate the harts. */
if (dm->hart_count < 0) {
for (int i = 0; i < MIN(RISCV_MAX_HARTS, 1 << info->hartsellen); ++i) {
r->current_hartid = i;
if (riscv013_select_current_hart(target) != ERROR_OK)
if (dm013_select_hart(target, i) != ERROR_OK)
return ERROR_FAIL;
uint32_t s;
@ -1678,8 +1690,6 @@ static int examine(struct target *target)
LOG_DEBUG("Detected %d harts.", dm->hart_count);
}
r->current_hartid = target->coreid;
if (dm->hart_count == 0) {
LOG_ERROR("No harts found!");
return ERROR_FAIL;
@ -1688,7 +1698,7 @@ static int examine(struct target *target)
/* Don't call any riscv_* functions until after we've counted the number of
* cores and initialized registers. */
if (riscv013_select_current_hart(target) != ERROR_OK)
if (dm013_select_hart(target, info->index) != ERROR_OK)
return ERROR_FAIL;
bool halted = riscv_is_halted(target);
@ -1948,7 +1958,7 @@ static int riscv013_get_register_buf(struct target *target,
{
assert(regno >= GDB_REGNO_V0 && regno <= GDB_REGNO_V31);
if (riscv_select_current_hart(target) != ERROR_OK)
if (dm013_select_target(target) != ERROR_OK)
return ERROR_FAIL;
if (riscv_save_register(target, GDB_REGNO_S0) != ERROR_OK)
@ -2004,7 +2014,7 @@ static int riscv013_set_register_buf(struct target *target,
{
assert(regno >= GDB_REGNO_V0 && regno <= GDB_REGNO_V31);
if (riscv_select_current_hart(target) != ERROR_OK)
if (dm013_select_target(target) != ERROR_OK)
return ERROR_FAIL;
if (riscv_save_register(target, GDB_REGNO_S0) != ERROR_OK)
@ -2270,7 +2280,7 @@ static int init_target(struct command_context *cmd_ctx,
generic_info->set_register = &riscv013_set_register;
generic_info->get_register_buf = &riscv013_get_register_buf;
generic_info->set_register_buf = &riscv013_set_register_buf;
generic_info->select_current_hart = &riscv013_select_current_hart;
generic_info->select_target = &dm013_select_target;
generic_info->is_halted = &riscv013_is_halted;
generic_info->resume_go = &riscv013_resume_go;
generic_info->step_current_hart = &riscv013_step_current_hart;
@ -2329,7 +2339,7 @@ static int init_target(struct command_context *cmd_ctx,
static int assert_reset(struct target *target)
{
RISCV_INFO(r);
RISCV013_INFO(info);
select_dmi(target);
@ -2347,7 +2357,7 @@ static int assert_reset(struct target *target)
/* Set haltreq for each hart. */
uint32_t control = control_base;
control = set_hartsel(control_base, target->coreid);
control = set_hartsel(control_base, info->index);
control = set_field(control, DM_DMCONTROL_HALTREQ,
target->reset_halt ? 1 : 0);
dmi_write(target, DM_DMCONTROL, control);
@ -2358,7 +2368,7 @@ static int assert_reset(struct target *target)
} else {
/* Reset just this hart. */
uint32_t control = set_hartsel(control_base, r->current_hartid);
uint32_t control = set_hartsel(control_base, info->index);
control = set_field(control, DM_DMCONTROL_HALTREQ,
target->reset_halt ? 1 : 0);
control = set_field(control, DM_DMCONTROL_NDMRESET, 1);
@ -2381,7 +2391,6 @@ static int assert_reset(struct target *target)
static int deassert_reset(struct target *target)
{
RISCV_INFO(r);
RISCV013_INFO(info);
select_dmi(target);
@ -2389,22 +2398,21 @@ static int deassert_reset(struct target *target)
uint32_t control = 0;
control = set_field(control, DM_DMCONTROL_HALTREQ, target->reset_halt ? 1 : 0);
control = set_field(control, DM_DMCONTROL_DMACTIVE, 1);
dmi_write(target, DM_DMCONTROL,
set_hartsel(control, r->current_hartid));
dmi_write(target, DM_DMCONTROL, set_hartsel(control, info->index));
uint32_t dmstatus;
int dmi_busy_delay = info->dmi_busy_delay;
time_t start = time(NULL);
for (int i = 0; i < riscv_count_harts(target); ++i) {
int index = i;
for (unsigned int i = 0; i < riscv_count_harts(target); ++i) {
unsigned int index = i;
if (target->rtos) {
if (index != target->coreid)
if (index != info->index)
continue;
dmi_write(target, DM_DMCONTROL,
set_hartsel(control, index));
} else {
index = r->current_hartid;
index = info->index;
}
LOG_DEBUG("Waiting for hart %d to come out of reset.", index);
@ -2454,6 +2462,9 @@ static int deassert_reset(struct target *target)
static int execute_fence(struct target *target)
{
if (dm013_select_target(target) != ERROR_OK)
return ERROR_FAIL;
/* FIXME: For non-coherent systems we need to flush the caches right
* here, but there's no ISA-defined way of doing that. */
{
@ -3416,6 +3427,9 @@ static int read_memory_progbuf(struct target *target, target_addr_t address,
LOG_DEBUG("reading %d words of %d bytes from 0x%" TARGET_PRIxADDR, count,
size, address);
if (dm013_select_target(target) != ERROR_OK)
return ERROR_FAIL;
select_dmi(target);
memset(buffer, 0, count*size);
@ -4045,7 +4059,7 @@ static int riscv013_get_register(struct target *target,
LOG_DEBUG("[%s] reading register %s", target_name(target),
gdb_regno_name(rid));
if (riscv_select_current_hart(target) != ERROR_OK)
if (dm013_select_target(target) != ERROR_OK)
return ERROR_FAIL;
int result = ERROR_OK;
@ -4070,7 +4084,8 @@ static int riscv013_get_register(struct target *target,
static int riscv013_set_register(struct target *target, int rid, uint64_t value)
{
riscv013_select_current_hart(target);
if (dm013_select_target(target) != ERROR_OK)
return ERROR_FAIL;
LOG_TARGET_DEBUG(target, "writing 0x%" PRIx64 " to register %s",
value, gdb_regno_name(rid));
@ -4100,21 +4115,23 @@ static int riscv013_set_register(struct target *target, int rid, uint64_t value)
return ERROR_OK;
}
static int riscv013_select_current_hart(struct target *target)
static int dm013_select_hart(struct target *target, int hart_index)
{
RISCV_INFO(r);
dm013_info_t *dm = get_dm(target);
if (!dm)
return ERROR_FAIL;
if (r->current_hartid == dm->current_hartid)
if (hart_index == dm->current_hartid)
return ERROR_OK;
uint32_t dmcontrol = DM_DMCONTROL_DMACTIVE;
dmcontrol = set_hartsel(dmcontrol, r->current_hartid);
int result = dmi_write(target, DM_DMCONTROL, dmcontrol);
dm->current_hartid = r->current_hartid;
return result;
dmcontrol = set_hartsel(dmcontrol, hart_index);
if (dmi_write(target, DM_DMCONTROL, dmcontrol) != ERROR_OK) {
/* Who knows what the state is? */
dm->current_hartid = -2;
return ERROR_FAIL;
}
dm->current_hartid = hart_index;
return ERROR_OK;
}
/* Select all harts that were prepped and that are selectable, clearing the
@ -4128,6 +4145,7 @@ static int select_prepped_harts(struct target *target, bool *use_hasel)
RISCV_INFO(r);
r->prepped = false;
*use_hasel = false;
dm013_select_target(target);
return ERROR_OK;
}
@ -4178,18 +4196,19 @@ static int riscv013_halt_prep(struct target *target)
static int riscv013_halt_go(struct target *target)
{
RISCV013_INFO(info);
bool use_hasel = false;
if (select_prepped_harts(target, &use_hasel) != ERROR_OK)
return ERROR_FAIL;
RISCV_INFO(r);
LOG_DEBUG("halting hart %d", r->current_hartid);
LOG_TARGET_DEBUG(target, "halting hart");
/* Issue the halt command, and then wait for the current hart to halt. */
uint32_t dmcontrol = DM_DMCONTROL_DMACTIVE | DM_DMCONTROL_HALTREQ;
if (use_hasel)
dmcontrol |= DM_DMCONTROL_HASEL;
dmcontrol = set_hartsel(dmcontrol, r->current_hartid);
dmcontrol = set_hartsel(dmcontrol, info->index);
dmi_write(target, DM_DMCONTROL, dmcontrol);
for (size_t i = 0; i < 256; ++i)
if (riscv_is_halted(target))
@ -4258,20 +4277,23 @@ static int riscv013_on_halt(struct target *target)
static bool riscv013_is_halted(struct target *target)
{
RISCV013_INFO(info);
uint32_t dmstatus;
if (dm013_select_target(target) != ERROR_OK)
return false;
if (dmstatus_read(target, &dmstatus, true) != ERROR_OK)
return false;
if (get_field(dmstatus, DM_DMSTATUS_ANYUNAVAIL))
LOG_ERROR("Hart %d is unavailable.", riscv_current_hartid(target));
LOG_TARGET_ERROR(target, "Hart is unavailable.");
if (get_field(dmstatus, DM_DMSTATUS_ANYNONEXISTENT))
LOG_ERROR("Hart %d doesn't exist.", riscv_current_hartid(target));
LOG_TARGET_ERROR(target, "Hart doesn't exist.");
if (get_field(dmstatus, DM_DMSTATUS_ANYHAVERESET)) {
int hartid = riscv_current_hartid(target);
LOG_INFO("Hart %d unexpectedly reset!", hartid);
LOG_TARGET_INFO(target, "Hart unexpectedly reset!");
/* TODO: Can we make this more obvious to eg. a gdb user? */
uint32_t dmcontrol = DM_DMCONTROL_DMACTIVE |
DM_DMCONTROL_ACKHAVERESET;
dmcontrol = set_hartsel(dmcontrol, hartid);
dmcontrol = set_hartsel(dmcontrol, info->index);
/* 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
* message that a reset happened, that the target is running, and then
@ -4776,9 +4798,8 @@ static int riscv013_on_step_or_resume(struct target *target, bool step)
static int riscv013_step_or_resume_current_hart(struct target *target,
bool step, bool use_hasel)
{
RISCV_INFO(r);
if (!riscv_is_halted(target)) {
LOG_ERROR("Hart %d is not halted!", r->current_hartid);
LOG_TARGET_ERROR(target, "Hart is not halted!");
return ERROR_FAIL;
}
LOG_TARGET_DEBUG(target, "resuming (for step?=%d)", step);
@ -4786,11 +4807,12 @@ static int riscv013_step_or_resume_current_hart(struct target *target,
if (riscv_flush_registers(target) != ERROR_OK)
return ERROR_FAIL;
dm013_info_t *dm = get_dm(target);
/* Issue the resume command, and then wait for the current hart to resume. */
uint32_t dmcontrol = DM_DMCONTROL_DMACTIVE | DM_DMCONTROL_RESUMEREQ;
if (use_hasel)
dmcontrol |= DM_DMCONTROL_HASEL;
dmcontrol = set_hartsel(dmcontrol, r->current_hartid);
dmcontrol = set_hartsel(dmcontrol, dm->current_hartid);
dmi_write(target, DM_DMCONTROL, dmcontrol);
dmcontrol = set_field(dmcontrol, DM_DMCONTROL_HASEL, 0);

View File

@ -1155,11 +1155,6 @@ static int old_or_new_riscv_poll(struct target *target)
return riscv_openocd_poll(target);
}
int riscv_select_current_hart(struct target *target)
{
return riscv_set_current_hartid(target, target->coreid);
}
int riscv_flush_registers(struct target *target)
{
RISCV_INFO(r);
@ -1228,14 +1223,11 @@ int halt_prep(struct target *target)
LOG_DEBUG("[%s] prep hart, debug_reason=%d", target_name(target),
target->debug_reason);
if (riscv_select_current_hart(target) != ERROR_OK)
return ERROR_FAIL;
if (riscv_is_halted(target)) {
LOG_DEBUG("[%s] Hart is already halted (debug_reason=%d).",
target_name(target), target->debug_reason);
if (target->debug_reason == DBG_REASON_NOTHALTED) {
enum riscv_halt_reason halt_reason =
riscv_halt_reason(target, r->current_hartid);
enum riscv_halt_reason halt_reason = riscv_halt_reason(target);
if (set_debug_reason(target, halt_reason) != ERROR_OK)
return ERROR_FAIL;
}
@ -1252,8 +1244,6 @@ int riscv_halt_go_all_harts(struct target *target)
{
RISCV_INFO(r);
if (riscv_select_current_hart(target) != ERROR_OK)
return ERROR_FAIL;
if (riscv_is_halted(target)) {
LOG_DEBUG("[%s] Hart is already halted.", target_name(target));
} else {
@ -1464,8 +1454,6 @@ static int resume_prep(struct target *target, int current,
}
if (r->is_halted) {
if (riscv_select_current_hart(target) != ERROR_OK)
return ERROR_FAIL;
if (r->resume_prep(target) != ERROR_OK)
return ERROR_FAIL;
}
@ -1738,8 +1726,6 @@ static int riscv_read_phys_memory(struct target *target, target_addr_t phys_addr
uint32_t size, uint32_t count, uint8_t *buffer)
{
RISCV_INFO(r);
if (riscv_select_current_hart(target) != ERROR_OK)
return ERROR_FAIL;
return r->read_memory(target, phys_address, size, count, buffer, size);
}
@ -1751,9 +1737,6 @@ static int riscv_read_memory(struct target *target, target_addr_t address,
return ERROR_OK;
}
if (riscv_select_current_hart(target) != ERROR_OK)
return ERROR_FAIL;
target_addr_t physical_addr;
if (target->type->virt2phys(target, address, &physical_addr) == ERROR_OK)
address = physical_addr;
@ -1765,8 +1748,6 @@ static int riscv_read_memory(struct target *target, target_addr_t address,
static int riscv_write_phys_memory(struct target *target, target_addr_t phys_address,
uint32_t size, uint32_t count, const uint8_t *buffer)
{
if (riscv_select_current_hart(target) != ERROR_OK)
return ERROR_FAIL;
struct target_type *tt = get_target_type(target);
return tt->write_memory(target, phys_address, size, count, buffer);
}
@ -1779,9 +1760,6 @@ static int riscv_write_memory(struct target *target, target_addr_t address,
return ERROR_OK;
}
if (riscv_select_current_hart(target) != ERROR_OK)
return ERROR_FAIL;
target_addr_t physical_addr;
if (target->type->virt2phys(target, address, &physical_addr) == ERROR_OK)
address = physical_addr;
@ -1813,9 +1791,6 @@ static int riscv_get_gdb_reg_list_internal(struct target *target,
return ERROR_FAIL;
}
if (riscv_select_current_hart(target) != ERROR_OK)
return ERROR_FAIL;
switch (reg_class) {
case REG_CLASS_GENERAL:
*reg_list_size = 33;
@ -1971,9 +1946,9 @@ static int riscv_run_algorithm(struct target *target, int num_mem_params,
return result;
}
/* The current hart id might have been changed in poll(). */
if (riscv_select_current_hart(target) != ERROR_OK)
return ERROR_FAIL;
/* TODO: The current hart id might have been changed in poll(). */
/* if (riscv_select_current_hart(target) != ERROR_OK)
return ERROR_FAIL; */
if (reg_pc->type->get(reg_pc) != ERROR_OK)
return ERROR_FAIL;
@ -2113,8 +2088,6 @@ enum riscv_poll_hart {
static enum riscv_poll_hart riscv_poll_hart(struct target *target, int hartid)
{
RISCV_INFO(r);
if (riscv_set_current_hartid(target, hartid) != ERROR_OK)
return RPH_ERROR;
LOG_TARGET_DEBUG(target, "polling, target->state=%d", target->state);
@ -2194,7 +2167,6 @@ exit:
int riscv_openocd_poll(struct target *target)
{
LOG_DEBUG("polling all harts");
int halted_hart = -1;
enum target_state old_state = target->state;
if (target->smp) {
@ -2205,8 +2177,7 @@ int riscv_openocd_poll(struct target *target)
struct target *t = list->target;
if (!target_was_examined(t))
continue;
riscv_info_t *r = riscv_info(t);
enum riscv_poll_hart out = riscv_poll_hart(t, r->current_hartid);
enum riscv_poll_hart out = riscv_poll_hart(t, t->coreid);
switch (out) {
case RPH_NO_CHANGE:
break;
@ -2217,7 +2188,7 @@ int riscv_openocd_poll(struct target *target)
case RPH_DISCOVERED_HALTED:
t->state = TARGET_HALTED;
enum riscv_halt_reason halt_reason =
riscv_halt_reason(t, r->current_hartid);
riscv_halt_reason(t);
if (set_debug_reason(t, halt_reason) != ERROR_OK)
return ERROR_FAIL;
@ -2273,8 +2244,7 @@ int riscv_openocd_poll(struct target *target)
return ERROR_OK;
} else {
enum riscv_poll_hart out = riscv_poll_hart(target,
riscv_current_hartid(target));
enum riscv_poll_hart out = riscv_poll_hart(target, target->coreid);
if (out == RPH_NO_CHANGE || out == RPH_DISCOVERED_RUNNING) {
if (target->state == TARGET_RUNNING)
sample_memory(target);
@ -2283,10 +2253,10 @@ int riscv_openocd_poll(struct target *target)
return ERROR_FAIL;
}
halted_hart = riscv_current_hartid(target);
LOG_DEBUG(" hart %d halted", halted_hart);
LOG_TARGET_DEBUG(target, "hart halted");
enum riscv_halt_reason halt_reason = riscv_halt_reason(target, halted_hart);
target->state = TARGET_HALTED;
enum riscv_halt_reason halt_reason = riscv_halt_reason(target);
if (set_debug_reason(target, halt_reason) != ERROR_OK)
return ERROR_FAIL;
target->state = TARGET_HALTED;
@ -3516,7 +3486,6 @@ void riscv_info_init(struct target *target, riscv_info_t *r)
{
memset(r, 0, sizeof(*r));
r->dtm_version = 1;
r->current_hartid = target->coreid;
r->version_specific = NULL;
memset(r->trigger_unique_id, 0xff, sizeof(r->trigger_unique_id));
@ -3542,8 +3511,6 @@ static int riscv_resume_go_all_harts(struct target *target)
RISCV_INFO(r);
LOG_TARGET_DEBUG(target, "resuming hart, state=%d", target->state);
if (riscv_select_current_hart(target) != ERROR_OK)
return ERROR_FAIL;
if (riscv_is_halted(target)) {
if (r->resume_go(target) != ERROR_OK)
return ERROR_FAIL;
@ -3605,8 +3572,6 @@ int riscv_interrupts_restore(struct target *target, uint64_t old_mstatus)
int riscv_step_rtos_hart(struct target *target)
{
RISCV_INFO(r);
if (riscv_select_current_hart(target) != ERROR_OK)
return ERROR_FAIL;
LOG_DEBUG("[%s] stepping", target_name(target));
if (!riscv_is_halted(target)) {
@ -3643,21 +3608,6 @@ unsigned riscv_xlen(const struct target *target)
return r->xlen;
}
int riscv_set_current_hartid(struct target *target, int hartid)
{
RISCV_INFO(r);
if (!r->select_current_hart)
return ERROR_OK;
int previous_hartid = riscv_current_hartid(target);
r->current_hartid = hartid;
LOG_DEBUG("setting hartid to %d, was %d", hartid, previous_hartid);
if (r->select_current_hart(target) != ERROR_OK)
return ERROR_FAIL;
return ERROR_OK;
}
void riscv_invalidate_register_cache(struct target *target)
{
/* Do not invalidate the register cache if it is not yet set up
@ -3673,13 +3623,8 @@ void riscv_invalidate_register_cache(struct target *target)
}
}
int riscv_current_hartid(const struct target *target)
{
RISCV_INFO(r);
return r->current_hartid;
}
int riscv_count_harts(struct target *target)
unsigned int riscv_count_harts(struct target *target)
{
if (!target)
return 1;
@ -3846,12 +3791,10 @@ bool riscv_is_halted(struct target *target)
return r->is_halted(target);
}
enum riscv_halt_reason riscv_halt_reason(struct target *target, int hartid)
enum riscv_halt_reason riscv_halt_reason(struct target *target)
{
RISCV_INFO(r);
if (riscv_set_current_hartid(target, hartid) != ERROR_OK)
return RISCV_HALT_ERROR;
if (!riscv_is_halted(target)) {
if (target->state != TARGET_HALTED) {
LOG_ERROR("Hart is not halted!");
return RISCV_HALT_UNKNOWN;
}

View File

@ -99,12 +99,6 @@ typedef struct {
struct command_context *cmd_ctx;
void *version_specific;
/* The hart that is currently being debugged. Note that this is
* different than the hartid that the RTOS is expected to use. This
* one will change all the time, it's more of a global argument to
* every function than an actual */
int current_hartid;
/* Single buffer that contains all register names, instead of calling
* malloc for each register. Needs to be freed when reg_list is freed. */
char *reg_names;
@ -154,7 +148,7 @@ typedef struct {
int (*get_register_buf)(struct target *target, uint8_t *buf, int regno);
int (*set_register_buf)(struct target *target, int regno,
const uint8_t *buf);
int (*select_current_hart)(struct target *target);
int (*select_target)(struct target *target);
bool (*is_halted)(struct target *target);
/* Resume this target, as well as every other prepped target that can be
* resumed near-simultaneously. Clear the prepped flag on any target that
@ -354,7 +348,7 @@ int riscv_current_hartid(const struct target *target);
/* Lists the number of harts in the system, which are assumed to be
* consecutive and start with mhartid=0. */
int riscv_count_harts(struct target *target);
unsigned int riscv_count_harts(struct target *target);
/** Set register, updating the cache. */
int riscv_set_register(struct target *target, enum gdb_regno i, riscv_reg_t v);
@ -370,7 +364,7 @@ int riscv_flush_registers(struct target *target);
/* Checks the state of the current hart -- "is_halted" checks the actual
* on-device register. */
bool riscv_is_halted(struct target *target);
enum riscv_halt_reason riscv_halt_reason(struct target *target, int hartid);
enum riscv_halt_reason riscv_halt_reason(struct target *target);
/* These helper functions let the generic program interface get target-specific
* information. */