Merge remote-tracking branch 'origin/notice_reset' into riscv-compliance
commit
6217f56186
|
@ -160,11 +160,10 @@ void dump_field(const struct scan_field *field)
|
||||||
|
|
||||||
log_printf_lf(LOG_LVL_DEBUG,
|
log_printf_lf(LOG_LVL_DEBUG,
|
||||||
__FILE__, __LINE__, __PRETTY_FUNCTION__,
|
__FILE__, __LINE__, __PRETTY_FUNCTION__,
|
||||||
"%db %s %08x @%02x -> %s %08x @%02x [0x%p -> 0x%p]",
|
"%db %s %08x @%02x -> %s %08x @%02x",
|
||||||
field->num_bits,
|
field->num_bits,
|
||||||
op_string[out_op], out_data, out_address,
|
op_string[out_op], out_data, out_address,
|
||||||
status_string[in_op], in_data, in_address,
|
status_string[in_op], in_data, in_address);
|
||||||
field->out_value, field->in_value);
|
|
||||||
} else {
|
} else {
|
||||||
log_printf_lf(LOG_LVL_DEBUG,
|
log_printf_lf(LOG_LVL_DEBUG,
|
||||||
__FILE__, __LINE__, __PRETTY_FUNCTION__, "%db %s %08x @%02x -> ?",
|
__FILE__, __LINE__, __PRETTY_FUNCTION__, "%db %s %08x @%02x -> ?",
|
||||||
|
|
|
@ -39,7 +39,7 @@ static void riscv013_clear_abstract_error(struct target *target);
|
||||||
static int riscv013_get_register(struct target *target,
|
static int riscv013_get_register(struct target *target,
|
||||||
riscv_reg_t *value, int hid, int rid);
|
riscv_reg_t *value, int hid, int rid);
|
||||||
static int riscv013_set_register(struct target *target, int hartid, int regid, uint64_t value);
|
static int riscv013_set_register(struct target *target, int hartid, int regid, uint64_t value);
|
||||||
static void riscv013_select_current_hart(struct target *target);
|
static int riscv013_select_current_hart(struct target *target);
|
||||||
static int riscv013_halt_current_hart(struct target *target);
|
static int riscv013_halt_current_hart(struct target *target);
|
||||||
static int riscv013_resume_current_hart(struct target *target);
|
static int riscv013_resume_current_hart(struct target *target);
|
||||||
static int riscv013_step_current_hart(struct target *target);
|
static int riscv013_step_current_hart(struct target *target);
|
||||||
|
@ -283,8 +283,11 @@ static void decode_dmi(char *text, unsigned address, unsigned data)
|
||||||
/* TODO: hartsellhi */
|
/* TODO: hartsellhi */
|
||||||
{ DMI_DMCONTROL, DMI_DMCONTROL_NDMRESET, "ndmreset" },
|
{ DMI_DMCONTROL, DMI_DMCONTROL_NDMRESET, "ndmreset" },
|
||||||
{ DMI_DMCONTROL, DMI_DMCONTROL_DMACTIVE, "dmactive" },
|
{ DMI_DMCONTROL, DMI_DMCONTROL_DMACTIVE, "dmactive" },
|
||||||
|
{ DMI_DMCONTROL, DMI_DMCONTROL_ACKHAVERESET, "ackhavereset" },
|
||||||
|
|
||||||
{ DMI_DMSTATUS, DMI_DMSTATUS_IMPEBREAK, "impebreak" },
|
{ DMI_DMSTATUS, DMI_DMSTATUS_IMPEBREAK, "impebreak" },
|
||||||
|
{ DMI_DMSTATUS, DMI_DMSTATUS_ALLHAVERESET, "allhavereset" },
|
||||||
|
{ DMI_DMSTATUS, DMI_DMSTATUS_ANYHAVERESET, "anyhavereset" },
|
||||||
{ DMI_DMSTATUS, DMI_DMSTATUS_ALLRESUMEACK, "allresumeack" },
|
{ DMI_DMSTATUS, DMI_DMSTATUS_ALLRESUMEACK, "allresumeack" },
|
||||||
{ DMI_DMSTATUS, DMI_DMSTATUS_ANYRESUMEACK, "anyresumeack" },
|
{ DMI_DMSTATUS, DMI_DMSTATUS_ANYRESUMEACK, "anyresumeack" },
|
||||||
{ DMI_DMSTATUS, DMI_DMSTATUS_ALLNONEXISTENT, "allnonexistent" },
|
{ DMI_DMSTATUS, DMI_DMSTATUS_ALLNONEXISTENT, "allnonexistent" },
|
||||||
|
@ -482,59 +485,90 @@ static dmi_status_t dmi_scan(struct target *target, uint32_t *address_in,
|
||||||
return buf_get_u32(in, DTM_DMI_OP_OFFSET, DTM_DMI_OP_LENGTH);
|
return buf_get_u32(in, DTM_DMI_OP_OFFSET, DTM_DMI_OP_LENGTH);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int dmi_read(struct target *target, uint32_t *value, uint32_t address)
|
static int dmi_op(struct target *target, uint32_t *data_in, int dmi_op,
|
||||||
|
uint32_t address, uint32_t data_out)
|
||||||
{
|
{
|
||||||
select_dmi(target);
|
select_dmi(target);
|
||||||
|
|
||||||
dmi_status_t status;
|
dmi_status_t status;
|
||||||
uint32_t address_in;
|
uint32_t address_in;
|
||||||
|
|
||||||
unsigned i = 0;
|
const char *op_name;
|
||||||
|
switch (dmi_op) {
|
||||||
|
case DMI_OP_NOP:
|
||||||
|
op_name = "nop";
|
||||||
|
break;
|
||||||
|
case DMI_OP_READ:
|
||||||
|
op_name = "read";
|
||||||
|
break;
|
||||||
|
case DMI_OP_WRITE:
|
||||||
|
op_name = "write";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
LOG_ERROR("Invalid DMI operation: %d", dmi_op);
|
||||||
|
return ERROR_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
/* This first loop ensures that the read request was actually sent
|
time_t start = time(NULL);
|
||||||
* to the target. Note that if for some reason this stays busy,
|
/* This first loop performs the request. Note that if for some reason this
|
||||||
* it is actually due to the previous dmi_read or dmi_write. */
|
* stays busy, it is actually due to the previous access. */
|
||||||
for (i = 0; i < 256; i++) {
|
while (1) {
|
||||||
status = dmi_scan(target, NULL, NULL, DMI_OP_READ, address, 0,
|
status = dmi_scan(target, NULL, NULL, dmi_op, address, data_out,
|
||||||
false);
|
false);
|
||||||
if (status == DMI_STATUS_BUSY) {
|
if (status == DMI_STATUS_BUSY) {
|
||||||
increase_dmi_busy_delay(target);
|
increase_dmi_busy_delay(target);
|
||||||
} else if (status == DMI_STATUS_SUCCESS) {
|
} else if (status == DMI_STATUS_SUCCESS) {
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
LOG_ERROR("failed read from 0x%x, status=%d", address, status);
|
LOG_ERROR("failed %s at 0x%x, status=%d", op_name, address, status);
|
||||||
|
return ERROR_FAIL;
|
||||||
|
}
|
||||||
|
if (time(NULL) - start > riscv_command_timeout_sec) {
|
||||||
|
LOG_ERROR("dmi.op is still busy after %d seconds. The target is "
|
||||||
|
"either really slow or broken. You could increase the "
|
||||||
|
"timeout with riscv set_command_timeout_sec.",
|
||||||
|
riscv_command_timeout_sec);
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
}
|
}
|
||||||
usleep(100000);
|
usleep(100000);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (status != DMI_STATUS_SUCCESS) {
|
if (status != DMI_STATUS_SUCCESS) {
|
||||||
LOG_ERROR("Failed read from 0x%x; status=%d", address, status);
|
LOG_ERROR("Failed %s at 0x%x; status=%d", op_name, address, status);
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This second loop ensures that we got the read
|
/* This second loop ensures the request succeeded, and gets back data.
|
||||||
* data back. Note that NOP can result in a 'busy' result as well, but
|
* Note that NOP can result in a 'busy' result as well, but that would be
|
||||||
* that would be noticed on the next DMI access we do. */
|
* noticed on the next DMI access we do. */
|
||||||
for (i = 0; i < 256; i++) {
|
while (1) {
|
||||||
status = dmi_scan(target, &address_in, value, DMI_OP_NOP, address, 0,
|
status = dmi_scan(target, &address_in, data_in, DMI_OP_NOP, address, 0,
|
||||||
false);
|
false);
|
||||||
if (status == DMI_STATUS_BUSY) {
|
if (status == DMI_STATUS_BUSY) {
|
||||||
increase_dmi_busy_delay(target);
|
increase_dmi_busy_delay(target);
|
||||||
} else if (status == DMI_STATUS_SUCCESS) {
|
} else if (status == DMI_STATUS_SUCCESS) {
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
LOG_ERROR("failed read (NOP) at 0x%x, status=%d", address, status);
|
LOG_ERROR("failed %s (NOP) at 0x%x, status=%d", op_name, address,
|
||||||
|
status);
|
||||||
|
return ERROR_FAIL;
|
||||||
|
}
|
||||||
|
if (time(NULL) - start > riscv_command_timeout_sec) {
|
||||||
|
LOG_ERROR("dmi.op is still busy after %d seconds. The target is "
|
||||||
|
"either really slow or broken. You could increase the "
|
||||||
|
"timeout with riscv set_command_timeout_sec.",
|
||||||
|
riscv_command_timeout_sec);
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (status != DMI_STATUS_SUCCESS) {
|
if (status != DMI_STATUS_SUCCESS) {
|
||||||
if (status == DMI_STATUS_FAILED) {
|
if (status == DMI_STATUS_FAILED || !data_in) {
|
||||||
LOG_ERROR("Failed read (NOP) from 0x%x; status=%d", address, status);
|
LOG_ERROR("Failed %s (NOP) at 0x%x; status=%d", op_name, address,
|
||||||
|
status);
|
||||||
} else {
|
} else {
|
||||||
LOG_ERROR("Failed read (NOP) from 0x%x; value=0x%x, status=%d",
|
LOG_ERROR("Failed %s (NOP) at 0x%x; value=0x%x, status=%d",
|
||||||
address, *value, status);
|
op_name, address, *data_in, status);
|
||||||
}
|
}
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
}
|
}
|
||||||
|
@ -542,53 +576,14 @@ static int dmi_read(struct target *target, uint32_t *value, uint32_t address)
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int dmi_read(struct target *target, uint32_t *value, uint32_t address)
|
||||||
|
{
|
||||||
|
return dmi_op(target, value, DMI_OP_READ, address, 0);
|
||||||
|
}
|
||||||
|
|
||||||
static int dmi_write(struct target *target, uint32_t address, uint32_t value)
|
static int dmi_write(struct target *target, uint32_t address, uint32_t value)
|
||||||
{
|
{
|
||||||
select_dmi(target);
|
return dmi_op(target, NULL, DMI_OP_WRITE, address, value);
|
||||||
dmi_status_t status = DMI_STATUS_BUSY;
|
|
||||||
unsigned i = 0;
|
|
||||||
|
|
||||||
/* The first loop ensures that we successfully sent the write request. */
|
|
||||||
for (i = 0; i < 256; i++) {
|
|
||||||
status = dmi_scan(target, NULL, NULL, DMI_OP_WRITE, address, value,
|
|
||||||
address == DMI_COMMAND);
|
|
||||||
if (status == DMI_STATUS_BUSY) {
|
|
||||||
increase_dmi_busy_delay(target);
|
|
||||||
} else if (status == DMI_STATUS_SUCCESS) {
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
LOG_ERROR("failed write to 0x%x, status=%d", address, status);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (status != DMI_STATUS_SUCCESS) {
|
|
||||||
LOG_ERROR("Failed write to 0x%x;, status=%d",
|
|
||||||
address, status);
|
|
||||||
return ERROR_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* The second loop isn't strictly necessary, but would ensure that the
|
|
||||||
* write is complete/ has no non-busy errors before returning from this
|
|
||||||
* function. */
|
|
||||||
for (i = 0; i < 256; i++) {
|
|
||||||
status = dmi_scan(target, NULL, NULL, DMI_OP_NOP, address, 0,
|
|
||||||
false);
|
|
||||||
if (status == DMI_STATUS_BUSY) {
|
|
||||||
increase_dmi_busy_delay(target);
|
|
||||||
} else if (status == DMI_STATUS_SUCCESS) {
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
LOG_ERROR("failed write (NOP) at 0x%x, status=%d", address, status);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (status != DMI_STATUS_SUCCESS) {
|
|
||||||
LOG_ERROR("failed to write (NOP) 0x%x to 0x%x; status=%d", value, address, status);
|
|
||||||
return ERROR_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int dmstatus_read(struct target *target, uint32_t *dmstatus,
|
int dmstatus_read(struct target *target, uint32_t *dmstatus,
|
||||||
|
@ -1129,10 +1124,9 @@ static int register_read_direct(struct target *target, uint64_t *value, uint32_t
|
||||||
int result = register_read_abstract(target, value, number,
|
int result = register_read_abstract(target, value, number,
|
||||||
register_size(target, number));
|
register_size(target, number));
|
||||||
|
|
||||||
if (result != ERROR_OK && info->progbufsize + r->impebreak >= 2 &&
|
if (result != ERROR_OK &&
|
||||||
riscv_is_halted(target)) {
|
info->progbufsize + r->impebreak >= 2 &&
|
||||||
assert(number != GDB_REGNO_S0);
|
number > GDB_REGNO_XPR31) {
|
||||||
|
|
||||||
struct riscv_program program;
|
struct riscv_program program;
|
||||||
riscv_program_init(&program, target);
|
riscv_program_init(&program, target);
|
||||||
|
|
||||||
|
@ -1358,7 +1352,8 @@ static int examine(struct target *target)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
r->current_hartid = i;
|
r->current_hartid = i;
|
||||||
riscv013_select_current_hart(target);
|
if (riscv013_select_current_hart(target) != ERROR_OK)
|
||||||
|
return ERROR_FAIL;
|
||||||
|
|
||||||
uint32_t s;
|
uint32_t s;
|
||||||
if (dmstatus_read(target, &s, true) != ERROR_OK)
|
if (dmstatus_read(target, &s, true) != ERROR_OK)
|
||||||
|
@ -1367,6 +1362,11 @@ static int examine(struct target *target)
|
||||||
break;
|
break;
|
||||||
r->hart_count = i + 1;
|
r->hart_count = i + 1;
|
||||||
|
|
||||||
|
if (get_field(s, DMI_DMSTATUS_ANYHAVERESET))
|
||||||
|
dmi_write(target, DMI_DMCONTROL,
|
||||||
|
set_field(DMI_DMCONTROL_DMACTIVE | DMI_DMCONTROL_ACKHAVERESET,
|
||||||
|
hartsel_mask(target), i));
|
||||||
|
|
||||||
if (!riscv_is_halted(target)) {
|
if (!riscv_is_halted(target)) {
|
||||||
if (riscv013_halt_current_hart(target) != ERROR_OK) {
|
if (riscv013_halt_current_hart(target) != ERROR_OK) {
|
||||||
LOG_ERROR("Fatal: Hart %d failed to halt during examine()", i);
|
LOG_ERROR("Fatal: Hart %d failed to halt during examine()", i);
|
||||||
|
@ -1538,7 +1538,7 @@ static int assert_reset(struct target *target)
|
||||||
|
|
||||||
/* TODO: Try to use hasel in dmcontrol */
|
/* TODO: Try to use hasel in dmcontrol */
|
||||||
|
|
||||||
/* Set haltreq/resumereq for each hart. */
|
/* Set haltreq for each hart. */
|
||||||
uint32_t control = control_base;
|
uint32_t control = control_base;
|
||||||
for (int i = 0; i < riscv_count_harts(target); ++i) {
|
for (int i = 0; i < riscv_count_harts(target); ++i) {
|
||||||
if (!riscv_hart_enabled(target, i))
|
if (!riscv_hart_enabled(target, i))
|
||||||
|
@ -1559,21 +1559,9 @@ static int assert_reset(struct target *target)
|
||||||
r->current_hartid);
|
r->current_hartid);
|
||||||
control = set_field(control, DMI_DMCONTROL_HALTREQ,
|
control = set_field(control, DMI_DMCONTROL_HALTREQ,
|
||||||
target->reset_halt ? 1 : 0);
|
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;
|
|
||||||
if (dmi_read(target, &rb, DMI_DMCONTROL) != ERROR_OK)
|
|
||||||
return ERROR_FAIL;
|
|
||||||
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);
|
control = set_field(control, DMI_DMCONTROL_NDMRESET, 1);
|
||||||
dmi_write(target, DMI_DMCONTROL, control);
|
dmi_write(target, DMI_DMCONTROL, control);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
target->state = TARGET_RESET;
|
target->state = TARGET_RESET;
|
||||||
|
|
||||||
|
@ -1586,58 +1574,75 @@ static int deassert_reset(struct target *target)
|
||||||
RISCV013_INFO(info);
|
RISCV013_INFO(info);
|
||||||
select_dmi(target);
|
select_dmi(target);
|
||||||
|
|
||||||
LOG_DEBUG("%d", r->current_hartid);
|
|
||||||
|
|
||||||
/* Clear the reset, but make sure haltreq is still set */
|
/* Clear the reset, but make sure haltreq is still set */
|
||||||
uint32_t control = 0;
|
uint32_t control = 0;
|
||||||
control = set_field(control, DMI_DMCONTROL_HALTREQ, target->reset_halt ? 1 : 0);
|
control = set_field(control, DMI_DMCONTROL_HALTREQ, target->reset_halt ? 1 : 0);
|
||||||
control = set_field(control, hartsel_mask(target), r->current_hartid);
|
|
||||||
control = set_field(control, DMI_DMCONTROL_DMACTIVE, 1);
|
control = set_field(control, DMI_DMCONTROL_DMACTIVE, 1);
|
||||||
dmi_write(target, DMI_DMCONTROL, control);
|
dmi_write(target, DMI_DMCONTROL,
|
||||||
|
set_field(control, hartsel_mask(target), r->current_hartid));
|
||||||
|
|
||||||
uint32_t dmstatus;
|
uint32_t dmstatus;
|
||||||
int dmi_busy_delay = info->dmi_busy_delay;
|
int dmi_busy_delay = info->dmi_busy_delay;
|
||||||
time_t start = time(NULL);
|
time_t start = time(NULL);
|
||||||
|
|
||||||
|
for (int i = 0; i < riscv_count_harts(target); ++i) {
|
||||||
|
int index = i;
|
||||||
|
if (target->rtos) {
|
||||||
|
if (!riscv_hart_enabled(target, index))
|
||||||
|
continue;
|
||||||
|
dmi_write(target, DMI_DMCONTROL,
|
||||||
|
set_field(control, hartsel_mask(target), index));
|
||||||
|
} else {
|
||||||
|
index = r->current_hartid;
|
||||||
|
}
|
||||||
|
|
||||||
if (target->reset_halt) {
|
if (target->reset_halt) {
|
||||||
LOG_DEBUG("Waiting for hart to be halted.");
|
LOG_DEBUG("Waiting for hart %d to halt out of reset.", index);
|
||||||
do {
|
do {
|
||||||
if (dmstatus_read(target, &dmstatus, true) != ERROR_OK)
|
if (dmstatus_read(target, &dmstatus, true) != ERROR_OK)
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
if (time(NULL) - start > riscv_reset_timeout_sec) {
|
if (time(NULL) - start > riscv_reset_timeout_sec) {
|
||||||
LOG_ERROR("Hart didn't halt coming out of reset in %ds; "
|
LOG_ERROR("Hart %d didn't halt coming out of reset in %ds; "
|
||||||
"dmstatus=0x%x; "
|
"dmstatus=0x%x; "
|
||||||
"Increase the timeout with riscv set_reset_timeout_sec.",
|
"Increase the timeout with riscv set_reset_timeout_sec.",
|
||||||
riscv_reset_timeout_sec, dmstatus);
|
index, riscv_reset_timeout_sec, dmstatus);
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
}
|
}
|
||||||
target->state = TARGET_HALTED;
|
|
||||||
} while (get_field(dmstatus, DMI_DMSTATUS_ALLHALTED) == 0);
|
} while (get_field(dmstatus, DMI_DMSTATUS_ALLHALTED) == 0);
|
||||||
|
target->state = TARGET_HALTED;
|
||||||
control = set_field(control, DMI_DMCONTROL_HALTREQ, 0);
|
|
||||||
dmi_write(target, DMI_DMCONTROL, control);
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
LOG_DEBUG("Waiting for hart to be running.");
|
LOG_DEBUG("Waiting for hart %d to run out of reset.", index);
|
||||||
do {
|
while (get_field(dmstatus, DMI_DMSTATUS_ALLRUNNING) == 0) {
|
||||||
if (dmstatus_read(target, &dmstatus, true) != ERROR_OK)
|
if (dmstatus_read(target, &dmstatus, true) != ERROR_OK)
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
if (get_field(dmstatus, DMI_DMSTATUS_ANYHALTED) ||
|
if (get_field(dmstatus, DMI_DMSTATUS_ANYHALTED) ||
|
||||||
get_field(dmstatus, DMI_DMSTATUS_ANYUNAVAIL)) {
|
get_field(dmstatus, DMI_DMSTATUS_ANYUNAVAIL)) {
|
||||||
LOG_ERROR("Unexpected hart status during reset. dmstatus=0x%x",
|
LOG_ERROR("Unexpected hart %d status during reset. dmstatus=0x%x",
|
||||||
dmstatus);
|
index, dmstatus);
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
}
|
}
|
||||||
if (time(NULL) - start > riscv_reset_timeout_sec) {
|
if (time(NULL) - start > riscv_reset_timeout_sec) {
|
||||||
LOG_ERROR("Hart didn't run coming out of reset in %ds; "
|
LOG_ERROR("Hart %d didn't run coming out of reset in %ds; "
|
||||||
"dmstatus=0x%x; "
|
"dmstatus=0x%x; "
|
||||||
"Increase the timeout with riscv set_reset_timeout_sec.",
|
"Increase the timeout with riscv set_reset_timeout_sec.",
|
||||||
riscv_reset_timeout_sec, dmstatus);
|
index, riscv_reset_timeout_sec, dmstatus);
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
}
|
}
|
||||||
} while (get_field(dmstatus, DMI_DMSTATUS_ALLRUNNING) == 0);
|
}
|
||||||
target->state = TARGET_RUNNING;
|
target->state = TARGET_RUNNING;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (get_field(dmstatus, DMI_DMSTATUS_ALLHAVERESET)) {
|
||||||
|
/* Ack reset. */
|
||||||
|
dmi_write(target, DMI_DMCONTROL,
|
||||||
|
set_field(control, hartsel_mask(target), index) |
|
||||||
|
DMI_DMCONTROL_ACKHAVERESET);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!target->rtos)
|
||||||
|
break;
|
||||||
|
}
|
||||||
info->dmi_busy_delay = dmi_busy_delay;
|
info->dmi_busy_delay = dmi_busy_delay;
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
@ -2664,14 +2669,15 @@ static int riscv013_set_register(struct target *target, int hid, int rid, uint64
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void riscv013_select_current_hart(struct target *target)
|
static int riscv013_select_current_hart(struct target *target)
|
||||||
{
|
{
|
||||||
RISCV_INFO(r);
|
RISCV_INFO(r);
|
||||||
|
|
||||||
uint32_t dmcontrol;
|
uint32_t dmcontrol;
|
||||||
dmi_read(target, &dmcontrol, DMI_DMCONTROL);
|
if (dmi_read(target, &dmcontrol, DMI_DMCONTROL) != ERROR_OK)
|
||||||
|
return ERROR_FAIL;
|
||||||
dmcontrol = set_field(dmcontrol, hartsel_mask(target), r->current_hartid);
|
dmcontrol = set_field(dmcontrol, hartsel_mask(target), r->current_hartid);
|
||||||
dmi_write(target, DMI_DMCONTROL, dmcontrol);
|
return dmi_write(target, DMI_DMCONTROL, dmcontrol);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int riscv013_halt_current_hart(struct target *target)
|
static int riscv013_halt_current_hart(struct target *target)
|
||||||
|
@ -2741,9 +2747,25 @@ static bool riscv013_is_halted(struct target *target)
|
||||||
if (dmstatus_read(target, &dmstatus, true) != ERROR_OK)
|
if (dmstatus_read(target, &dmstatus, true) != ERROR_OK)
|
||||||
return false;
|
return false;
|
||||||
if (get_field(dmstatus, DMI_DMSTATUS_ANYUNAVAIL))
|
if (get_field(dmstatus, DMI_DMSTATUS_ANYUNAVAIL))
|
||||||
LOG_ERROR("hart %d is unavailiable", riscv_current_hartid(target));
|
LOG_ERROR("Hart %d is unavailable.", riscv_current_hartid(target));
|
||||||
if (get_field(dmstatus, DMI_DMSTATUS_ANYNONEXISTENT))
|
if (get_field(dmstatus, DMI_DMSTATUS_ANYNONEXISTENT))
|
||||||
LOG_ERROR("hart %d doesn't exist", riscv_current_hartid(target));
|
LOG_ERROR("Hart %d doesn't exist.", riscv_current_hartid(target));
|
||||||
|
if (get_field(dmstatus, DMI_DMSTATUS_ANYHAVERESET)) {
|
||||||
|
int hartid = riscv_current_hartid(target);
|
||||||
|
LOG_INFO("Hart %d unexpectedly reset!", hartid);
|
||||||
|
/* TODO: Can we make this more obvious to eg. a gdb user? */
|
||||||
|
uint32_t dmcontrol = DMI_DMCONTROL_DMACTIVE |
|
||||||
|
DMI_DMCONTROL_ACKHAVERESET;
|
||||||
|
dmcontrol = set_field(dmcontrol, hartsel_mask(target), hartid);
|
||||||
|
/* 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
|
||||||
|
* that it is halted again once the request goes through.
|
||||||
|
*/
|
||||||
|
if (target->state == TARGET_HALTED)
|
||||||
|
dmcontrol |= DMI_DMCONTROL_HALTREQ;
|
||||||
|
dmi_write(target, DMI_DMCONTROL, dmcontrol);
|
||||||
|
}
|
||||||
return get_field(dmstatus, DMI_DMSTATUS_ALLHALTED);
|
return get_field(dmstatus, DMI_DMSTATUS_ALLHALTED);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2872,11 +2894,9 @@ static int riscv013_step_or_resume_current_hart(struct target *target, bool step
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
|
|
||||||
/* 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;
|
uint32_t dmcontrol = DMI_DMCONTROL_DMACTIVE;
|
||||||
if (dmi_read(target, &dmcontrol, DMI_DMCONTROL) != ERROR_OK)
|
dmcontrol = set_field(dmcontrol, hartsel_mask(target), r->current_hartid);
|
||||||
return ERROR_FAIL;
|
dmi_write(target, DMI_DMCONTROL, dmcontrol | DMI_DMCONTROL_RESUMEREQ);
|
||||||
dmcontrol = set_field(dmcontrol, DMI_DMCONTROL_RESUMEREQ, 1);
|
|
||||||
dmi_write(target, DMI_DMCONTROL, dmcontrol);
|
|
||||||
|
|
||||||
uint32_t dmstatus;
|
uint32_t dmstatus;
|
||||||
for (size_t i = 0; i < 256; ++i) {
|
for (size_t i = 0; i < 256; ++i) {
|
||||||
|
@ -2888,17 +2908,16 @@ static int riscv013_step_or_resume_current_hart(struct target *target, bool step
|
||||||
if (step && get_field(dmstatus, DMI_DMSTATUS_ALLHALTED) == 0)
|
if (step && get_field(dmstatus, DMI_DMSTATUS_ALLHALTED) == 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
dmcontrol = set_field(dmcontrol, DMI_DMCONTROL_RESUMEREQ, 0);
|
|
||||||
dmi_write(target, DMI_DMCONTROL, dmcontrol);
|
dmi_write(target, DMI_DMCONTROL, dmcontrol);
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dmstatus_read(target, &dmstatus, true) != ERROR_OK)
|
LOG_ERROR("unable to resume hart %d", r->current_hartid);
|
||||||
return ERROR_FAIL;
|
|
||||||
if (dmi_read(target, &dmcontrol, DMI_DMCONTROL) != ERROR_OK)
|
if (dmi_read(target, &dmcontrol, DMI_DMCONTROL) != ERROR_OK)
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
LOG_ERROR("unable to resume hart %d", r->current_hartid);
|
|
||||||
LOG_ERROR(" dmcontrol=0x%08x", dmcontrol);
|
LOG_ERROR(" dmcontrol=0x%08x", dmcontrol);
|
||||||
|
if (dmstatus_read(target, &dmstatus, true) != ERROR_OK)
|
||||||
|
return ERROR_FAIL;
|
||||||
LOG_ERROR(" dmstatus =0x%08x", dmstatus);
|
LOG_ERROR(" dmstatus =0x%08x", dmstatus);
|
||||||
|
|
||||||
if (step) {
|
if (step) {
|
||||||
|
@ -2923,7 +2942,7 @@ void riscv013_clear_abstract_error(struct target *target)
|
||||||
LOG_ERROR("abstractcs.busy is not going low after %d seconds "
|
LOG_ERROR("abstractcs.busy is not going low after %d seconds "
|
||||||
"(abstractcs=0x%x). The target is either really slow or "
|
"(abstractcs=0x%x). The target is either really slow or "
|
||||||
"broken. You could increase the timeout with riscv "
|
"broken. You could increase the timeout with riscv "
|
||||||
"set_reset_timeout_sec.",
|
"set_command_timeout_sec.",
|
||||||
riscv_command_timeout_sec, abstractcs);
|
riscv_command_timeout_sec, abstractcs);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -741,19 +741,20 @@ static int old_or_new_riscv_resume(
|
||||||
return riscv_openocd_resume(target, current, address, handle_breakpoints, debug_execution);
|
return riscv_openocd_resume(target, current, address, handle_breakpoints, debug_execution);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void riscv_select_current_hart(struct target *target)
|
static int riscv_select_current_hart(struct target *target)
|
||||||
{
|
{
|
||||||
RISCV_INFO(r);
|
RISCV_INFO(r);
|
||||||
if (r->rtos_hartid != -1 && riscv_rtos_enabled(target))
|
if (r->rtos_hartid != -1 && riscv_rtos_enabled(target))
|
||||||
riscv_set_current_hartid(target, r->rtos_hartid);
|
return riscv_set_current_hartid(target, r->rtos_hartid);
|
||||||
else
|
else
|
||||||
riscv_set_current_hartid(target, target->coreid);
|
return riscv_set_current_hartid(target, target->coreid);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int riscv_read_memory(struct target *target, target_addr_t address,
|
static int riscv_read_memory(struct target *target, target_addr_t address,
|
||||||
uint32_t size, uint32_t count, uint8_t *buffer)
|
uint32_t size, uint32_t count, uint8_t *buffer)
|
||||||
{
|
{
|
||||||
riscv_select_current_hart(target);
|
if (riscv_select_current_hart(target) != ERROR_OK)
|
||||||
|
return ERROR_FAIL;
|
||||||
struct target_type *tt = get_target_type(target);
|
struct target_type *tt = get_target_type(target);
|
||||||
return tt->read_memory(target, address, size, count, buffer);
|
return tt->read_memory(target, address, size, count, buffer);
|
||||||
}
|
}
|
||||||
|
@ -761,7 +762,8 @@ static int riscv_read_memory(struct target *target, target_addr_t address,
|
||||||
static int riscv_write_memory(struct target *target, target_addr_t address,
|
static int riscv_write_memory(struct target *target, target_addr_t address,
|
||||||
uint32_t size, uint32_t count, const uint8_t *buffer)
|
uint32_t size, uint32_t count, const uint8_t *buffer)
|
||||||
{
|
{
|
||||||
riscv_select_current_hart(target);
|
if (riscv_select_current_hart(target) != ERROR_OK)
|
||||||
|
return ERROR_FAIL;
|
||||||
struct target_type *tt = get_target_type(target);
|
struct target_type *tt = get_target_type(target);
|
||||||
return tt->write_memory(target, address, size, count, buffer);
|
return tt->write_memory(target, address, size, count, buffer);
|
||||||
}
|
}
|
||||||
|
@ -779,7 +781,8 @@ static int riscv_get_gdb_reg_list(struct target *target,
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
riscv_select_current_hart(target);
|
if (riscv_select_current_hart(target) != ERROR_OK)
|
||||||
|
return ERROR_FAIL;
|
||||||
|
|
||||||
switch (reg_class) {
|
switch (reg_class) {
|
||||||
case REG_CLASS_GENERAL:
|
case REG_CLASS_GENERAL:
|
||||||
|
@ -968,50 +971,61 @@ int riscv_blank_check_memory(struct target *target,
|
||||||
|
|
||||||
/*** OpenOCD Helper Functions ***/
|
/*** OpenOCD Helper Functions ***/
|
||||||
|
|
||||||
/* 0 means nothing happened, 1 means the hart's state changed (and thus the
|
enum riscv_poll_hart {
|
||||||
* poll should terminate), and -1 means there was an error. */
|
RPH_NO_CHANGE,
|
||||||
static int riscv_poll_hart(struct target *target, int hartid)
|
RPH_DISCOVERED_HALTED,
|
||||||
|
RPH_DISCOVERED_RUNNING,
|
||||||
|
RPH_ERROR
|
||||||
|
};
|
||||||
|
static enum riscv_poll_hart riscv_poll_hart(struct target *target, int hartid)
|
||||||
{
|
{
|
||||||
RISCV_INFO(r);
|
RISCV_INFO(r);
|
||||||
riscv_set_current_hartid(target, hartid);
|
if (riscv_set_current_hartid(target, hartid) != ERROR_OK)
|
||||||
|
return RPH_ERROR;
|
||||||
|
|
||||||
LOG_DEBUG("polling hart %d, target->state=%d (TARGET_HALTED=%d)", hartid, target->state, TARGET_HALTED);
|
LOG_DEBUG("polling hart %d, target->state=%d", hartid, target->state);
|
||||||
|
|
||||||
/* If OpenOCD this we're running but this hart is halted then it's time
|
/* If OpenOCD thinks we're running but this hart is halted then it's time
|
||||||
* to raise an event. */
|
* to raise an event. */
|
||||||
if (target->state != TARGET_HALTED && riscv_is_halted(target)) {
|
bool halted = riscv_is_halted(target);
|
||||||
|
if (target->state != TARGET_HALTED && halted) {
|
||||||
LOG_DEBUG(" triggered a halt");
|
LOG_DEBUG(" triggered a halt");
|
||||||
r->on_halt(target);
|
r->on_halt(target);
|
||||||
return 1;
|
return RPH_DISCOVERED_HALTED;
|
||||||
|
} else if (target->state != TARGET_RUNNING && !halted) {
|
||||||
|
LOG_DEBUG(" triggered running");
|
||||||
|
target->state = TARGET_RUNNING;
|
||||||
|
return RPH_DISCOVERED_RUNNING;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return RPH_NO_CHANGE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*** OpenOCD Interface ***/
|
/*** OpenOCD Interface ***/
|
||||||
int riscv_openocd_poll(struct target *target)
|
int riscv_openocd_poll(struct target *target)
|
||||||
{
|
{
|
||||||
LOG_DEBUG("polling all harts");
|
LOG_DEBUG("polling all harts");
|
||||||
int triggered_hart = -1;
|
int halted_hart = -1;
|
||||||
if (riscv_rtos_enabled(target)) {
|
if (riscv_rtos_enabled(target)) {
|
||||||
/* Check every hart for an event. */
|
/* Check every hart for an event. */
|
||||||
for (int i = 0; i < riscv_count_harts(target); ++i) {
|
for (int i = 0; i < riscv_count_harts(target); ++i) {
|
||||||
int out = riscv_poll_hart(target, i);
|
enum riscv_poll_hart out = riscv_poll_hart(target, i);
|
||||||
switch (out) {
|
switch (out) {
|
||||||
case 0:
|
case RPH_NO_CHANGE:
|
||||||
|
case RPH_DISCOVERED_RUNNING:
|
||||||
continue;
|
continue;
|
||||||
case 1:
|
case RPH_DISCOVERED_HALTED:
|
||||||
triggered_hart = i;
|
halted_hart = i;
|
||||||
break;
|
break;
|
||||||
case -1:
|
case RPH_ERROR:
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (triggered_hart == -1) {
|
if (halted_hart == -1) {
|
||||||
LOG_DEBUG(" no harts just halted, target->state=%d", target->state);
|
LOG_DEBUG(" no harts just halted, target->state=%d", target->state);
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
LOG_DEBUG(" hart %d halted", triggered_hart);
|
LOG_DEBUG(" hart %d halted", halted_hart);
|
||||||
|
|
||||||
/* If we're here then at least one hart triggered. That means
|
/* If we're here then at least one hart triggered. That means
|
||||||
* we want to go and halt _every_ hart in the system, as that's
|
* we want to go and halt _every_ hart in the system, as that's
|
||||||
|
@ -1022,15 +1036,19 @@ int riscv_openocd_poll(struct target *target)
|
||||||
for (int i = 0; i < riscv_count_harts(target); ++i)
|
for (int i = 0; i < riscv_count_harts(target); ++i)
|
||||||
riscv_halt_one_hart(target, i);
|
riscv_halt_one_hart(target, i);
|
||||||
} else {
|
} else {
|
||||||
if (riscv_poll_hart(target, riscv_current_hartid(target)) == 0)
|
enum riscv_poll_hart out = riscv_poll_hart(target,
|
||||||
|
riscv_current_hartid(target));
|
||||||
|
if (out == RPH_NO_CHANGE || out == RPH_DISCOVERED_RUNNING)
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
|
else if (out == RPH_ERROR)
|
||||||
|
return ERROR_FAIL;
|
||||||
|
|
||||||
triggered_hart = riscv_current_hartid(target);
|
halted_hart = riscv_current_hartid(target);
|
||||||
LOG_DEBUG(" hart %d halted", triggered_hart);
|
LOG_DEBUG(" hart %d halted", halted_hart);
|
||||||
}
|
}
|
||||||
|
|
||||||
target->state = TARGET_HALTED;
|
target->state = TARGET_HALTED;
|
||||||
switch (riscv_halt_reason(target, triggered_hart)) {
|
switch (riscv_halt_reason(target, halted_hart)) {
|
||||||
case RISCV_HALT_BREAKPOINT:
|
case RISCV_HALT_BREAKPOINT:
|
||||||
target->debug_reason = DBG_REASON_BREAKPOINT;
|
target->debug_reason = DBG_REASON_BREAKPOINT;
|
||||||
break;
|
break;
|
||||||
|
@ -1046,11 +1064,13 @@ int riscv_openocd_poll(struct target *target)
|
||||||
case RISCV_HALT_UNKNOWN:
|
case RISCV_HALT_UNKNOWN:
|
||||||
target->debug_reason = DBG_REASON_UNDEFINED;
|
target->debug_reason = DBG_REASON_UNDEFINED;
|
||||||
break;
|
break;
|
||||||
|
case RISCV_HALT_ERROR:
|
||||||
|
return ERROR_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (riscv_rtos_enabled(target)) {
|
if (riscv_rtos_enabled(target)) {
|
||||||
target->rtos->current_threadid = triggered_hart + 1;
|
target->rtos->current_threadid = halted_hart + 1;
|
||||||
target->rtos->current_thread = triggered_hart + 1;
|
target->rtos->current_thread = halted_hart + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
target->state = TARGET_HALTED;
|
target->state = TARGET_HALTED;
|
||||||
|
@ -1610,7 +1630,8 @@ int riscv_halt_one_hart(struct target *target, int hartid)
|
||||||
{
|
{
|
||||||
RISCV_INFO(r);
|
RISCV_INFO(r);
|
||||||
LOG_DEBUG("halting hart %d", hartid);
|
LOG_DEBUG("halting hart %d", hartid);
|
||||||
riscv_set_current_hartid(target, hartid);
|
if (riscv_set_current_hartid(target, hartid) != ERROR_OK)
|
||||||
|
return ERROR_FAIL;
|
||||||
if (riscv_is_halted(target)) {
|
if (riscv_is_halted(target)) {
|
||||||
LOG_DEBUG(" hart %d requested halt, but was already halted", hartid);
|
LOG_DEBUG(" hart %d requested halt, but was already halted", hartid);
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
|
@ -1636,7 +1657,8 @@ int riscv_resume_one_hart(struct target *target, int hartid)
|
||||||
{
|
{
|
||||||
RISCV_INFO(r);
|
RISCV_INFO(r);
|
||||||
LOG_DEBUG("resuming hart %d", hartid);
|
LOG_DEBUG("resuming hart %d", hartid);
|
||||||
riscv_set_current_hartid(target, hartid);
|
if (riscv_set_current_hartid(target, hartid) != ERROR_OK)
|
||||||
|
return ERROR_FAIL;
|
||||||
if (!riscv_is_halted(target)) {
|
if (!riscv_is_halted(target)) {
|
||||||
LOG_DEBUG(" hart %d requested resume, but was already resumed", hartid);
|
LOG_DEBUG(" hart %d requested resume, but was already resumed", hartid);
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
|
@ -1657,7 +1679,8 @@ int riscv_step_rtos_hart(struct target *target)
|
||||||
hartid = 0;
|
hartid = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
riscv_set_current_hartid(target, hartid);
|
if (riscv_set_current_hartid(target, hartid) != ERROR_OK)
|
||||||
|
return ERROR_FAIL;
|
||||||
LOG_DEBUG("stepping hart %d", hartid);
|
LOG_DEBUG("stepping hart %d", hartid);
|
||||||
|
|
||||||
if (!riscv_is_halted(target)) {
|
if (!riscv_is_halted(target)) {
|
||||||
|
@ -1707,33 +1730,35 @@ bool riscv_rtos_enabled(const struct target *target)
|
||||||
return target->rtos != NULL;
|
return target->rtos != NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void riscv_set_current_hartid(struct target *target, int hartid)
|
int riscv_set_current_hartid(struct target *target, int hartid)
|
||||||
{
|
{
|
||||||
RISCV_INFO(r);
|
RISCV_INFO(r);
|
||||||
if (!r->select_current_hart)
|
if (!r->select_current_hart)
|
||||||
return;
|
return ERROR_FAIL;
|
||||||
|
|
||||||
int previous_hartid = riscv_current_hartid(target);
|
int previous_hartid = riscv_current_hartid(target);
|
||||||
r->current_hartid = hartid;
|
r->current_hartid = hartid;
|
||||||
assert(riscv_hart_enabled(target, hartid));
|
assert(riscv_hart_enabled(target, hartid));
|
||||||
LOG_DEBUG("setting hartid to %d, was %d", hartid, previous_hartid);
|
LOG_DEBUG("setting hartid to %d, was %d", hartid, previous_hartid);
|
||||||
r->select_current_hart(target);
|
if (r->select_current_hart(target) != ERROR_OK)
|
||||||
|
return ERROR_FAIL;
|
||||||
|
|
||||||
/* This might get called during init, in which case we shouldn't be
|
/* This might get called during init, in which case we shouldn't be
|
||||||
* setting up the register cache. */
|
* setting up the register cache. */
|
||||||
if (!target_was_examined(target))
|
if (!target_was_examined(target))
|
||||||
return;
|
return ERROR_OK;
|
||||||
|
|
||||||
/* Avoid invalidating the register cache all the time. */
|
/* Avoid invalidating the register cache all the time. */
|
||||||
if (r->registers_initialized
|
if (r->registers_initialized
|
||||||
&& (!riscv_rtos_enabled(target) || (previous_hartid == hartid))
|
&& (!riscv_rtos_enabled(target) || (previous_hartid == hartid))
|
||||||
&& target->reg_cache->reg_list[GDB_REGNO_ZERO].size == (unsigned)riscv_xlen(target)
|
&& target->reg_cache->reg_list[GDB_REGNO_ZERO].size == (unsigned)riscv_xlen(target)
|
||||||
&& (!riscv_rtos_enabled(target) || (r->rtos_hartid != -1))) {
|
&& (!riscv_rtos_enabled(target) || (r->rtos_hartid != -1))) {
|
||||||
return;
|
return ERROR_OK;
|
||||||
} else
|
} else
|
||||||
LOG_DEBUG("Initializing registers: xlen=%d", riscv_xlen(target));
|
LOG_DEBUG("Initializing registers: xlen=%d", riscv_xlen(target));
|
||||||
|
|
||||||
riscv_invalidate_register_cache(target);
|
riscv_invalidate_register_cache(target);
|
||||||
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
void riscv_invalidate_register_cache(struct target *target)
|
void riscv_invalidate_register_cache(struct target *target)
|
||||||
|
@ -1823,7 +1848,8 @@ 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, int hartid)
|
||||||
{
|
{
|
||||||
RISCV_INFO(r);
|
RISCV_INFO(r);
|
||||||
riscv_set_current_hartid(target, hartid);
|
if (riscv_set_current_hartid(target, hartid) != ERROR_OK)
|
||||||
|
return RISCV_HALT_ERROR;
|
||||||
if (!riscv_is_halted(target)) {
|
if (!riscv_is_halted(target)) {
|
||||||
LOG_ERROR("Hart is not halted!");
|
LOG_ERROR("Hart is not halted!");
|
||||||
return RISCV_HALT_UNKNOWN;
|
return RISCV_HALT_UNKNOWN;
|
||||||
|
|
|
@ -31,7 +31,8 @@ enum riscv_halt_reason {
|
||||||
RISCV_HALT_BREAKPOINT,
|
RISCV_HALT_BREAKPOINT,
|
||||||
RISCV_HALT_SINGLESTEP,
|
RISCV_HALT_SINGLESTEP,
|
||||||
RISCV_HALT_TRIGGER,
|
RISCV_HALT_TRIGGER,
|
||||||
RISCV_HALT_UNKNOWN
|
RISCV_HALT_UNKNOWN,
|
||||||
|
RISCV_HALT_ERROR
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
@ -92,7 +93,7 @@ typedef struct {
|
||||||
riscv_reg_t *value, int hid, int rid);
|
riscv_reg_t *value, int hid, int rid);
|
||||||
int (*set_register)(struct target *, int hartid, int regid,
|
int (*set_register)(struct target *, int hartid, int regid,
|
||||||
uint64_t value);
|
uint64_t value);
|
||||||
void (*select_current_hart)(struct target *);
|
int (*select_current_hart)(struct target *);
|
||||||
bool (*is_halted)(struct target *target);
|
bool (*is_halted)(struct target *target);
|
||||||
int (*halt_current_hart)(struct target *);
|
int (*halt_current_hart)(struct target *);
|
||||||
int (*resume_current_hart)(struct target *target);
|
int (*resume_current_hart)(struct target *target);
|
||||||
|
@ -195,7 +196,7 @@ bool riscv_rtos_enabled(const struct target *target);
|
||||||
|
|
||||||
/* Sets the current hart, which is the hart that will actually be used when
|
/* Sets the current hart, which is the hart that will actually be used when
|
||||||
* issuing debug commands. */
|
* issuing debug commands. */
|
||||||
void riscv_set_current_hartid(struct target *target, int hartid);
|
int riscv_set_current_hartid(struct target *target, int hartid);
|
||||||
int riscv_current_hartid(const struct target *target);
|
int riscv_current_hartid(const struct target *target);
|
||||||
|
|
||||||
/*** Support functions for the RISC-V 'RTOS', which provides multihart support
|
/*** Support functions for the RISC-V 'RTOS', which provides multihart support
|
||||||
|
|
Loading…
Reference in New Issue