aboutsummaryrefslogtreecommitdiff
path: root/src/target
diff options
context:
space:
mode:
authorTim Newsome <tim@sifive.com>2018-03-02 18:20:08 -0800
committerTim Newsome <tim@sifive.com>2018-03-09 18:02:18 -0800
commit075610d4952cae011fddb46c3793ba4bbc4faf3e (patch)
tree36b6d103dc6435aeb84650ab21237cddb1f763ce /src/target
parentfd9de02fac3fa38de53d230e5e32a266864cb9e3 (diff)
downloadriscv-openocd-075610d4952cae011fddb46c3793ba4bbc4faf3e.zip
riscv-openocd-075610d4952cae011fddb46c3793ba4bbc4faf3e.tar.gz
riscv-openocd-075610d4952cae011fddb46c3793ba4bbc4faf3e.tar.bz2
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
Diffstat (limited to 'src/target')
-rw-r--r--src/target/riscv/riscv-013.c199
1 files changed, 181 insertions, 18 deletions
diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c
index 3b7c6cc..2c039e5 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_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(struct target *target, target_addr_t address,
+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)