At least some memory writes work.

Change-Id: I6fcf261341f10ec34df01bb844744439d02471a8
This commit is contained in:
Tim Newsome 2017-10-13 12:50:02 -07:00
parent e7bb815e87
commit 7ec7bc32fe
3 changed files with 93 additions and 129 deletions

View File

@ -40,6 +40,17 @@ int riscv_program_init(struct riscv_program *p, struct target *target)
return ERROR_OK; return ERROR_OK;
} }
int riscv_program_write(struct riscv_program *program)
{
for (unsigned i = 0; i < riscv_debug_buffer_size(program->target); ++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)
return ERROR_FAIL;
}
return ERROR_OK;
}
/** Add ebreak and execute the program. */ /** Add ebreak and execute the program. */
int riscv_program_exec(struct riscv_program *p, struct target *t) int riscv_program_exec(struct riscv_program *p, struct target *t)
{ {
@ -74,16 +85,8 @@ int riscv_program_exec(struct riscv_program *p, struct target *t)
return ERROR_FAIL; return ERROR_FAIL;
} }
for (unsigned i = 0; i < riscv_debug_buffer_size(p->target); ++i) { if (riscv_program_write(p) != ERROR_OK)
if (i < p->instruction_count) { return ERROR_FAIL;
LOG_DEBUG("%p: debug_buffer[%02x] = DASM(0x%08x)", p, i, p->debug_buffer[i]);
riscv_write_debug_buffer(t, i, p->debug_buffer[i]);
}
if (i >= riscv_debug_buffer_size(p->target) - p->data_count) {
LOG_DEBUG("%p: debug_buffer[%02x] = 0x%08x", p, i, p->debug_buffer[i]);
riscv_write_debug_buffer(t, i, p->debug_buffer[i]);
}
}
if (riscv_execute_debug_buffer(t) != ERROR_OK) { if (riscv_execute_debug_buffer(t) != ERROR_OK) {
LOG_ERROR("Unable to execute program %p", p); LOG_ERROR("Unable to execute program %p", p);

View File

@ -40,6 +40,9 @@ struct riscv_program {
/* Initializes a program with the header. */ /* Initializes a program with the header. */
int riscv_program_init(struct riscv_program *p, struct target *t); int riscv_program_init(struct riscv_program *p, struct target *t);
/* Write the program to the program buffer. */
int riscv_program_write(struct riscv_program *program);
/* Executes a program, returning 0 if the program successfully executed. Note /* Executes a program, returning 0 if the program successfully executed. Note
* that this may cause registers to be saved or restored, which could result to * that this may cause registers to be saved or restored, which could result to
* calls to things like riscv_save_register which itself could require a * calls to things like riscv_save_register which itself could require a

View File

@ -34,8 +34,6 @@ static void riscv013_step_or_resume_current_hart(struct target *target, bool ste
//static riscv_addr_t riscv013_progbuf_addr(struct target *target); //static riscv_addr_t riscv013_progbuf_addr(struct target *target);
//static riscv_addr_t riscv013_data_size(struct target *target); //static riscv_addr_t riscv013_data_size(struct target *target);
//static riscv_addr_t riscv013_data_addr(struct target *target); //static riscv_addr_t riscv013_data_addr(struct target *target);
//static void riscv013_set_autoexec(struct target *target, unsigned index,
//bool enabled);
//static int riscv013_debug_buffer_register(struct target *target, riscv_addr_t addr); //static int riscv013_debug_buffer_register(struct target *target, riscv_addr_t addr);
static void riscv013_clear_abstract_error(struct target *target); static void riscv013_clear_abstract_error(struct target *target);
@ -518,7 +516,6 @@ static void dmi_write(struct target *target, uint16_t address, uint64_t value)
} }
} }
#if 0
static void increase_ac_busy_delay(struct target *target) static void increase_ac_busy_delay(struct target *target)
{ {
riscv013_info_t *info = get_info(target); riscv013_info_t *info = get_info(target);
@ -527,7 +524,6 @@ static void increase_ac_busy_delay(struct target *target)
info->dtmcontrol_idle, info->dmi_busy_delay, info->dtmcontrol_idle, info->dmi_busy_delay,
info->ac_busy_delay); info->ac_busy_delay);
} }
#endif
uint32_t abstract_register_size(unsigned width) uint32_t abstract_register_size(unsigned width)
{ {
@ -1467,30 +1463,26 @@ static int read_memory(struct target *target, target_addr_t address,
static int write_memory(struct target *target, target_addr_t address, static int write_memory(struct target *target, target_addr_t address,
uint32_t size, uint32_t count, const uint8_t *buffer) uint32_t size, uint32_t count, const uint8_t *buffer)
{ {
//RISCV013_INFO(info); RISCV013_INFO(info);
LOG_DEBUG("writing %d words of %d bytes to 0x%08lx", count, size, (long)address); LOG_DEBUG("writing %d words of %d bytes to 0x%08lx", count, size, (long)address);
/*
* s0 holds the next address to write to
* s1 holds the next data value to write
*/
select_dmi(target); select_dmi(target);
/* This program uses two temporary registers. A word of data and the uint64_t s0, s1;
* associated address are stored at some location in memory. The if (register_read_direct(target, &s0, GDB_REGNO_S0) != ERROR_OK)
* program stores the word to that address and then increments the return ERROR_FAIL;
* address. The debugger is expected to feed the memory word-by-word if (register_read_direct(target, &s1, GDB_REGNO_S1) != ERROR_OK)
* into the chip with AUTOEXEC set in order to trigger program return ERROR_FAIL;
* execution on every word. */
uint64_t s0 = riscv_get_register(target, GDB_REGNO_S0);
uint64_t s1 = riscv_get_register(target, GDB_REGNO_S1);
// Write the program (store, increment)
struct riscv_program program; struct riscv_program program;
riscv_program_init(&program, target); 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);
riscv_program_lw(&program, GDB_REGNO_S1, r_data);
switch (size) { switch (size) {
case 1: case 1:
@ -1508,83 +1500,35 @@ static int write_memory(struct target *target, target_addr_t address,
} }
riscv_program_addi(&program, GDB_REGNO_S0, GDB_REGNO_S0, size); riscv_program_addi(&program, GDB_REGNO_S0, GDB_REGNO_S0, size);
riscv_program_sx(&program, GDB_REGNO_S0, r_addr);
/* The first round through the program's execution we use the regular if (riscv_debug_buffer_leave(target, &program) != ERROR_OK)
* program execution mechanism. */
uint32_t value;
switch (size) {
case 1:
value = buffer[0];
break;
case 2:
value = buffer[0]
| ((uint32_t) buffer[1] << 8);
break;
case 4:
value = buffer[0]
| ((uint32_t) buffer[1] << 8)
| ((uint32_t) buffer[2] << 16)
| ((uint32_t) buffer[3] << 24);
break;
default:
LOG_ERROR("unsupported access size: %d", size);
return ERROR_FAIL;
}
switch (riscv_xlen(target)) {
case 64:
riscv_program_write_ram(&program, r_addr + 4, (uint64_t)address >> 32);
case 32:
riscv_program_write_ram(&program, r_addr, address);
break;
default:
LOG_ERROR("unknown XLEN %d", riscv_xlen(target));
return ERROR_FAIL;
}
riscv_program_write_ram(&program, r_data, value);
LOG_DEBUG("M[0x%08lx] writes 0x%08x", (long)address, value);
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");
return ERROR_FAIL; return ERROR_FAIL;
}
/* The rest of this program is designed to be fast so it reads various riscv_program_write(&program);
* 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); if (register_write_direct(target, GDB_REGNO_S0, address) != ERROR_OK)
return ERROR_FAIL;
/* Copying memory might fail because we're going too quickly, in which riscv_addr_t cur_addr = address;
* 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 = 0xbadbeef;
riscv_addr_t fin_addr = address + (count * size); riscv_addr_t fin_addr = address + (count * size);
bool setup_needed = true;
LOG_DEBUG("writing until final address 0x%016" PRIx64, fin_addr); LOG_DEBUG("writing until final address 0x%016" PRIx64, fin_addr);
while ((cur_addr = riscv_read_debug_buffer_x(target, d_addr)) < fin_addr) { while (cur_addr < fin_addr) {
LOG_DEBUG("transferring burst starting at address 0x%016" PRIx64, LOG_DEBUG("transferring burst starting at address 0x%016" PRIx64,
cur_addr); cur_addr);
riscv_addr_t start = (cur_addr - address) / size;
assert (cur_addr > address);
struct riscv_batch *batch = riscv_batch_alloc( struct riscv_batch *batch = riscv_batch_alloc(
target, target,
32, 32,
info->dmi_busy_delay + info->ac_busy_delay); info->dmi_busy_delay + info->ac_busy_delay);
for (riscv_addr_t i = start; i < count; ++i) { /* To write another word, we put it in S1 and execute the program. */
riscv_addr_t offset = size*i; unsigned start = (cur_addr - address) / size;
riscv_addr_t t_addr = address + offset; for (unsigned i = start; i < count; ++i) {
unsigned offset = size*i;
const uint8_t *t_buffer = buffer + offset; const uint8_t *t_buffer = buffer + offset;
uint32_t value;
switch (size) { switch (size) {
case 1: case 1:
value = t_buffer[0]; value = t_buffer[0];
@ -1604,14 +1548,44 @@ static int write_memory(struct target *target, target_addr_t address,
return ERROR_FAIL; return ERROR_FAIL;
} }
LOG_DEBUG("M[0x%08lx] writes 0x%08x", (long)t_addr, value); LOG_DEBUG("M[0x%08" PRIx64 "] writes 0x%08x", address + offset, value);
riscv_batch_add_dmi_write( if (setup_needed) {
batch, // Write value.
riscv013_debug_buffer_register(target, r_data), dmi_write(target, DMI_DATA0, value);
value);
if (riscv_batch_full(batch)) // Write and execute command that moves value into S0 and
break; // 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);
int result = execute_abstract_command(target, command);
if (result != ERROR_OK)
return result;
// Turn on autoexec
dmi_write(target, DMI_ABSTRACTAUTO,
1 << DMI_ABSTRACTAUTO_AUTOEXECDATA_OFFSET);
} else {
riscv_batch_add_dmi_write(batch, DMI_DATA0, value);
if (riscv_batch_full(batch))
break;
}
cur_addr += size;
} }
riscv_batch_run(batch); riscv_batch_run(batch);
@ -1619,8 +1593,7 @@ static int write_memory(struct target *target, target_addr_t address,
// Note that if the scan resulted in a Busy DMI response, it // Note that if the scan resulted in a Busy DMI response, it
// is this read to abstractcs that will cause the dmi_busy_delay // is this read to abstractcs that will cause the dmi_busy_delay
// to be incremented if necessary. The loop condition above // to be incremented if necessary.
// catches the case where no writes went through at all.
uint32_t abstractcs = dmi_read(target, DMI_ABSTRACTCS); uint32_t abstractcs = dmi_read(target, DMI_ABSTRACTCS);
while (get_field(abstractcs, DMI_ABSTRACTCS_BUSY)) while (get_field(abstractcs, DMI_ABSTRACTCS_BUSY))
@ -1634,10 +1607,16 @@ static int write_memory(struct target *target, target_addr_t address,
LOG_DEBUG("memory write resulted in busy response"); LOG_DEBUG("memory write resulted in busy response");
riscv013_clear_abstract_error(target); riscv013_clear_abstract_error(target);
increase_ac_busy_delay(target); increase_ac_busy_delay(target);
dmi_write(target, DMI_ABSTRACTAUTO, 0);
if (register_read_direct(target, &cur_addr, GDB_REGNO_S0) != ERROR_OK)
return ERROR_FAIL;
setup_needed = true;
break; break;
default: default:
LOG_ERROR("error when writing memory, abstractcs=0x%08lx", (long)abstractcs); LOG_ERROR("error when writing memory, abstractcs=0x%08lx", (long)abstractcs);
riscv013_set_autoexec(target, d_data, 0); dmi_write(target, DMI_ABSTRACTAUTO, 0);
riscv013_clear_abstract_error(target); riscv013_clear_abstract_error(target);
riscv_set_register(target, GDB_REGNO_S0, s0); riscv_set_register(target, GDB_REGNO_S0, s0);
riscv_set_register(target, GDB_REGNO_S1, s1); riscv_set_register(target, GDB_REGNO_S1, s1);
@ -1645,10 +1624,13 @@ static int write_memory(struct target *target, target_addr_t address,
} }
} }
riscv013_set_autoexec(target, d_data, 0); dmi_write(target, DMI_ABSTRACTAUTO, 0);
#endif
riscv_set_register(target, GDB_REGNO_S0, s0); if (register_write_direct(target, GDB_REGNO_S1, s1) != ERROR_OK)
riscv_set_register(target, GDB_REGNO_S1, s1); return ERROR_FAIL;
if (register_write_direct(target, GDB_REGNO_S0, s0) != ERROR_OK)
return ERROR_FAIL;
return ERROR_OK; return ERROR_OK;
} }
@ -1990,30 +1972,6 @@ riscv_addr_t riscv013_data_addr(struct target *target)
} }
#endif #endif
#if 0
void riscv013_set_autoexec(struct target *target, unsigned index, bool enabled)
{
RISCV013_INFO(info);
if (index >= info->progsize) {
LOG_DEBUG("setting bit %d in AUTOEXECDATA to %d", index, enabled);
uint32_t aa = dmi_read(target, DMI_ABSTRACTAUTO);
uint32_t aa_aed = get_field(aa, DMI_ABSTRACTAUTO_AUTOEXECDATA);
aa_aed &= ~(1 << (index - info->progsize));
aa_aed |= (enabled << (index - info->progsize));
aa = set_field(aa, DMI_ABSTRACTAUTO_AUTOEXECDATA, aa_aed);
dmi_write(target, DMI_ABSTRACTAUTO, aa);
} else {
LOG_DEBUG("setting bit %d in AUTOEXECPROGBUF to %d", index, enabled);
uint32_t aa = dmi_read(target, DMI_ABSTRACTAUTO);
uint32_t aa_aed = get_field(aa, DMI_ABSTRACTAUTO_AUTOEXECPROGBUF);
aa_aed &= ~(1 << index);
aa_aed |= (enabled << index);
aa = set_field(aa, DMI_ABSTRACTAUTO_AUTOEXECPROGBUF, aa_aed);
dmi_write(target, DMI_ABSTRACTAUTO, aa);
}
}
#endif
#if 0 #if 0
int riscv013_debug_buffer_register(struct target *target, riscv_addr_t addr) int riscv013_debug_buffer_register(struct target *target, riscv_addr_t addr)
{ {