2017-03-24 20:21:56 -05:00
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
#include "config.h"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include "target/target.h"
|
2017-09-14 18:21:49 -05:00
|
|
|
#include "target/register.h"
|
2017-03-24 20:21:56 -05:00
|
|
|
#include "riscv.h"
|
|
|
|
#include "program.h"
|
|
|
|
#include "helper/log.h"
|
|
|
|
|
|
|
|
#include "asm.h"
|
|
|
|
#include "encoding.h"
|
|
|
|
|
|
|
|
/* Program interface. */
|
|
|
|
int riscv_program_init(struct riscv_program *p, struct target *target)
|
|
|
|
{
|
|
|
|
memset(p, 0, sizeof(*p));
|
|
|
|
p->target = target;
|
|
|
|
p->instruction_count = 0;
|
|
|
|
p->target_xlen = riscv_xlen(target);
|
2017-12-22 16:35:38 -06:00
|
|
|
for (size_t i = 0; i < RISCV_REGISTER_COUNT; ++i)
|
2017-03-24 20:21:56 -05:00
|
|
|
p->writes_xreg[i] = 0;
|
|
|
|
|
2017-12-22 16:35:38 -06:00
|
|
|
for (size_t i = 0; i < RISCV_MAX_DEBUG_BUFFER_SIZE; ++i)
|
2017-03-24 20:21:56 -05:00
|
|
|
p->debug_buffer[i] = -1;
|
|
|
|
|
|
|
|
return ERROR_OK;
|
|
|
|
}
|
|
|
|
|
2017-10-13 14:50:02 -05:00
|
|
|
int riscv_program_write(struct riscv_program *program)
|
|
|
|
{
|
2017-10-16 22:38:35 -05:00
|
|
|
for (unsigned i = 0; i < program->instruction_count; ++i) {
|
2017-10-13 14:50:02 -05:00
|
|
|
LOG_DEBUG("%p: debug_buffer[%02x] = DASM(0x%08x)", program, i, program->debug_buffer[i]);
|
|
|
|
if (riscv_write_debug_buffer(program->target, i,
|
|
|
|
program->debug_buffer[i]) != ERROR_OK)
|
|
|
|
return ERROR_FAIL;
|
|
|
|
}
|
|
|
|
return ERROR_OK;
|
|
|
|
}
|
|
|
|
|
2017-10-12 16:38:52 -05:00
|
|
|
/** Add ebreak and execute the program. */
|
2017-03-24 20:21:56 -05:00
|
|
|
int riscv_program_exec(struct riscv_program *p, struct target *t)
|
|
|
|
{
|
2017-08-15 15:31:06 -05:00
|
|
|
keep_alive();
|
|
|
|
|
2017-03-24 20:21:56 -05:00
|
|
|
riscv_reg_t saved_registers[GDB_REGNO_XPR31 + 1];
|
2017-11-27 16:47:33 -06:00
|
|
|
for (size_t i = GDB_REGNO_ZERO + 1; i <= GDB_REGNO_XPR31; ++i) {
|
2017-03-24 20:21:56 -05:00
|
|
|
if (p->writes_xreg[i]) {
|
|
|
|
LOG_DEBUG("Saving register %d as used by program", (int)i);
|
2017-12-29 16:35:49 -06:00
|
|
|
int result = riscv_get_register(t, &saved_registers[i], i);
|
|
|
|
if (result != ERROR_OK)
|
|
|
|
return result;
|
2017-03-24 20:21:56 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (riscv_program_ebreak(p) != ERROR_OK) {
|
|
|
|
LOG_ERROR("Unable to write ebreak");
|
2017-12-22 16:35:38 -06:00
|
|
|
for (size_t i = 0; i < riscv_debug_buffer_size(p->target); ++i)
|
2017-03-24 20:21:56 -05:00
|
|
|
LOG_ERROR("ram[%02x]: DASM(0x%08lx) [0x%08lx]", (int)i, (long)p->debug_buffer[i], (long)p->debug_buffer[i]);
|
|
|
|
return ERROR_FAIL;
|
|
|
|
}
|
|
|
|
|
2017-10-13 14:50:02 -05:00
|
|
|
if (riscv_program_write(p) != ERROR_OK)
|
|
|
|
return ERROR_FAIL;
|
2017-03-24 20:21:56 -05:00
|
|
|
|
|
|
|
if (riscv_execute_debug_buffer(t) != ERROR_OK) {
|
2017-06-15 16:43:15 -05:00
|
|
|
LOG_ERROR("Unable to execute program %p", p);
|
2017-03-24 20:21:56 -05:00
|
|
|
return ERROR_FAIL;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (size_t i = 0; i < riscv_debug_buffer_size(p->target); ++i)
|
2017-10-18 14:43:03 -05:00
|
|
|
if (i >= riscv_debug_buffer_size(p->target))
|
2017-03-24 20:21:56 -05:00
|
|
|
p->debug_buffer[i] = riscv_read_debug_buffer(t, i);
|
|
|
|
|
2017-11-27 16:47:33 -06:00
|
|
|
for (size_t i = GDB_REGNO_ZERO; i <= GDB_REGNO_XPR31; ++i)
|
2017-03-24 20:21:56 -05:00
|
|
|
if (p->writes_xreg[i])
|
|
|
|
riscv_set_register(t, i, saved_registers[i]);
|
|
|
|
|
|
|
|
return ERROR_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
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));
|
|
|
|
}
|
|
|
|
|
|
|
|
int riscv_program_shr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno b, int offset)
|
|
|
|
{
|
|
|
|
return riscv_program_insert(p, sh(d, b, offset));
|
|
|
|
}
|
|
|
|
|
|
|
|
int riscv_program_sbr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno b, int offset)
|
|
|
|
{
|
|
|
|
return riscv_program_insert(p, sb(d, b, 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));
|
|
|
|
}
|
|
|
|
|
|
|
|
int riscv_program_lhr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno b, int offset)
|
|
|
|
{
|
|
|
|
return riscv_program_insert(p, lh(d, b, offset));
|
|
|
|
}
|
|
|
|
|
|
|
|
int riscv_program_lbr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno b, int offset)
|
|
|
|
{
|
|
|
|
return riscv_program_insert(p, lb(d, b, offset));
|
|
|
|
}
|
|
|
|
|
|
|
|
int riscv_program_csrr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno csr)
|
|
|
|
{
|
2017-10-12 16:38:52 -05:00
|
|
|
assert(csr >= GDB_REGNO_CSR0 && csr <= GDB_REGNO_CSR4095);
|
2017-11-27 16:47:33 -06:00
|
|
|
return riscv_program_insert(p, csrrs(d, GDB_REGNO_ZERO, csr - GDB_REGNO_CSR0));
|
2017-03-24 20:21:56 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
int riscv_program_csrw(struct riscv_program *p, enum gdb_regno s, enum gdb_regno csr)
|
|
|
|
{
|
|
|
|
assert(csr >= GDB_REGNO_CSR0);
|
2017-11-27 16:47:33 -06:00
|
|
|
return riscv_program_insert(p, csrrw(GDB_REGNO_ZERO, s, csr - GDB_REGNO_CSR0));
|
2017-03-24 20:21:56 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
int riscv_program_fence_i(struct riscv_program *p)
|
|
|
|
{
|
|
|
|
return riscv_program_insert(p, fence_i());
|
|
|
|
}
|
|
|
|
|
|
|
|
int riscv_program_fence(struct riscv_program *p)
|
|
|
|
{
|
|
|
|
return riscv_program_insert(p, fence());
|
|
|
|
}
|
|
|
|
|
|
|
|
int riscv_program_ebreak(struct riscv_program *p)
|
|
|
|
{
|
2017-10-18 16:21:23 -05:00
|
|
|
struct target *target = p->target;
|
|
|
|
RISCV_INFO(r);
|
|
|
|
if (p->instruction_count == riscv_debug_buffer_size(p->target) &&
|
|
|
|
r->impebreak) {
|
2017-10-16 22:38:35 -05:00
|
|
|
return ERROR_OK;
|
|
|
|
}
|
2017-03-24 20:21:56 -05:00
|
|
|
return riscv_program_insert(p, ebreak());
|
|
|
|
}
|
|
|
|
|
|
|
|
int riscv_program_addi(struct riscv_program *p, enum gdb_regno d, enum gdb_regno s, int16_t u)
|
|
|
|
{
|
|
|
|
return riscv_program_insert(p, addi(d, s, u));
|
|
|
|
}
|
|
|
|
|
|
|
|
int riscv_program_insert(struct riscv_program *p, riscv_insn_t i)
|
|
|
|
{
|
2017-10-18 14:43:03 -05:00
|
|
|
if (p->instruction_count >= riscv_debug_buffer_size(p->target)) {
|
2017-06-15 16:43:15 -05:00
|
|
|
LOG_ERROR("Unable to insert instruction:");
|
|
|
|
LOG_ERROR(" instruction_count=%d", (int)p->instruction_count);
|
|
|
|
LOG_ERROR(" buffer size =%d", (int)riscv_debug_buffer_size(p->target));
|
2017-12-27 15:04:30 -06:00
|
|
|
return ERROR_FAIL;
|
2017-03-24 20:21:56 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
p->debug_buffer[p->instruction_count] = i;
|
|
|
|
p->instruction_count++;
|
|
|
|
return ERROR_OK;
|
|
|
|
}
|