Merge pull request #203 from riscv/sysbusbits

Add support for system bus master, and for targets that don't have any program buffer
sba_tests
Tim Newsome 2018-02-20 09:22:22 -08:00 committed by GitHub
commit 3c1c6e059c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 368 additions and 31 deletions

View File

@ -143,6 +143,9 @@ typedef struct {
/* Number of words in the Program Buffer. */
unsigned progbufsize;
/* We cache the read-only bits of sbcs here. */
uint32_t sbcs;
yes_no_maybe_t progbuf_writable;
/* We only need the address so that we know the alignment of the buffer. */
riscv_addr_t progbuf_address;
@ -156,6 +159,10 @@ typedef struct {
* in between accesses. */
unsigned int dmi_busy_delay;
/* Number of run-test/idle cycles to add between consecutive bus master
* reads/writes respectively. */
unsigned int bus_master_write_delay, bus_master_read_delay;
/* This value is increased every time we tried to execute two commands
* consecutively, and the second one failed because the previous hadn't
* completed yet. It's used to add extra run-test/idle cycles after
@ -233,6 +240,18 @@ static void decode_dmi(char *text, unsigned address, unsigned data)
{ DMI_ABSTRACTCS, DMI_ABSTRACTCS_DATACOUNT, "datacount" },
{ DMI_COMMAND, DMI_COMMAND_CMDTYPE, "cmdtype" },
{ DMI_SBCS, DMI_SBCS_SBREADONADDR, "sbreadonaddr" },
{ DMI_SBCS, DMI_SBCS_SBACCESS, "sbaccess" },
{ DMI_SBCS, DMI_SBCS_SBAUTOINCREMENT, "sbautoincrement" },
{ DMI_SBCS, DMI_SBCS_SBREADONDATA, "sbreadondata" },
{ DMI_SBCS, DMI_SBCS_SBERROR, "sberror" },
{ DMI_SBCS, DMI_SBCS_SBASIZE, "sbasize" },
{ DMI_SBCS, DMI_SBCS_SBACCESS128, "sbaccess128" },
{ DMI_SBCS, DMI_SBCS_SBACCESS64, "sbaccess64" },
{ DMI_SBCS, DMI_SBCS_SBACCESS32, "sbaccess32" },
{ DMI_SBCS, DMI_SBCS_SBACCESS16, "sbaccess16" },
{ DMI_SBCS, DMI_SBCS_SBACCESS8, "sbaccess8" },
};
text[0] = 0;
@ -592,14 +611,14 @@ static int execute_abstract_command(struct target *target, uint32_t command)
return ERROR_OK;
}
static riscv_reg_t read_abstract_arg(struct target *target, unsigned index)
static riscv_reg_t read_abstract_arg(struct target *target, unsigned index,
unsigned size_bits)
{
riscv_reg_t value = 0;
unsigned xlen = riscv_xlen(target);
unsigned offset = index * xlen / 32;
switch (xlen) {
unsigned offset = index * size_bits / 32;
switch (size_bits) {
default:
LOG_ERROR("Unsupported xlen: %d", xlen);
LOG_ERROR("Unsupported size: %d", size_bits);
return ~0;
case 64:
value |= ((uint64_t) dmi_read(target, DMI_DATA0 + offset + 1)) << 32;
@ -610,14 +629,13 @@ static riscv_reg_t read_abstract_arg(struct target *target, unsigned index)
}
static int write_abstract_arg(struct target *target, unsigned index,
riscv_reg_t value)
riscv_reg_t value, unsigned size_bits)
{
unsigned xlen = riscv_xlen(target);
unsigned offset = index * xlen / 32;
switch (xlen) {
unsigned offset = index * size_bits / 32;
switch (size_bits) {
default:
LOG_ERROR("Unsupported xlen: %d", xlen);
return ~0;
LOG_ERROR("Unsupported size: %d", size_bits);
return ERROR_FAIL;
case 64:
dmi_write(target, DMI_DATA0 + offset + 1, value >> 32);
case 32:
@ -692,7 +710,7 @@ static int register_read_abstract(struct target *target, uint64_t *value,
}
if (value)
*value = read_abstract_arg(target, 0);
*value = read_abstract_arg(target, 0, size);
return ERROR_OK;
}
@ -713,7 +731,7 @@ static int register_write_abstract(struct target *target, uint32_t number,
AC_ACCESS_REGISTER_TRANSFER |
AC_ACCESS_REGISTER_WRITE);
if (write_abstract_arg(target, 0, value) != ERROR_OK)
if (write_abstract_arg(target, 0, value, size) != ERROR_OK)
return ERROR_FAIL;
int result = execute_abstract_command(target, command);
@ -927,16 +945,31 @@ static int scratch_write64(struct target *target, scratch_mem_t *scratch,
return ERROR_OK;
}
/** Return register size in bits. */
static unsigned register_size(struct target *target, unsigned number)
{
/* If reg_cache hasn't been initialized yet, make a guess. We need this for
* when this function is called during examine(). */
if (target->reg_cache)
return target->reg_cache->reg_list[number].size;
else
return riscv_xlen(target);
}
static int register_write_direct(struct target *target, unsigned number,
uint64_t value)
{
RISCV013_INFO(info);
RISCV_INFO(r);
LOG_DEBUG("[%d] reg[0x%x] <- 0x%" PRIx64, riscv_current_hartid(target),
number, value);
int result = register_write_abstract(target, number, value,
riscv_xlen(target));
if (result == ERROR_OK)
return ERROR_OK;
register_size(target, number));
if (result == ERROR_OK ||
info->progbufsize + r->impebreak < 2)
return result;
struct riscv_program program;
riscv_program_init(&program, target);
@ -992,10 +1025,14 @@ static int register_write_direct(struct target *target, unsigned number,
/** Actually read registers from the target right now. */
static int register_read_direct(struct target *target, uint64_t *value, uint32_t number)
{
int result = register_read_abstract(target, value, number,
riscv_xlen(target));
RISCV013_INFO(info);
RISCV_INFO(r);
if (result != ERROR_OK) {
int result = register_read_abstract(target, value, number,
register_size(target, number));
if (result != ERROR_OK &&
info->progbufsize + r->impebreak >= 2) {
assert(number != GDB_REGNO_S0);
struct riscv_program program;
@ -1108,6 +1145,8 @@ static int init_target(struct command_context *cmd_ctx,
info->progbufsize = -1;
info->dmi_busy_delay = 0;
info->bus_master_read_delay = 0;
info->bus_master_write_delay = 0;
info->ac_busy_delay = 0;
/* Assume all these abstract commands are supported until we learn
@ -1157,6 +1196,7 @@ static int examine(struct target *target)
info->dtmcontrol_idle = get_field(dtmcontrol, DTM_DTMCS_IDLE);
uint32_t dmstatus = dmi_read(target, DMI_DMSTATUS);
LOG_DEBUG("dmstatus: 0x%08x", dmstatus);
if (get_field(dmstatus, DMI_DMSTATUS_VERSION) != 2) {
LOG_ERROR("OpenOCD only supports Debug Module version 2, not %d "
"(dmstatus=0x%x)", get_field(dmstatus, DMI_DMSTATUS_VERSION), dmstatus);
@ -1197,14 +1237,25 @@ static int examine(struct target *target)
return ERROR_FAIL;
}
info->sbcs = dmi_read(target, DMI_SBCS);
/* Check that abstract data registers are accessible. */
uint32_t abstractcs = dmi_read(target, DMI_ABSTRACTCS);
info->datacount = get_field(abstractcs, DMI_ABSTRACTCS_DATACOUNT);
info->progbufsize = get_field(abstractcs, DMI_ABSTRACTCS_PROGBUFSIZE);
LOG_INFO("datacount=%d progbufsize=%d", info->datacount, info->progbufsize);
RISCV_INFO(r);
r->impebreak = get_field(dmstatus, DMI_DMSTATUS_IMPEBREAK);
if (info->progbufsize + r->impebreak < 2) {
LOG_WARNING("We won't be able to execute fence instructions on this "
"target. Memory may not always appear consistent. "
"(progbufsize=%d, impebreak=%d)", info->progbufsize,
r->impebreak);
}
/* Before doing anything else we must first enumerate the harts. */
/* Don't call any riscv_* functions until after we've counted the number of
@ -1451,11 +1502,171 @@ static void log_memory_access(target_addr_t address, uint64_t value,
LOG_DEBUG(fmt, value);
}
/* Read the relevant sbdata regs depending on size, and put the results into
* buffer. */
static int read_memory_bus_word(struct target *target, target_addr_t address,
uint32_t size, uint8_t *buffer)
{
uint32_t value;
if (size > 12) {
value = dmi_read(target, DMI_SBDATA3);
write_to_buf(buffer + 12, value, 4);
log_memory_access(address + 12, value, 4, true);
}
if (size > 8) {
value = dmi_read(target, DMI_SBDATA2);
write_to_buf(buffer + 8, value, 4);
log_memory_access(address + 8, value, 4, true);
}
if (size > 4) {
value = dmi_read(target, DMI_SBDATA1);
write_to_buf(buffer + 4, value, 4);
log_memory_access(address + 4, value, 4, true);
}
value = dmi_read(target, DMI_SBDATA0);
write_to_buf(buffer, value, MIN(size, 4));
log_memory_access(address, value, MIN(size, 4), true);
return ERROR_OK;
}
static uint32_t sb_sbaccess(unsigned size_bytes)
{
switch (size_bytes) {
case 1:
return set_field(0, DMI_SBCS_SBACCESS, 0);
case 2:
return set_field(0, DMI_SBCS_SBACCESS, 1);
case 4:
return set_field(0, DMI_SBCS_SBACCESS, 2);
case 8:
return set_field(0, DMI_SBCS_SBACCESS, 3);
case 16:
return set_field(0, DMI_SBCS_SBACCESS, 4);
}
assert(0);
return 0; /* Make mingw happy. */
}
static target_addr_t sb_read_address(struct target *target)
{
RISCV013_INFO(info);
unsigned sbasize = get_field(info->sbcs, DMI_SBCS_SBASIZE);
target_addr_t address = 0;
if (sbasize > 32) {
#if BUILD_TARGET64
address |= dmi_read(target, DMI_SBADDRESS1);
address <<= 32;
#endif
}
address |= dmi_read(target, DMI_SBADDRESS0);
return address;
}
static int sb_write_address(struct target *target, target_addr_t address)
{
RISCV013_INFO(info);
unsigned sbasize = get_field(info->sbcs, DMI_SBCS_SBASIZE);
/* There currently is no support for >64-bit addresses in OpenOCD. */
if (sbasize > 96) {
dmi_write(target, DMI_SBADDRESS3, 0);
}
if (sbasize > 64) {
dmi_write(target, DMI_SBADDRESS2, 0);
}
if (sbasize > 32) {
#if BUILD_TARGET64
dmi_write(target, DMI_SBADDRESS1, address >> 32);
#else
dmi_write(target, DMI_SBADDRESS1, 0);
#endif
}
return dmi_write(target, DMI_SBADDRESS0, address);
}
static int read_sbcs_nonbusy(struct target *target, uint32_t *sbcs)
{
time_t start = time(NULL);
while (1) {
*sbcs = dmi_read(target, DMI_SBCS);
if (!get_field(*sbcs, DMI_SBCS_SBBUSY))
return ERROR_OK;
if (time(NULL) - start > riscv_command_timeout_sec) {
LOG_ERROR("Timed out after %ds waiting for sbbusy to go low (sbcs=0x%x). "
"Increase the timeout with riscv set_command_timeout_sec.",
riscv_command_timeout_sec, *sbcs);
}
return ERROR_FAIL;
}
}
/**
* Read the requested memory using the system bus interface.
*/
static int read_memory_bus(struct target *target, target_addr_t address,
uint32_t size, uint32_t count, uint8_t *buffer)
{
RISCV013_INFO(info);
target_addr_t next_address = address;
target_addr_t end_address = address + count * size;
while (next_address < end_address) {
uint32_t sbcs = set_field(0, DMI_SBCS_SBREADONADDR, 1);
sbcs |= sb_sbaccess(size);
sbcs = set_field(sbcs, DMI_SBCS_SBAUTOINCREMENT, 1);
sbcs = set_field(sbcs, DMI_SBCS_SBREADONDATA, count > 1);
dmi_write(target, DMI_SBCS, sbcs);
/* This address write will trigger the first read. */
sb_write_address(target, next_address);
if (info->bus_master_read_delay) {
jtag_add_runtest(info->bus_master_read_delay, TAP_IDLE);
if (jtag_execute_queue() != ERROR_OK) {
LOG_ERROR("Failed to scan idle sequence");
return ERROR_FAIL;
}
}
for (uint32_t i = (next_address - address) / size; i < count - 1; i++) {
read_memory_bus_word(target, address + i * size, size,
buffer + i * size);
}
sbcs = set_field(sbcs, DMI_SBCS_SBREADONDATA, 0);
dmi_write(target, DMI_SBCS, sbcs);
read_memory_bus_word(target, address + (count - 1) * size, size,
buffer + (count - 1) * size);
if (read_sbcs_nonbusy(target, &sbcs) != ERROR_OK)
return ERROR_FAIL;
if (get_field(sbcs, DMI_SBCS_SBBUSYERROR)) {
/* We read while the target was busy. Slow down and try again. */
dmi_write(target, DMI_SBCS, DMI_SBCS_SBBUSYERROR);
next_address = sb_read_address(target);
info->bus_master_read_delay += info->bus_master_read_delay / 10 + 1;
}
unsigned error = get_field(sbcs, DMI_SBCS_SBERROR);
if (error == 0) {
next_address = end_address;
} else {
/* Some error indicating the bus access failed, but not because of
* something we did wrong. */
dmi_write(target, DMI_SBCS, DMI_SBCS_SBERROR);
return ERROR_FAIL;
}
}
return ERROR_OK;
}
/**
* Read the requested memory, taking care to execute every read exactly once,
* even if cmderr=busy is encountered.
*/
static int read_memory(struct target *target, target_addr_t address,
static int read_memory_progbuf(struct target *target, target_addr_t address,
uint32_t size, uint32_t count, uint8_t *buffer)
{
RISCV013_INFO(info);
@ -1691,7 +1902,103 @@ error:
return result;
}
static int write_memory(struct target *target, target_addr_t address,
static int read_memory(struct target *target, target_addr_t address,
uint32_t size, uint32_t count, uint8_t *buffer)
{
RISCV013_INFO(info);
if (info->progbufsize >= 2) {
return read_memory_progbuf(target, address, size, count, buffer);
} else if ((get_field(info->sbcs, DMI_SBCS_SBVERSION) == 1) && (
(get_field(info->sbcs, DMI_SBCS_SBACCESS8) && size == 1) ||
(get_field(info->sbcs, DMI_SBCS_SBACCESS16) && size == 2) ||
(get_field(info->sbcs, DMI_SBCS_SBACCESS32) && size == 4) ||
(get_field(info->sbcs, DMI_SBCS_SBACCESS64) && size == 8) ||
(get_field(info->sbcs, DMI_SBCS_SBACCESS128) && size == 16))) {
return read_memory_bus(target, address, size, count, buffer);
} else {
LOG_ERROR("Don't know how to read memory on this target.");
return ERROR_FAIL;
}
}
static int write_memory_bus(struct target *target, target_addr_t address,
uint32_t size, uint32_t count, const uint8_t *buffer)
{
RISCV013_INFO(info);
uint32_t sbcs = sb_sbaccess(size);
sbcs = set_field(sbcs, DMI_SBCS_SBAUTOINCREMENT, 1);
dmi_write(target, DMI_SBCS, sbcs);
target_addr_t next_address = address;
target_addr_t end_address = address + count * size;
sb_write_address(target, next_address);
while (next_address < end_address) {
for (uint32_t i = (next_address - address) / size; i < count; i++) {
const uint8_t *p = buffer + i * size;
if (size > 12)
dmi_write(target, DMI_SBDATA3,
((uint32_t) p[12]) |
(((uint32_t) p[13]) << 8) |
(((uint32_t) p[14]) << 16) |
(((uint32_t) p[15]) << 24));
if (size > 8)
dmi_write(target, DMI_SBDATA2,
((uint32_t) p[8]) |
(((uint32_t) p[9]) << 8) |
(((uint32_t) p[10]) << 16) |
(((uint32_t) p[11]) << 24));
if (size > 4)
dmi_write(target, DMI_SBDATA1,
((uint32_t) p[4]) |
(((uint32_t) p[5]) << 8) |
(((uint32_t) p[6]) << 16) |
(((uint32_t) p[7]) << 24));
uint32_t value = p[0];
if (size > 2) {
value |= ((uint32_t) p[2]) << 16;
value |= ((uint32_t) p[3]) << 24;
}
if (size > 1)
value |= ((uint32_t) p[1]) << 8;
dmi_write(target, DMI_SBDATA0, value);
log_memory_access(address + i * size, value, size, false);
if (info->bus_master_write_delay) {
jtag_add_runtest(info->bus_master_write_delay, TAP_IDLE);
if (jtag_execute_queue() != ERROR_OK) {
LOG_ERROR("Failed to scan idle sequence");
return ERROR_FAIL;
}
}
}
if (read_sbcs_nonbusy(target, &sbcs) != ERROR_OK)
return ERROR_FAIL;
if (get_field(sbcs, DMI_SBCS_SBBUSYERROR)) {
/* We wrote while the target was busy. Slow down and try again. */
dmi_write(target, DMI_SBCS, DMI_SBCS_SBBUSYERROR);
next_address = sb_read_address(target);
info->bus_master_write_delay += info->bus_master_write_delay / 10 + 1;
}
unsigned error = get_field(sbcs, DMI_SBCS_SBERROR);
if (error == 0) {
next_address = end_address;
} else {
/* Some error indicating the bus access failed, but not because of
* something we did wrong. */
dmi_write(target, DMI_SBCS, DMI_SBCS_SBERROR);
return ERROR_FAIL;
}
}
return ERROR_OK;
}
static int write_memory_progbuf(struct target *target, target_addr_t address,
uint32_t size, uint32_t count, const uint8_t *buffer)
{
RISCV013_INFO(info);
@ -1868,6 +2175,25 @@ error:
return result;
}
static int write_memory(struct target *target, target_addr_t address,
uint32_t size, uint32_t count, const uint8_t *buffer)
{
RISCV013_INFO(info);
if (info->progbufsize >= 2) {
return write_memory_progbuf(target, address, size, count, buffer);
} else if ((get_field(info->sbcs, DMI_SBCS_SBVERSION) == 1) && (
(get_field(info->sbcs, DMI_SBCS_SBACCESS8) && size == 1) ||
(get_field(info->sbcs, DMI_SBCS_SBACCESS16) && size == 2) ||
(get_field(info->sbcs, DMI_SBCS_SBACCESS32) && size == 4) ||
(get_field(info->sbcs, DMI_SBCS_SBACCESS64) && size == 8) ||
(get_field(info->sbcs, DMI_SBCS_SBACCESS128) && size == 16))) {
return write_memory_bus(target, address, size, count, buffer);
} else {
LOG_ERROR("Don't know how to write memory on this target.");
return ERROR_FAIL;
}
}
static int arch_state(struct target *target)
{
return ERROR_OK;
@ -2105,14 +2431,26 @@ int riscv013_dmi_write_u64_bits(struct target *target)
return info->abits + DTM_DMI_DATA_LENGTH + DTM_DMI_OP_LENGTH;
}
static int maybe_execute_fence_i(struct target *target)
{
RISCV013_INFO(info);
RISCV_INFO(r);
if (info->progbufsize + r->impebreak >= 2) {
struct riscv_program program;
riscv_program_init(&program, target);
if (riscv_program_fence_i(&program) != ERROR_OK)
return ERROR_FAIL;
if (riscv_program_exec(&program, target) != ERROR_OK)
return ERROR_FAIL;
}
return ERROR_OK;
}
/* Helper Functions. */
static int riscv013_on_step_or_resume(struct target *target, bool step)
{
struct riscv_program program;
riscv_program_init(&program, target);
riscv_program_fence_i(&program);
if (riscv_program_exec(&program, target) != ERROR_OK)
LOG_ERROR("Unable to execute fence.i");
if (maybe_execute_fence_i(target) != ERROR_OK)
return ERROR_FAIL;
/* We want to twiddle some bits in the debug CSR so debugging works. */
riscv_reg_t dcsr;
@ -2135,10 +2473,7 @@ static int riscv013_step_or_resume_current_hart(struct target *target, bool step
return ERROR_FAIL;
}
struct riscv_program program;
riscv_program_init(&program, target);
riscv_program_fence_i(&program);
if (riscv_program_exec(&program, target) != ERROR_OK)
if (maybe_execute_fence_i(target) != ERROR_OK)
return ERROR_FAIL;
/* Issue the resume command, and then wait for the current hart to resume. */

View File

@ -1917,7 +1917,6 @@ int riscv_init_registers(struct target *target)
* between). */
for (uint32_t number = 0; number < GDB_REGNO_COUNT; number++) {
struct reg *r = &target->reg_cache->reg_list[number];
r->caller_save = true;
r->dirty = false;
r->valid = false;
r->exist = true;
@ -1929,6 +1928,7 @@ int riscv_init_registers(struct target *target)
* target is in theory allowed to change XLEN on us. But I expect a lot
* of other things to break in that case as well. */
if (number <= GDB_REGNO_XPR31) {
r->caller_save = true;
switch (number) {
case GDB_REGNO_ZERO:
r->name = "zero";
@ -2030,10 +2030,12 @@ int riscv_init_registers(struct target *target)
r->group = "general";
r->feature = &feature_cpu;
} else if (number == GDB_REGNO_PC) {
r->caller_save = true;
sprintf(reg_name, "pc");
r->group = "general";
r->feature = &feature_cpu;
} else if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31) {
r->caller_save = true;
if (riscv_supports_extension(target, 'D')) {
r->reg_data_type = &type_ieee_double;
r->size = 64;