Browse Source

Implement abstract memory read/write command in Spike

This commit implements the abstract memory read/write commands in the debug module. The changes include:

- Added support for abstract memory access commands (cmdtype 2) in perform_abstract_command()
- Implemented perform_abstract_memory_access() method to handle memory operations

Signed-off-by: Farid Khaydari <f.khaydari@syntacore.com>
pull/2086/head
Farid Khaydari 11 months ago
parent
commit
91300da288
  1. 342
      riscv/debug_module.cc
  2. 13
      riscv/debug_module.h

342
riscv/debug_module.cc

@ -697,11 +697,26 @@ bool debug_module_t::perform_abstract_command()
return true;
}
if ((command >> 24) == 0) {
// register access
unsigned size = get_field(command, AC_ACCESS_REGISTER_AARSIZE);
bool write = get_field(command, AC_ACCESS_REGISTER_WRITE);
unsigned regno = get_field(command, AC_ACCESS_REGISTER_REGNO);
auto cmdtype = get_field(command, DM_COMMAND_CMDTYPE);
constexpr decltype(cmdtype) CMDTYPE_ACCESS_REGISTER = 0ULL;
constexpr decltype(cmdtype) CMDTYPE_ACCESS_MEMORY = 2ULL;
if (cmdtype == CMDTYPE_ACCESS_REGISTER)
return perform_abstract_register_access();
if (cmdtype == CMDTYPE_ACCESS_MEMORY)
return perform_abstract_memory_access();
abstractcs.cmderr = CMDERR_NOTSUP;
return true;
}
bool debug_module_t::perform_abstract_register_access()
{
// register access
unsigned size = get_field(command, AC_ACCESS_REGISTER_AARSIZE);
bool write = get_field(command, AC_ACCESS_REGISTER_WRITE);
unsigned regno = get_field(command, AC_ACCESS_REGISTER_REGNO);
if (!selected_hart_state().halted) {
abstractcs.cmderr = CMDERR_HALTRESUME;
@ -715,120 +730,120 @@ bool debug_module_t::perform_abstract_command()
return true;
}
unsigned i = 0;
if (get_field(command, AC_ACCESS_REGISTER_TRANSFER)) {
unsigned i = 0;
if (get_field(command, AC_ACCESS_REGISTER_TRANSFER)) {
if (is_fpu_reg(regno)) {
// Save S0
write32(debug_abstract, i++, csrw(S0, CSR_DSCRATCH0));
// Save mstatus
write32(debug_abstract, i++, csrr(S0, CSR_MSTATUS));
write32(debug_abstract, i++, csrw(S0, CSR_DSCRATCH1));
// Set mstatus.fs
assert((MSTATUS_FS & 0xfff) == 0);
write32(debug_abstract, i++, lui(S0, MSTATUS_FS >> 12));
write32(debug_abstract, i++, csrrs(ZERO, S0, CSR_MSTATUS));
}
if (is_fpu_reg(regno)) {
// Save S0
if (regno < 0x1000 && config.support_abstract_csr_access) {
if (!is_fpu_reg(regno)) {
write32(debug_abstract, i++, csrw(S0, CSR_DSCRATCH0));
// Save mstatus
write32(debug_abstract, i++, csrr(S0, CSR_MSTATUS));
write32(debug_abstract, i++, csrw(S0, CSR_DSCRATCH1));
// Set mstatus.fs
assert((MSTATUS_FS & 0xfff) == 0);
write32(debug_abstract, i++, lui(S0, MSTATUS_FS >> 12));
write32(debug_abstract, i++, csrrs(ZERO, S0, CSR_MSTATUS));
}
if (regno < 0x1000 && config.support_abstract_csr_access) {
if (!is_fpu_reg(regno)) {
write32(debug_abstract, i++, csrw(S0, CSR_DSCRATCH0));
}
if (write) {
switch (size) {
case 2:
write32(debug_abstract, i++, lw(S0, ZERO, debug_data_start));
break;
case 3:
write32(debug_abstract, i++, ld(S0, ZERO, debug_data_start));
break;
default:
abstractcs.cmderr = CMDERR_NOTSUP;
return true;
}
write32(debug_abstract, i++, csrw(S0, regno));
} else {
write32(debug_abstract, i++, csrr(S0, regno));
switch (size) {
case 2:
write32(debug_abstract, i++, sw(S0, ZERO, debug_data_start));
break;
case 3:
write32(debug_abstract, i++, sd(S0, ZERO, debug_data_start));
break;
default:
abstractcs.cmderr = CMDERR_NOTSUP;
return true;
}
}
if (!is_fpu_reg(regno)) {
write32(debug_abstract, i++, csrr(S0, CSR_DSCRATCH0));
if (write) {
switch (size) {
case 2:
write32(debug_abstract, i++, lw(S0, ZERO, debug_data_start));
break;
case 3:
write32(debug_abstract, i++, ld(S0, ZERO, debug_data_start));
break;
default:
abstractcs.cmderr = CMDERR_NOTSUP;
return true;
}
write32(debug_abstract, i++, csrw(S0, regno));
} else if (regno >= 0x1000 && regno < 0x1020) {
unsigned regnum = regno - 0x1000;
} else {
write32(debug_abstract, i++, csrr(S0, regno));
switch (size) {
case 2:
if (write)
write32(debug_abstract, i++, lw(regnum, ZERO, debug_data_start));
else
write32(debug_abstract, i++, sw(regnum, ZERO, debug_data_start));
write32(debug_abstract, i++, sw(S0, ZERO, debug_data_start));
break;
case 3:
if (write)
write32(debug_abstract, i++, ld(regnum, ZERO, debug_data_start));
else
write32(debug_abstract, i++, sd(regnum, ZERO, debug_data_start));
write32(debug_abstract, i++, sd(S0, ZERO, debug_data_start));
break;
default:
abstractcs.cmderr = CMDERR_NOTSUP;
return true;
}
}
if (!is_fpu_reg(regno)) {
write32(debug_abstract, i++, csrr(S0, CSR_DSCRATCH0));
}
if (regno == 0x1000 + S0 && write) {
/*
* The exception handler starts out be restoring dscratch to s0,
* which was saved before executing the abstract memory region. Since
* we just wrote s0, also make sure to write that same value to
* dscratch in case an exception occurs in a program buffer that
* might be executed later.
*/
write32(debug_abstract, i++, csrw(S0, CSR_DSCRATCH0));
}
} else if (regno >= 0x1000 && regno < 0x1020) {
unsigned regnum = regno - 0x1000;
} else if (regno >= 0x1020 && regno < 0x1040 && config.support_abstract_fpr_access) {
unsigned fprnum = regno - 0x1020;
switch (size) {
case 2:
if (write)
write32(debug_abstract, i++, lw(regnum, ZERO, debug_data_start));
else
write32(debug_abstract, i++, sw(regnum, ZERO, debug_data_start));
break;
case 3:
if (write)
write32(debug_abstract, i++, ld(regnum, ZERO, debug_data_start));
else
write32(debug_abstract, i++, sd(regnum, ZERO, debug_data_start));
break;
default:
abstractcs.cmderr = CMDERR_NOTSUP;
return true;
}
if (write) {
switch (size) {
case 2:
write32(debug_abstract, i++, flw(fprnum, ZERO, debug_data_start));
break;
case 3:
write32(debug_abstract, i++, fld(fprnum, ZERO, debug_data_start));
break;
default:
abstractcs.cmderr = CMDERR_NOTSUP;
return true;
}
if (regno == 0x1000 + S0 && write) {
/*
* The exception handler starts out be restoring dscratch to s0,
* which was saved before executing the abstract memory region. Since
* we just wrote s0, also make sure to write that same value to
* dscratch in case an exception occurs in a program buffer that
* might be executed later.
*/
write32(debug_abstract, i++, csrw(S0, CSR_DSCRATCH0));
}
} else {
switch (size) {
case 2:
write32(debug_abstract, i++, fsw(fprnum, ZERO, debug_data_start));
break;
case 3:
write32(debug_abstract, i++, fsd(fprnum, ZERO, debug_data_start));
break;
default:
abstractcs.cmderr = CMDERR_NOTSUP;
return true;
}
} else if (regno >= 0x1020 && regno < 0x1040 && config.support_abstract_fpr_access) {
unsigned fprnum = regno - 0x1020;
if (write) {
switch (size) {
case 2:
write32(debug_abstract, i++, flw(fprnum, ZERO, debug_data_start));
break;
case 3:
write32(debug_abstract, i++, fld(fprnum, ZERO, debug_data_start));
break;
default:
abstractcs.cmderr = CMDERR_NOTSUP;
return true;
}
} else {
switch (size) {
case 2:
write32(debug_abstract, i++, fsw(fprnum, ZERO, debug_data_start));
break;
case 3:
write32(debug_abstract, i++, fsd(fprnum, ZERO, debug_data_start));
break;
default:
abstractcs.cmderr = CMDERR_NOTSUP;
return true;
}
}
} else if (regno >= 0xc000 && (regno & 1) == 1) {
// Support odd-numbered custom registers, to allow for debugger testing.
unsigned custom_number = regno - 0xc000;
@ -844,39 +859,124 @@ bool debug_module_t::perform_abstract_command()
}
return true;
} else {
abstractcs.cmderr = CMDERR_NOTSUP;
return true;
}
if (is_fpu_reg(regno)) {
// restore mstatus
write32(debug_abstract, i++, csrr(S0, CSR_DSCRATCH1));
write32(debug_abstract, i++, csrw(S0, CSR_MSTATUS));
// restore s0
write32(debug_abstract, i++, csrr(S0, CSR_DSCRATCH0));
}
}
if (get_field(command, AC_ACCESS_REGISTER_POSTEXEC)) {
write32(debug_abstract, i,
jal(ZERO, debug_progbuf_start - debug_abstract_start - 4 * i));
i++;
} else {
write32(debug_abstract, i++, ebreak());
abstractcs.cmderr = CMDERR_NOTSUP;
return true;
}
debug_rom_flags[selected_hart_id()] |= 1 << DEBUG_ROM_FLAG_GO;
rti_remaining = config.abstract_rti;
abstract_command_completed = false;
if (is_fpu_reg(regno)) {
// restore mstatus
write32(debug_abstract, i++, csrr(S0, CSR_DSCRATCH1));
write32(debug_abstract, i++, csrw(S0, CSR_MSTATUS));
// restore s0
write32(debug_abstract, i++, csrr(S0, CSR_DSCRATCH0));
}
}
abstractcs.busy = true;
if (get_field(command, AC_ACCESS_REGISTER_POSTEXEC)) {
write32(debug_abstract, i,
jal(ZERO, debug_progbuf_start - debug_abstract_start - 4 * i));
i++;
} else {
write32(debug_abstract, i++, ebreak());
}
debug_rom_flags[selected_hart_id()] |= 1 << DEBUG_ROM_FLAG_GO;
rti_remaining = config.abstract_rti;
abstract_command_completed = false;
abstractcs.busy = true;
return true;
}
static unsigned idx(unsigned xlen)
{
return field_width(xlen) - 3U;
}
bool debug_module_t::perform_abstract_memory_access() {
unsigned aamsize = get_field(command, AC_ACCESS_MEMORY_AAMSIZE);
bool aampostincrement = get_field(command, AC_ACCESS_MEMORY_AAMPOSTINCREMENT);
bool aamvirtual = get_field(command, AC_ACCESS_MEMORY_AAMVIRTUAL);
bool is_write = get_field(command, AC_ACCESS_MEMORY_WRITE);
auto xlen = sim->get_harts().at(selected_hart_id())->get_xlen();
if (!selected_hart_state().halted) {
abstractcs.cmderr = CMDERR_HALTRESUME;
return true;
}
if (aamvirtual || aamsize > 3 || aamsize > idx(xlen)) {
abstractcs.cmderr = CMDERR_NOTSUP;
return true;
}
unsigned offset = 0;
generate_initial_sequence(offset);
is_write ? handle_memory_write(xlen, aamsize, offset)
: handle_memory_read(xlen, aamsize, offset);
if (aampostincrement)
handle_post_increment(xlen, aamsize, offset);
generate_termination_sequence(offset);
start_command_execution();
abstractcs.cmderr = CMDERR_NONE;
return true;
}
using handle_memory_func = uint32_t (*)(unsigned rd_src, unsigned base, uint16_t offset);
static constexpr std::array<handle_memory_func, 4> lx = {&lb, &lh, &lw, &ld};
static constexpr std::array<handle_memory_func, 4> sx = {&sb, &sh, &sw, &sd};
unsigned debug_module_t::arg(unsigned xlen, unsigned idx)
{
return debug_data_start + idx * xlen / 8;
}
void debug_module_t::handle_memory_read(size_t xlen, unsigned aamsize, unsigned &offset)
{
write32(debug_abstract, offset++, lx[idx(xlen)](S0, ZERO, arg(xlen, 1)));
write32(debug_abstract, offset++, lx[aamsize](S0, S0, 0));
write32(debug_abstract, offset++, sx[idx(xlen)](S0, ZERO, arg(xlen, 0)));
}
void debug_module_t::handle_memory_write(size_t xlen, unsigned aamsize, unsigned &offset)
{
write32(debug_abstract, offset++, lx[idx(xlen)](S0, ZERO, arg(xlen, 0)));
write32(debug_abstract, offset++, lx[idx(xlen)](S1, ZERO, arg(xlen, 1)));
write32(debug_abstract, offset++, sx[aamsize](S0, S1, 0));
}
void debug_module_t::handle_post_increment(size_t xlen, unsigned aamsize, unsigned &offset)
{
write32(debug_abstract, offset++, lx[idx(xlen)](S1, ZERO, arg(xlen, 1)));
write32(debug_abstract, offset++, addi(S1, S1, 1U << aamsize));
write32(debug_abstract, offset++, sx[idx(xlen)](S1, ZERO, arg(xlen, 1)));
}
void debug_module_t::generate_initial_sequence(unsigned &offset)
{
write32(debug_abstract, offset++, csrw(S0, CSR_DSCRATCH0));
write32(debug_abstract, offset++, csrw(S1, CSR_DSCRATCH1));
}
void debug_module_t::generate_termination_sequence(unsigned &offset)
{
write32(debug_abstract, offset++, csrr(S0, CSR_DSCRATCH0));
write32(debug_abstract, offset++, csrr(S1, CSR_DSCRATCH1));
write32(debug_abstract, offset++, ebreak());
}
void debug_module_t::start_command_execution()
{
debug_rom_flags[selected_hart_id()] |= 1 << DEBUG_ROM_FLAG_GO;
rti_remaining = config.abstract_rti;
abstract_command_completed = false;
abstractcs.busy = true;
}
bool debug_module_t::dmi_write(unsigned address, uint32_t value)
{
D(fprintf(stderr, "dmi_write(0x%x, 0x%x)\n", address, value));

13
riscv/debug_module.h

@ -201,7 +201,20 @@ class debug_module_t : public abstract_device_t
bool hart_selected(unsigned hartid) const;
void reset();
bool perform_abstract_command();
bool perform_abstract_register_access();
bool perform_abstract_memory_access();
unsigned arg(unsigned xlen, unsigned i);
void handle_post_increment(size_t xlen, unsigned aamsize, unsigned &offset);
void handle_memory_read(size_t xlen, unsigned aamsize, unsigned &offset);
void handle_memory_write(size_t xlen, unsigned aamsize, unsigned &offset);
void generate_initial_sequence(unsigned &offset);
void generate_termination_sequence(unsigned &offset);
void start_command_execution();
bool abstract_command_completed;
unsigned rti_remaining;

Loading…
Cancel
Save