Add command "exec_progbuf" (#795)
* Add command "exec_progbuf" Command "exec_progbuf" allows to execute a user-specified sequence of instructions using the program buffer. Change-Id: If3b9614129d0b6fcbc33fade29d3d60b35e52f98 Signed-off-by: Jan Matyas <jan.matyas@codasip.com> * Updated the doc: - Minor reword and reorder of the sentences. - Added information about C-instructions in progbuf. - Fixed a typo (per the review). - Added examples. Change-Id: I88c9a3ff3c6b60614be7eafd3a6f21be722a77b7 Signed-off-by: Jan Matyas <jan.matyas@codasip.com> * Cosmetic changes Change-Id: I7135c9f435f640e189c7d7922a2702814dfd595f Signed-off-by: Jan Matyas <jan.matyas@codasip.com> --------- Signed-off-by: Jan Matyas <jan.matyas@codasip.com> Co-authored-by: Jan Matyas <jan.matyas@codasip.com>
This commit is contained in:
parent
9cafc75678
commit
872ebb14ca
|
@ -10753,6 +10753,39 @@ For details on this trigger type, see the RISC-V Debug Specification.
|
||||||
Clear the type 4 trigger that was set using @command{riscv itrigger set}.
|
Clear the type 4 trigger that was set using @command{riscv itrigger set}.
|
||||||
@end deffn
|
@end deffn
|
||||||
|
|
||||||
|
@subsection RISC-V Program Buffer Commands
|
||||||
|
|
||||||
|
Program Buffer is an optional feature of RISC-V targets - it is a mechanism that debuggers
|
||||||
|
can use to execute sequences of arbitrary instructions (small programs) on the target.
|
||||||
|
For details on the Program Buffer, please refer to the RISC-V Debug Specification.
|
||||||
|
|
||||||
|
@deffn {Command} {riscv exec_progbuf} inst1 [inst2 [... inst16]]
|
||||||
|
Execute the given sequence of instructions on the target using the Program Buffer.
|
||||||
|
The command can only be used on halted targets.
|
||||||
|
|
||||||
|
The instructions @var{inst1} .. @var{inst16} shall be specified in their binary form
|
||||||
|
(as 32-bit integers). In case a pair of compressed (16-bit) instructions is used,
|
||||||
|
the first instruction should be placed to the lower 16-bits of the 32-bit value.
|
||||||
|
The terminating @var{ebreak} instruction needs not be specified - it is added
|
||||||
|
automatically if needed.
|
||||||
|
@end deffn
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
|
||||||
|
@example
|
||||||
|
# Execute 32-bit instructions "fence rw,rw" (0x0330000f)
|
||||||
|
# and "fence.i" (0x0000100f) using the Program Buffer,
|
||||||
|
# in this order:
|
||||||
|
|
||||||
|
riscv exec_progbuf 0x0330000f 0x0000100f
|
||||||
|
|
||||||
|
# Execute 16-bit instructions "c.addi s0,s0,1" (0x0405)
|
||||||
|
# and "c.add s1,s1,s0" (0x94a2) using the Program Buffer,
|
||||||
|
# in this order:
|
||||||
|
|
||||||
|
riscv exec_progbuf 0x94a20405
|
||||||
|
@end example
|
||||||
|
|
||||||
@section ARC Architecture
|
@section ARC Architecture
|
||||||
@cindex ARC
|
@cindex ARC
|
||||||
|
|
||||||
|
|
|
@ -32,7 +32,8 @@ 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("debug_buffer[%02x] = DASM(0x%08x)", i, program->debug_buffer[i]);
|
LOG_TARGET_DEBUG(program->target, "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;
|
||||||
|
@ -48,7 +49,7 @@ int riscv_program_exec(struct riscv_program *p, struct target *t)
|
||||||
riscv_reg_t saved_registers[GDB_REGNO_XPR31 + 1];
|
riscv_reg_t saved_registers[GDB_REGNO_XPR31 + 1];
|
||||||
for (size_t i = GDB_REGNO_ZERO + 1; i <= GDB_REGNO_XPR31; ++i) {
|
for (size_t i = GDB_REGNO_ZERO + 1; i <= GDB_REGNO_XPR31; ++i) {
|
||||||
if (p->writes_xreg[i]) {
|
if (p->writes_xreg[i]) {
|
||||||
LOG_DEBUG("Saving register %d as used by program", (int)i);
|
LOG_TARGET_DEBUG(t, "Saving register %d as used by program", (int)i);
|
||||||
int result = riscv_get_register(t, &saved_registers[i], i);
|
int result = riscv_get_register(t, &saved_registers[i], i);
|
||||||
if (result != ERROR_OK)
|
if (result != ERROR_OK)
|
||||||
return result;
|
return result;
|
||||||
|
@ -56,9 +57,9 @@ 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_TARGET_ERROR(t, "Unable to insert ebreak into program buffer");
|
||||||
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%08" PRIx32 ") [0x%08" PRIx32 "]",
|
LOG_TARGET_ERROR(t, "ram[%02x]: DASM(0x%08" PRIx32 ") [0x%08" PRIx32 "]",
|
||||||
(int)i, p->debug_buffer[i], p->debug_buffer[i]);
|
(int)i, p->debug_buffer[i], p->debug_buffer[i]);
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
}
|
}
|
||||||
|
@ -67,7 +68,7 @@ int riscv_program_exec(struct riscv_program *p, struct target *t)
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
|
|
||||||
if (riscv_execute_debug_buffer(t) != ERROR_OK) {
|
if (riscv_execute_debug_buffer(t) != ERROR_OK) {
|
||||||
LOG_DEBUG("Unable to execute program %p", p);
|
LOG_TARGET_DEBUG(t, "Unable to execute program %p", p);
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -175,9 +176,9 @@ int riscv_program_addi(struct riscv_program *p, enum gdb_regno d, enum gdb_regno
|
||||||
int riscv_program_insert(struct riscv_program *p, riscv_insn_t i)
|
int riscv_program_insert(struct riscv_program *p, riscv_insn_t i)
|
||||||
{
|
{
|
||||||
if (p->instruction_count >= riscv_debug_buffer_size(p->target)) {
|
if (p->instruction_count >= riscv_debug_buffer_size(p->target)) {
|
||||||
LOG_ERROR("Unable to insert instruction:");
|
LOG_TARGET_ERROR(p->target, "Unable to insert program into progbuf, "
|
||||||
LOG_ERROR(" instruction_count=%d", (int)p->instruction_count);
|
"capacity would be exceeded (progbufsize=%d).",
|
||||||
LOG_ERROR(" buffer size =%d", (int)riscv_debug_buffer_size(p->target));
|
(int)riscv_debug_buffer_size(p->target));
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1700,7 +1700,7 @@ static int examine(struct target *target)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Without knowing anything else we can at least mess with the
|
/* Without knowing anything else we can at least mess with the
|
||||||
* program buffer. */
|
* program buffer. */
|
||||||
r->debug_buffer_size = info->progbufsize;
|
r->debug_buffer_size = info->progbufsize;
|
||||||
|
|
||||||
int result = register_read_abstract(target, NULL, GDB_REGNO_S0, 64);
|
int result = register_read_abstract(target, NULL, GDB_REGNO_S0, 64);
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
#include "helper/base64.h"
|
#include "helper/base64.h"
|
||||||
#include "helper/time_support.h"
|
#include "helper/time_support.h"
|
||||||
#include "riscv.h"
|
#include "riscv.h"
|
||||||
|
#include "program.h"
|
||||||
#include "gdb_regs.h"
|
#include "gdb_regs.h"
|
||||||
#include "rtos/rtos.h"
|
#include "rtos/rtos.h"
|
||||||
#include "debug_defines.h"
|
#include "debug_defines.h"
|
||||||
|
@ -3589,6 +3590,52 @@ COMMAND_HANDLER(handle_info)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
COMMAND_HANDLER(riscv_exec_progbuf)
|
||||||
|
{
|
||||||
|
if (CMD_ARGC < 1 || CMD_ARGC > 16) {
|
||||||
|
LOG_ERROR("Command 'exec_progbuf' takes 1 to 16 arguments.");
|
||||||
|
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct target *target = get_current_target(CMD_CTX);
|
||||||
|
|
||||||
|
RISCV_INFO(r);
|
||||||
|
if (r->dtm_version != 1) {
|
||||||
|
LOG_TARGET_ERROR(target, "exec_progbuf: Program buffer is "
|
||||||
|
"only supported on v0.13 or v1.0 targets.");
|
||||||
|
return ERROR_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (target->state != TARGET_HALTED) {
|
||||||
|
LOG_TARGET_ERROR(target, "exec_progbuf: Can't execute "
|
||||||
|
"program buffer, target not halted.");
|
||||||
|
return ERROR_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (riscv_debug_buffer_size(target) == 0) {
|
||||||
|
LOG_TARGET_ERROR(target, "exec_progbuf: Program buffer not implemented "
|
||||||
|
"in the target.");
|
||||||
|
return ERROR_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct riscv_program prog;
|
||||||
|
riscv_program_init(&prog, target);
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < CMD_ARGC; i++) {
|
||||||
|
riscv_insn_t instr;
|
||||||
|
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[i], instr);
|
||||||
|
if (riscv_program_insert(&prog, instr) != ERROR_OK)
|
||||||
|
return ERROR_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (riscv_program_exec(&prog, target) == ERROR_OK)
|
||||||
|
LOG_TARGET_DEBUG(target, "exec_progbuf: Program buffer execution successful.");
|
||||||
|
else
|
||||||
|
LOG_TARGET_ERROR(target, "exec_progbuf: Program buffer execution failed.");
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
static const struct command_registration riscv_exec_command_handlers[] = {
|
static const struct command_registration riscv_exec_command_handlers[] = {
|
||||||
{
|
{
|
||||||
.name = "dump_sample_buf",
|
.name = "dump_sample_buf",
|
||||||
|
@ -3804,6 +3851,14 @@ static const struct command_registration riscv_exec_command_handlers[] = {
|
||||||
.usage = "set [vs] [vu] [nmi] [m] [s] [u] <mie_bits>|clear",
|
.usage = "set [vs] [vu] [nmi] [m] [s] [u] <mie_bits>|clear",
|
||||||
.help = "Set or clear a single interrupt trigger."
|
.help = "Set or clear a single interrupt trigger."
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
.name = "exec_progbuf",
|
||||||
|
.handler = riscv_exec_progbuf,
|
||||||
|
.mode = COMMAND_EXEC,
|
||||||
|
.usage = "instr1 [instr2 [... instr16]]",
|
||||||
|
.help = "Execute a sequence of 32-bit instructions using the program buffer. "
|
||||||
|
"The final ebreak instruction is added automatically, if needed."
|
||||||
|
},
|
||||||
COMMAND_REGISTRATION_DONE
|
COMMAND_REGISTRATION_DONE
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue