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
sba_tests
Tim Newsome 2018-03-02 18:20:08 -08:00
parent fd9de02fac
commit 075610d495
1 changed files with 181 additions and 18 deletions

View File

@ -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)