Merge pull request #875 from zqb-all/support_multiple_DMs
target/riscv: support multiple DMs
This commit is contained in:
commit
1997e68dcb
|
@ -10891,15 +10891,28 @@ Write the 32-bit value to authdata or authdata0 (index=0), or authdata1
|
|||
|
||||
@subsection RISC-V DMI Commands
|
||||
|
||||
The following commands allow direct access to the Debug Module Interface, which
|
||||
can be used to interact with custom debug features.
|
||||
The following commands allow for direct low-level access to the registers
|
||||
of the Debug Module (DM). They can be useful to access custom features in the DM.
|
||||
|
||||
@deffn {Command} {riscv dm_read} reg_address
|
||||
Perform a 32-bit read from the register indicated by reg_address from the DM of the
|
||||
current target.
|
||||
@end deffn
|
||||
|
||||
@deffn {Command} {riscv dm_write} reg_address value
|
||||
Write the 32-bit value to the register indicated by reg_address from the DM of the
|
||||
current target.
|
||||
@end deffn
|
||||
|
||||
The following commands allow for direct low-level access to the Debug Module
|
||||
Interface (DMI). They can be useful to access any device that resides on the DMI.
|
||||
|
||||
@deffn {Command} {riscv dmi_read} address
|
||||
Perform a 32-bit DMI read at address, returning the value.
|
||||
Perform a 32-bit read from the given DMI address, returning the value.
|
||||
@end deffn
|
||||
|
||||
@deffn {Command} {riscv dmi_write} address value
|
||||
Perform a 32-bit DMI write of value at address.
|
||||
Perform a 32-bit write to the given DMI address.
|
||||
@end deffn
|
||||
|
||||
@subsection RISC-V Trigger Commands
|
||||
|
|
|
@ -127,17 +127,17 @@ int riscv_batch_run(struct riscv_batch *batch)
|
|||
return ERROR_OK;
|
||||
}
|
||||
|
||||
void riscv_batch_add_dmi_write(struct riscv_batch *batch, unsigned int address, uint64_t data,
|
||||
void riscv_batch_add_dm_write(struct riscv_batch *batch, unsigned int address, uint64_t data,
|
||||
bool read_back)
|
||||
{
|
||||
assert(batch->used_scans < batch->allocated_scans);
|
||||
struct scan_field *field = batch->fields + batch->used_scans;
|
||||
field->num_bits = riscv_dmi_write_u64_bits(batch->target);
|
||||
field->out_value = (void *)(batch->data_out + batch->used_scans * DMI_SCAN_BUF_SIZE);
|
||||
riscv_fill_dmi_write_u64(batch->target, (char *)field->out_value, address, data);
|
||||
riscv_fill_dm_write_u64(batch->target, (char *)field->out_value, address, data);
|
||||
if (read_back) {
|
||||
field->in_value = (void *)(batch->data_in + batch->used_scans * DMI_SCAN_BUF_SIZE);
|
||||
riscv_fill_dmi_nop_u64(batch->target, (char *)field->in_value);
|
||||
riscv_fill_dm_nop_u64(batch->target, (char *)field->in_value);
|
||||
} else {
|
||||
field->in_value = NULL;
|
||||
}
|
||||
|
@ -145,15 +145,15 @@ void riscv_batch_add_dmi_write(struct riscv_batch *batch, unsigned int address,
|
|||
batch->used_scans++;
|
||||
}
|
||||
|
||||
size_t riscv_batch_add_dmi_read(struct riscv_batch *batch, unsigned address)
|
||||
size_t riscv_batch_add_dm_read(struct riscv_batch *batch, unsigned int address)
|
||||
{
|
||||
assert(batch->used_scans < batch->allocated_scans);
|
||||
struct scan_field *field = batch->fields + batch->used_scans;
|
||||
field->num_bits = riscv_dmi_write_u64_bits(batch->target);
|
||||
field->out_value = (void *)(batch->data_out + batch->used_scans * DMI_SCAN_BUF_SIZE);
|
||||
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_nop_u64(batch->target, (char *)field->in_value);
|
||||
riscv_fill_dm_read_u64(batch->target, (char *)field->out_value, address);
|
||||
riscv_fill_dm_nop_u64(batch->target, (char *)field->in_value);
|
||||
batch->last_scan = RISCV_SCAN_TYPE_READ;
|
||||
batch->used_scans++;
|
||||
|
||||
|
@ -188,8 +188,8 @@ void riscv_batch_add_nop(struct riscv_batch *batch)
|
|||
field->num_bits = riscv_dmi_write_u64_bits(batch->target);
|
||||
field->out_value = (void *)(batch->data_out + batch->used_scans * DMI_SCAN_BUF_SIZE);
|
||||
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->in_value);
|
||||
riscv_fill_dm_nop_u64(batch->target, (char *)field->out_value);
|
||||
riscv_fill_dm_nop_u64(batch->target, (char *)field->in_value);
|
||||
batch->last_scan = RISCV_SCAN_TYPE_NOP;
|
||||
batch->used_scans++;
|
||||
}
|
||||
|
|
|
@ -58,14 +58,14 @@ bool riscv_batch_full(struct riscv_batch *batch);
|
|||
/* Executes this scan batch. */
|
||||
int riscv_batch_run(struct riscv_batch *batch);
|
||||
|
||||
/* Adds a DMI write to this batch. */
|
||||
void riscv_batch_add_dmi_write(struct riscv_batch *batch, unsigned int address, uint64_t data,
|
||||
/* Adds a DM register write to this batch. */
|
||||
void riscv_batch_add_dm_write(struct riscv_batch *batch, unsigned int address, uint64_t data,
|
||||
bool read_back);
|
||||
|
||||
/* DMI reads must be handled in two parts: the first one schedules a read and
|
||||
/* DM register reads must be handled in two parts: the first one schedules a read and
|
||||
* 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_dm_read(struct riscv_batch *batch, unsigned int address);
|
||||
unsigned int riscv_batch_get_dmi_read_op(const struct riscv_batch *batch, size_t key);
|
||||
uint32_t riscv_batch_get_dmi_read_data(const struct riscv_batch *batch, size_t key);
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -3479,14 +3479,13 @@ COMMAND_HANDLER(riscv_dmi_read)
|
|||
if (r->dmi_read(target, &value, address) != ERROR_OK)
|
||||
return ERROR_FAIL;
|
||||
command_print(CMD, "0x%" PRIx32, value);
|
||||
return ERROR_OK;
|
||||
} else {
|
||||
LOG_TARGET_ERROR(target, "dmi_read is not implemented for this target.");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
|
||||
COMMAND_HANDLER(riscv_dmi_write)
|
||||
{
|
||||
if (CMD_ARGC != 2) {
|
||||
|
@ -3524,6 +3523,76 @@ COMMAND_HANDLER(riscv_dmi_write)
|
|||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
|
||||
COMMAND_HANDLER(riscv_dm_read)
|
||||
{
|
||||
if (CMD_ARGC != 1) {
|
||||
LOG_ERROR("Command takes 1 parameter");
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
}
|
||||
|
||||
struct target *target = get_current_target(CMD_CTX);
|
||||
if (!target) {
|
||||
LOG_ERROR("target is NULL!");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
RISCV_INFO(r);
|
||||
if (!r) {
|
||||
LOG_TARGET_ERROR(target, "riscv_info is NULL!");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
if (r->dm_read) {
|
||||
uint32_t address, value;
|
||||
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], address);
|
||||
if (r->dm_read(target, &value, address) != ERROR_OK)
|
||||
return ERROR_FAIL;
|
||||
command_print(CMD, "0x%" PRIx32, value);
|
||||
} else {
|
||||
LOG_TARGET_ERROR(target, "dm_read is not implemented for this target.");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
COMMAND_HANDLER(riscv_dm_write)
|
||||
{
|
||||
if (CMD_ARGC != 2) {
|
||||
LOG_ERROR("Command takes exactly 2 arguments");
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
}
|
||||
|
||||
struct target *target = get_current_target(CMD_CTX);
|
||||
RISCV_INFO(r);
|
||||
|
||||
uint32_t address, value;
|
||||
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], address);
|
||||
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], value);
|
||||
|
||||
if (r->dm_write) {
|
||||
/* Perform the DM write */
|
||||
int retval = r->dm_write(target, address, value);
|
||||
|
||||
/* Invalidate our cached progbuf copy:
|
||||
- if the user tinkered directly with a progbuf register
|
||||
- if debug module was reset, in which case progbuf registers
|
||||
may not retain their value.
|
||||
*/
|
||||
bool progbuf_touched = (address >= DM_PROGBUF0 && address <= DM_PROGBUF15);
|
||||
bool dm_deactivated = (address == DM_DMCONTROL && (value & DM_DMCONTROL_DMACTIVE) == 0);
|
||||
if (progbuf_touched || dm_deactivated) {
|
||||
if (r->invalidate_cached_debug_buffer)
|
||||
r->invalidate_cached_debug_buffer(target);
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
LOG_TARGET_ERROR(target, "dm_write is not implemented for this target.");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
COMMAND_HANDLER(riscv_reset_delays)
|
||||
{
|
||||
int wait = 0;
|
||||
|
@ -4285,6 +4354,20 @@ static const struct command_registration riscv_exec_command_handlers[] = {
|
|||
.usage = "address value",
|
||||
.help = "Perform a 32-bit DMI write of value at address."
|
||||
},
|
||||
{
|
||||
.name = "dm_read",
|
||||
.handler = riscv_dm_read,
|
||||
.mode = COMMAND_ANY,
|
||||
.usage = "reg_address",
|
||||
.help = "Perform a 32-bit read from DM register at reg_address, returning the value."
|
||||
},
|
||||
{
|
||||
.name = "dm_write",
|
||||
.handler = riscv_dm_write,
|
||||
.mode = COMMAND_ANY,
|
||||
.usage = "reg_address value",
|
||||
.help = "Write a 32-bit value to the DM register at reg_address."
|
||||
},
|
||||
{
|
||||
.name = "reset_delays",
|
||||
.handler = riscv_reset_delays,
|
||||
|
@ -4916,22 +4999,22 @@ int riscv_execute_debug_buffer(struct target *target)
|
|||
return r->execute_debug_buffer(target);
|
||||
}
|
||||
|
||||
void riscv_fill_dmi_write_u64(struct target *target, char *buf, int a, uint64_t d)
|
||||
void riscv_fill_dm_write_u64(struct target *target, char *buf, int a, uint64_t d)
|
||||
{
|
||||
RISCV_INFO(r);
|
||||
r->fill_dmi_write_u64(target, buf, a, d);
|
||||
r->fill_dm_write_u64(target, buf, a, d);
|
||||
}
|
||||
|
||||
void riscv_fill_dmi_read_u64(struct target *target, char *buf, int a)
|
||||
void riscv_fill_dm_read_u64(struct target *target, char *buf, int a)
|
||||
{
|
||||
RISCV_INFO(r);
|
||||
r->fill_dmi_read_u64(target, buf, a);
|
||||
r->fill_dm_read_u64(target, buf, a);
|
||||
}
|
||||
|
||||
void riscv_fill_dmi_nop_u64(struct target *target, char *buf)
|
||||
void riscv_fill_dm_nop_u64(struct target *target, char *buf)
|
||||
{
|
||||
RISCV_INFO(r);
|
||||
r->fill_dmi_nop_u64(target, buf);
|
||||
r->fill_dm_nop_u64(target, buf);
|
||||
}
|
||||
|
||||
int riscv_dmi_write_u64_bits(struct target *target)
|
||||
|
|
|
@ -19,6 +19,7 @@ struct riscv_program;
|
|||
#define RISCV_MAX_HARTS ((int)BIT(20))
|
||||
#define RISCV_MAX_TRIGGERS 32
|
||||
#define RISCV_MAX_HWBPS 16
|
||||
#define RISCV_MAX_DMS 100
|
||||
|
||||
#define DEFAULT_COMMAND_TIMEOUT_SEC 2
|
||||
#define DEFAULT_RESET_TIMEOUT_SEC 30
|
||||
|
@ -220,9 +221,9 @@ struct riscv_info {
|
|||
int (*execute_debug_buffer)(struct target *target);
|
||||
int (*invalidate_cached_debug_buffer)(struct target *target);
|
||||
int (*dmi_write_u64_bits)(struct target *target);
|
||||
void (*fill_dmi_write_u64)(struct target *target, char *buf, int a, uint64_t d);
|
||||
void (*fill_dmi_read_u64)(struct target *target, char *buf, int a);
|
||||
void (*fill_dmi_nop_u64)(struct target *target, char *buf);
|
||||
void (*fill_dm_write_u64)(struct target *target, char *buf, int a, uint64_t d);
|
||||
void (*fill_dm_read_u64)(struct target *target, char *buf, int a);
|
||||
void (*fill_dm_nop_u64)(struct target *target, char *buf);
|
||||
|
||||
int (*authdata_read)(struct target *target, uint32_t *value, unsigned int index);
|
||||
int (*authdata_write)(struct target *target, uint32_t value, unsigned int index);
|
||||
|
@ -230,6 +231,9 @@ struct riscv_info {
|
|||
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 (*dm_read)(struct target *target, uint32_t *value, uint32_t address);
|
||||
int (*dm_write)(struct target *target, uint32_t address, uint32_t value);
|
||||
|
||||
int (*sample_memory)(struct target *target,
|
||||
struct riscv_sample_buf *buf,
|
||||
riscv_sample_config_t *config,
|
||||
|
@ -412,9 +416,9 @@ riscv_insn_t riscv_read_debug_buffer(struct target *target, int index);
|
|||
int riscv_write_debug_buffer(struct target *target, int index, riscv_insn_t insn);
|
||||
int riscv_execute_debug_buffer(struct target *target);
|
||||
|
||||
void riscv_fill_dmi_nop_u64(struct target *target, char *buf);
|
||||
void riscv_fill_dmi_write_u64(struct target *target, char *buf, int a, uint64_t d);
|
||||
void riscv_fill_dmi_read_u64(struct target *target, char *buf, int a);
|
||||
void riscv_fill_dm_nop_u64(struct target *target, char *buf);
|
||||
void riscv_fill_dm_write_u64(struct target *target, char *buf, int a, uint64_t d);
|
||||
void riscv_fill_dm_read_u64(struct target *target, char *buf, int a);
|
||||
int riscv_dmi_write_u64_bits(struct target *target);
|
||||
|
||||
int riscv_enumerate_triggers(struct target *target);
|
||||
|
|
Loading…
Reference in New Issue