Upstream a whole host of RISC-V changes.
Made no attempt to separate this out into reviewable chunks, since this is all RISC-V-specific code developed at https://github.com/riscv/riscv-openocd Memory sample and repeat read functionality was left out of this change since it requires some target-independent changes that I'll upstream some other time. Change-Id: I92917c86d549c232cbf36ffbfefc93331c05accd Signed-off-by: Tim Newsome <tim@sifive.com> Reviewed-on: https://review.openocd.org/c/openocd/+/6529 Tested-by: jenkins Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com>
This commit is contained in:
parent
f4612e06c6
commit
615709d140
|
@ -27,23 +27,33 @@ struct riscv_batch *riscv_batch_alloc(struct target *target, size_t scans, size_
|
||||||
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) * DMI_SCAN_BUF_SIZE);
|
out->data_out = malloc(sizeof(*out->data_out) * (scans) * DMI_SCAN_BUF_SIZE);
|
||||||
if (!out->data_out)
|
if (!out->data_out) {
|
||||||
|
LOG_ERROR("Failed to allocate data_out in RISC-V batch.");
|
||||||
goto error1;
|
goto error1;
|
||||||
|
};
|
||||||
out->data_in = malloc(sizeof(*out->data_in) * (scans) * DMI_SCAN_BUF_SIZE);
|
out->data_in = malloc(sizeof(*out->data_in) * (scans) * DMI_SCAN_BUF_SIZE);
|
||||||
if (!out->data_in)
|
if (!out->data_in) {
|
||||||
|
LOG_ERROR("Failed to allocate data_in in RISC-V batch.");
|
||||||
goto error2;
|
goto error2;
|
||||||
|
}
|
||||||
out->fields = malloc(sizeof(*out->fields) * (scans));
|
out->fields = malloc(sizeof(*out->fields) * (scans));
|
||||||
if (!out->fields)
|
if (!out->fields) {
|
||||||
|
LOG_ERROR("Failed to allocate fields in RISC-V batch.");
|
||||||
goto error3;
|
goto error3;
|
||||||
|
}
|
||||||
if (bscan_tunnel_ir_width != 0) {
|
if (bscan_tunnel_ir_width != 0) {
|
||||||
out->bscan_ctxt = malloc(sizeof(*out->bscan_ctxt) * (scans));
|
out->bscan_ctxt = malloc(sizeof(*out->bscan_ctxt) * (scans));
|
||||||
if (!out->bscan_ctxt)
|
if (!out->bscan_ctxt) {
|
||||||
|
LOG_ERROR("Failed to allocate bscan_ctxt in RISC-V batch.");
|
||||||
goto error4;
|
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)
|
if (!out->read_keys) {
|
||||||
|
LOG_ERROR("Failed to allocate read_keys in RISC-V batch.");
|
||||||
goto error5;
|
goto error5;
|
||||||
|
}
|
||||||
return out;
|
return out;
|
||||||
|
|
||||||
error5:
|
error5:
|
||||||
|
@ -82,8 +92,6 @@ int riscv_batch_run(struct riscv_batch *batch)
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
keep_alive();
|
|
||||||
|
|
||||||
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) {
|
||||||
|
@ -96,11 +104,15 @@ int riscv_batch_run(struct riscv_batch *batch)
|
||||||
jtag_add_runtest(batch->idle_count, TAP_IDLE);
|
jtag_add_runtest(batch->idle_count, TAP_IDLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
keep_alive();
|
||||||
|
|
||||||
if (jtag_execute_queue() != ERROR_OK) {
|
if (jtag_execute_queue() != ERROR_OK) {
|
||||||
LOG_ERROR("Unable to execute JTAG queue");
|
LOG_ERROR("Unable to execute JTAG queue");
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
keep_alive();
|
||||||
|
|
||||||
if (bscan_tunnel_ir_width != 0) {
|
if (bscan_tunnel_ir_width != 0) {
|
||||||
/* need to right-shift "in" by one bit, because of clock skew between BSCAN TAP and DM TAP */
|
/* 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)
|
for (size_t i = 0; i < batch->used_scans; ++i)
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -17,214 +17,202 @@ static uint32_t bit(uint32_t value, unsigned int b)
|
||||||
return (value >> b) & 1;
|
return (value >> b) & 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static uint32_t inst_rd(uint32_t r) __attribute__ ((unused));
|
||||||
|
static uint32_t inst_rd(uint32_t r)
|
||||||
|
{
|
||||||
|
return bits(r, 4, 0) << 7;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t inst_rs1(uint32_t r) __attribute__ ((unused));
|
||||||
|
static uint32_t inst_rs1(uint32_t r)
|
||||||
|
{
|
||||||
|
return bits(r, 4, 0) << 15;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t inst_rs2(uint32_t r) __attribute__ ((unused));
|
||||||
|
static uint32_t inst_rs2(uint32_t r)
|
||||||
|
{
|
||||||
|
return bits(r, 4, 0) << 20;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t imm_i(uint32_t imm) __attribute__ ((unused));
|
||||||
|
static uint32_t imm_i(uint32_t imm)
|
||||||
|
{
|
||||||
|
return bits(imm, 11, 0) << 20;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t imm_s(uint32_t imm) __attribute__ ((unused));
|
||||||
|
static uint32_t imm_s(uint32_t imm)
|
||||||
|
{
|
||||||
|
return (bits(imm, 4, 0) << 7) | (bits(imm, 11, 5) << 25);
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t imm_b(uint32_t imm) __attribute__ ((unused));
|
||||||
|
static uint32_t imm_b(uint32_t imm)
|
||||||
|
{
|
||||||
|
return (bit(imm, 11) << 7) | (bits(imm, 4, 1) << 8) | (bits(imm, 10, 5) << 25) | (bit(imm, 12) << 31);
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t imm_u(uint32_t imm) __attribute__ ((unused));
|
||||||
|
static uint32_t imm_u(uint32_t imm)
|
||||||
|
{
|
||||||
|
return bits(imm, 31, 12) << 12;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t imm_j(uint32_t imm) __attribute__ ((unused));
|
||||||
|
static uint32_t imm_j(uint32_t imm)
|
||||||
|
{
|
||||||
|
return (bits(imm, 19, 12) << 12) | (bit(imm, 11) << 20) | (bits(imm, 10, 1) << 21) | (bit(imm, 20) << 31);
|
||||||
|
}
|
||||||
|
|
||||||
static uint32_t jal(unsigned int rd, uint32_t imm) __attribute__ ((unused));
|
static uint32_t jal(unsigned int rd, uint32_t imm) __attribute__ ((unused));
|
||||||
static uint32_t jal(unsigned int rd, uint32_t imm)
|
static uint32_t jal(unsigned int rd, uint32_t imm)
|
||||||
{
|
{
|
||||||
return (bit(imm, 20) << 31) |
|
return imm_j(imm) | inst_rd(rd) | MATCH_JAL;
|
||||||
(bits(imm, 10, 1) << 21) |
|
|
||||||
(bit(imm, 11) << 20) |
|
|
||||||
(bits(imm, 19, 12) << 12) |
|
|
||||||
(rd << 7) |
|
|
||||||
MATCH_JAL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t csrsi(unsigned int csr, uint16_t imm) __attribute__ ((unused));
|
static uint32_t csrsi(unsigned int csr, uint16_t imm) __attribute__ ((unused));
|
||||||
static uint32_t csrsi(unsigned int csr, uint16_t imm)
|
static uint32_t csrsi(unsigned int csr, uint16_t imm)
|
||||||
{
|
{
|
||||||
return (csr << 20) |
|
return imm_i(csr) | inst_rs1(imm) | MATCH_CSRRSI;
|
||||||
(bits(imm, 4, 0) << 15) |
|
|
||||||
MATCH_CSRRSI;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t sw(unsigned int src, unsigned int base, uint16_t offset) __attribute__ ((unused));
|
static uint32_t sw(unsigned int src, unsigned int base, uint16_t offset) __attribute__ ((unused));
|
||||||
static uint32_t sw(unsigned int src, unsigned int base, uint16_t offset)
|
static uint32_t sw(unsigned int src, unsigned int base, uint16_t offset)
|
||||||
{
|
{
|
||||||
return (bits(offset, 11, 5) << 25) |
|
return imm_s(offset) | inst_rs2(src) | inst_rs1(base) | MATCH_SW;
|
||||||
(src << 20) |
|
|
||||||
(base << 15) |
|
|
||||||
(bits(offset, 4, 0) << 7) |
|
|
||||||
MATCH_SW;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t sd(unsigned int src, unsigned int base, uint16_t offset) __attribute__ ((unused));
|
static uint32_t sd(unsigned int src, unsigned int base, uint16_t offset) __attribute__ ((unused));
|
||||||
static uint32_t sd(unsigned int src, unsigned int base, uint16_t offset)
|
static uint32_t sd(unsigned int src, unsigned int base, uint16_t offset)
|
||||||
{
|
{
|
||||||
return (bits(offset, 11, 5) << 25) |
|
return imm_s(offset) | inst_rs2(src) | inst_rs1(base) | MATCH_SD;
|
||||||
(src << 20) |
|
|
||||||
(base << 15) |
|
|
||||||
(bits(offset, 4, 0) << 7) |
|
|
||||||
MATCH_SD;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t sh(unsigned int src, unsigned int base, uint16_t offset) __attribute__ ((unused));
|
static uint32_t sh(unsigned int src, unsigned int base, uint16_t offset) __attribute__ ((unused));
|
||||||
static uint32_t sh(unsigned int src, unsigned int base, uint16_t offset)
|
static uint32_t sh(unsigned int src, unsigned int base, uint16_t offset)
|
||||||
{
|
{
|
||||||
return (bits(offset, 11, 5) << 25) |
|
return imm_s(offset) | inst_rs2(src) | inst_rs1(base) | MATCH_SH;
|
||||||
(src << 20) |
|
|
||||||
(base << 15) |
|
|
||||||
(bits(offset, 4, 0) << 7) |
|
|
||||||
MATCH_SH;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t sb(unsigned int src, unsigned int base, uint16_t offset) __attribute__ ((unused));
|
static uint32_t sb(unsigned int src, unsigned int base, uint16_t offset) __attribute__ ((unused));
|
||||||
static uint32_t sb(unsigned int src, unsigned int base, uint16_t offset)
|
static uint32_t sb(unsigned int src, unsigned int base, uint16_t offset)
|
||||||
{
|
{
|
||||||
return (bits(offset, 11, 5) << 25) |
|
return imm_s(offset) | inst_rs2(src) | inst_rs1(base) | MATCH_SB;
|
||||||
(src << 20) |
|
|
||||||
(base << 15) |
|
|
||||||
(bits(offset, 4, 0) << 7) |
|
|
||||||
MATCH_SB;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t ld(unsigned int rd, unsigned int base, uint16_t offset) __attribute__ ((unused));
|
static uint32_t ld(unsigned int rd, unsigned int base, uint16_t offset) __attribute__ ((unused));
|
||||||
static uint32_t ld(unsigned int rd, unsigned int base, uint16_t offset)
|
static uint32_t ld(unsigned int rd, unsigned int base, uint16_t offset)
|
||||||
{
|
{
|
||||||
return (bits(offset, 11, 0) << 20) |
|
return imm_i(offset) | inst_rs1(base) | inst_rd(rd) | MATCH_LD;
|
||||||
(base << 15) |
|
|
||||||
(bits(rd, 4, 0) << 7) |
|
|
||||||
MATCH_LD;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t lw(unsigned int rd, unsigned int base, uint16_t offset) __attribute__ ((unused));
|
static uint32_t lw(unsigned int rd, unsigned int base, uint16_t offset) __attribute__ ((unused));
|
||||||
static uint32_t lw(unsigned int rd, unsigned int base, uint16_t offset)
|
static uint32_t lw(unsigned int rd, unsigned int base, uint16_t offset)
|
||||||
{
|
{
|
||||||
return (bits(offset, 11, 0) << 20) |
|
return imm_i(offset) | inst_rs1(base) | inst_rd(rd) | MATCH_LW;
|
||||||
(base << 15) |
|
|
||||||
(bits(rd, 4, 0) << 7) |
|
|
||||||
MATCH_LW;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t lh(unsigned int rd, unsigned int base, uint16_t offset) __attribute__ ((unused));
|
static uint32_t lh(unsigned int rd, unsigned int base, uint16_t offset) __attribute__ ((unused));
|
||||||
static uint32_t lh(unsigned int rd, unsigned int base, uint16_t offset)
|
static uint32_t lh(unsigned int rd, unsigned int base, uint16_t offset)
|
||||||
{
|
{
|
||||||
return (bits(offset, 11, 0) << 20) |
|
return imm_i(offset) | inst_rs1(base) | inst_rd(rd) | MATCH_LH;
|
||||||
(base << 15) |
|
|
||||||
(bits(rd, 4, 0) << 7) |
|
|
||||||
MATCH_LH;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t lb(unsigned int rd, unsigned int base, uint16_t offset) __attribute__ ((unused));
|
static uint32_t lb(unsigned int rd, unsigned int base, uint16_t offset) __attribute__ ((unused));
|
||||||
static uint32_t lb(unsigned int rd, unsigned int base, uint16_t offset)
|
static uint32_t lb(unsigned int rd, unsigned int base, uint16_t offset)
|
||||||
{
|
{
|
||||||
return (bits(offset, 11, 0) << 20) |
|
return imm_i(offset) | inst_rs1(base) | inst_rd(rd) | MATCH_LB;
|
||||||
(base << 15) |
|
|
||||||
(bits(rd, 4, 0) << 7) |
|
|
||||||
MATCH_LB;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t csrw(unsigned int source, unsigned int csr) __attribute__ ((unused));
|
static uint32_t csrw(unsigned int source, unsigned int csr) __attribute__ ((unused));
|
||||||
static uint32_t csrw(unsigned int source, unsigned int csr)
|
static uint32_t csrw(unsigned int source, unsigned int csr)
|
||||||
{
|
{
|
||||||
return (csr << 20) | (source << 15) | MATCH_CSRRW;
|
return imm_i(csr) | inst_rs1(source) | MATCH_CSRRW;
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t addi(unsigned int dest, unsigned int src, uint16_t imm) __attribute__ ((unused));
|
static uint32_t addi(unsigned int dest, unsigned int src, uint16_t imm) __attribute__ ((unused));
|
||||||
static uint32_t addi(unsigned int dest, unsigned int src, uint16_t imm)
|
static uint32_t addi(unsigned int dest, unsigned int src, uint16_t imm)
|
||||||
{
|
{
|
||||||
return (bits(imm, 11, 0) << 20) |
|
return imm_i(imm) | inst_rs1(src) | inst_rd(dest) | MATCH_ADDI;
|
||||||
(src << 15) |
|
|
||||||
(dest << 7) |
|
|
||||||
MATCH_ADDI;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t csrr(unsigned int rd, unsigned int csr) __attribute__ ((unused));
|
static uint32_t csrr(unsigned int rd, unsigned int csr) __attribute__ ((unused));
|
||||||
static uint32_t csrr(unsigned int rd, unsigned int csr)
|
static uint32_t csrr(unsigned int rd, unsigned int csr)
|
||||||
{
|
{
|
||||||
return (csr << 20) | (rd << 7) | MATCH_CSRRS;
|
return imm_i(csr) | inst_rd(rd) | MATCH_CSRRS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t csrrs(unsigned int rd, unsigned int rs, unsigned int csr) __attribute__ ((unused));
|
static uint32_t csrrs(unsigned int rd, unsigned int rs, unsigned int csr) __attribute__ ((unused));
|
||||||
static uint32_t csrrs(unsigned int rd, unsigned int rs, unsigned int csr)
|
static uint32_t csrrs(unsigned int rd, unsigned int rs, unsigned int csr)
|
||||||
{
|
{
|
||||||
return (csr << 20) | (rs << 15) | (rd << 7) | MATCH_CSRRS;
|
return imm_i(csr) | inst_rs1(rs) | inst_rd(rd) | MATCH_CSRRS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t csrrw(unsigned int rd, unsigned int rs, unsigned int csr) __attribute__ ((unused));
|
static uint32_t csrrw(unsigned int rd, unsigned int rs, unsigned int csr) __attribute__ ((unused));
|
||||||
static uint32_t csrrw(unsigned int rd, unsigned int rs, unsigned int csr)
|
static uint32_t csrrw(unsigned int rd, unsigned int rs, unsigned int csr)
|
||||||
{
|
{
|
||||||
return (csr << 20) | (rs << 15) | (rd << 7) | MATCH_CSRRW;
|
return imm_i(csr) | inst_rs1(rs) | inst_rd(rd) | 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) __attribute__ ((unused));
|
||||||
static uint32_t csrrci(unsigned int rd, unsigned int zimm, unsigned int csr)
|
static uint32_t csrrci(unsigned int rd, unsigned int zimm, unsigned int csr)
|
||||||
{
|
{
|
||||||
return (csr << 20) | (zimm << 15) | (rd << 7) | MATCH_CSRRCI;
|
return imm_i(csr) | inst_rs1(zimm) | inst_rd(rd) | 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) __attribute__ ((unused));
|
||||||
static uint32_t csrrsi(unsigned int rd, unsigned int zimm, unsigned int csr)
|
static uint32_t csrrsi(unsigned int rd, unsigned int zimm, unsigned int csr)
|
||||||
{
|
{
|
||||||
return (csr << 20) | (zimm << 15) | (rd << 7) | MATCH_CSRRSI;
|
return imm_i(csr) | inst_rs1(zimm) | inst_rd(rd) | 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)
|
||||||
{
|
{
|
||||||
return (bits(offset, 11, 5) << 25) |
|
return imm_s(offset) | inst_rs2(src) | inst_rs1(base) | MATCH_FSW;
|
||||||
(bits(src, 4, 0) << 20) |
|
|
||||||
(base << 15) |
|
|
||||||
(bits(offset, 4, 0) << 7) |
|
|
||||||
MATCH_FSW;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t fsd(unsigned int src, unsigned int base, uint16_t offset) __attribute__ ((unused));
|
static uint32_t fsd(unsigned int src, unsigned int base, uint16_t offset) __attribute__ ((unused));
|
||||||
static uint32_t fsd(unsigned int src, unsigned int base, uint16_t offset)
|
static uint32_t fsd(unsigned int src, unsigned int base, uint16_t offset)
|
||||||
{
|
{
|
||||||
return (bits(offset, 11, 5) << 25) |
|
return imm_s(offset) | inst_rs2(src) | inst_rs1(base) | MATCH_FSD;
|
||||||
(bits(src, 4, 0) << 20) |
|
|
||||||
(base << 15) |
|
|
||||||
(bits(offset, 4, 0) << 7) |
|
|
||||||
MATCH_FSD;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t flw(unsigned int dest, unsigned int base, uint16_t offset) __attribute__ ((unused));
|
static uint32_t flw(unsigned int dest, unsigned int base, uint16_t offset) __attribute__ ((unused));
|
||||||
static uint32_t flw(unsigned int dest, unsigned int base, uint16_t offset)
|
static uint32_t flw(unsigned int dest, unsigned int base, uint16_t offset)
|
||||||
{
|
{
|
||||||
return (bits(offset, 11, 0) << 20) |
|
return imm_i(offset) | inst_rs1(base) | inst_rd(dest) | MATCH_FLW;
|
||||||
(base << 15) |
|
|
||||||
(bits(dest, 4, 0) << 7) |
|
|
||||||
MATCH_FLW;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t fld(unsigned int dest, unsigned int base, uint16_t offset) __attribute__ ((unused));
|
static uint32_t fld(unsigned int dest, unsigned int base, uint16_t offset) __attribute__ ((unused));
|
||||||
static uint32_t fld(unsigned int dest, unsigned int base, uint16_t offset)
|
static uint32_t fld(unsigned int dest, unsigned int base, uint16_t offset)
|
||||||
{
|
{
|
||||||
return (bits(offset, 11, 0) << 20) |
|
return imm_i(offset) | inst_rs1(base) | inst_rd(dest) | MATCH_FLD;
|
||||||
(base << 15) |
|
|
||||||
(bits(dest, 4, 0) << 7) |
|
|
||||||
MATCH_FLD;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t fmv_x_w(unsigned dest, unsigned src) __attribute__ ((unused));
|
static uint32_t fmv_x_w(unsigned dest, unsigned src) __attribute__ ((unused));
|
||||||
static uint32_t fmv_x_w(unsigned dest, unsigned src)
|
static uint32_t fmv_x_w(unsigned dest, unsigned src)
|
||||||
{
|
{
|
||||||
return src << 15 |
|
return inst_rs1(src) | inst_rd(dest) | MATCH_FMV_X_W;
|
||||||
dest << 7 |
|
|
||||||
MATCH_FMV_X_W;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t fmv_x_d(unsigned dest, unsigned src) __attribute__ ((unused));
|
static uint32_t fmv_x_d(unsigned dest, unsigned src) __attribute__ ((unused));
|
||||||
static uint32_t fmv_x_d(unsigned dest, unsigned src)
|
static uint32_t fmv_x_d(unsigned dest, unsigned src)
|
||||||
{
|
{
|
||||||
return src << 15 |
|
return inst_rs1(src) | inst_rd(dest) | MATCH_FMV_X_D;
|
||||||
dest << 7 |
|
|
||||||
MATCH_FMV_X_D;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t fmv_w_x(unsigned dest, unsigned src) __attribute__ ((unused));
|
static uint32_t fmv_w_x(unsigned dest, unsigned src) __attribute__ ((unused));
|
||||||
static uint32_t fmv_w_x(unsigned dest, unsigned src)
|
static uint32_t fmv_w_x(unsigned dest, unsigned src)
|
||||||
{
|
{
|
||||||
return src << 15 |
|
return inst_rs1(src) | inst_rd(dest) | MATCH_FMV_W_X;
|
||||||
dest << 7 |
|
|
||||||
MATCH_FMV_W_X;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t fmv_d_x(unsigned dest, unsigned src) __attribute__ ((unused));
|
static uint32_t fmv_d_x(unsigned dest, unsigned src) __attribute__ ((unused));
|
||||||
static uint32_t fmv_d_x(unsigned dest, unsigned src)
|
static uint32_t fmv_d_x(unsigned dest, unsigned src)
|
||||||
{
|
{
|
||||||
return src << 15 |
|
return inst_rs1(src) | inst_rd(dest) | MATCH_FMV_D_X;
|
||||||
dest << 7 |
|
|
||||||
MATCH_FMV_D_X;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t ebreak(void) __attribute__ ((unused));
|
static uint32_t ebreak(void) __attribute__ ((unused));
|
||||||
|
@ -250,9 +238,7 @@ static uint32_t fence_i(void)
|
||||||
static uint32_t lui(unsigned int dest, uint32_t imm) __attribute__ ((unused));
|
static uint32_t lui(unsigned int dest, uint32_t imm) __attribute__ ((unused));
|
||||||
static uint32_t lui(unsigned int dest, uint32_t imm)
|
static uint32_t lui(unsigned int dest, uint32_t imm)
|
||||||
{
|
{
|
||||||
return (bits(imm, 19, 0) << 12) |
|
return imm_u(imm) | inst_rd(dest) | MATCH_LUI;
|
||||||
(dest << 7) |
|
|
||||||
MATCH_LUI;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -299,19 +285,13 @@ static uint32_t nop(void)
|
||||||
static uint32_t xori(unsigned int dest, unsigned int src, uint16_t imm) __attribute__ ((unused));
|
static uint32_t xori(unsigned int dest, unsigned int src, uint16_t imm) __attribute__ ((unused));
|
||||||
static uint32_t xori(unsigned int dest, unsigned int src, uint16_t imm)
|
static uint32_t xori(unsigned int dest, unsigned int src, uint16_t imm)
|
||||||
{
|
{
|
||||||
return (bits(imm, 11, 0) << 20) |
|
return imm_i(imm) | inst_rs1(src) | inst_rd(dest) | MATCH_XORI;
|
||||||
(src << 15) |
|
|
||||||
(dest << 7) |
|
|
||||||
MATCH_XORI;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t srli(unsigned int dest, unsigned int src, uint8_t shamt) __attribute__ ((unused));
|
static uint32_t srli(unsigned int dest, unsigned int src, uint8_t shamt) __attribute__ ((unused));
|
||||||
static uint32_t srli(unsigned int dest, unsigned int src, uint8_t shamt)
|
static uint32_t srli(unsigned int dest, unsigned int src, uint8_t shamt)
|
||||||
{
|
{
|
||||||
return (bits(shamt, 4, 0) << 20) |
|
return inst_rs2(shamt) | inst_rs1(src) | inst_rd(dest) | MATCH_SRLI;
|
||||||
(src << 15) |
|
|
||||||
(dest << 7) |
|
|
||||||
MATCH_SRLI;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t fence(void) __attribute__((unused));
|
static uint32_t fence(void) __attribute__((unused));
|
||||||
|
@ -323,28 +303,25 @@ static uint32_t fence(void)
|
||||||
static uint32_t auipc(unsigned int dest) __attribute__((unused));
|
static uint32_t auipc(unsigned int dest) __attribute__((unused));
|
||||||
static uint32_t auipc(unsigned int dest)
|
static uint32_t auipc(unsigned int dest)
|
||||||
{
|
{
|
||||||
return MATCH_AUIPC | (dest << 7);
|
return MATCH_AUIPC | inst_rd(dest);
|
||||||
}
|
}
|
||||||
|
|
||||||
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) __attribute__((unused));
|
||||||
static uint32_t vsetvli(unsigned int dest, unsigned int src, uint16_t imm)
|
static uint32_t vsetvli(unsigned int dest, unsigned int src, uint16_t imm)
|
||||||
{
|
{
|
||||||
return (bits(imm, 10, 0) << 20) |
|
return (bits(imm, 10, 0) << 20) | inst_rs1(src) | inst_rd(dest) | MATCH_VSETVLI;
|
||||||
(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) __attribute__((unused));
|
||||||
static uint32_t vmv_x_s(unsigned int rd, unsigned int vs2)
|
static uint32_t vmv_x_s(unsigned int rd, unsigned int vs2)
|
||||||
{
|
{
|
||||||
return (vs2 << 20) | (rd << 7) | MATCH_VMV_X_S;
|
return inst_rs2(vs2) | inst_rd(rd) | 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 vs2) __attribute__((unused));
|
||||||
static uint32_t vmv_s_x(unsigned int vd, unsigned int rs1)
|
static uint32_t vmv_s_x(unsigned int vd, unsigned int rs1)
|
||||||
{
|
{
|
||||||
return (rs1 << 15) | (vd << 7) | MATCH_VMV_S_X;
|
return inst_rs1(rs1) | inst_rd(vd) | MATCH_VMV_S_X;
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t vslide1down_vx(unsigned int vd, unsigned int vs2,
|
static uint32_t vslide1down_vx(unsigned int vd, unsigned int vs2,
|
||||||
|
@ -352,6 +329,6 @@ static uint32_t vslide1down_vx(unsigned int vd, unsigned int vs2,
|
||||||
static uint32_t vslide1down_vx(unsigned int vd, unsigned int vs2,
|
static uint32_t vslide1down_vx(unsigned int vd, unsigned int vs2,
|
||||||
unsigned int rs1, unsigned int vm)
|
unsigned int rs1, unsigned int vm)
|
||||||
{
|
{
|
||||||
return (vm << 25) | (vs2 << 20) | (rs1 << 15) | (vd << 7) |
|
return ((vm & 1) << 25) | inst_rs2(vs2) | inst_rs1(rs1) | inst_rd(vd) | MATCH_VSLIDE1DOWN_VX;
|
||||||
MATCH_VSLIDE1DOWN_VX;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -40,20 +40,10 @@ int riscv_program_write(struct riscv_program *program);
|
||||||
* program to execute. That's OK, just make sure this eventually terminates.
|
* program to execute. That's OK, just make sure this eventually terminates.
|
||||||
* */
|
* */
|
||||||
int riscv_program_exec(struct riscv_program *p, struct target *t);
|
int riscv_program_exec(struct riscv_program *p, struct target *t);
|
||||||
int riscv_program_load(struct riscv_program *p, struct target *t);
|
|
||||||
|
|
||||||
/* Clears a program, removing all the state associated with it. */
|
|
||||||
int riscv_program_clear(struct riscv_program *p, struct target *t);
|
|
||||||
|
|
||||||
/* A lower level interface, you shouldn't use this unless you have a reason. */
|
/* A lower level interface, you shouldn't use this unless you have a reason. */
|
||||||
int riscv_program_insert(struct riscv_program *p, riscv_insn_t i);
|
int riscv_program_insert(struct riscv_program *p, riscv_insn_t i);
|
||||||
|
|
||||||
/* There is hardware support for saving at least one register. This register
|
|
||||||
* doesn't need to be saved/restored the usual way, which is useful during
|
|
||||||
* early initialization when we can't save/restore arbitrary registerrs to host
|
|
||||||
* memory. */
|
|
||||||
int riscv_program_save_to_dscratch(struct riscv_program *p, enum gdb_regno to_save);
|
|
||||||
|
|
||||||
/* 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. */
|
||||||
|
|
|
@ -152,6 +152,9 @@ typedef enum slot {
|
||||||
#define DMINFO_AUTHTYPE (3<<2)
|
#define DMINFO_AUTHTYPE (3<<2)
|
||||||
#define DMINFO_VERSION 3
|
#define DMINFO_VERSION 3
|
||||||
|
|
||||||
|
#define DMAUTHDATA0 0x12
|
||||||
|
#define DMAUTHDATA1 0x13
|
||||||
|
|
||||||
/*** Info about the core being debugged. ***/
|
/*** Info about the core being debugged. ***/
|
||||||
|
|
||||||
#define DBUS_ADDRESS_UNKNOWN 0xffff
|
#define DBUS_ADDRESS_UNKNOWN 0xffff
|
||||||
|
@ -216,8 +219,7 @@ typedef struct {
|
||||||
|
|
||||||
static int poll_target(struct target *target, bool announce);
|
static int poll_target(struct target *target, bool announce);
|
||||||
static int riscv011_poll(struct target *target);
|
static int riscv011_poll(struct target *target);
|
||||||
static int get_register(struct target *target, riscv_reg_t *value, int hartid,
|
static int get_register(struct target *target, riscv_reg_t *value, int regid);
|
||||||
int regid);
|
|
||||||
|
|
||||||
/*** Utility functions. ***/
|
/*** Utility functions. ***/
|
||||||
|
|
||||||
|
@ -226,6 +228,8 @@ static int get_register(struct target *target, riscv_reg_t *value, int hartid,
|
||||||
static riscv011_info_t *get_info(const struct target *target)
|
static riscv011_info_t *get_info(const struct target *target)
|
||||||
{
|
{
|
||||||
riscv_info_t *info = (riscv_info_t *) target->arch_info;
|
riscv_info_t *info = (riscv_info_t *) target->arch_info;
|
||||||
|
assert(info);
|
||||||
|
assert(info->version_specific);
|
||||||
return (riscv011_info_t *) info->version_specific;
|
return (riscv011_info_t *) info->version_specific;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1230,7 +1234,7 @@ static int update_mstatus_actual(struct target *target)
|
||||||
/* Force reading the register. In that process mstatus_actual will be
|
/* Force reading the register. In that process mstatus_actual will be
|
||||||
* updated. */
|
* updated. */
|
||||||
riscv_reg_t mstatus;
|
riscv_reg_t mstatus;
|
||||||
return get_register(target, &mstatus, 0, GDB_REGNO_MSTATUS);
|
return get_register(target, &mstatus, GDB_REGNO_MSTATUS);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*** OpenOCD target functions. ***/
|
/*** OpenOCD target functions. ***/
|
||||||
|
@ -1334,10 +1338,8 @@ static int register_write(struct target *target, unsigned int number,
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int get_register(struct target *target, riscv_reg_t *value, int hartid,
|
static int get_register(struct target *target, riscv_reg_t *value, int regid)
|
||||||
int regid)
|
|
||||||
{
|
{
|
||||||
assert(hartid == 0);
|
|
||||||
riscv011_info_t *info = get_info(target);
|
riscv011_info_t *info = get_info(target);
|
||||||
|
|
||||||
maybe_write_tselect(target);
|
maybe_write_tselect(target);
|
||||||
|
@ -1380,10 +1382,8 @@ static int get_register(struct target *target, riscv_reg_t *value, int hartid,
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int set_register(struct target *target, int hartid, int regid,
|
static int set_register(struct target *target, int regid, uint64_t value)
|
||||||
uint64_t value)
|
|
||||||
{
|
{
|
||||||
assert(hartid == 0);
|
|
||||||
return register_write(target, regid, value);
|
return register_write(target, regid, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1523,7 +1523,7 @@ static int examine(struct target *target)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Pretend this is a 32-bit system until we have found out the true value. */
|
/* Pretend this is a 32-bit system until we have found out the true value. */
|
||||||
r->xlen[0] = 32;
|
r->xlen = 32;
|
||||||
|
|
||||||
/* Figure out XLEN, and test writing all of Debug RAM while we're at it. */
|
/* Figure out XLEN, and test writing all of Debug RAM while we're at it. */
|
||||||
cache_set32(target, 0, xori(S1, ZERO, -1));
|
cache_set32(target, 0, xori(S1, ZERO, -1));
|
||||||
|
@ -1551,11 +1551,11 @@ static int examine(struct target *target)
|
||||||
uint32_t word1 = cache_get32(target, 1);
|
uint32_t word1 = cache_get32(target, 1);
|
||||||
riscv_info_t *generic_info = (riscv_info_t *) target->arch_info;
|
riscv_info_t *generic_info = (riscv_info_t *) target->arch_info;
|
||||||
if (word0 == 1 && word1 == 0) {
|
if (word0 == 1 && word1 == 0) {
|
||||||
generic_info->xlen[0] = 32;
|
generic_info->xlen = 32;
|
||||||
} else if (word0 == 0xffffffff && word1 == 3) {
|
} else if (word0 == 0xffffffff && word1 == 3) {
|
||||||
generic_info->xlen[0] = 64;
|
generic_info->xlen = 64;
|
||||||
} else if (word0 == 0xffffffff && word1 == 0xffffffff) {
|
} else if (word0 == 0xffffffff && word1 == 0xffffffff) {
|
||||||
generic_info->xlen[0] = 128;
|
generic_info->xlen = 128;
|
||||||
} else {
|
} else {
|
||||||
uint32_t exception = cache_get32(target, info->dramsize-1);
|
uint32_t exception = cache_get32(target, info->dramsize-1);
|
||||||
LOG_ERROR("Failed to discover xlen; word0=0x%x, word1=0x%x, exception=0x%x",
|
LOG_ERROR("Failed to discover xlen; word0=0x%x, word1=0x%x, exception=0x%x",
|
||||||
|
@ -1565,11 +1565,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_remote_csr(target, &r->misa[0], CSR_MISA) != ERROR_OK) {
|
if (read_remote_csr(target, &r->misa, 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_remote_csr(target, &r->misa[0], old_csr_misa) != ERROR_OK) {
|
if (read_remote_csr(target, &r->misa, 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);
|
||||||
|
@ -1591,7 +1591,7 @@ static int examine(struct target *target)
|
||||||
for (size_t i = 0; i < 32; ++i)
|
for (size_t i = 0; i < 32; ++i)
|
||||||
reg_cache_set(target, i, -1);
|
reg_cache_set(target, i, -1);
|
||||||
LOG_INFO("Examined RISCV core; XLEN=%d, misa=0x%" PRIx64,
|
LOG_INFO("Examined RISCV core; XLEN=%d, misa=0x%" PRIx64,
|
||||||
riscv_xlen(target), r->misa[0]);
|
riscv_xlen(target), r->misa);
|
||||||
|
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
@ -2294,21 +2294,95 @@ static int arch_state(struct target *target)
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
COMMAND_HELPER(riscv011_print_info, struct target *target)
|
||||||
|
{
|
||||||
|
/* Abstract description. */
|
||||||
|
riscv_print_info_line(CMD, "target", "memory.read_while_running8", 0);
|
||||||
|
riscv_print_info_line(CMD, "target", "memory.write_while_running8", 0);
|
||||||
|
riscv_print_info_line(CMD, "target", "memory.read_while_running16", 0);
|
||||||
|
riscv_print_info_line(CMD, "target", "memory.write_while_running16", 0);
|
||||||
|
riscv_print_info_line(CMD, "target", "memory.read_while_running32", 0);
|
||||||
|
riscv_print_info_line(CMD, "target", "memory.write_while_running32", 0);
|
||||||
|
riscv_print_info_line(CMD, "target", "memory.read_while_running64", 0);
|
||||||
|
riscv_print_info_line(CMD, "target", "memory.write_while_running64", 0);
|
||||||
|
riscv_print_info_line(CMD, "target", "memory.read_while_running128", 0);
|
||||||
|
riscv_print_info_line(CMD, "target", "memory.write_while_running128", 0);
|
||||||
|
|
||||||
|
uint32_t dminfo = dbus_read(target, DMINFO);
|
||||||
|
riscv_print_info_line(CMD, "dm", "authenticated", get_field(dminfo, DMINFO_AUTHENTICATED));
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int wait_for_authbusy(struct target *target)
|
||||||
|
{
|
||||||
|
time_t start = time(NULL);
|
||||||
|
while (1) {
|
||||||
|
uint32_t dminfo = dbus_read(target, DMINFO);
|
||||||
|
if (!get_field(dminfo, DMINFO_AUTHBUSY))
|
||||||
|
break;
|
||||||
|
if (time(NULL) - start > riscv_command_timeout_sec) {
|
||||||
|
LOG_ERROR("Timed out after %ds waiting for authbusy to go low (dminfo=0x%x). "
|
||||||
|
"Increase the timeout with riscv set_command_timeout_sec.",
|
||||||
|
riscv_command_timeout_sec,
|
||||||
|
dminfo);
|
||||||
|
return ERROR_FAIL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int riscv011_authdata_read(struct target *target, uint32_t *value, unsigned int index)
|
||||||
|
{
|
||||||
|
if (index > 1) {
|
||||||
|
LOG_ERROR("Spec 0.11 only has a two authdata registers.");
|
||||||
|
return ERROR_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wait_for_authbusy(target) != ERROR_OK)
|
||||||
|
return ERROR_FAIL;
|
||||||
|
|
||||||
|
uint16_t authdata_address = index ? DMAUTHDATA1 : DMAUTHDATA0;
|
||||||
|
*value = dbus_read(target, authdata_address);
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int riscv011_authdata_write(struct target *target, uint32_t value, unsigned int index)
|
||||||
|
{
|
||||||
|
if (index > 1) {
|
||||||
|
LOG_ERROR("Spec 0.11 only has a two authdata registers.");
|
||||||
|
return ERROR_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wait_for_authbusy(target) != ERROR_OK)
|
||||||
|
return ERROR_FAIL;
|
||||||
|
|
||||||
|
uint16_t authdata_address = index ? DMAUTHDATA1 : DMAUTHDATA0;
|
||||||
|
dbus_write(target, authdata_address, value);
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
static int init_target(struct command_context *cmd_ctx,
|
static int init_target(struct command_context *cmd_ctx,
|
||||||
struct target *target)
|
struct target *target)
|
||||||
{
|
{
|
||||||
LOG_DEBUG("init");
|
LOG_DEBUG("init");
|
||||||
riscv_info_t *generic_info = (riscv_info_t *)target->arch_info;
|
RISCV_INFO(generic_info);
|
||||||
generic_info->get_register = get_register;
|
generic_info->get_register = get_register;
|
||||||
generic_info->set_register = set_register;
|
generic_info->set_register = set_register;
|
||||||
generic_info->read_memory = read_memory;
|
generic_info->read_memory = read_memory;
|
||||||
|
generic_info->authdata_read = &riscv011_authdata_read;
|
||||||
|
generic_info->authdata_write = &riscv011_authdata_write;
|
||||||
|
generic_info->print_info = &riscv011_print_info;
|
||||||
|
|
||||||
generic_info->version_specific = calloc(1, sizeof(riscv011_info_t));
|
generic_info->version_specific = calloc(1, sizeof(riscv011_info_t));
|
||||||
if (!generic_info->version_specific)
|
if (!generic_info->version_specific)
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
|
|
||||||
/* Assume 32-bit until we discover the real value in examine(). */
|
/* Assume 32-bit until we discover the real value in examine(). */
|
||||||
generic_info->xlen[0] = 32;
|
generic_info->xlen = 32;
|
||||||
riscv_init_registers(target);
|
riscv_init_registers(target);
|
||||||
|
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -10,6 +10,7 @@ struct riscv_program;
|
||||||
#include "gdb_regs.h"
|
#include "gdb_regs.h"
|
||||||
#include "jtag/jtag.h"
|
#include "jtag/jtag.h"
|
||||||
#include "target/register.h"
|
#include "target/register.h"
|
||||||
|
#include <helper/command.h>
|
||||||
|
|
||||||
/* The register cache is statically allocated. */
|
/* The register cache is statically allocated. */
|
||||||
#define RISCV_MAX_HARTS 1024
|
#define RISCV_MAX_HARTS 1024
|
||||||
|
@ -26,6 +27,8 @@ struct riscv_program;
|
||||||
|
|
||||||
# define PG_MAX_LEVEL 4
|
# define PG_MAX_LEVEL 4
|
||||||
|
|
||||||
|
#define RISCV_NUM_MEM_ACCESS_METHODS 3
|
||||||
|
|
||||||
extern struct target_type riscv011_target;
|
extern struct target_type riscv011_target;
|
||||||
extern struct target_type riscv013_target;
|
extern struct target_type riscv013_target;
|
||||||
|
|
||||||
|
@ -36,6 +39,13 @@ typedef uint64_t riscv_reg_t;
|
||||||
typedef uint32_t riscv_insn_t;
|
typedef uint32_t riscv_insn_t;
|
||||||
typedef uint64_t riscv_addr_t;
|
typedef uint64_t riscv_addr_t;
|
||||||
|
|
||||||
|
enum riscv_mem_access_method {
|
||||||
|
RISCV_MEM_ACCESS_UNSPECIFIED,
|
||||||
|
RISCV_MEM_ACCESS_PROGBUF,
|
||||||
|
RISCV_MEM_ACCESS_SYSBUS,
|
||||||
|
RISCV_MEM_ACCESS_ABSTRACT
|
||||||
|
};
|
||||||
|
|
||||||
enum riscv_halt_reason {
|
enum riscv_halt_reason {
|
||||||
RISCV_HALT_INTERRUPT,
|
RISCV_HALT_INTERRUPT,
|
||||||
RISCV_HALT_BREAKPOINT,
|
RISCV_HALT_BREAKPOINT,
|
||||||
|
@ -51,15 +61,35 @@ typedef struct {
|
||||||
unsigned custom_number;
|
unsigned custom_number;
|
||||||
} riscv_reg_info_t;
|
} riscv_reg_info_t;
|
||||||
|
|
||||||
|
#define RISCV_SAMPLE_BUF_TIMESTAMP_BEFORE 0x80
|
||||||
|
#define RISCV_SAMPLE_BUF_TIMESTAMP_AFTER 0x81
|
||||||
|
struct riscv_sample_buf {
|
||||||
|
uint8_t *buf;
|
||||||
|
unsigned int used;
|
||||||
|
unsigned int size;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
bool enabled;
|
||||||
|
struct {
|
||||||
|
bool enabled;
|
||||||
|
target_addr_t address;
|
||||||
|
uint32_t size_bytes;
|
||||||
|
} bucket[16];
|
||||||
|
} riscv_sample_config_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
struct list_head list;
|
||||||
|
uint16_t low, high;
|
||||||
|
char *name;
|
||||||
|
} range_list_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
unsigned dtm_version;
|
unsigned dtm_version;
|
||||||
|
|
||||||
struct command_context *cmd_ctx;
|
struct command_context *cmd_ctx;
|
||||||
void *version_specific;
|
void *version_specific;
|
||||||
|
|
||||||
/* The hart that the RTOS thinks is currently being debugged. */
|
|
||||||
int rtos_hartid;
|
|
||||||
|
|
||||||
/* The hart that is currently being debugged. Note that this is
|
/* The hart that is currently being debugged. Note that this is
|
||||||
* different than the hartid that the RTOS is expected to use. This
|
* different than the hartid that the RTOS is expected to use. This
|
||||||
* one will change all the time, it's more of a global argument to
|
* one will change all the time, it's more of a global argument to
|
||||||
|
@ -76,13 +106,13 @@ typedef struct {
|
||||||
char *reg_names;
|
char *reg_names;
|
||||||
|
|
||||||
/* 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_reg_t misa[RISCV_MAX_HARTS];
|
riscv_reg_t misa;
|
||||||
/* Cached value of vlenb. 0 if vlenb is not readable for some reason. */
|
/* Cached value of vlenb. 0 if vlenb is not readable for some reason. */
|
||||||
unsigned vlenb[RISCV_MAX_HARTS];
|
unsigned int vlenb;
|
||||||
|
|
||||||
/* The number of triggers per hart. */
|
/* The number of triggers per hart. */
|
||||||
unsigned trigger_count[RISCV_MAX_HARTS];
|
unsigned int trigger_count;
|
||||||
|
|
||||||
/* For each physical trigger, contains -1 if the hwbp is available, or the
|
/* For each physical trigger, contains -1 if the hwbp is available, or the
|
||||||
* unique_id of the breakpoint/watchpoint that is using it.
|
* unique_id of the breakpoint/watchpoint that is using it.
|
||||||
|
@ -91,7 +121,7 @@ typedef struct {
|
||||||
int trigger_unique_id[RISCV_MAX_HWBPS];
|
int trigger_unique_id[RISCV_MAX_HWBPS];
|
||||||
|
|
||||||
/* The number of entries in the debug buffer. */
|
/* The number of entries in the debug buffer. */
|
||||||
int debug_buffer_size[RISCV_MAX_HARTS];
|
int debug_buffer_size;
|
||||||
|
|
||||||
/* This avoids invalidating the register cache too often. */
|
/* This avoids invalidating the register cache too often. */
|
||||||
bool registers_initialized;
|
bool registers_initialized;
|
||||||
|
@ -112,10 +142,8 @@ typedef struct {
|
||||||
|
|
||||||
/* 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 regid);
|
||||||
riscv_reg_t *value, int hid, int rid);
|
int (*set_register)(struct target *target, int regid, uint64_t value);
|
||||||
int (*set_register)(struct target *target, int hartid, int regid,
|
|
||||||
uint64_t value);
|
|
||||||
int (*get_register_buf)(struct target *target, uint8_t *buf, int regno);
|
int (*get_register_buf)(struct target *target, uint8_t *buf, int regno);
|
||||||
int (*set_register_buf)(struct target *target, int regno,
|
int (*set_register_buf)(struct target *target, int regno,
|
||||||
const uint8_t *buf);
|
const uint8_t *buf);
|
||||||
|
@ -143,8 +171,8 @@ typedef struct {
|
||||||
void (*fill_dmi_read_u64)(struct target *target, char *buf, int a);
|
void (*fill_dmi_read_u64)(struct target *target, char *buf, int a);
|
||||||
void (*fill_dmi_nop_u64)(struct target *target, char *buf);
|
void (*fill_dmi_nop_u64)(struct target *target, char *buf);
|
||||||
|
|
||||||
int (*authdata_read)(struct target *target, uint32_t *value);
|
int (*authdata_read)(struct target *target, uint32_t *value, unsigned int index);
|
||||||
int (*authdata_write)(struct target *target, uint32_t value);
|
int (*authdata_write)(struct target *target, uint32_t value, unsigned int index);
|
||||||
|
|
||||||
int (*dmi_read)(struct target *target, uint32_t *value, uint32_t address);
|
int (*dmi_read)(struct target *target, uint32_t *value, uint32_t address);
|
||||||
int (*dmi_write)(struct target *target, uint32_t address, uint32_t value);
|
int (*dmi_write)(struct target *target, uint32_t address, uint32_t value);
|
||||||
|
@ -152,7 +180,10 @@ typedef struct {
|
||||||
int (*test_sba_config_reg)(struct target *target, target_addr_t legal_address,
|
int (*test_sba_config_reg)(struct target *target, target_addr_t legal_address,
|
||||||
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 (*sample_memory)(struct target *target,
|
||||||
|
struct riscv_sample_buf *buf,
|
||||||
|
riscv_sample_config_t *config,
|
||||||
|
int64_t until_ms);
|
||||||
|
|
||||||
int (*read_memory)(struct target *target, target_addr_t address,
|
int (*read_memory)(struct target *target, target_addr_t address,
|
||||||
uint32_t size, uint32_t count, uint8_t *buffer, uint32_t increment);
|
uint32_t size, uint32_t count, uint8_t *buffer, uint32_t increment);
|
||||||
|
@ -161,6 +192,8 @@ typedef struct {
|
||||||
int (*hart_count)(struct target *target);
|
int (*hart_count)(struct target *target);
|
||||||
unsigned (*data_bits)(struct target *target);
|
unsigned (*data_bits)(struct target *target);
|
||||||
|
|
||||||
|
COMMAND_HELPER((*print_info), struct target *target);
|
||||||
|
|
||||||
/* Storage for vector register types. */
|
/* Storage for vector register types. */
|
||||||
struct reg_data_type_vector vector_uint8;
|
struct reg_data_type_vector vector_uint8;
|
||||||
struct reg_data_type_vector vector_uint16;
|
struct reg_data_type_vector vector_uint16;
|
||||||
|
@ -179,8 +212,31 @@ typedef struct {
|
||||||
/* Set when trigger registers are changed by the user. This indicates we eed
|
/* 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. */
|
* to beware that we may hit a trigger that we didn't realize had been set. */
|
||||||
bool manual_hwbp_set;
|
bool manual_hwbp_set;
|
||||||
|
|
||||||
|
/* Memory access methods to use, ordered by priority, highest to lowest. */
|
||||||
|
int mem_access_methods[RISCV_NUM_MEM_ACCESS_METHODS];
|
||||||
|
|
||||||
|
/* Different memory regions may need different methods but single configuration is applied
|
||||||
|
* for all. Following flags are used to warn only once about failing memory access method. */
|
||||||
|
bool mem_access_progbuf_warn;
|
||||||
|
bool mem_access_sysbus_warn;
|
||||||
|
bool mem_access_abstract_warn;
|
||||||
|
|
||||||
|
/* In addition to the ones in the standard spec, we'll also expose additional
|
||||||
|
* CSRs in this list. */
|
||||||
|
struct list_head expose_csr;
|
||||||
|
/* Same, but for custom registers.
|
||||||
|
* Custom registers are for non-standard extensions and use abstract register numbers
|
||||||
|
* from range 0xc000 ... 0xffff. */
|
||||||
|
struct list_head expose_custom;
|
||||||
|
|
||||||
|
riscv_sample_config_t sample_config;
|
||||||
|
struct riscv_sample_buf sample_buf;
|
||||||
} riscv_info_t;
|
} riscv_info_t;
|
||||||
|
|
||||||
|
COMMAND_HELPER(riscv_print_info_line, const char *section, const char *key,
|
||||||
|
unsigned int value);
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint8_t tunneled_dr_width;
|
uint8_t tunneled_dr_width;
|
||||||
struct scan_field tunneled_dr[4];
|
struct scan_field tunneled_dr[4];
|
||||||
|
@ -205,8 +261,6 @@ extern int riscv_command_timeout_sec;
|
||||||
/* Wall-clock timeout after reset. Settable via RISC-V Target commands.*/
|
/* Wall-clock timeout after reset. Settable via RISC-V Target commands.*/
|
||||||
extern int riscv_reset_timeout_sec;
|
extern int riscv_reset_timeout_sec;
|
||||||
|
|
||||||
extern bool riscv_prefer_sba;
|
|
||||||
|
|
||||||
extern bool riscv_enable_virtual;
|
extern bool riscv_enable_virtual;
|
||||||
extern bool riscv_ebreakm;
|
extern bool riscv_ebreakm;
|
||||||
extern bool riscv_ebreaks;
|
extern bool riscv_ebreaks;
|
||||||
|
@ -216,7 +270,10 @@ extern bool riscv_ebreaku;
|
||||||
* 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));
|
||||||
static inline riscv_info_t *riscv_info(const struct target *target)
|
static inline riscv_info_t *riscv_info(const struct target *target)
|
||||||
{ return target->arch_info; }
|
{
|
||||||
|
assert(target->arch_info);
|
||||||
|
return target->arch_info;
|
||||||
|
}
|
||||||
#define RISCV_INFO(R) riscv_info_t *R = riscv_info(target);
|
#define RISCV_INFO(R) riscv_info_t *R = riscv_info(target);
|
||||||
|
|
||||||
extern uint8_t ir_dtmcontrol[4];
|
extern uint8_t ir_dtmcontrol[4];
|
||||||
|
@ -269,44 +326,30 @@ void riscv_info_init(struct target *target, riscv_info_t *r);
|
||||||
* then the only hart. */
|
* then the only hart. */
|
||||||
int riscv_step_rtos_hart(struct target *target);
|
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, char letter);
|
||||||
|
|
||||||
/* Returns XLEN for the given (or current) hart. */
|
/* Returns XLEN for the given (or current) hart. */
|
||||||
unsigned 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);
|
||||||
|
|
||||||
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. */
|
||||||
int riscv_set_current_hartid(struct target *target, int hartid);
|
int riscv_set_current_hartid(struct target *target, int hartid);
|
||||||
|
int riscv_select_current_hart(struct target *target);
|
||||||
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
|
||||||
* without requiring multiple targets. */
|
* without requiring multiple targets. */
|
||||||
|
|
||||||
/* When using the RTOS to debug, this selects the hart that is currently being
|
|
||||||
* debugged. This doesn't propagate to the hardware. */
|
|
||||||
void riscv_set_all_rtos_harts(struct target *target);
|
|
||||||
void riscv_set_rtos_hartid(struct target *target, int hartid);
|
|
||||||
|
|
||||||
/* Lists the number of harts in the system, which are assumed to be
|
/* Lists the number of harts in the system, which are assumed to be
|
||||||
* consecutive and start with mhartid=0. */
|
* consecutive and start with mhartid=0. */
|
||||||
int riscv_count_harts(struct target *target);
|
int riscv_count_harts(struct target *target);
|
||||||
|
|
||||||
/* Returns TRUE if the target has the given register on the given hart. */
|
|
||||||
bool riscv_has_register(struct target *target, int hartid, int regid);
|
|
||||||
|
|
||||||
/** Set register, updating the cache. */
|
/** Set register, updating the cache. */
|
||||||
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);
|
|
||||||
/** Get register, from the cache if it's in there. */
|
/** 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 hartid, enum gdb_regno regid);
|
|
||||||
|
|
||||||
/* Checks the state of the current hart -- "is_halted" checks the actual
|
/* Checks the state of the current hart -- "is_halted" checks the actual
|
||||||
* on-device register. */
|
* on-device register. */
|
||||||
|
@ -329,9 +372,6 @@ int riscv_dmi_write_u64_bits(struct target *target);
|
||||||
/* Invalidates the register cache. */
|
/* Invalidates the register cache. */
|
||||||
void riscv_invalidate_register_cache(struct target *target);
|
void riscv_invalidate_register_cache(struct target *target);
|
||||||
|
|
||||||
/* Returns TRUE when a hart is enabled in this target. */
|
|
||||||
bool riscv_hart_enabled(struct target *target, int hartid);
|
|
||||||
|
|
||||||
int riscv_enumerate_triggers(struct target *target);
|
int riscv_enumerate_triggers(struct target *target);
|
||||||
|
|
||||||
int riscv_add_breakpoint(struct target *target, struct breakpoint *breakpoint);
|
int riscv_add_breakpoint(struct target *target, struct breakpoint *breakpoint);
|
||||||
|
@ -356,4 +396,7 @@ semihosting_result_t riscv_semihosting(struct target *target, int *retval);
|
||||||
void riscv_add_bscan_tunneled_scan(struct target *target, struct scan_field *field,
|
void riscv_add_bscan_tunneled_scan(struct target *target, struct scan_field *field,
|
||||||
riscv_bscan_tunneled_scan_context_t *ctxt);
|
riscv_bscan_tunneled_scan_context_t *ctxt);
|
||||||
|
|
||||||
|
int riscv_read_by_any_size(struct target *target, target_addr_t address, uint32_t size, uint8_t *buffer);
|
||||||
|
int riscv_write_by_any_size(struct target *target, target_addr_t address, uint32_t size, uint8_t *buffer);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -85,12 +85,15 @@ semihosting_result_t riscv_semihosting(struct target *target, int *retval)
|
||||||
if (result != ERROR_OK)
|
if (result != ERROR_OK)
|
||||||
return SEMI_ERROR;
|
return SEMI_ERROR;
|
||||||
|
|
||||||
uint8_t tmp[12];
|
uint8_t tmp_buf[12];
|
||||||
|
|
||||||
/* Read the current instruction, including the bracketing */
|
/* Read three uncompressed instructions: The previous, the current one (pointed to by PC) and the next one */
|
||||||
*retval = target_read_memory(target, pc - 4, 2, 6, tmp);
|
for (int i = 0; i < 3; i++) {
|
||||||
if (*retval != ERROR_OK)
|
/* Instruction memories may not support arbitrary read size. Use any size that will work. */
|
||||||
return SEMI_ERROR;
|
*retval = riscv_read_by_any_size(target, (pc - 4) + 4 * i, 4, tmp_buf + 4 * i);
|
||||||
|
if (*retval != ERROR_OK)
|
||||||
|
return SEMI_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The instructions that trigger a semihosting call,
|
* The instructions that trigger a semihosting call,
|
||||||
|
@ -100,9 +103,9 @@ semihosting_result_t riscv_semihosting(struct target *target, int *retval)
|
||||||
* 00100073 ebreak
|
* 00100073 ebreak
|
||||||
* 40705013 srai zero,zero,0x7
|
* 40705013 srai zero,zero,0x7
|
||||||
*/
|
*/
|
||||||
uint32_t pre = target_buffer_get_u32(target, tmp);
|
uint32_t pre = target_buffer_get_u32(target, tmp_buf);
|
||||||
uint32_t ebreak = target_buffer_get_u32(target, tmp + 4);
|
uint32_t ebreak = target_buffer_get_u32(target, tmp_buf + 4);
|
||||||
uint32_t post = target_buffer_get_u32(target, tmp + 8);
|
uint32_t post = target_buffer_get_u32(target, tmp_buf + 8);
|
||||||
LOG_DEBUG("check %08x %08x %08x from 0x%" PRIx64 "-4", pre, ebreak, post, pc);
|
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) {
|
||||||
|
|
Loading…
Reference in New Issue