Upstream tons of RISC-V changes.
These are all the changes from https://github.com/riscv/riscv-openocd
(approximately 91dc0c0c
) made just to src/target/riscv/*. Some of the
new code is disabled because it requires some other target-independent
changes which I didn't want to include here.
Built like this, OpenOCD passes:
* All single-RV32 tests against spike.
* All single-RV64 tests against spike.
* Enough HiFive1 tests. (I suspect the failures are due to the test
suite rotting.)
* Many dual-RV32 (-rtos hwthread) against spike.
* Many dual-RV64 (-rtos hwthread) against spike.
I suspect this is an overall improvement compared to what's in mainline
right now, and it gets me a lot closer to getting all the riscv-openocd
work upstreamed.
Change-Id: Ide2f80c9397400780ff6780d78a206bc6a6e2f98
Signed-off-by: Tim Newsome <tim@sifive.com>
Reviewed-on: http://openocd.zylin.com/5821
Tested-by: jenkins
Reviewed-by: Jan Matyas <matyas@codasip.com>
Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com>
Reviewed-by: Karl Palsson <karlp@tweak.net.au>
This commit is contained in:
parent
fc7edd57ac
commit
b68674a1da
|
@ -9714,8 +9714,31 @@ This is used to access 64-bit floating point registers on 32-bit targets.
|
||||||
@end deffn
|
@end deffn
|
||||||
|
|
||||||
@deffn Command {riscv set_prefer_sba} on|off
|
@deffn Command {riscv set_prefer_sba} on|off
|
||||||
When on, prefer to use System Bus Access to access memory. When off, prefer to
|
When on, prefer to use System Bus Access to access memory. When off (default),
|
||||||
use the Program Buffer to access memory.
|
prefer to use the Program Buffer to access memory.
|
||||||
|
@end deffn
|
||||||
|
|
||||||
|
@deffn Command {riscv set_enable_virtual} on|off
|
||||||
|
When on, memory accesses are performed on physical or virtual memory depending
|
||||||
|
on the current system configuration. When off (default), all memory accessses are performed
|
||||||
|
on physical memory.
|
||||||
|
@end deffn
|
||||||
|
|
||||||
|
@deffn Command {riscv set_enable_virt2phys} on|off
|
||||||
|
When on (default), memory accesses are performed on physical or virtual memory
|
||||||
|
depending on the current satp configuration. When off, all memory accessses are
|
||||||
|
performed on physical memory.
|
||||||
|
@end deffn
|
||||||
|
|
||||||
|
@deffn Command {riscv resume_order} normal|reversed
|
||||||
|
Some software assumes all harts are executing nearly continuously. Such
|
||||||
|
software may be sensitive to the order that harts are resumed in. On harts
|
||||||
|
that don't support hasel, this option allows the user to choose the order the
|
||||||
|
harts are resumed in. If you are using this option, it's probably masking a
|
||||||
|
race condition problem in your code.
|
||||||
|
|
||||||
|
Normal order is from lowest hart index to highest. This is the default
|
||||||
|
behavior. Reversed order is from highest hart index to lowest.
|
||||||
@end deffn
|
@end deffn
|
||||||
|
|
||||||
@deffn Command {riscv set_ir} (@option{idcode}|@option{dtmcs}|@option{dmi}) [value]
|
@deffn Command {riscv set_ir} (@option{idcode}|@option{dtmcs}|@option{dmi}) [value]
|
||||||
|
@ -9729,6 +9752,26 @@ When utilizing version 0.11 of the RISC-V Debug Specification,
|
||||||
and DBUS registers, respectively.
|
and DBUS registers, respectively.
|
||||||
@end deffn
|
@end deffn
|
||||||
|
|
||||||
|
@deffn Command {riscv use_bscan_tunnel} value
|
||||||
|
Enable or disable use of a BSCAN tunnel to reach DM. Supply the width of
|
||||||
|
the DM transport TAP's instruction register to enable. Supply a value of 0 to disable.
|
||||||
|
@end deffn
|
||||||
|
|
||||||
|
@deffn Command {riscv set_ebreakm} on|off
|
||||||
|
Control dcsr.ebreakm. When on (default), M-mode ebreak instructions trap to
|
||||||
|
OpenOCD. When off, they generate a breakpoint exception handled internally.
|
||||||
|
@end deffn
|
||||||
|
|
||||||
|
@deffn Command {riscv set_ebreaks} on|off
|
||||||
|
Control dcsr.ebreaks. When on (default), S-mode ebreak instructions trap to
|
||||||
|
OpenOCD. When off, they generate a breakpoint exception handled internally.
|
||||||
|
@end deffn
|
||||||
|
|
||||||
|
@deffn Command {riscv set_ebreaku} on|off
|
||||||
|
Control dcsr.ebreaku. When on (default), U-mode ebreak instructions trap to
|
||||||
|
OpenOCD. When off, they generate a breakpoint exception handled internally.
|
||||||
|
@end deffn
|
||||||
|
|
||||||
@subsection RISC-V Authentication Commands
|
@subsection RISC-V Authentication Commands
|
||||||
|
|
||||||
The following commands can be used to authenticate to a RISC-V system. Eg. a
|
The following commands can be used to authenticate to a RISC-V system. Eg. a
|
||||||
|
@ -9752,7 +9795,7 @@ Write the 32-bit value to authdata.
|
||||||
The following commands allow direct access to the Debug Module Interface, which
|
The following commands allow direct access to the Debug Module Interface, which
|
||||||
can be used to interact with custom debug features.
|
can be used to interact with custom debug features.
|
||||||
|
|
||||||
@deffn Command {riscv dmi_read}
|
@deffn Command {riscv dmi_read} address
|
||||||
Perform a 32-bit DMI read at address, returning the value.
|
Perform a 32-bit DMI read at address, returning the value.
|
||||||
@end deffn
|
@end deffn
|
||||||
|
|
||||||
|
|
|
@ -154,6 +154,7 @@ extern int debug_level;
|
||||||
#define ERROR_WAIT (-5)
|
#define ERROR_WAIT (-5)
|
||||||
/* ERROR_TIMEOUT is already taken by winerror.h. */
|
/* ERROR_TIMEOUT is already taken by winerror.h. */
|
||||||
#define ERROR_TIMEOUT_REACHED (-6)
|
#define ERROR_TIMEOUT_REACHED (-6)
|
||||||
|
#define ERROR_NOT_IMPLEMENTED (-7)
|
||||||
|
|
||||||
|
|
||||||
#endif /* OPENOCD_HELPER_LOG_H */
|
#endif /* OPENOCD_HELPER_LOG_H */
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||||
|
|
||||||
#ifndef TARGET__RISCV__ASM_H
|
#ifndef TARGET__RISCV__ASM_H
|
||||||
#define TARGET__RISCV__ASM_H
|
#define TARGET__RISCV__ASM_H
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||||
|
|
||||||
#ifdef HAVE_CONFIG_H
|
#ifdef HAVE_CONFIG_H
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#endif
|
#endif
|
||||||
|
@ -9,21 +11,53 @@
|
||||||
#define get_field(reg, mask) (((reg) & (mask)) / ((mask) & ~((mask) << 1)))
|
#define get_field(reg, mask) (((reg) & (mask)) / ((mask) & ~((mask) << 1)))
|
||||||
#define set_field(reg, mask, val) (((reg) & ~(mask)) | (((val) * ((mask) & ~((mask) << 1))) & (mask)))
|
#define set_field(reg, mask, val) (((reg) & ~(mask)) | (((val) * ((mask) & ~((mask) << 1))) & (mask)))
|
||||||
|
|
||||||
|
#define DTM_DMI_MAX_ADDRESS_LENGTH ((1<<DTM_DTMCS_ABITS_LENGTH)-1)
|
||||||
|
#define DMI_SCAN_MAX_BIT_LENGTH (DTM_DMI_MAX_ADDRESS_LENGTH + DTM_DMI_DATA_LENGTH + DTM_DMI_OP_LENGTH)
|
||||||
|
#define DMI_SCAN_BUF_SIZE (DIV_ROUND_UP(DMI_SCAN_MAX_BIT_LENGTH, 8))
|
||||||
|
|
||||||
static void dump_field(int idle, const struct scan_field *field);
|
static void dump_field(int idle, const struct scan_field *field);
|
||||||
|
|
||||||
struct riscv_batch *riscv_batch_alloc(struct target *target, size_t scans, size_t idle)
|
struct riscv_batch *riscv_batch_alloc(struct target *target, size_t scans, size_t idle)
|
||||||
{
|
{
|
||||||
scans += 4;
|
scans += 4;
|
||||||
struct riscv_batch *out = calloc(1, sizeof(*out));
|
struct riscv_batch *out = calloc(1, sizeof(*out));
|
||||||
|
if (!out)
|
||||||
|
goto error0;
|
||||||
out->target = target;
|
out->target = target;
|
||||||
out->allocated_scans = scans;
|
out->allocated_scans = scans;
|
||||||
out->idle_count = idle;
|
out->idle_count = idle;
|
||||||
out->data_out = malloc(sizeof(*out->data_out) * (scans) * sizeof(uint64_t));
|
out->data_out = malloc(sizeof(*out->data_out) * (scans) * DMI_SCAN_BUF_SIZE);
|
||||||
out->data_in = malloc(sizeof(*out->data_in) * (scans) * sizeof(uint64_t));
|
if (!out->data_out)
|
||||||
|
goto error1;
|
||||||
|
out->data_in = malloc(sizeof(*out->data_in) * (scans) * DMI_SCAN_BUF_SIZE);
|
||||||
|
if (!out->data_in)
|
||||||
|
goto error2;
|
||||||
out->fields = malloc(sizeof(*out->fields) * (scans));
|
out->fields = malloc(sizeof(*out->fields) * (scans));
|
||||||
|
if (!out->fields)
|
||||||
|
goto error3;
|
||||||
|
if (bscan_tunnel_ir_width != 0) {
|
||||||
|
out->bscan_ctxt = malloc(sizeof(*out->bscan_ctxt) * (scans));
|
||||||
|
if (!out->bscan_ctxt)
|
||||||
|
goto error4;
|
||||||
|
}
|
||||||
out->last_scan = RISCV_SCAN_TYPE_INVALID;
|
out->last_scan = RISCV_SCAN_TYPE_INVALID;
|
||||||
out->read_keys = malloc(sizeof(*out->read_keys) * (scans));
|
out->read_keys = malloc(sizeof(*out->read_keys) * (scans));
|
||||||
|
if (!out->read_keys)
|
||||||
|
goto error5;
|
||||||
return out;
|
return out;
|
||||||
|
|
||||||
|
error5:
|
||||||
|
free(out->bscan_ctxt);
|
||||||
|
error4:
|
||||||
|
free(out->fields);
|
||||||
|
error3:
|
||||||
|
free(out->data_in);
|
||||||
|
error2:
|
||||||
|
free(out->data_out);
|
||||||
|
error1:
|
||||||
|
free(out);
|
||||||
|
error0:
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void riscv_batch_free(struct riscv_batch *batch)
|
void riscv_batch_free(struct riscv_batch *batch)
|
||||||
|
@ -31,6 +65,8 @@ void riscv_batch_free(struct riscv_batch *batch)
|
||||||
free(batch->data_in);
|
free(batch->data_in);
|
||||||
free(batch->data_out);
|
free(batch->data_out);
|
||||||
free(batch->fields);
|
free(batch->fields);
|
||||||
|
free(batch->bscan_ctxt);
|
||||||
|
free(batch->read_keys);
|
||||||
free(batch);
|
free(batch);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,7 +87,11 @@ int riscv_batch_run(struct riscv_batch *batch)
|
||||||
riscv_batch_add_nop(batch);
|
riscv_batch_add_nop(batch);
|
||||||
|
|
||||||
for (size_t i = 0; i < batch->used_scans; ++i) {
|
for (size_t i = 0; i < batch->used_scans; ++i) {
|
||||||
jtag_add_dr_scan(batch->target->tap, 1, batch->fields + i, TAP_IDLE);
|
if (bscan_tunnel_ir_width != 0)
|
||||||
|
riscv_add_bscan_tunneled_scan(batch->target, batch->fields+i, batch->bscan_ctxt+i);
|
||||||
|
else
|
||||||
|
jtag_add_dr_scan(batch->target->tap, 1, batch->fields + i, TAP_IDLE);
|
||||||
|
|
||||||
if (batch->idle_count > 0)
|
if (batch->idle_count > 0)
|
||||||
jtag_add_runtest(batch->idle_count, TAP_IDLE);
|
jtag_add_runtest(batch->idle_count, TAP_IDLE);
|
||||||
}
|
}
|
||||||
|
@ -61,6 +101,12 @@ int riscv_batch_run(struct riscv_batch *batch)
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (bscan_tunnel_ir_width != 0) {
|
||||||
|
/* need to right-shift "in" by one bit, because of clock skew between BSCAN TAP and DM TAP */
|
||||||
|
for (size_t i = 0; i < batch->used_scans; ++i)
|
||||||
|
buffer_shr((batch->fields + i)->in_value, DMI_SCAN_BUF_SIZE, 1);
|
||||||
|
}
|
||||||
|
|
||||||
for (size_t i = 0; i < batch->used_scans; ++i)
|
for (size_t i = 0; i < batch->used_scans; ++i)
|
||||||
dump_field(batch->idle_count, batch->fields + i);
|
dump_field(batch->idle_count, batch->fields + i);
|
||||||
|
|
||||||
|
@ -72,8 +118,8 @@ void riscv_batch_add_dmi_write(struct riscv_batch *batch, unsigned address, uint
|
||||||
assert(batch->used_scans < batch->allocated_scans);
|
assert(batch->used_scans < batch->allocated_scans);
|
||||||
struct scan_field *field = batch->fields + batch->used_scans;
|
struct scan_field *field = batch->fields + batch->used_scans;
|
||||||
field->num_bits = riscv_dmi_write_u64_bits(batch->target);
|
field->num_bits = riscv_dmi_write_u64_bits(batch->target);
|
||||||
field->out_value = (void *)(batch->data_out + batch->used_scans * sizeof(uint64_t));
|
field->out_value = (void *)(batch->data_out + batch->used_scans * DMI_SCAN_BUF_SIZE);
|
||||||
field->in_value = (void *)(batch->data_in + batch->used_scans * sizeof(uint64_t));
|
field->in_value = (void *)(batch->data_in + batch->used_scans * DMI_SCAN_BUF_SIZE);
|
||||||
riscv_fill_dmi_write_u64(batch->target, (char *)field->out_value, address, data);
|
riscv_fill_dmi_write_u64(batch->target, (char *)field->out_value, address, data);
|
||||||
riscv_fill_dmi_nop_u64(batch->target, (char *)field->in_value);
|
riscv_fill_dmi_nop_u64(batch->target, (char *)field->in_value);
|
||||||
batch->last_scan = RISCV_SCAN_TYPE_WRITE;
|
batch->last_scan = RISCV_SCAN_TYPE_WRITE;
|
||||||
|
@ -85,35 +131,35 @@ size_t riscv_batch_add_dmi_read(struct riscv_batch *batch, unsigned address)
|
||||||
assert(batch->used_scans < batch->allocated_scans);
|
assert(batch->used_scans < batch->allocated_scans);
|
||||||
struct scan_field *field = batch->fields + batch->used_scans;
|
struct scan_field *field = batch->fields + batch->used_scans;
|
||||||
field->num_bits = riscv_dmi_write_u64_bits(batch->target);
|
field->num_bits = riscv_dmi_write_u64_bits(batch->target);
|
||||||
field->out_value = (void *)(batch->data_out + batch->used_scans * sizeof(uint64_t));
|
field->out_value = (void *)(batch->data_out + batch->used_scans * DMI_SCAN_BUF_SIZE);
|
||||||
field->in_value = (void *)(batch->data_in + batch->used_scans * sizeof(uint64_t));
|
field->in_value = (void *)(batch->data_in + batch->used_scans * DMI_SCAN_BUF_SIZE);
|
||||||
riscv_fill_dmi_read_u64(batch->target, (char *)field->out_value, address);
|
riscv_fill_dmi_read_u64(batch->target, (char *)field->out_value, address);
|
||||||
riscv_fill_dmi_nop_u64(batch->target, (char *)field->in_value);
|
riscv_fill_dmi_nop_u64(batch->target, (char *)field->in_value);
|
||||||
batch->last_scan = RISCV_SCAN_TYPE_READ;
|
batch->last_scan = RISCV_SCAN_TYPE_READ;
|
||||||
batch->used_scans++;
|
batch->used_scans++;
|
||||||
|
|
||||||
/* FIXME We get the read response back on the next scan. For now I'm
|
batch->read_keys[batch->read_keys_used] = batch->used_scans;
|
||||||
* just sticking a NOP in there, but this should be coalesced away. */
|
|
||||||
riscv_batch_add_nop(batch);
|
|
||||||
|
|
||||||
batch->read_keys[batch->read_keys_used] = batch->used_scans - 1;
|
|
||||||
return batch->read_keys_used++;
|
return batch->read_keys_used++;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t riscv_batch_get_dmi_read(struct riscv_batch *batch, size_t key)
|
unsigned riscv_batch_get_dmi_read_op(struct riscv_batch *batch, size_t key)
|
||||||
{
|
{
|
||||||
assert(key < batch->read_keys_used);
|
assert(key < batch->read_keys_used);
|
||||||
size_t index = batch->read_keys[key];
|
size_t index = batch->read_keys[key];
|
||||||
assert(index <= batch->used_scans);
|
assert(index <= batch->used_scans);
|
||||||
uint8_t *base = batch->data_in + 8 * index;
|
uint8_t *base = batch->data_in + DMI_SCAN_BUF_SIZE * index;
|
||||||
return base[0] |
|
/* extract "op" field from the DMI read result */
|
||||||
((uint64_t) base[1]) << 8 |
|
return (unsigned)buf_get_u32(base, DTM_DMI_OP_OFFSET, DTM_DMI_OP_LENGTH);
|
||||||
((uint64_t) base[2]) << 16 |
|
}
|
||||||
((uint64_t) base[3]) << 24 |
|
|
||||||
((uint64_t) base[4]) << 32 |
|
uint32_t riscv_batch_get_dmi_read_data(struct riscv_batch *batch, size_t key)
|
||||||
((uint64_t) base[5]) << 40 |
|
{
|
||||||
((uint64_t) base[6]) << 48 |
|
assert(key < batch->read_keys_used);
|
||||||
((uint64_t) base[7]) << 56;
|
size_t index = batch->read_keys[key];
|
||||||
|
assert(index <= batch->used_scans);
|
||||||
|
uint8_t *base = batch->data_in + DMI_SCAN_BUF_SIZE * index;
|
||||||
|
/* extract "data" field from the DMI read result */
|
||||||
|
return buf_get_u32(base, DTM_DMI_DATA_OFFSET, DTM_DMI_DATA_LENGTH);
|
||||||
}
|
}
|
||||||
|
|
||||||
void riscv_batch_add_nop(struct riscv_batch *batch)
|
void riscv_batch_add_nop(struct riscv_batch *batch)
|
||||||
|
@ -121,8 +167,8 @@ void riscv_batch_add_nop(struct riscv_batch *batch)
|
||||||
assert(batch->used_scans < batch->allocated_scans);
|
assert(batch->used_scans < batch->allocated_scans);
|
||||||
struct scan_field *field = batch->fields + batch->used_scans;
|
struct scan_field *field = batch->fields + batch->used_scans;
|
||||||
field->num_bits = riscv_dmi_write_u64_bits(batch->target);
|
field->num_bits = riscv_dmi_write_u64_bits(batch->target);
|
||||||
field->out_value = (void *)(batch->data_out + batch->used_scans * sizeof(uint64_t));
|
field->out_value = (void *)(batch->data_out + batch->used_scans * DMI_SCAN_BUF_SIZE);
|
||||||
field->in_value = (void *)(batch->data_in + batch->used_scans * sizeof(uint64_t));
|
field->in_value = (void *)(batch->data_in + batch->used_scans * DMI_SCAN_BUF_SIZE);
|
||||||
riscv_fill_dmi_nop_u64(batch->target, (char *)field->out_value);
|
riscv_fill_dmi_nop_u64(batch->target, (char *)field->out_value);
|
||||||
riscv_fill_dmi_nop_u64(batch->target, (char *)field->in_value);
|
riscv_fill_dmi_nop_u64(batch->target, (char *)field->in_value);
|
||||||
batch->last_scan = RISCV_SCAN_TYPE_NOP;
|
batch->last_scan = RISCV_SCAN_TYPE_NOP;
|
||||||
|
@ -151,13 +197,17 @@ void dump_field(int idle, 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 %di %s %08x @%02x -> %s %08x @%02x",
|
"%db %s %08x @%02x -> %s %08x @%02x; %di",
|
||||||
field->num_bits, idle,
|
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, idle);
|
||||||
status_string[in_op], in_data, in_address);
|
|
||||||
} else {
|
} else {
|
||||||
log_printf_lf(LOG_LVL_DEBUG,
|
log_printf_lf(LOG_LVL_DEBUG,
|
||||||
__FILE__, __LINE__, __PRETTY_FUNCTION__, "%db %di %s %08x @%02x -> ?",
|
__FILE__, __LINE__, __PRETTY_FUNCTION__, "%db %s %08x @%02x -> ?; %di",
|
||||||
field->num_bits, idle, op_string[out_op], out_data, out_address);
|
field->num_bits, op_string[out_op], out_data, out_address, idle);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t riscv_batch_available_scans(struct riscv_batch *batch)
|
||||||
|
{
|
||||||
|
return batch->allocated_scans - batch->used_scans - 4;
|
||||||
|
}
|
||||||
|
|
|
@ -1,8 +1,11 @@
|
||||||
|
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||||
|
|
||||||
#ifndef TARGET__RISCV__SCANS_H
|
#ifndef TARGET__RISCV__SCANS_H
|
||||||
#define TARGET__RISCV__SCANS_H
|
#define TARGET__RISCV__SCANS_H
|
||||||
|
|
||||||
#include "target/target.h"
|
#include "target/target.h"
|
||||||
#include "jtag/jtag.h"
|
#include "jtag/jtag.h"
|
||||||
|
#include "riscv.h"
|
||||||
|
|
||||||
enum riscv_scan_type {
|
enum riscv_scan_type {
|
||||||
RISCV_SCAN_TYPE_INVALID,
|
RISCV_SCAN_TYPE_INVALID,
|
||||||
|
@ -27,6 +30,11 @@ struct riscv_batch {
|
||||||
uint8_t *data_in;
|
uint8_t *data_in;
|
||||||
struct scan_field *fields;
|
struct scan_field *fields;
|
||||||
|
|
||||||
|
/* If in BSCAN mode, this field will be allocated (one per scan),
|
||||||
|
and utilized to tunnel all the scans in the batch. If not in
|
||||||
|
BSCAN mode, this field is unallocated and stays NULL */
|
||||||
|
riscv_bscan_tunneled_scan_context_t *bscan_ctxt;
|
||||||
|
|
||||||
/* In JTAG we scan out the previous value's output when performing a
|
/* In JTAG we scan out the previous value's output when performing a
|
||||||
* scan. This is a pain for users, so we just provide them the
|
* scan. This is a pain for users, so we just provide them the
|
||||||
* illusion of not having to do this by eliding all but the last NOP.
|
* illusion of not having to do this by eliding all but the last NOP.
|
||||||
|
@ -54,11 +62,16 @@ int riscv_batch_run(struct riscv_batch *batch);
|
||||||
void riscv_batch_add_dmi_write(struct riscv_batch *batch, unsigned address, uint64_t data);
|
void riscv_batch_add_dmi_write(struct riscv_batch *batch, unsigned address, uint64_t data);
|
||||||
|
|
||||||
/* DMI reads must be handled in two parts: the first one schedules a read and
|
/* DMI reads must be handled in two parts: the first one schedules a read and
|
||||||
* provides a key, the second one actually obtains the value of that read .*/
|
* provides a key, the second one actually obtains the result of the read -
|
||||||
|
* status (op) and the actual data. */
|
||||||
size_t riscv_batch_add_dmi_read(struct riscv_batch *batch, unsigned address);
|
size_t riscv_batch_add_dmi_read(struct riscv_batch *batch, unsigned address);
|
||||||
uint64_t riscv_batch_get_dmi_read(struct riscv_batch *batch, size_t key);
|
unsigned riscv_batch_get_dmi_read_op(struct riscv_batch *batch, size_t key);
|
||||||
|
uint32_t riscv_batch_get_dmi_read_data(struct riscv_batch *batch, size_t key);
|
||||||
|
|
||||||
/* Scans in a NOP. */
|
/* Scans in a NOP. */
|
||||||
void riscv_batch_add_nop(struct riscv_batch *batch);
|
void riscv_batch_add_nop(struct riscv_batch *batch);
|
||||||
|
|
||||||
|
/* Returns the number of available scans. */
|
||||||
|
size_t riscv_batch_available_scans(struct riscv_batch *batch);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -1,3 +1,5 @@
|
||||||
|
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||||
|
|
||||||
#ifndef TARGET__RISCV__GDB_REGS_H
|
#ifndef TARGET__RISCV__GDB_REGS_H
|
||||||
#define TARGET__RISCV__GDB_REGS_H
|
#define TARGET__RISCV__GDB_REGS_H
|
||||||
|
|
||||||
|
@ -21,6 +23,7 @@ enum gdb_regno {
|
||||||
GDB_REGNO_A3,
|
GDB_REGNO_A3,
|
||||||
GDB_REGNO_A4,
|
GDB_REGNO_A4,
|
||||||
GDB_REGNO_A5,
|
GDB_REGNO_A5,
|
||||||
|
GDB_REGNO_XPR15 = GDB_REGNO_A5,
|
||||||
GDB_REGNO_A6,
|
GDB_REGNO_A6,
|
||||||
GDB_REGNO_A7,
|
GDB_REGNO_A7,
|
||||||
GDB_REGNO_S2,
|
GDB_REGNO_S2,
|
||||||
|
@ -75,16 +78,37 @@ enum gdb_regno {
|
||||||
GDB_REGNO_FT11,
|
GDB_REGNO_FT11,
|
||||||
GDB_REGNO_FPR31 = GDB_REGNO_FT11,
|
GDB_REGNO_FPR31 = GDB_REGNO_FT11,
|
||||||
GDB_REGNO_CSR0 = 65,
|
GDB_REGNO_CSR0 = 65,
|
||||||
|
GDB_REGNO_VSTART = CSR_VSTART + GDB_REGNO_CSR0,
|
||||||
|
GDB_REGNO_VXSAT = CSR_VXSAT + GDB_REGNO_CSR0,
|
||||||
|
GDB_REGNO_VXRM = CSR_VXRM + GDB_REGNO_CSR0,
|
||||||
|
GDB_REGNO_VLENB = CSR_VLENB + GDB_REGNO_CSR0,
|
||||||
|
GDB_REGNO_VL = CSR_VL + GDB_REGNO_CSR0,
|
||||||
|
GDB_REGNO_VTYPE = CSR_VTYPE + GDB_REGNO_CSR0,
|
||||||
GDB_REGNO_TSELECT = CSR_TSELECT + GDB_REGNO_CSR0,
|
GDB_REGNO_TSELECT = CSR_TSELECT + GDB_REGNO_CSR0,
|
||||||
GDB_REGNO_TDATA1 = CSR_TDATA1 + GDB_REGNO_CSR0,
|
GDB_REGNO_TDATA1 = CSR_TDATA1 + GDB_REGNO_CSR0,
|
||||||
GDB_REGNO_TDATA2 = CSR_TDATA2 + GDB_REGNO_CSR0,
|
GDB_REGNO_TDATA2 = CSR_TDATA2 + GDB_REGNO_CSR0,
|
||||||
GDB_REGNO_MISA = CSR_MISA + GDB_REGNO_CSR0,
|
GDB_REGNO_MISA = CSR_MISA + GDB_REGNO_CSR0,
|
||||||
GDB_REGNO_DPC = CSR_DPC + GDB_REGNO_CSR0,
|
GDB_REGNO_DPC = CSR_DPC + GDB_REGNO_CSR0,
|
||||||
GDB_REGNO_DCSR = CSR_DCSR + GDB_REGNO_CSR0,
|
GDB_REGNO_DCSR = CSR_DCSR + GDB_REGNO_CSR0,
|
||||||
GDB_REGNO_DSCRATCH = CSR_DSCRATCH + GDB_REGNO_CSR0,
|
GDB_REGNO_DSCRATCH0 = CSR_DSCRATCH0 + GDB_REGNO_CSR0,
|
||||||
GDB_REGNO_MSTATUS = CSR_MSTATUS + GDB_REGNO_CSR0,
|
GDB_REGNO_MSTATUS = CSR_MSTATUS + GDB_REGNO_CSR0,
|
||||||
|
GDB_REGNO_MEPC = CSR_MEPC + GDB_REGNO_CSR0,
|
||||||
|
GDB_REGNO_MCAUSE = CSR_MCAUSE + GDB_REGNO_CSR0,
|
||||||
|
GDB_REGNO_SATP = CSR_SATP + GDB_REGNO_CSR0,
|
||||||
GDB_REGNO_CSR4095 = GDB_REGNO_CSR0 + 4095,
|
GDB_REGNO_CSR4095 = GDB_REGNO_CSR0 + 4095,
|
||||||
GDB_REGNO_PRIV = 4161,
|
GDB_REGNO_PRIV = 4161,
|
||||||
|
/* It's still undecided what register numbers GDB will actually use for
|
||||||
|
* these. See
|
||||||
|
* https://groups.google.com/a/groups.riscv.org/d/msg/sw-dev/7lQYiTUN9Ms/gTxGhzaYBQAJ
|
||||||
|
*/
|
||||||
|
GDB_REGNO_V0, GDB_REGNO_V1, GDB_REGNO_V2, GDB_REGNO_V3,
|
||||||
|
GDB_REGNO_V4, GDB_REGNO_V5, GDB_REGNO_V6, GDB_REGNO_V7,
|
||||||
|
GDB_REGNO_V8, GDB_REGNO_V9, GDB_REGNO_V10, GDB_REGNO_V11,
|
||||||
|
GDB_REGNO_V12, GDB_REGNO_V13, GDB_REGNO_V14, GDB_REGNO_V15,
|
||||||
|
GDB_REGNO_V16, GDB_REGNO_V17, GDB_REGNO_V18, GDB_REGNO_V19,
|
||||||
|
GDB_REGNO_V20, GDB_REGNO_V21, GDB_REGNO_V22, GDB_REGNO_V23,
|
||||||
|
GDB_REGNO_V24, GDB_REGNO_V25, GDB_REGNO_V26, GDB_REGNO_V27,
|
||||||
|
GDB_REGNO_V28, GDB_REGNO_V29, GDB_REGNO_V30, GDB_REGNO_V31,
|
||||||
GDB_REGNO_COUNT
|
GDB_REGNO_COUNT
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||||
|
|
||||||
#include "encoding.h"
|
#include "encoding.h"
|
||||||
|
|
||||||
#define ZERO 0
|
#define ZERO 0
|
||||||
|
@ -143,6 +145,18 @@ static uint32_t csrrw(unsigned int rd, unsigned int rs, unsigned int csr)
|
||||||
return (csr << 20) | (rs << 15) | (rd << 7) | MATCH_CSRRW;
|
return (csr << 20) | (rs << 15) | (rd << 7) | MATCH_CSRRW;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static uint32_t csrrci(unsigned int rd, unsigned int zimm, unsigned int csr) __attribute__ ((unused));
|
||||||
|
static uint32_t csrrci(unsigned int rd, unsigned int zimm, unsigned int csr)
|
||||||
|
{
|
||||||
|
return (csr << 20) | (zimm << 15) | (rd << 7) | MATCH_CSRRCI;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t csrrsi(unsigned int rd, unsigned int zimm, unsigned int csr) __attribute__ ((unused));
|
||||||
|
static uint32_t csrrsi(unsigned int rd, unsigned int zimm, unsigned int csr)
|
||||||
|
{
|
||||||
|
return (csr << 20) | (zimm << 15) | (rd << 7) | MATCH_CSRRSI;
|
||||||
|
}
|
||||||
|
|
||||||
static uint32_t fsw(unsigned int src, unsigned int base, uint16_t offset) __attribute__ ((unused));
|
static uint32_t fsw(unsigned int src, unsigned int base, uint16_t offset) __attribute__ ((unused));
|
||||||
static uint32_t fsw(unsigned int src, unsigned int base, uint16_t offset)
|
static uint32_t fsw(unsigned int src, unsigned int base, uint16_t offset)
|
||||||
{
|
{
|
||||||
|
@ -311,3 +325,33 @@ static uint32_t auipc(unsigned int dest)
|
||||||
{
|
{
|
||||||
return MATCH_AUIPC | (dest << 7);
|
return MATCH_AUIPC | (dest << 7);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static uint32_t vsetvli(unsigned int dest, unsigned int src, uint16_t imm) __attribute__((unused));
|
||||||
|
static uint32_t vsetvli(unsigned int dest, unsigned int src, uint16_t imm)
|
||||||
|
{
|
||||||
|
return (bits(imm, 10, 0) << 20) |
|
||||||
|
(src << 15) |
|
||||||
|
(dest << 7) |
|
||||||
|
MATCH_VSETVLI;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t vmv_x_s(unsigned int rd, unsigned int vs2) __attribute__((unused));
|
||||||
|
static uint32_t vmv_x_s(unsigned int rd, unsigned int vs2)
|
||||||
|
{
|
||||||
|
return (vs2 << 20) | (rd << 7) | MATCH_VMV_X_S;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t vmv_s_x(unsigned int vd, unsigned int vs2) __attribute__((unused));
|
||||||
|
static uint32_t vmv_s_x(unsigned int vd, unsigned int rs1)
|
||||||
|
{
|
||||||
|
return (rs1 << 15) | (vd << 7) | MATCH_VMV_S_X;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t vslide1down_vx(unsigned int vd, unsigned int vs2,
|
||||||
|
unsigned int rs1, unsigned int vm) __attribute__((unused));
|
||||||
|
static uint32_t vslide1down_vx(unsigned int vd, unsigned int vs2,
|
||||||
|
unsigned int rs1, unsigned int vm)
|
||||||
|
{
|
||||||
|
return (vm << 25) | (vs2 << 20) | (rs1 << 15) | (vd << 7) |
|
||||||
|
MATCH_VSLIDE1DOWN_VX;
|
||||||
|
}
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||||
|
|
||||||
#ifdef HAVE_CONFIG_H
|
#ifdef HAVE_CONFIG_H
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#endif
|
#endif
|
||||||
|
@ -30,7 +32,7 @@ int riscv_program_init(struct riscv_program *p, struct target *target)
|
||||||
int riscv_program_write(struct riscv_program *program)
|
int riscv_program_write(struct riscv_program *program)
|
||||||
{
|
{
|
||||||
for (unsigned i = 0; i < program->instruction_count; ++i) {
|
for (unsigned i = 0; i < program->instruction_count; ++i) {
|
||||||
LOG_DEBUG("%p: debug_buffer[%02x] = DASM(0x%08x)", program, i, program->debug_buffer[i]);
|
LOG_DEBUG("debug_buffer[%02x] = DASM(0x%08x)", i, program->debug_buffer[i]);
|
||||||
if (riscv_write_debug_buffer(program->target, i,
|
if (riscv_write_debug_buffer(program->target, i,
|
||||||
program->debug_buffer[i]) != ERROR_OK)
|
program->debug_buffer[i]) != ERROR_OK)
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
|
@ -56,7 +58,8 @@ int riscv_program_exec(struct riscv_program *p, struct target *t)
|
||||||
if (riscv_program_ebreak(p) != ERROR_OK) {
|
if (riscv_program_ebreak(p) != ERROR_OK) {
|
||||||
LOG_ERROR("Unable to write ebreak");
|
LOG_ERROR("Unable to write ebreak");
|
||||||
for (size_t i = 0; i < riscv_debug_buffer_size(p->target); ++i)
|
for (size_t i = 0; i < riscv_debug_buffer_size(p->target); ++i)
|
||||||
LOG_ERROR("ram[%02x]: DASM(0x%08lx) [0x%08lx]", (int)i, (long)p->debug_buffer[i], (long)p->debug_buffer[i]);
|
LOG_ERROR("ram[%02x]: DASM(0x%08" PRIx32 ") [0x%08" PRIx32 "]",
|
||||||
|
(int)i, p->debug_buffer[i], p->debug_buffer[i]);
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -79,6 +82,11 @@ int riscv_program_exec(struct riscv_program *p, struct target *t)
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int riscv_program_sdr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno b, int offset)
|
||||||
|
{
|
||||||
|
return riscv_program_insert(p, sd(d, b, offset));
|
||||||
|
}
|
||||||
|
|
||||||
int riscv_program_swr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno b, int offset)
|
int riscv_program_swr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno b, int offset)
|
||||||
{
|
{
|
||||||
return riscv_program_insert(p, sw(d, b, offset));
|
return riscv_program_insert(p, sw(d, b, offset));
|
||||||
|
@ -94,6 +102,11 @@ int riscv_program_sbr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno
|
||||||
return riscv_program_insert(p, sb(d, b, offset));
|
return riscv_program_insert(p, sb(d, b, offset));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int riscv_program_ldr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno b, int offset)
|
||||||
|
{
|
||||||
|
return riscv_program_insert(p, ld(d, b, offset));
|
||||||
|
}
|
||||||
|
|
||||||
int riscv_program_lwr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno b, int offset)
|
int riscv_program_lwr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno b, int offset)
|
||||||
{
|
{
|
||||||
return riscv_program_insert(p, lw(d, b, offset));
|
return riscv_program_insert(p, lw(d, b, offset));
|
||||||
|
@ -109,6 +122,18 @@ int riscv_program_lbr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno
|
||||||
return riscv_program_insert(p, lb(d, b, offset));
|
return riscv_program_insert(p, lb(d, b, offset));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int riscv_program_csrrsi(struct riscv_program *p, enum gdb_regno d, unsigned int z, enum gdb_regno csr)
|
||||||
|
{
|
||||||
|
assert(csr >= GDB_REGNO_CSR0 && csr <= GDB_REGNO_CSR4095);
|
||||||
|
return riscv_program_insert(p, csrrsi(d, z, csr - GDB_REGNO_CSR0));
|
||||||
|
}
|
||||||
|
|
||||||
|
int riscv_program_csrrci(struct riscv_program *p, enum gdb_regno d, unsigned int z, enum gdb_regno csr)
|
||||||
|
{
|
||||||
|
assert(csr >= GDB_REGNO_CSR0 && csr <= GDB_REGNO_CSR4095);
|
||||||
|
return riscv_program_insert(p, csrrci(d, z, csr - GDB_REGNO_CSR0));
|
||||||
|
}
|
||||||
|
|
||||||
int riscv_program_csrr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno csr)
|
int riscv_program_csrr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno csr)
|
||||||
{
|
{
|
||||||
assert(csr >= GDB_REGNO_CSR0 && csr <= GDB_REGNO_CSR4095);
|
assert(csr >= GDB_REGNO_CSR0 && csr <= GDB_REGNO_CSR4095);
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||||
|
|
||||||
#ifndef TARGET__RISCV__PROGRAM_H
|
#ifndef TARGET__RISCV__PROGRAM_H
|
||||||
#define TARGET__RISCV__PROGRAM_H
|
#define TARGET__RISCV__PROGRAM_H
|
||||||
|
|
||||||
|
@ -55,14 +57,18 @@ int riscv_program_save_to_dscratch(struct riscv_program *p, enum gdb_regno to_sa
|
||||||
/* Helpers to assemble various instructions. Return 0 on success. These might
|
/* Helpers to assemble various instructions. Return 0 on success. These might
|
||||||
* assemble into a multi-instruction sequence that overwrites some other
|
* assemble into a multi-instruction sequence that overwrites some other
|
||||||
* register, but those will be properly saved and restored. */
|
* register, but those will be properly saved and restored. */
|
||||||
|
int riscv_program_ldr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno a, int o);
|
||||||
int riscv_program_lwr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno a, int o);
|
int riscv_program_lwr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno a, int o);
|
||||||
int riscv_program_lhr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno a, int o);
|
int riscv_program_lhr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno a, int o);
|
||||||
int riscv_program_lbr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno a, int o);
|
int riscv_program_lbr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno a, int o);
|
||||||
|
|
||||||
|
int riscv_program_sdr(struct riscv_program *p, enum gdb_regno s, enum gdb_regno a, int o);
|
||||||
int riscv_program_swr(struct riscv_program *p, enum gdb_regno s, enum gdb_regno a, int o);
|
int riscv_program_swr(struct riscv_program *p, enum gdb_regno s, enum gdb_regno a, int o);
|
||||||
int riscv_program_shr(struct riscv_program *p, enum gdb_regno s, enum gdb_regno a, int o);
|
int riscv_program_shr(struct riscv_program *p, enum gdb_regno s, enum gdb_regno a, int o);
|
||||||
int riscv_program_sbr(struct riscv_program *p, enum gdb_regno s, enum gdb_regno a, int o);
|
int riscv_program_sbr(struct riscv_program *p, enum gdb_regno s, enum gdb_regno a, int o);
|
||||||
|
|
||||||
|
int riscv_program_csrrsi(struct riscv_program *p, enum gdb_regno d, unsigned int z, enum gdb_regno csr);
|
||||||
|
int riscv_program_csrrci(struct riscv_program *p, enum gdb_regno d, unsigned int z, enum gdb_regno csr);
|
||||||
int riscv_program_csrr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno csr);
|
int riscv_program_csrr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno csr);
|
||||||
int riscv_program_csrw(struct riscv_program *p, enum gdb_regno s, enum gdb_regno csr);
|
int riscv_program_csrw(struct riscv_program *p, enum gdb_regno s, enum gdb_regno csr);
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Support for RISC-V, debug version 0.11. This was never an officially adopted
|
* Support for RISC-V, debug version 0.11. This was never an officially adopted
|
||||||
* spec, but SiFive made some silicon that uses it.
|
* spec, but SiFive made some silicon that uses it.
|
||||||
|
@ -204,7 +206,6 @@ typedef struct {
|
||||||
* before the interrupt is cleared. */
|
* before the interrupt is cleared. */
|
||||||
unsigned int interrupt_high_delay;
|
unsigned int interrupt_high_delay;
|
||||||
|
|
||||||
bool need_strict_step;
|
|
||||||
bool never_halted;
|
bool never_halted;
|
||||||
} riscv011_info_t;
|
} riscv011_info_t;
|
||||||
|
|
||||||
|
@ -519,6 +520,8 @@ typedef struct {
|
||||||
static scans_t *scans_new(struct target *target, unsigned int scan_count)
|
static scans_t *scans_new(struct target *target, unsigned int scan_count)
|
||||||
{
|
{
|
||||||
scans_t *scans = malloc(sizeof(scans_t));
|
scans_t *scans = malloc(sizeof(scans_t));
|
||||||
|
if (!scans)
|
||||||
|
goto error0;
|
||||||
scans->scan_count = scan_count;
|
scans->scan_count = scan_count;
|
||||||
/* This code also gets called before xlen is detected. */
|
/* This code also gets called before xlen is detected. */
|
||||||
if (riscv_xlen(target))
|
if (riscv_xlen(target))
|
||||||
|
@ -527,10 +530,25 @@ static scans_t *scans_new(struct target *target, unsigned int scan_count)
|
||||||
scans->scan_size = 2 + 128 / 8;
|
scans->scan_size = 2 + 128 / 8;
|
||||||
scans->next_scan = 0;
|
scans->next_scan = 0;
|
||||||
scans->in = calloc(scans->scan_size, scans->scan_count);
|
scans->in = calloc(scans->scan_size, scans->scan_count);
|
||||||
|
if (!scans->in)
|
||||||
|
goto error1;
|
||||||
scans->out = calloc(scans->scan_size, scans->scan_count);
|
scans->out = calloc(scans->scan_size, scans->scan_count);
|
||||||
|
if (!scans->out)
|
||||||
|
goto error2;
|
||||||
scans->field = calloc(scans->scan_count, sizeof(struct scan_field));
|
scans->field = calloc(scans->scan_count, sizeof(struct scan_field));
|
||||||
|
if (!scans->field)
|
||||||
|
goto error3;
|
||||||
scans->target = target;
|
scans->target = target;
|
||||||
return scans;
|
return scans;
|
||||||
|
|
||||||
|
error3:
|
||||||
|
free(scans->out);
|
||||||
|
error2:
|
||||||
|
free(scans->in);
|
||||||
|
error1:
|
||||||
|
free(scans);
|
||||||
|
error0:
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static scans_t *scans_delete(scans_t *scans)
|
static scans_t *scans_delete(scans_t *scans)
|
||||||
|
@ -844,6 +862,8 @@ static int cache_write(struct target *target, unsigned int address, bool run)
|
||||||
LOG_DEBUG("enter");
|
LOG_DEBUG("enter");
|
||||||
riscv011_info_t *info = get_info(target);
|
riscv011_info_t *info = get_info(target);
|
||||||
scans_t *scans = scans_new(target, info->dramsize + 2);
|
scans_t *scans = scans_new(target, info->dramsize + 2);
|
||||||
|
if (!scans)
|
||||||
|
return ERROR_FAIL;
|
||||||
|
|
||||||
unsigned int last = info->dramsize;
|
unsigned int last = info->dramsize;
|
||||||
for (unsigned int i = 0; i < info->dramsize; i++) {
|
for (unsigned int i = 0; i < info->dramsize; i++) {
|
||||||
|
@ -1012,7 +1032,7 @@ static int wait_for_state(struct target *target, enum target_state state)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int read_csr(struct target *target, uint64_t *value, uint32_t csr)
|
static int read_remote_csr(struct target *target, uint64_t *value, uint32_t csr)
|
||||||
{
|
{
|
||||||
riscv011_info_t *info = get_info(target);
|
riscv011_info_t *info = get_info(target);
|
||||||
cache_set32(target, 0, csrr(S0, csr));
|
cache_set32(target, 0, csrr(S0, csr));
|
||||||
|
@ -1034,7 +1054,7 @@ static int read_csr(struct target *target, uint64_t *value, uint32_t csr)
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int write_csr(struct target *target, uint32_t csr, uint64_t value)
|
static int write_remote_csr(struct target *target, uint32_t csr, uint64_t value)
|
||||||
{
|
{
|
||||||
LOG_DEBUG("csr 0x%x <- 0x%" PRIx64, csr, value);
|
LOG_DEBUG("csr 0x%x <- 0x%" PRIx64, csr, value);
|
||||||
cache_set_load(target, 0, S0, SLOT0);
|
cache_set_load(target, 0, S0, SLOT0);
|
||||||
|
@ -1062,7 +1082,7 @@ static int maybe_read_tselect(struct target *target)
|
||||||
riscv011_info_t *info = get_info(target);
|
riscv011_info_t *info = get_info(target);
|
||||||
|
|
||||||
if (info->tselect_dirty) {
|
if (info->tselect_dirty) {
|
||||||
int result = read_csr(target, &info->tselect, CSR_TSELECT);
|
int result = read_remote_csr(target, &info->tselect, CSR_TSELECT);
|
||||||
if (result != ERROR_OK)
|
if (result != ERROR_OK)
|
||||||
return result;
|
return result;
|
||||||
info->tselect_dirty = false;
|
info->tselect_dirty = false;
|
||||||
|
@ -1076,7 +1096,7 @@ static int maybe_write_tselect(struct target *target)
|
||||||
riscv011_info_t *info = get_info(target);
|
riscv011_info_t *info = get_info(target);
|
||||||
|
|
||||||
if (!info->tselect_dirty) {
|
if (!info->tselect_dirty) {
|
||||||
int result = write_csr(target, CSR_TSELECT, info->tselect);
|
int result = write_remote_csr(target, CSR_TSELECT, info->tselect);
|
||||||
if (result != ERROR_OK)
|
if (result != ERROR_OK)
|
||||||
return result;
|
return result;
|
||||||
info->tselect_dirty = true;
|
info->tselect_dirty = true;
|
||||||
|
@ -1115,7 +1135,10 @@ static int execute_resume(struct target *target, bool step)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
info->dcsr |= DCSR_EBREAKM | DCSR_EBREAKH | DCSR_EBREAKS | DCSR_EBREAKU;
|
info->dcsr = set_field(info->dcsr, DCSR_EBREAKM, riscv_ebreakm);
|
||||||
|
info->dcsr = set_field(info->dcsr, DCSR_EBREAKS, riscv_ebreaks);
|
||||||
|
info->dcsr = set_field(info->dcsr, DCSR_EBREAKU, riscv_ebreaku);
|
||||||
|
info->dcsr = set_field(info->dcsr, DCSR_EBREAKH, 1);
|
||||||
info->dcsr &= ~DCSR_HALT;
|
info->dcsr &= ~DCSR_HALT;
|
||||||
|
|
||||||
if (step)
|
if (step)
|
||||||
|
@ -1255,7 +1278,7 @@ static int register_write(struct target *target, unsigned int number,
|
||||||
|
|
||||||
if (number == S0) {
|
if (number == S0) {
|
||||||
cache_set_load(target, 0, S0, SLOT0);
|
cache_set_load(target, 0, S0, SLOT0);
|
||||||
cache_set32(target, 1, csrw(S0, CSR_DSCRATCH));
|
cache_set32(target, 1, csrw(S0, CSR_DSCRATCH0));
|
||||||
cache_set_jump(target, 2);
|
cache_set_jump(target, 2);
|
||||||
} else if (number == S1) {
|
} else if (number == S1) {
|
||||||
cache_set_load(target, 0, S0, SLOT0);
|
cache_set_load(target, 0, S0, SLOT0);
|
||||||
|
@ -1384,25 +1407,6 @@ static int halt(struct target *target)
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int init_target(struct command_context *cmd_ctx,
|
|
||||||
struct target *target)
|
|
||||||
{
|
|
||||||
LOG_DEBUG("init");
|
|
||||||
riscv_info_t *generic_info = (riscv_info_t *) target->arch_info;
|
|
||||||
generic_info->get_register = get_register;
|
|
||||||
generic_info->set_register = set_register;
|
|
||||||
|
|
||||||
generic_info->version_specific = calloc(1, sizeof(riscv011_info_t));
|
|
||||||
if (!generic_info->version_specific)
|
|
||||||
return ERROR_FAIL;
|
|
||||||
|
|
||||||
/* Assume 32-bit until we discover the real value in examine(). */
|
|
||||||
generic_info->xlen[0] = 32;
|
|
||||||
riscv_init_registers(target);
|
|
||||||
|
|
||||||
return ERROR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void deinit_target(struct target *target)
|
static void deinit_target(struct target *target)
|
||||||
{
|
{
|
||||||
LOG_DEBUG("riscv_deinit_target()");
|
LOG_DEBUG("riscv_deinit_target()");
|
||||||
|
@ -1413,8 +1417,6 @@ static void deinit_target(struct target *target)
|
||||||
|
|
||||||
static int strict_step(struct target *target, bool announce)
|
static int strict_step(struct target *target, bool announce)
|
||||||
{
|
{
|
||||||
riscv011_info_t *info = get_info(target);
|
|
||||||
|
|
||||||
LOG_DEBUG("enter");
|
LOG_DEBUG("enter");
|
||||||
|
|
||||||
struct watchpoint *watchpoint = target->watchpoints;
|
struct watchpoint *watchpoint = target->watchpoints;
|
||||||
|
@ -1433,16 +1435,12 @@ static int strict_step(struct target *target, bool announce)
|
||||||
watchpoint = watchpoint->next;
|
watchpoint = watchpoint->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
info->need_strict_step = false;
|
|
||||||
|
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int step(struct target *target, int current, target_addr_t address,
|
static int step(struct target *target, int current, target_addr_t address,
|
||||||
int handle_breakpoints)
|
int handle_breakpoints)
|
||||||
{
|
{
|
||||||
riscv011_info_t *info = get_info(target);
|
|
||||||
|
|
||||||
jtag_add_ir_scan(target->tap, &select_dbus, TAP_IDLE);
|
jtag_add_ir_scan(target->tap, &select_dbus, TAP_IDLE);
|
||||||
|
|
||||||
if (!current) {
|
if (!current) {
|
||||||
|
@ -1455,7 +1453,7 @@ static int step(struct target *target, int current, target_addr_t address,
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (info->need_strict_step || handle_breakpoints) {
|
if (handle_breakpoints) {
|
||||||
int result = strict_step(target, true);
|
int result = strict_step(target, true);
|
||||||
if (result != ERROR_OK)
|
if (result != ERROR_OK)
|
||||||
return result;
|
return result;
|
||||||
|
@ -1486,7 +1484,6 @@ static int examine(struct target *target)
|
||||||
}
|
}
|
||||||
|
|
||||||
RISCV_INFO(r);
|
RISCV_INFO(r);
|
||||||
r->hart_count = 1;
|
|
||||||
|
|
||||||
riscv011_info_t *info = get_info(target);
|
riscv011_info_t *info = get_info(target);
|
||||||
info->addrbits = get_field(dtmcontrol, DTMCONTROL_ADDRBITS);
|
info->addrbits = get_field(dtmcontrol, DTMCONTROL_ADDRBITS);
|
||||||
|
@ -1570,11 +1567,11 @@ static int examine(struct target *target)
|
||||||
}
|
}
|
||||||
LOG_DEBUG("Discovered XLEN is %d", riscv_xlen(target));
|
LOG_DEBUG("Discovered XLEN is %d", riscv_xlen(target));
|
||||||
|
|
||||||
if (read_csr(target, &r->misa[0], CSR_MISA) != ERROR_OK) {
|
if (read_remote_csr(target, &r->misa[0], CSR_MISA) != ERROR_OK) {
|
||||||
const unsigned old_csr_misa = 0xf10;
|
const unsigned old_csr_misa = 0xf10;
|
||||||
LOG_WARNING("Failed to read misa at 0x%x; trying 0x%x.", CSR_MISA,
|
LOG_WARNING("Failed to read misa at 0x%x; trying 0x%x.", CSR_MISA,
|
||||||
old_csr_misa);
|
old_csr_misa);
|
||||||
if (read_csr(target, &r->misa[0], old_csr_misa) != ERROR_OK) {
|
if (read_remote_csr(target, &r->misa[0], old_csr_misa) != ERROR_OK) {
|
||||||
/* Maybe this is an old core that still has $misa at the old
|
/* Maybe this is an old core that still has $misa at the old
|
||||||
* address. */
|
* address. */
|
||||||
LOG_ERROR("Failed to read misa at 0x%x.", old_csr_misa);
|
LOG_ERROR("Failed to read misa at 0x%x.", old_csr_misa);
|
||||||
|
@ -1606,6 +1603,8 @@ static riscv_error_t handle_halt_routine(struct target *target)
|
||||||
riscv011_info_t *info = get_info(target);
|
riscv011_info_t *info = get_info(target);
|
||||||
|
|
||||||
scans_t *scans = scans_new(target, 256);
|
scans_t *scans = scans_new(target, 256);
|
||||||
|
if (!scans)
|
||||||
|
return RE_FAIL;
|
||||||
|
|
||||||
/* Read all GPRs as fast as we can, because gdb is going to ask for them
|
/* Read all GPRs as fast as we can, because gdb is going to ask for them
|
||||||
* anyway. Reading them one at a time is much slower. */
|
* anyway. Reading them one at a time is much slower. */
|
||||||
|
@ -1634,7 +1633,7 @@ static riscv_error_t handle_halt_routine(struct target *target)
|
||||||
scans_add_read(scans, SLOT0, false);
|
scans_add_read(scans, SLOT0, false);
|
||||||
|
|
||||||
/* Read S0 from dscratch */
|
/* Read S0 from dscratch */
|
||||||
unsigned int csr[] = {CSR_DSCRATCH, CSR_DPC, CSR_DCSR};
|
unsigned int csr[] = {CSR_DSCRATCH0, CSR_DPC, CSR_DCSR};
|
||||||
for (unsigned int i = 0; i < DIM(csr); i++) {
|
for (unsigned int i = 0; i < DIM(csr); i++) {
|
||||||
scans_add_write32(scans, 0, csrr(S0, csr[i]), true);
|
scans_add_write32(scans, 0, csrr(S0, csr[i]), true);
|
||||||
scans_add_read(scans, SLOT0, false);
|
scans_add_read(scans, SLOT0, false);
|
||||||
|
@ -1848,9 +1847,6 @@ static int handle_halt(struct target *target, bool announce)
|
||||||
break;
|
break;
|
||||||
case DCSR_CAUSE_HWBP:
|
case DCSR_CAUSE_HWBP:
|
||||||
target->debug_reason = DBG_REASON_WATCHPOINT;
|
target->debug_reason = DBG_REASON_WATCHPOINT;
|
||||||
/* If we halted because of a data trigger, gdb doesn't know to do
|
|
||||||
* the disable-breakpoints-step-enable-breakpoints dance. */
|
|
||||||
info->need_strict_step = true;
|
|
||||||
break;
|
break;
|
||||||
case DCSR_CAUSE_DEBUGINT:
|
case DCSR_CAUSE_DEBUGINT:
|
||||||
target->debug_reason = DBG_REASON_DBGRQ;
|
target->debug_reason = DBG_REASON_DBGRQ;
|
||||||
|
@ -1935,26 +1931,10 @@ static int riscv011_poll(struct target *target)
|
||||||
static int riscv011_resume(struct target *target, int current,
|
static int riscv011_resume(struct target *target, int current,
|
||||||
target_addr_t address, int handle_breakpoints, int debug_execution)
|
target_addr_t address, int handle_breakpoints, int debug_execution)
|
||||||
{
|
{
|
||||||
riscv011_info_t *info = get_info(target);
|
RISCV_INFO(r);
|
||||||
|
|
||||||
jtag_add_ir_scan(target->tap, &select_dbus, TAP_IDLE);
|
jtag_add_ir_scan(target->tap, &select_dbus, TAP_IDLE);
|
||||||
|
|
||||||
if (!current) {
|
r->prepped = false;
|
||||||
if (riscv_xlen(target) > 32) {
|
|
||||||
LOG_WARNING("Asked to resume at 32-bit PC on %d-bit target.",
|
|
||||||
riscv_xlen(target));
|
|
||||||
}
|
|
||||||
int result = register_write(target, GDB_REGNO_PC, address);
|
|
||||||
if (result != ERROR_OK)
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (info->need_strict_step || handle_breakpoints) {
|
|
||||||
int result = strict_step(target, false);
|
|
||||||
if (result != ERROR_OK)
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
return resume(target, debug_execution, false);
|
return resume(target, debug_execution, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1973,8 +1953,11 @@ static int assert_reset(struct target *target)
|
||||||
|
|
||||||
/* Not sure what we should do when there are multiple cores.
|
/* Not sure what we should do when there are multiple cores.
|
||||||
* Here just reset the single hart we're talking to. */
|
* Here just reset the single hart we're talking to. */
|
||||||
info->dcsr |= DCSR_EBREAKM | DCSR_EBREAKH | DCSR_EBREAKS |
|
info->dcsr = set_field(info->dcsr, DCSR_EBREAKM, riscv_ebreakm);
|
||||||
DCSR_EBREAKU | DCSR_HALT;
|
info->dcsr = set_field(info->dcsr, DCSR_EBREAKS, riscv_ebreaks);
|
||||||
|
info->dcsr = set_field(info->dcsr, DCSR_EBREAKU, riscv_ebreaku);
|
||||||
|
info->dcsr = set_field(info->dcsr, DCSR_EBREAKH, 1);
|
||||||
|
info->dcsr |= DCSR_HALT;
|
||||||
if (target->reset_halt)
|
if (target->reset_halt)
|
||||||
info->dcsr |= DCSR_NDRESET;
|
info->dcsr |= DCSR_NDRESET;
|
||||||
else
|
else
|
||||||
|
@ -2001,8 +1984,13 @@ static int deassert_reset(struct target *target)
|
||||||
}
|
}
|
||||||
|
|
||||||
static int read_memory(struct target *target, target_addr_t address,
|
static int 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, uint32_t increment)
|
||||||
{
|
{
|
||||||
|
if (increment != size) {
|
||||||
|
LOG_ERROR("read_memory with custom increment not implemented");
|
||||||
|
return ERROR_NOT_IMPLEMENTED;
|
||||||
|
}
|
||||||
|
|
||||||
jtag_add_ir_scan(target->tap, &select_dbus, TAP_IDLE);
|
jtag_add_ir_scan(target->tap, &select_dbus, TAP_IDLE);
|
||||||
|
|
||||||
cache_set32(target, 0, lw(S0, ZERO, DEBUG_RAM_START + 16));
|
cache_set32(target, 0, lw(S0, ZERO, DEBUG_RAM_START + 16));
|
||||||
|
@ -2029,6 +2017,8 @@ static int read_memory(struct target *target, target_addr_t address,
|
||||||
riscv011_info_t *info = get_info(target);
|
riscv011_info_t *info = get_info(target);
|
||||||
const unsigned max_batch_size = 256;
|
const unsigned max_batch_size = 256;
|
||||||
scans_t *scans = scans_new(target, max_batch_size);
|
scans_t *scans = scans_new(target, max_batch_size);
|
||||||
|
if (!scans)
|
||||||
|
return ERROR_FAIL;
|
||||||
|
|
||||||
uint32_t result_value = 0x777;
|
uint32_t result_value = 0x777;
|
||||||
uint32_t i = 0;
|
uint32_t i = 0;
|
||||||
|
@ -2185,6 +2175,8 @@ static int write_memory(struct target *target, target_addr_t address,
|
||||||
|
|
||||||
const unsigned max_batch_size = 256;
|
const unsigned max_batch_size = 256;
|
||||||
scans_t *scans = scans_new(target, max_batch_size);
|
scans_t *scans = scans_new(target, max_batch_size);
|
||||||
|
if (!scans)
|
||||||
|
return ERROR_FAIL;
|
||||||
|
|
||||||
uint32_t result_value = 0x777;
|
uint32_t result_value = 0x777;
|
||||||
uint32_t i = 0;
|
uint32_t i = 0;
|
||||||
|
@ -2304,6 +2296,26 @@ static int arch_state(struct target *target)
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int init_target(struct command_context *cmd_ctx,
|
||||||
|
struct target *target)
|
||||||
|
{
|
||||||
|
LOG_DEBUG("init");
|
||||||
|
riscv_info_t *generic_info = (riscv_info_t *)target->arch_info;
|
||||||
|
generic_info->get_register = get_register;
|
||||||
|
generic_info->set_register = set_register;
|
||||||
|
generic_info->read_memory = read_memory;
|
||||||
|
|
||||||
|
generic_info->version_specific = calloc(1, sizeof(riscv011_info_t));
|
||||||
|
if (!generic_info->version_specific)
|
||||||
|
return ERROR_FAIL;
|
||||||
|
|
||||||
|
/* Assume 32-bit until we discover the real value in examine(). */
|
||||||
|
generic_info->xlen[0] = 32;
|
||||||
|
riscv_init_registers(target);
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
struct target_type riscv011_target = {
|
struct target_type riscv011_target = {
|
||||||
.name = "riscv",
|
.name = "riscv",
|
||||||
|
|
||||||
|
@ -2321,7 +2333,6 @@ struct target_type riscv011_target = {
|
||||||
.assert_reset = assert_reset,
|
.assert_reset = assert_reset,
|
||||||
.deassert_reset = deassert_reset,
|
.deassert_reset = deassert_reset,
|
||||||
|
|
||||||
.read_memory = read_memory,
|
|
||||||
.write_memory = write_memory,
|
.write_memory = write_memory,
|
||||||
|
|
||||||
.arch_state = arch_state,
|
.arch_state = arch_state,
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -1,3 +1,5 @@
|
||||||
|
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||||
|
|
||||||
#ifndef RISCV_H
|
#ifndef RISCV_H
|
||||||
#define RISCV_H
|
#define RISCV_H
|
||||||
|
|
||||||
|
@ -6,9 +8,11 @@ struct riscv_program;
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include "opcodes.h"
|
#include "opcodes.h"
|
||||||
#include "gdb_regs.h"
|
#include "gdb_regs.h"
|
||||||
|
#include "jtag/jtag.h"
|
||||||
|
#include "target/register.h"
|
||||||
|
|
||||||
/* The register cache is statically allocated. */
|
/* The register cache is statically allocated. */
|
||||||
#define RISCV_MAX_HARTS 32
|
#define RISCV_MAX_HARTS 1024
|
||||||
#define RISCV_MAX_REGISTERS 5000
|
#define RISCV_MAX_REGISTERS 5000
|
||||||
#define RISCV_MAX_TRIGGERS 32
|
#define RISCV_MAX_TRIGGERS 32
|
||||||
#define RISCV_MAX_HWBPS 16
|
#define RISCV_MAX_HWBPS 16
|
||||||
|
@ -16,6 +20,12 @@ struct riscv_program;
|
||||||
#define DEFAULT_COMMAND_TIMEOUT_SEC 2
|
#define DEFAULT_COMMAND_TIMEOUT_SEC 2
|
||||||
#define DEFAULT_RESET_TIMEOUT_SEC 30
|
#define DEFAULT_RESET_TIMEOUT_SEC 30
|
||||||
|
|
||||||
|
#define RISCV_SATP_MODE(xlen) ((xlen) == 32 ? SATP32_MODE : SATP64_MODE)
|
||||||
|
#define RISCV_SATP_PPN(xlen) ((xlen) == 32 ? SATP32_PPN : SATP64_PPN)
|
||||||
|
#define RISCV_PGSHIFT 12
|
||||||
|
|
||||||
|
# define PG_MAX_LEVEL 4
|
||||||
|
|
||||||
extern struct target_type riscv011_target;
|
extern struct target_type riscv011_target;
|
||||||
extern struct target_type riscv013_target;
|
extern struct target_type riscv013_target;
|
||||||
|
|
||||||
|
@ -32,6 +42,7 @@ enum riscv_halt_reason {
|
||||||
RISCV_HALT_SINGLESTEP,
|
RISCV_HALT_SINGLESTEP,
|
||||||
RISCV_HALT_TRIGGER,
|
RISCV_HALT_TRIGGER,
|
||||||
RISCV_HALT_UNKNOWN,
|
RISCV_HALT_UNKNOWN,
|
||||||
|
RISCV_HALT_GROUP,
|
||||||
RISCV_HALT_ERROR
|
RISCV_HALT_ERROR
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -46,9 +57,6 @@ typedef struct {
|
||||||
struct command_context *cmd_ctx;
|
struct command_context *cmd_ctx;
|
||||||
void *version_specific;
|
void *version_specific;
|
||||||
|
|
||||||
/* The number of harts on this system. */
|
|
||||||
int hart_count;
|
|
||||||
|
|
||||||
/* The hart that the RTOS thinks is currently being debugged. */
|
/* The hart that the RTOS thinks is currently being debugged. */
|
||||||
int rtos_hartid;
|
int rtos_hartid;
|
||||||
|
|
||||||
|
@ -58,11 +66,6 @@ typedef struct {
|
||||||
* every function than an actual */
|
* every function than an actual */
|
||||||
int current_hartid;
|
int current_hartid;
|
||||||
|
|
||||||
/* Enough space to store all the registers we might need to save. */
|
|
||||||
/* FIXME: This should probably be a bunch of register caches. */
|
|
||||||
uint64_t saved_registers[RISCV_MAX_HARTS][RISCV_MAX_REGISTERS];
|
|
||||||
bool valid_saved_registers[RISCV_MAX_HARTS][RISCV_MAX_REGISTERS];
|
|
||||||
|
|
||||||
/* OpenOCD's register cache points into here. This is not per-hart because
|
/* OpenOCD's register cache points into here. This is not per-hart because
|
||||||
* we just invalidate the entire cache when we change which hart is
|
* we just invalidate the entire cache when we change which hart is
|
||||||
* selected. */
|
* selected. */
|
||||||
|
@ -75,6 +78,8 @@ typedef struct {
|
||||||
/* It's possible that each core has a different supported ISA set. */
|
/* It's possible that each core has a different supported ISA set. */
|
||||||
int xlen[RISCV_MAX_HARTS];
|
int xlen[RISCV_MAX_HARTS];
|
||||||
riscv_reg_t misa[RISCV_MAX_HARTS];
|
riscv_reg_t misa[RISCV_MAX_HARTS];
|
||||||
|
/* Cached value of vlenb. 0 if vlenb is not readable for some reason. */
|
||||||
|
unsigned vlenb[RISCV_MAX_HARTS];
|
||||||
|
|
||||||
/* The number of triggers per hart. */
|
/* The number of triggers per hart. */
|
||||||
unsigned trigger_count[RISCV_MAX_HARTS];
|
unsigned trigger_count[RISCV_MAX_HARTS];
|
||||||
|
@ -100,19 +105,33 @@ typedef struct {
|
||||||
* delays, causing them to be relearned. Used for testing. */
|
* delays, causing them to be relearned. Used for testing. */
|
||||||
int reset_delays_wait;
|
int reset_delays_wait;
|
||||||
|
|
||||||
|
/* This target has been prepped and is ready to step/resume. */
|
||||||
|
bool prepped;
|
||||||
|
/* This target was selected using hasel. */
|
||||||
|
bool selected;
|
||||||
|
|
||||||
/* Helper functions that target the various RISC-V debug spec
|
/* Helper functions that target the various RISC-V debug spec
|
||||||
* implementations. */
|
* implementations. */
|
||||||
int (*get_register)(struct target *target,
|
int (*get_register)(struct target *target,
|
||||||
riscv_reg_t *value, int hid, int rid);
|
riscv_reg_t *value, int hid, int rid);
|
||||||
int (*set_register)(struct target *target, int hartid, int regid,
|
int (*set_register)(struct target *target, int hartid, int regid,
|
||||||
uint64_t value);
|
uint64_t value);
|
||||||
|
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_current_hart)(struct target *target);
|
||||||
bool (*is_halted)(struct target *target);
|
bool (*is_halted)(struct target *target);
|
||||||
int (*halt_current_hart)(struct target *target);
|
/* Resume this target, as well as every other prepped target that can be
|
||||||
int (*resume_current_hart)(struct target *target);
|
* resumed near-simultaneously. Clear the prepped flag on any target that
|
||||||
|
* was resumed. */
|
||||||
|
int (*resume_go)(struct target *target);
|
||||||
int (*step_current_hart)(struct target *target);
|
int (*step_current_hart)(struct target *target);
|
||||||
int (*on_halt)(struct target *target);
|
int (*on_halt)(struct target *target);
|
||||||
int (*on_resume)(struct target *target);
|
/* Get this target as ready as possible to resume, without actually
|
||||||
|
* resuming. */
|
||||||
|
int (*resume_prep)(struct target *target);
|
||||||
|
int (*halt_prep)(struct target *target);
|
||||||
|
int (*halt_go)(struct target *target);
|
||||||
int (*on_step)(struct target *target);
|
int (*on_step)(struct target *target);
|
||||||
enum riscv_halt_reason (*halt_reason)(struct target *target);
|
enum riscv_halt_reason (*halt_reason)(struct target *target);
|
||||||
int (*write_debug_buffer)(struct target *target, unsigned index,
|
int (*write_debug_buffer)(struct target *target, unsigned index,
|
||||||
|
@ -134,8 +153,52 @@ typedef struct {
|
||||||
uint32_t num_words, target_addr_t illegal_address, bool run_sbbusyerror_test);
|
uint32_t num_words, target_addr_t illegal_address, bool run_sbbusyerror_test);
|
||||||
|
|
||||||
int (*test_compliance)(struct target *target);
|
int (*test_compliance)(struct target *target);
|
||||||
|
|
||||||
|
int (*read_memory)(struct target *target, target_addr_t address,
|
||||||
|
uint32_t size, uint32_t count, uint8_t *buffer, uint32_t increment);
|
||||||
|
|
||||||
|
/* How many harts are attached to the DM that this target is attached to? */
|
||||||
|
int (*hart_count)(struct target *target);
|
||||||
|
unsigned (*data_bits)(struct target *target);
|
||||||
|
|
||||||
|
/* Storage for vector register types. */
|
||||||
|
struct reg_data_type_vector vector_uint8;
|
||||||
|
struct reg_data_type_vector vector_uint16;
|
||||||
|
struct reg_data_type_vector vector_uint32;
|
||||||
|
struct reg_data_type_vector vector_uint64;
|
||||||
|
struct reg_data_type_vector vector_uint128;
|
||||||
|
struct reg_data_type type_uint8_vector;
|
||||||
|
struct reg_data_type type_uint16_vector;
|
||||||
|
struct reg_data_type type_uint32_vector;
|
||||||
|
struct reg_data_type type_uint64_vector;
|
||||||
|
struct reg_data_type type_uint128_vector;
|
||||||
|
struct reg_data_type_union_field vector_fields[5];
|
||||||
|
struct reg_data_type_union vector_union;
|
||||||
|
struct reg_data_type type_vector;
|
||||||
|
|
||||||
|
/* Set when trigger registers are changed by the user. This indicates we eed
|
||||||
|
* to beware that we may hit a trigger that we didn't realize had been set. */
|
||||||
|
bool manual_hwbp_set;
|
||||||
} riscv_info_t;
|
} riscv_info_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint8_t tunneled_dr_width;
|
||||||
|
struct scan_field tunneled_dr[4];
|
||||||
|
} riscv_bscan_tunneled_scan_context_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
const char *name;
|
||||||
|
int level;
|
||||||
|
unsigned va_bits;
|
||||||
|
unsigned pte_shift;
|
||||||
|
unsigned vpn_shift[PG_MAX_LEVEL];
|
||||||
|
unsigned vpn_mask[PG_MAX_LEVEL];
|
||||||
|
unsigned pte_ppn_shift[PG_MAX_LEVEL];
|
||||||
|
unsigned pte_ppn_mask[PG_MAX_LEVEL];
|
||||||
|
unsigned pa_ppn_shift[PG_MAX_LEVEL];
|
||||||
|
unsigned pa_ppn_mask[PG_MAX_LEVEL];
|
||||||
|
} virt2phys_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.*/
|
||||||
extern int riscv_command_timeout_sec;
|
extern int riscv_command_timeout_sec;
|
||||||
|
|
||||||
|
@ -144,6 +207,11 @@ extern int riscv_reset_timeout_sec;
|
||||||
|
|
||||||
extern bool riscv_prefer_sba;
|
extern bool riscv_prefer_sba;
|
||||||
|
|
||||||
|
extern bool riscv_enable_virtual;
|
||||||
|
extern bool riscv_ebreakm;
|
||||||
|
extern bool riscv_ebreaks;
|
||||||
|
extern bool riscv_ebreaku;
|
||||||
|
|
||||||
/* Everything needs the RISC-V specific info structure, so here's a nice macro
|
/* Everything needs the RISC-V specific info structure, so here's a nice macro
|
||||||
* that provides that. */
|
* that provides that. */
|
||||||
static inline riscv_info_t *riscv_info(const struct target *target) __attribute__((unused));
|
static inline riscv_info_t *riscv_info(const struct target *target) __attribute__((unused));
|
||||||
|
@ -158,17 +226,28 @@ extern struct scan_field select_dbus;
|
||||||
extern uint8_t ir_idcode[4];
|
extern uint8_t ir_idcode[4];
|
||||||
extern struct scan_field select_idcode;
|
extern struct scan_field select_idcode;
|
||||||
|
|
||||||
|
extern struct scan_field select_user4;
|
||||||
|
extern struct scan_field *bscan_tunneled_select_dmi;
|
||||||
|
extern uint32_t bscan_tunneled_select_dmi_num_fields;
|
||||||
|
typedef enum { BSCAN_TUNNEL_NESTED_TAP, BSCAN_TUNNEL_DATA_REGISTER } bscan_tunnel_type_t;
|
||||||
|
extern int bscan_tunnel_ir_width;
|
||||||
|
extern bscan_tunnel_type_t bscan_tunnel_type;
|
||||||
|
|
||||||
|
uint32_t dtmcontrol_scan_via_bscan(struct target *target, uint32_t out);
|
||||||
|
void select_dmi_via_bscan(struct target *target);
|
||||||
|
|
||||||
/*** OpenOCD Interface */
|
/*** OpenOCD Interface */
|
||||||
int riscv_openocd_poll(struct target *target);
|
int riscv_openocd_poll(struct target *target);
|
||||||
|
|
||||||
int riscv_openocd_halt(struct target *target);
|
int riscv_halt(struct target *target);
|
||||||
|
|
||||||
int riscv_openocd_resume(
|
int riscv_resume(
|
||||||
struct target *target,
|
struct target *target,
|
||||||
int current,
|
int current,
|
||||||
target_addr_t address,
|
target_addr_t address,
|
||||||
int handle_breakpoints,
|
int handle_breakpoints,
|
||||||
int debug_execution
|
int debug_execution,
|
||||||
|
bool single_hart
|
||||||
);
|
);
|
||||||
|
|
||||||
int riscv_openocd_step(
|
int riscv_openocd_step(
|
||||||
|
@ -186,14 +265,6 @@ int riscv_openocd_deassert_reset(struct target *target);
|
||||||
/* Initializes the shared RISC-V structure. */
|
/* Initializes the shared RISC-V structure. */
|
||||||
void riscv_info_init(struct target *target, riscv_info_t *r);
|
void riscv_info_init(struct target *target, riscv_info_t *r);
|
||||||
|
|
||||||
/* Run control, possibly for multiple harts. The _all_harts versions resume
|
|
||||||
* all the enabled harts, which when running in RTOS mode is all the harts on
|
|
||||||
* the system. */
|
|
||||||
int riscv_halt_all_harts(struct target *target);
|
|
||||||
int riscv_halt_one_hart(struct target *target, int hartid);
|
|
||||||
int riscv_resume_all_harts(struct target *target);
|
|
||||||
int riscv_resume_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. */
|
||||||
int riscv_step_rtos_hart(struct target *target);
|
int riscv_step_rtos_hart(struct target *target);
|
||||||
|
@ -201,7 +272,7 @@ int riscv_step_rtos_hart(struct target *target);
|
||||||
bool riscv_supports_extension(struct target *target, int hartid, char letter);
|
bool riscv_supports_extension(struct target *target, int hartid, char letter);
|
||||||
|
|
||||||
/* Returns XLEN for the given (or current) hart. */
|
/* Returns XLEN for the given (or current) hart. */
|
||||||
int riscv_xlen(const struct target *target);
|
unsigned riscv_xlen(const struct target *target);
|
||||||
int riscv_xlen_of_hart(const struct target *target, int hartid);
|
int riscv_xlen_of_hart(const struct target *target, int hartid);
|
||||||
|
|
||||||
bool riscv_rtos_enabled(const struct target *target);
|
bool riscv_rtos_enabled(const struct target *target);
|
||||||
|
@ -226,12 +297,14 @@ int riscv_count_harts(struct target *target);
|
||||||
/* Returns TRUE if the target has the given register on the given hart. */
|
/* Returns TRUE if the target has the given register on the given hart. */
|
||||||
bool riscv_has_register(struct target *target, int hartid, int regid);
|
bool riscv_has_register(struct target *target, int hartid, int regid);
|
||||||
|
|
||||||
/* Returns the value of the given register on the given hart. 32-bit registers
|
/** Set register, updating the cache. */
|
||||||
* are zero extended to 64 bits. */
|
|
||||||
int riscv_set_register(struct target *target, enum gdb_regno i, riscv_reg_t v);
|
int riscv_set_register(struct target *target, enum gdb_regno i, riscv_reg_t v);
|
||||||
|
/** Set register, updating the cache. */
|
||||||
int riscv_set_register_on_hart(struct target *target, int hid, enum gdb_regno rid, uint64_t v);
|
int riscv_set_register_on_hart(struct target *target, int hid, enum gdb_regno rid, uint64_t v);
|
||||||
|
/** Get register, from the cache if it's in there. */
|
||||||
int riscv_get_register(struct target *target, riscv_reg_t *value,
|
int riscv_get_register(struct target *target, riscv_reg_t *value,
|
||||||
enum gdb_regno r);
|
enum gdb_regno r);
|
||||||
|
/** Get register, from the cache if it's in there. */
|
||||||
int riscv_get_register_on_hart(struct target *target, riscv_reg_t *value,
|
int riscv_get_register_on_hart(struct target *target, riscv_reg_t *value,
|
||||||
int hartid, enum gdb_regno regid);
|
int hartid, enum gdb_regno regid);
|
||||||
|
|
||||||
|
@ -272,6 +345,15 @@ int riscv_hit_watchpoint(struct target *target, struct watchpoint **hit_wp_addre
|
||||||
int riscv_init_registers(struct target *target);
|
int riscv_init_registers(struct target *target);
|
||||||
|
|
||||||
void riscv_semihosting_init(struct target *target);
|
void riscv_semihosting_init(struct target *target);
|
||||||
int riscv_semihosting(struct target *target, int *retval);
|
typedef enum {
|
||||||
|
SEMI_NONE, /* Not halted for a semihosting call. */
|
||||||
|
SEMI_HANDLED, /* Call handled, and target was resumed. */
|
||||||
|
SEMI_WAITING, /* Call handled, target is halted waiting until we can resume. */
|
||||||
|
SEMI_ERROR /* Something went wrong. */
|
||||||
|
} semihosting_result_t;
|
||||||
|
semihosting_result_t riscv_semihosting(struct target *target, int *retval);
|
||||||
|
|
||||||
|
void riscv_add_bscan_tunneled_scan(struct target *target, struct scan_field *field,
|
||||||
|
riscv_bscan_tunneled_scan_context_t *ctxt);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||||
|
|
||||||
/***************************************************************************
|
/***************************************************************************
|
||||||
* Copyright (C) 2018 by Liviu Ionescu *
|
* Copyright (C) 2018 by Liviu Ionescu *
|
||||||
* ilg@livius.net *
|
* ilg@livius.net *
|
||||||
|
@ -60,35 +62,35 @@ void riscv_semihosting_init(struct target *target)
|
||||||
/**
|
/**
|
||||||
* Check for and process a semihosting request using the ARM protocol). This
|
* Check for and process a semihosting request using the ARM protocol). This
|
||||||
* is meant to be called when the target is stopped due to a debug mode entry.
|
* is meant to be called when the target is stopped due to a debug mode entry.
|
||||||
* If the value 0 is returned then there was nothing to process. A non-zero
|
|
||||||
* return value signifies that a request was processed and the target resumed,
|
|
||||||
* or an error was encountered, in which case the caller must return
|
|
||||||
* immediately.
|
|
||||||
*
|
*
|
||||||
* @param target Pointer to the target to process.
|
* @param target Pointer to the target to process.
|
||||||
* @param retval Pointer to a location where the return code will be stored
|
* @param retval Pointer to a location where the return code will be stored
|
||||||
* @return non-zero value if a request was processed or an error encountered
|
* @return non-zero value if a request was processed or an error encountered
|
||||||
*/
|
*/
|
||||||
int riscv_semihosting(struct target *target, int *retval)
|
semihosting_result_t riscv_semihosting(struct target *target, int *retval)
|
||||||
{
|
{
|
||||||
struct semihosting *semihosting = target->semihosting;
|
struct semihosting *semihosting = target->semihosting;
|
||||||
if (!semihosting)
|
if (!semihosting) {
|
||||||
return 0;
|
LOG_DEBUG(" -> NONE (!semihosting)");
|
||||||
|
return SEMI_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
if (!semihosting->is_active)
|
if (!semihosting->is_active) {
|
||||||
return 0;
|
LOG_DEBUG(" -> NONE (!semihosting->is_active)");
|
||||||
|
return SEMI_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
riscv_reg_t dpc;
|
riscv_reg_t pc;
|
||||||
int result = riscv_get_register(target, &dpc, GDB_REGNO_DPC);
|
int result = riscv_get_register(target, &pc, GDB_REGNO_PC);
|
||||||
if (result != ERROR_OK)
|
if (result != ERROR_OK)
|
||||||
return 0;
|
return SEMI_ERROR;
|
||||||
|
|
||||||
uint8_t tmp[12];
|
uint8_t tmp[12];
|
||||||
|
|
||||||
/* Read the current instruction, including the bracketing */
|
/* Read the current instruction, including the bracketing */
|
||||||
*retval = target_read_memory(target, dpc - 4, 2, 6, tmp);
|
*retval = target_read_memory(target, pc - 4, 2, 6, tmp);
|
||||||
if (*retval != ERROR_OK)
|
if (*retval != ERROR_OK)
|
||||||
return 0;
|
return SEMI_ERROR;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The instructions that trigger a semihosting call,
|
* The instructions that trigger a semihosting call,
|
||||||
|
@ -101,12 +103,12 @@ int riscv_semihosting(struct target *target, int *retval)
|
||||||
uint32_t pre = target_buffer_get_u32(target, tmp);
|
uint32_t pre = target_buffer_get_u32(target, tmp);
|
||||||
uint32_t ebreak = target_buffer_get_u32(target, tmp + 4);
|
uint32_t ebreak = target_buffer_get_u32(target, tmp + 4);
|
||||||
uint32_t post = target_buffer_get_u32(target, tmp + 8);
|
uint32_t post = target_buffer_get_u32(target, tmp + 8);
|
||||||
LOG_DEBUG("check %08x %08x %08x from 0x%" PRIx64 "-4", pre, ebreak, post, dpc);
|
LOG_DEBUG("check %08x %08x %08x from 0x%" PRIx64 "-4", pre, ebreak, post, pc);
|
||||||
|
|
||||||
if (pre != 0x01f01013 || ebreak != 0x00100073 || post != 0x40705013) {
|
if (pre != 0x01f01013 || ebreak != 0x00100073 || post != 0x40705013) {
|
||||||
|
|
||||||
/* Not the magic sequence defining semihosting. */
|
/* Not the magic sequence defining semihosting. */
|
||||||
return 0;
|
LOG_DEBUG(" -> NONE (no magic)");
|
||||||
|
return SEMI_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -114,18 +116,21 @@ int riscv_semihosting(struct target *target, int *retval)
|
||||||
* operation to complete.
|
* operation to complete.
|
||||||
*/
|
*/
|
||||||
if (!semihosting->hit_fileio) {
|
if (!semihosting->hit_fileio) {
|
||||||
|
|
||||||
/* RISC-V uses A0 and A1 to pass function arguments */
|
/* RISC-V uses A0 and A1 to pass function arguments */
|
||||||
riscv_reg_t r0;
|
riscv_reg_t r0;
|
||||||
riscv_reg_t r1;
|
riscv_reg_t r1;
|
||||||
|
|
||||||
result = riscv_get_register(target, &r0, GDB_REGNO_A0);
|
result = riscv_get_register(target, &r0, GDB_REGNO_A0);
|
||||||
if (result != ERROR_OK)
|
if (result != ERROR_OK) {
|
||||||
return 0;
|
LOG_DEBUG(" -> ERROR (couldn't read a0)");
|
||||||
|
return SEMI_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
result = riscv_get_register(target, &r1, GDB_REGNO_A1);
|
result = riscv_get_register(target, &r1, GDB_REGNO_A1);
|
||||||
if (result != ERROR_OK)
|
if (result != ERROR_OK) {
|
||||||
return 0;
|
LOG_DEBUG(" -> ERROR (couldn't read a1)");
|
||||||
|
return SEMI_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
semihosting->op = r0;
|
semihosting->op = r0;
|
||||||
semihosting->param = r1;
|
semihosting->param = r1;
|
||||||
|
@ -136,11 +141,12 @@ int riscv_semihosting(struct target *target, int *retval)
|
||||||
*retval = semihosting_common(target);
|
*retval = semihosting_common(target);
|
||||||
if (*retval != ERROR_OK) {
|
if (*retval != ERROR_OK) {
|
||||||
LOG_ERROR("Failed semihosting operation");
|
LOG_ERROR("Failed semihosting operation");
|
||||||
return 0;
|
return SEMI_ERROR;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* Unknown operation number, not a semihosting call. */
|
/* Unknown operation number, not a semihosting call. */
|
||||||
return 0;
|
LOG_DEBUG(" -> NONE (unknown operation number)");
|
||||||
|
return SEMI_NONE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -150,16 +156,16 @@ int riscv_semihosting(struct target *target, int *retval)
|
||||||
*/
|
*/
|
||||||
if (semihosting->is_resumable && !semihosting->hit_fileio) {
|
if (semihosting->is_resumable && !semihosting->hit_fileio) {
|
||||||
/* Resume right after the EBREAK 4 bytes instruction. */
|
/* Resume right after the EBREAK 4 bytes instruction. */
|
||||||
*retval = target_resume(target, 0, dpc+4, 0, 0);
|
*retval = riscv_set_register(target, GDB_REGNO_PC, pc + 4);
|
||||||
if (*retval != ERROR_OK) {
|
if (*retval != ERROR_OK)
|
||||||
LOG_ERROR("Failed to resume target");
|
return SEMI_ERROR;
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 1;
|
LOG_DEBUG(" -> HANDLED");
|
||||||
|
return SEMI_HANDLED;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
LOG_DEBUG(" -> WAITING");
|
||||||
|
return SEMI_WAITING;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------------------------------------
|
/* -------------------------------------------------------------------------
|
||||||
|
@ -171,7 +177,7 @@ int riscv_semihosting(struct target *target, int *retval)
|
||||||
*/
|
*/
|
||||||
static int riscv_semihosting_setup(struct target *target, int enable)
|
static int riscv_semihosting_setup(struct target *target, int enable)
|
||||||
{
|
{
|
||||||
LOG_DEBUG("enable=%d", enable);
|
LOG_DEBUG("[%s] enable=%d", target_name(target), enable);
|
||||||
|
|
||||||
struct semihosting *semihosting = target->semihosting;
|
struct semihosting *semihosting = target->semihosting;
|
||||||
if (semihosting)
|
if (semihosting)
|
||||||
|
|
Loading…
Reference in New Issue