From 075610d4952cae011fddb46c3793ba4bbc4faf3e Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Fri, 2 Mar 2018 18:20:08 -0800 Subject: [PATCH] Support v0 system bus access This code was submitted at https://github.com/riscv/riscv-openocd/pull/214. This change incorporates that code, makes it build, and fixes the style to fit the OpenOCD style guide. I have not tested the new code because I don't have a target. It does not cause any regressions. Change-Id: Ic3639d822c887bd4a5517f044855fdd9d4e5a46d --- src/target/riscv/riscv-013.c | 199 +++++++++++++++++++++++++++++++---- 1 file changed, 181 insertions(+), 18 deletions(-) diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c index 3b7c6cc02..2c039e5d3 100644 --- a/src/target/riscv/riscv-013.c +++ b/src/target/riscv/riscv-013.c @@ -1758,10 +1758,80 @@ static int read_sbcs_nonbusy(struct target *target, uint32_t *sbcs) } } +static int read_memory_bus_v0(struct target *target, target_addr_t address, + uint32_t size, uint32_t count, uint8_t *buffer) +{ + LOG_DEBUG("System Bus Access: size: %d\tcount:%d\tstart address: 0x%08" + TARGET_PRIxADDR, size, count, address); + uint8_t *t_buffer = buffer; + riscv_addr_t cur_addr = address; + riscv_addr_t fin_addr = address + (count * size); + uint64_t access = 0; + + const int DMI_SBCS_SBSINGLEREAD_OFFSET = 20; + const uint32_t DMI_SBCS_SBSINGLEREAD = (0x1U << DMI_SBCS_SBSINGLEREAD_OFFSET); + + const int DMI_SBCS_SBAUTOREAD_OFFSET = 15; + const uint32_t DMI_SBCS_SBAUTOREAD = (0x1U << DMI_SBCS_SBAUTOREAD_OFFSET); + + /* ww favorise one off reading if there is an issu */ + if (count == 1) { + for (uint32_t i = 0; i < count; i++) { + access = dmi_read(target, DMI_SBCS); + dmi_write(target, DMI_SBADDRESS0, cur_addr); + /* size/2 matching the bit access of the spec 0.13 */ + access = set_field(access, DMI_SBCS_SBACCESS, size/2); + access = set_field(access, DMI_SBCS_SBSINGLEREAD, 1); + LOG_DEBUG("\r\nread_memory: sab: access: 0x%08" PRIx64, access); + dmi_write(target, DMI_SBCS, access); + /* 3) read */ + uint32_t value = dmi_read(target, DMI_SBDATA0); + LOG_DEBUG("\r\nread_memory: sab: value: 0x%08x", value); + write_to_buf(t_buffer, value, size); + t_buffer += size; + cur_addr += size; + } + return ERROR_OK; + } + + /* has to be the same size if we want to read a block */ + LOG_DEBUG("reading block until final address 0x%" PRIx64, fin_addr); + access = dmi_read(target, DMI_SBCS); + /* set current address */ + dmi_write(target, DMI_SBADDRESS0, cur_addr); + /* 2) write sbaccess=2, sbsingleread,sbautoread,sbautoincrement + * size/2 matching the bit access of the spec 0.13 */ + access = set_field(access, DMI_SBCS_SBACCESS, size/2); + access = set_field(access, DMI_SBCS_SBAUTOREAD, 1); + access = set_field(access, DMI_SBCS_SBSINGLEREAD, 1); + access = set_field(access, DMI_SBCS_SBAUTOINCREMENT, 1); + LOG_DEBUG("\r\naccess: 0x%08" PRIx64, access); + dmi_write(target, DMI_SBCS, access); + + while (cur_addr < fin_addr) { + LOG_DEBUG("\r\nsab:autoincrement: \r\n size: %d\tcount:%d\taddress: 0x%08" + PRIx64, size, count, cur_addr); + /* read */ + uint32_t value = dmi_read(target, DMI_SBDATA0); + write_to_buf(t_buffer, value, size); + cur_addr += size; + t_buffer += size; + + /* if we are reaching last address, we must clear autoread */ + if (cur_addr == fin_addr && count != 1) { + dmi_write(target, DMI_SBCS, 0); + value = dmi_read(target, DMI_SBDATA0); + write_to_buf(t_buffer, value, size); + } + } + + return ERROR_OK; +} + /** * Read the requested memory using the system bus interface. */ -static int read_memory_bus(struct target *target, target_addr_t address, +static int read_memory_bus_v1(struct target *target, target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer) { RISCV013_INFO(info); @@ -2065,22 +2135,113 @@ 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) { + 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) || + + if ((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; + (get_field(info->sbcs, DMI_SBCS_SBACCESS128) && size == 16)) { + if (get_field(info->sbcs, DMI_SBCS_SBVERSION) == 0) + return read_memory_bus_v0(target, address, size, count, buffer); + else if (get_field(info->sbcs, DMI_SBCS_SBVERSION) == 1) + return read_memory_bus_v1(target, address, size, count, buffer); } + + 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, +static int write_memory_bus_v0(struct target *target, target_addr_t address, + uint32_t size, uint32_t count, const uint8_t *buffer) +{ + /*1) write sbaddress: for singlewrite and autoincrement, we need to write the address once*/ + LOG_DEBUG("System Bus Access: size: %d\tcount:%d\tstart address: 0x%08" + PRIx64, size, count, address); + dmi_write(target, DMI_SBADDRESS0, address); + int64_t value = 0; + int64_t access = 0; + riscv_addr_t offset = 0; + riscv_addr_t t_addr = 0; + const uint8_t *t_buffer = buffer + offset; + + /* B.8 Writing Memory, single write check if we write in one go */ + if (count == 1) { /* count is in bytes here */ + /* check the size */ + switch (size) { + case 1: + value = t_buffer[0]; + break; + case 2: + value = t_buffer[0] + | ((uint32_t) t_buffer[1] << 8); + break; + case 4: + value = t_buffer[0] + | ((uint32_t) t_buffer[1] << 8) + | ((uint32_t) t_buffer[2] << 16) + | ((uint32_t) t_buffer[3] << 24); + break; + default: + LOG_ERROR("unsupported access size: %d", size); + return ERROR_FAIL; + } + + access = 0; + access = set_field(access, DMI_SBCS_SBACCESS, size/2); + dmi_write(target, DMI_SBCS, access); + LOG_DEBUG("\r\naccess: 0x%08" PRIx64, access); + LOG_DEBUG("\r\nwrite_memory:SAB: ONE OFF: value 0x%08" PRIx64, value); + dmi_write(target, DMI_SBDATA0, value); + return ERROR_OK; + } + + /*B.8 Writing Memory, using autoincrement*/ + + access = 0; + access = set_field(access, DMI_SBCS_SBACCESS, size/2); + access = set_field(access, DMI_SBCS_SBAUTOINCREMENT, 1); + LOG_DEBUG("\r\naccess: 0x%08" PRIx64, access); + dmi_write(target, DMI_SBCS, access); + + /*2)set the value according to the size required and write*/ + for (riscv_addr_t i = 0; i < count; ++i) { + offset = size*i; + /* for monitoring only */ + t_addr = address + offset; + t_buffer = buffer + offset; + + switch (size) { + case 1: + value = t_buffer[0]; + break; + case 2: + value = t_buffer[0] + | ((uint32_t) t_buffer[1] << 8); + break; + case 4: + value = t_buffer[0] + | ((uint32_t) t_buffer[1] << 8) + | ((uint32_t) t_buffer[2] << 16) + | ((uint32_t) t_buffer[3] << 24); + break; + default: + LOG_ERROR("unsupported access size: %d", size); + return ERROR_FAIL; + } + LOG_DEBUG("SAB:autoincrement: expected address: 0x%08x value: 0x%08x" + PRIx64, (uint32_t)t_addr, (uint32_t)value); + dmi_write(target, DMI_SBDATA0, value); + } + /*reset the autoincrement when finished (something weird is happening if this is not done at the end*/ + access = set_field(access, DMI_SBCS_SBAUTOINCREMENT, 0); + dmi_write(target, DMI_SBCS, access); + + return ERROR_OK; +} + +static int write_memory_bus_v1(struct target *target, target_addr_t address, uint32_t size, uint32_t count, const uint8_t *buffer) { RISCV013_INFO(info); @@ -2338,19 +2499,21 @@ 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) { + 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) || + if ((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; + (get_field(info->sbcs, DMI_SBCS_SBACCESS128) && size == 16)) { + if (get_field(info->sbcs, DMI_SBCS_SBVERSION) == 0) + return write_memory_bus_v0(target, address, size, count, buffer); + else if (get_field(info->sbcs, DMI_SBCS_SBVERSION) == 1) + return write_memory_bus_v1(target, address, size, count, buffer); } + + LOG_ERROR("Don't know how to write memory on this target."); + return ERROR_FAIL; } static int arch_state(struct target *target)