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: Ic3639d822c887bd4a5517f044855fdd9d4e5a46dsba_tests
parent
fd9de02fac
commit
075610d495
|
@ -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 {
|
||||
(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;
|
||||
}
|
||||
|
||||
static int write_memory_bus(struct target *target, target_addr_t address,
|
||||
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,20 +2499,22 @@ 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 {
|
||||
(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)
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue