Memtest{16,32} pass.

Change-Id: I15c2a4fd2bb9a7b30762d07f3b3a74d2f477746b
This commit is contained in:
Tim Newsome 2017-10-16 20:38:35 -07:00
parent 7ec7bc32fe
commit d94b38279a
4 changed files with 125 additions and 216 deletions

View File

@ -32,17 +32,12 @@ int riscv_program_init(struct riscv_program *p, struct target *target)
for(size_t i = 0; i < RISCV_MAX_DEBUG_BUFFER_SIZE; ++i)
p->debug_buffer[i] = -1;
if (riscv_debug_buffer_enter(target, p) != ERROR_OK) {
LOG_ERROR("unable to write progam buffer enter code");
return ERROR_FAIL;
}
return ERROR_OK;
}
int riscv_program_write(struct riscv_program *program)
{
for (unsigned i = 0; i < riscv_debug_buffer_size(program->target); ++i) {
for (unsigned i = 0; i < program->instruction_count; ++i) {
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)
@ -56,11 +51,6 @@ int riscv_program_exec(struct riscv_program *p, struct target *t)
{
keep_alive();
if (riscv_debug_buffer_leave(t, p) != ERROR_OK) {
LOG_ERROR("unable to write program buffer exit code");
return ERROR_FAIL;
}
riscv_reg_t saved_registers[GDB_REGNO_XPR31 + 1];
for (size_t i = GDB_REGNO_XPR0 + 1; i <= GDB_REGNO_XPR31; ++i) {
if (p->writes_xreg[i]) {
@ -290,6 +280,11 @@ int riscv_program_fence(struct riscv_program *p)
int riscv_program_ebreak(struct riscv_program *p)
{
if (p->instruction_count == riscv_debug_buffer_size(p->target)) {
// TODO: Check for impebreak bit.
// There's an implicit ebreak here, so no need for us to add one.
return ERROR_OK;
}
return riscv_program_insert(p, ebreak());
}
@ -441,7 +436,7 @@ int riscv_program_insert(struct riscv_program *p, riscv_insn_t i)
LOG_ERROR(" instruction_count=%d", (int)p->instruction_count);
LOG_ERROR(" data_count =%d", (int)p->data_count);
LOG_ERROR(" buffer size =%d", (int)riscv_debug_buffer_size(p->target));
return ERROR_FAIL;
abort();
}
p->debug_buffer[p->instruction_count] = i;

View File

@ -49,8 +49,6 @@ static void riscv013_on_step(struct target *target);
static void riscv013_on_resume(struct target *target);
static bool riscv013_is_halted(struct target *target);
static enum riscv_halt_reason riscv013_halt_reason(struct target *target);
static void riscv013_debug_buffer_enter(struct target *target, struct riscv_program *p);
static void riscv013_debug_buffer_leave(struct target *target, struct riscv_program *p);
static void riscv013_write_debug_buffer(struct target *target, unsigned index,
riscv_insn_t d);
static riscv_insn_t riscv013_read_debug_buffer(struct target *target, unsigned
@ -637,11 +635,12 @@ static int write_abstract_arg(struct target *target, unsigned index,
return ERROR_OK;
}
static int register_read_abstract(struct target *target, uint64_t *value,
uint32_t number, unsigned size)
/**
* @size in bits
*/
static uint32_t access_register_command(uint32_t number, unsigned size,
uint32_t flags)
{
RISCV013_INFO(r);
uint32_t command = set_field(0, DMI_COMMAND_CMDTYPE, 0);
switch (size) {
case 32:
@ -651,38 +650,50 @@ static int register_read_abstract(struct target *target, uint64_t *value,
command = set_field(command, AC_ACCESS_REGISTER_SIZE, 3);
break;
default:
LOG_ERROR("Unsupported abstract register read size: %d", size);
return ERROR_FAIL;
assert(0);
}
command = set_field(command, AC_ACCESS_REGISTER_POSTEXEC, 0);
command = set_field(command, AC_ACCESS_REGISTER_TRANSFER, 1);
command = set_field(command, AC_ACCESS_REGISTER_WRITE, 0);
if (number <= GDB_REGNO_XPR31) {
command = set_field(command, AC_ACCESS_REGISTER_REGNO,
0x1000 + number - GDB_REGNO_XPR0);
} else if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31) {
if (!r->abstract_read_fpr_supported)
return ERROR_FAIL;
command = set_field(command, AC_ACCESS_REGISTER_REGNO,
0x1020 + number - GDB_REGNO_FPR0);
} else if (number >= GDB_REGNO_CSR0 && number <= GDB_REGNO_CSR4095) {
if (!r->abstract_read_csr_supported)
return ERROR_FAIL;
command = set_field(command, AC_ACCESS_REGISTER_REGNO,
number - GDB_REGNO_CSR0);
} else {
return ERROR_FAIL;
assert(0);
}
command |= flags;
return command;
}
static int register_read_abstract(struct target *target, uint64_t *value,
uint32_t number, unsigned size)
{
RISCV013_INFO(info);
if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31 &&
!info->abstract_read_fpr_supported)
return ERROR_FAIL;
if (number >= GDB_REGNO_CSR0 && number <= GDB_REGNO_CSR4095 &&
!info->abstract_read_csr_supported)
return ERROR_FAIL;
uint32_t command = access_register_command(number, size,
AC_ACCESS_REGISTER_TRANSFER);
int result = execute_abstract_command(target, command);
if (result != ERROR_OK) {
if (r->cmderr == CMDERR_NOT_SUPPORTED) {
if (info->cmderr == CMDERR_NOT_SUPPORTED) {
if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31) {
r->abstract_read_fpr_supported = false;
info->abstract_read_fpr_supported = false;
LOG_INFO("Disabling abstract command reads from FPRs.");
} else if (number >= GDB_REGNO_CSR0 && number <= GDB_REGNO_CSR4095) {
r->abstract_read_csr_supported = false;
info->abstract_read_csr_supported = false;
LOG_INFO("Disabling abstract command reads from CSRs.");
}
}
@ -699,38 +710,16 @@ static int register_write_abstract(struct target *target, uint32_t number,
{
RISCV013_INFO(info);
uint32_t command = set_field(0, DMI_COMMAND_CMDTYPE, 0);
switch (size) {
case 32:
command = set_field(command, AC_ACCESS_REGISTER_SIZE, 2);
break;
case 64:
command = set_field(command, AC_ACCESS_REGISTER_SIZE, 3);
break;
default:
LOG_ERROR("Unsupported abstract register read size: %d", size);
return ERROR_FAIL;
}
command = set_field(command, AC_ACCESS_REGISTER_POSTEXEC, 0);
command = set_field(command, AC_ACCESS_REGISTER_TRANSFER, 1);
command = set_field(command, AC_ACCESS_REGISTER_WRITE, 1);
if (number <= GDB_REGNO_XPR31) {
command = set_field(command, AC_ACCESS_REGISTER_REGNO,
0x1000 + number - GDB_REGNO_XPR0);
} else if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31) {
if (!info->abstract_read_fpr_supported)
return ERROR_FAIL;
command = set_field(command, AC_ACCESS_REGISTER_REGNO,
0x1020 + number - GDB_REGNO_FPR0);
} else if (number >= GDB_REGNO_CSR0 && number <= GDB_REGNO_CSR4095) {
if (!info->abstract_read_csr_supported)
return ERROR_FAIL;
command = set_field(command, AC_ACCESS_REGISTER_REGNO,
number - GDB_REGNO_CSR0);
} else {
if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31 &&
!info->abstract_write_fpr_supported)
return ERROR_FAIL;
}
if (number >= GDB_REGNO_CSR0 && number <= GDB_REGNO_CSR4095 &&
!info->abstract_write_csr_supported)
return ERROR_FAIL;
uint32_t command = access_register_command(number, size,
AC_ACCESS_REGISTER_TRANSFER |
AC_ACCESS_REGISTER_WRITE);
if (write_abstract_arg(target, 0, value) != ERROR_OK) {
return ERROR_FAIL;
@ -905,8 +894,6 @@ static int init_target(struct command_context *cmd_ctx,
generic_info->on_resume = &riscv013_on_resume;
generic_info->on_step = &riscv013_on_step;
generic_info->halt_reason = &riscv013_halt_reason;
generic_info->debug_buffer_enter = &riscv013_debug_buffer_enter;
generic_info->debug_buffer_leave = &riscv013_debug_buffer_leave;
generic_info->read_debug_buffer = &riscv013_read_debug_buffer;
generic_info->write_debug_buffer = &riscv013_write_debug_buffer;
generic_info->execute_debug_buffer = &riscv013_execute_debug_buffer;
@ -1249,7 +1236,9 @@ static int deassert_reset(struct target *target)
return ERROR_OK;
}
#if 0
/**
* @size in bytes
*/
static void write_to_buf(uint8_t *buffer, uint64_t value, unsigned size)
{
switch (size) {
@ -1270,7 +1259,6 @@ static void write_to_buf(uint8_t *buffer, uint64_t value, unsigned size)
assert(false);
}
}
#endif
/**
* Read the requested memory, taking care to execute every read exactly once,
@ -1279,30 +1267,27 @@ static void write_to_buf(uint8_t *buffer, uint64_t value, unsigned size)
static int read_memory(struct target *target, target_addr_t address,
uint32_t size, uint32_t count, uint8_t *buffer)
{
//RISCV013_INFO(info);
RISCV013_INFO(info);
LOG_DEBUG("reading %d words of %d bytes from 0x%" TARGET_PRIxADDR, count,
size, address);
select_dmi(target);
/* This program uses two temporary registers. A word of data and the
* associated address are stored at some location in memory. The
* program loads the word from that address and then increments the
* address. The debugger is expected to pull the memory word-by-word
* from the chip with AUTOEXEC set in order to trigger program
* execution on every word. */
uint64_t s0 = riscv_get_register(target, GDB_REGNO_S0);
uint64_t s1 = riscv_get_register(target, GDB_REGNO_S1);
/* s0 holds the next address to write to
* s1 holds the next data value to write
*/
uint64_t s0, s1;
if (register_read_direct(target, &s0, GDB_REGNO_S0) != ERROR_OK)
return ERROR_FAIL;
if (register_read_direct(target, &s1, GDB_REGNO_S1) != ERROR_OK)
return ERROR_FAIL;
// Write the program (load, increment)
struct riscv_program program;
riscv_program_init(&program, target);
assert(0);
#if 0
riscv_addr_t r_data = riscv_program_alloc_w(&program);
riscv_addr_t r_addr = riscv_program_alloc_x(&program);
riscv_program_fence(&program);
riscv_program_lx(&program, GDB_REGNO_S0, r_addr);
// TODO: riscv_program_fence(&program);
switch (size) {
case 1:
riscv_program_lbr(&program, GDB_REGNO_S1, GDB_REGNO_S0, 0);
@ -1318,70 +1303,43 @@ static int read_memory(struct target *target, target_addr_t address,
return ERROR_FAIL;
}
riscv_program_addi(&program, GDB_REGNO_S0, GDB_REGNO_S0, size);
riscv_program_sw(&program, GDB_REGNO_S1, r_data);
riscv_program_sx(&program, GDB_REGNO_S0, r_addr);
/* The first round through the program's execution we use the regular
* program execution mechanism. */
switch (riscv_xlen(target)) {
case 64:
riscv_program_write_ram(&program, r_addr + 4, ((riscv_addr_t) address) >> 32);
case 32:
riscv_program_write_ram(&program, r_addr, (riscv_addr_t) address);
break;
default:
LOG_ERROR("unknown XLEN %d", riscv_xlen(target));
if (riscv_program_ebreak(&program) != ERROR_OK)
return ERROR_FAIL;
}
riscv_program_write(&program);
if (riscv_program_exec(&program, target) != ERROR_OK) {
uint32_t acs = dmi_read(target, DMI_ABSTRACTCS);
LOG_ERROR("failed to execute program, abstractcs=0x%08x", acs);
riscv013_clear_abstract_error(target);
riscv_set_register(target, GDB_REGNO_S0, s0);
riscv_set_register(target, GDB_REGNO_S1, s1);
LOG_ERROR(" exiting with ERROR_FAIL");
// Write address to S0, and execute buffer.
if (register_write_direct(target, GDB_REGNO_S0, address) != ERROR_OK)
return ERROR_FAIL;
if (execute_abstract_command(target,
access_register_command(GDB_REGNO_S1, riscv_xlen(target),
AC_ACCESS_REGISTER_TRANSFER |
AC_ACCESS_REGISTER_POSTEXEC)) != ERROR_OK)
return ERROR_FAIL;
}
// Program has been executed once. d_addr contains address+size, and d_data
// contains *address.
/* The rest of this program is designed to be fast so it reads various
* DMI registers directly. */
int d_data = (r_data - riscv_debug_buffer_addr(target)) / 4;
int d_addr = (r_addr - riscv_debug_buffer_addr(target)) / 4;
riscv013_set_autoexec(target, d_data, 1);
dmi_write(target, DMI_ABSTRACTAUTO,
1 << DMI_ABSTRACTAUTO_AUTOEXECDATA_OFFSET);
/* Copying memory might fail because we're going too quickly, in which
* case we need to back off a bit and try again. There's two
* termination conditions to this loop: a non-BUSY error message, or
* the data was all copied. */
riscv_addr_t cur_addr = riscv_read_debug_buffer_x(target, d_addr);
* case we need to back off a bit and try again. */
riscv_addr_t cur_addr = address;
riscv_addr_t fin_addr = address + (count * size);
LOG_DEBUG("reading until final address 0x%" PRIx64, fin_addr);
while (cur_addr < fin_addr) {
while (cur_addr < fin_addr - size) {
// Invariant:
// d_data contains *addr
// d_addr contains addr + size
// s0 contains the next address to read
// s1 contains the data read at the previous address
unsigned start = (cur_addr - address) / size;
LOG_DEBUG("creating burst to read address 0x%" TARGET_PRIxADDR
" up to 0x%" TARGET_PRIxADDR "; start=0x%d", cur_addr, fin_addr, start);
assert(cur_addr >= address && cur_addr < fin_addr);
struct riscv_batch *batch = riscv_batch_alloc(
target,
32,
info->dmi_busy_delay + info->ac_busy_delay);
struct riscv_batch *batch = riscv_batch_alloc(target, 32,
info->dmi_busy_delay + info->ac_busy_delay);
size_t reads = 0;
for (riscv_addr_t addr = cur_addr; addr < fin_addr; addr += size) {
size_t const index =
riscv_batch_add_dmi_read(
batch,
riscv013_debug_buffer_register(target, r_data));
assert(index == reads);
for (riscv_addr_t addr = cur_addr; addr < fin_addr - size; addr += size) {
riscv_batch_add_dmi_read(batch, DMI_DATA0);
reads++;
if (riscv_batch_full(batch))
@ -1397,37 +1355,37 @@ static int read_memory(struct target *target, target_addr_t address,
abstractcs = dmi_read(target, DMI_ABSTRACTCS);
info->cmderr = get_field(abstractcs, DMI_ABSTRACTCS_CMDERR);
riscv_addr_t next_addr;
switch (info->cmderr) {
case CMDERR_NONE:
LOG_DEBUG("successful (partial?) memory read");
break;
case CMDERR_BUSY:
LOG_DEBUG("memory read resulted in busy response");
increase_ac_busy_delay(target);
riscv013_clear_abstract_error(target);
break;
default:
LOG_ERROR("error when reading memory, abstractcs=0x%08lx", (long)abstractcs);
riscv013_set_autoexec(target, d_data, 0);
riscv_set_register(target, GDB_REGNO_S0, s0);
riscv_set_register(target, GDB_REGNO_S1, s1);
riscv013_clear_abstract_error(target);
riscv_batch_free(batch);
return ERROR_FAIL;
}
case CMDERR_NONE:
LOG_DEBUG("successful (partial?) memory read");
next_addr = cur_addr + reads * size;
break;
case CMDERR_BUSY:
LOG_DEBUG("memory read resulted in busy response");
increase_ac_busy_delay(target);
riscv013_clear_abstract_error(target);
// Figure out how far we managed to read.
riscv_addr_t next_addr = riscv_read_debug_buffer_x(target, d_addr);
LOG_DEBUG("Batch read [0x%" TARGET_PRIxADDR ", 0x%" TARGET_PRIxADDR
"); reads=%d", cur_addr, next_addr, (unsigned) reads);
assert(next_addr >= address && next_addr <= fin_addr);
assert(info->cmderr != CMDERR_NONE ||
next_addr == cur_addr + reads * size);
dmi_write(target, DMI_ABSTRACTAUTO, 0);
if (register_read_direct(target, &next_addr, GDB_REGNO_S0) != ERROR_OK)
return ERROR_FAIL;
next_addr -= size;
dmi_write(target, DMI_ABSTRACTAUTO,
1 << DMI_ABSTRACTAUTO_AUTOEXECDATA_OFFSET);
break;
default:
LOG_ERROR("error when reading memory, abstractcs=0x%08lx", (long)abstractcs);
dmi_write(target, DMI_ABSTRACTAUTO, 0);
riscv_set_register(target, GDB_REGNO_S0, s0);
riscv_set_register(target, GDB_REGNO_S1, s1);
riscv013_clear_abstract_error(target);
riscv_batch_free(batch);
return ERROR_FAIL;
}
// Now read whatever we got out of the batch.
unsigned rereads = 0;
for (riscv_addr_t addr = cur_addr - size; addr < next_addr - size;
addr += size) {
for (riscv_addr_t addr = cur_addr; addr < next_addr; addr += size) {
riscv_addr_t offset = addr - address;
uint64_t dmi_out = riscv_batch_get_dmi_read(batch, rereads);
@ -1443,17 +1401,14 @@ static int read_memory(struct target *target, target_addr_t address,
cur_addr = next_addr;
}
riscv013_set_autoexec(target, d_data, 0);
dmi_write(target, DMI_ABSTRACTAUTO, 0);
// Read the last word.
// Access debug buffer without executing a program. This
// address logic was taken from program.c.
uint32_t value = riscv013_read_debug_buffer(target, d_data);
riscv_addr_t addr = cur_addr - size;
write_to_buf(buffer + addr - address, value, size);
LOG_DEBUG("M[0x%" TARGET_PRIxADDR "] reads 0x%08x", addr, value);
#endif
uint64_t value;
if (register_read_direct(target, &value, GDB_REGNO_S1) != ERROR_OK)
return ERROR_FAIL;
write_to_buf(buffer + cur_addr - address, value, size);
LOG_DEBUG("M[0x%" TARGET_PRIxADDR "] reads 0x%" PRIx64, cur_addr, value);
riscv_set_register(target, GDB_REGNO_S0, s0);
riscv_set_register(target, GDB_REGNO_S1, s1);
@ -1467,13 +1422,12 @@ static int write_memory(struct target *target, target_addr_t address,
LOG_DEBUG("writing %d words of %d bytes to 0x%08lx", count, size, (long)address);
/*
* s0 holds the next address to write to
select_dmi(target);
/* s0 holds the next address to write to
* s1 holds the next data value to write
*/
select_dmi(target);
uint64_t s0, s1;
if (register_read_direct(target, &s0, GDB_REGNO_S0) != ERROR_OK)
return ERROR_FAIL;
@ -1501,14 +1455,10 @@ static int write_memory(struct target *target, target_addr_t address,
riscv_program_addi(&program, GDB_REGNO_S0, GDB_REGNO_S0, size);
if (riscv_debug_buffer_leave(target, &program) != ERROR_OK)
if (riscv_program_ebreak(&program) != ERROR_OK)
return ERROR_FAIL;
riscv_program_write(&program);
if (register_write_direct(target, GDB_REGNO_S0, address) != ERROR_OK)
return ERROR_FAIL;
riscv_addr_t cur_addr = address;
riscv_addr_t fin_addr = address + (count * size);
bool setup_needed = true;
@ -1551,28 +1501,19 @@ static int write_memory(struct target *target, target_addr_t address,
LOG_DEBUG("M[0x%08" PRIx64 "] writes 0x%08x", address + offset, value);
if (setup_needed) {
if (register_write_direct(target, GDB_REGNO_S0,
address + offset) != ERROR_OK)
return ERROR_FAIL;
// Write value.
dmi_write(target, DMI_DATA0, value);
// Write and execute command that moves value into S0 and
// executes program buffer.
uint32_t command = set_field(0, DMI_COMMAND_CMDTYPE, 0);
switch (size) {
case 32:
command = set_field(command, AC_ACCESS_REGISTER_SIZE, 2);
break;
case 64:
command = set_field(command, AC_ACCESS_REGISTER_SIZE, 3);
break;
default:
LOG_ERROR("Unsupported abstract register read size: %d", size);
return ERROR_FAIL;
}
command = set_field(command, AC_ACCESS_REGISTER_POSTEXEC, 1);
command = set_field(command, AC_ACCESS_REGISTER_TRANSFER, 1);
command = set_field(command, AC_ACCESS_REGISTER_WRITE, 1);
command = set_field(command, AC_ACCESS_REGISTER_REGNO,
0x1000 + GDB_REGNO_S1 - GDB_REGNO_XPR0);
uint32_t command = access_register_command(GDB_REGNO_S1, 32,
AC_ACCESS_REGISTER_POSTEXEC |
AC_ACCESS_REGISTER_TRANSFER |
AC_ACCESS_REGISTER_WRITE);
int result = execute_abstract_command(target, command);
if (result != ERROR_OK)
return result;
@ -1810,14 +1751,6 @@ static enum riscv_halt_reason riscv013_halt_reason(struct target *target)
abort();
}
void riscv013_debug_buffer_enter(struct target *target, struct riscv_program *program)
{
}
void riscv013_debug_buffer_leave(struct target *target, struct riscv_program *program)
{
}
void riscv013_write_debug_buffer(struct target *target, unsigned index, riscv_insn_t data)
{
RISCV013_INFO(info);

View File

@ -1482,20 +1482,6 @@ size_t riscv_debug_buffer_size(struct target *target)
return r->debug_buffer_size[riscv_current_hartid(target)];
}
int riscv_debug_buffer_enter(struct target *target, struct riscv_program *program)
{
RISCV_INFO(r);
r->debug_buffer_enter(target, program);
return ERROR_OK;
}
int riscv_debug_buffer_leave(struct target *target, struct riscv_program *program)
{
RISCV_INFO(r);
r->debug_buffer_leave(target, program);
return ERROR_OK;
}
int riscv_write_debug_buffer(struct target *target, int index, riscv_insn_t insn)
{
RISCV_INFO(r);

View File

@ -92,8 +92,6 @@ typedef struct {
void (*on_resume)(struct target *target);
void (*on_step)(struct target *target);
enum riscv_halt_reason (*halt_reason)(struct target *target);
void (*debug_buffer_enter)(struct target *target, struct riscv_program *program);
void (*debug_buffer_leave)(struct target *target, struct riscv_program *program);
void (*write_debug_buffer)(struct target *target, unsigned index,
riscv_insn_t d);
riscv_insn_t (*read_debug_buffer)(struct target *target, unsigned index);
@ -211,9 +209,6 @@ int riscv_count_triggers_of_hart(struct target *target, int hartid);
* information. */
size_t riscv_debug_buffer_size(struct target *target);
int riscv_debug_buffer_enter(struct target *target, struct riscv_program *program);
int riscv_debug_buffer_leave(struct target *target, struct riscv_program *program);
riscv_insn_t riscv_read_debug_buffer(struct target *target, int index);
riscv_addr_t riscv_read_debug_buffer_x(struct target *target, int index);
int riscv_write_debug_buffer(struct target *target, int index, riscv_insn_t insn);