Skip to content

Commit

Permalink
target/riscv: Handle sbbusyerror in read_memory_bus_v1
Browse files Browse the repository at this point in the history
The existing code didn't seem to work right at all. I have spike
modifications that exercise these new cases. I'll merge those once this
has merged.

Change-Id: I89bd336f34f1b208a76f25b6b41fe3877800765b
Signed-off-by: Tim Newsome <[email protected]>
  • Loading branch information
timsifive committed Nov 15, 2023
1 parent 839f292 commit 08182bf
Showing 1 changed file with 37 additions and 7 deletions.
44 changes: 37 additions & 7 deletions src/target/riscv/riscv-013.c
Original file line number Diff line number Diff line change
Expand Up @@ -3168,15 +3168,17 @@ static int read_memory_bus_v1(struct target *target, target_addr_t address,
return ERROR_FAIL;

if (info->bus_master_read_delay) {
LOG_TARGET_DEBUG(target, "Waiting %d cycles for bus master read delay",
info->bus_master_read_delay);
jtag_add_runtest(info->bus_master_read_delay, TAP_IDLE);
if (jtag_execute_queue() != ERROR_OK) {
LOG_TARGET_ERROR(target, "Failed to scan idle sequence");
return ERROR_FAIL;
}
}

/* First value has been read, and is waiting for us to issue a DMI read
* to get it. */
/* First read has been started. Optimistically assume that it has
* completed. */

static int sbdata[4] = {DM_SBDATA0, DM_SBDATA1, DM_SBDATA2, DM_SBDATA3};
uint32_t sbvalue[4] = {0};
Expand All @@ -3195,7 +3197,19 @@ static int read_memory_bus_v1(struct target *target, target_addr_t address,
}
keep_alive();
dmi_status_t status = dmi_scan(target, NULL, &sbvalue[next_read_j],
DMI_OP_READ, sbdata[j], 0, false);
DMI_OP_READ, sbdata[j], 0, false);
/* By reading from sbdata0, we have just initiated another system bus read.
* If necessary add a delay so the read can finish. */
if (j == 0 && info->bus_master_read_delay) {
LOG_TARGET_DEBUG(target, "Waiting %d cycles for bus master read delay",
info->bus_master_read_delay);
jtag_add_runtest(info->bus_master_read_delay, TAP_IDLE);
if (jtag_execute_queue() != ERROR_OK) {
LOG_TARGET_ERROR(target, "Failed to scan idle sequence");
return ERROR_FAIL;
}
}

if (status == DMI_STATUS_BUSY)
increase_dmi_busy_delay(target);
else if (status == DMI_STATUS_SUCCESS)
Expand Down Expand Up @@ -3258,16 +3272,32 @@ static int read_memory_bus_v1(struct target *target, target_addr_t address,
}

if (get_field(sbcs_read, DM_SBCS_SBBUSYERROR)) {
/* We read while the target was busy. Slow down and try again. */
if (dm_write(target, DM_SBCS, sbcs_read | DM_SBCS_SBBUSYERROR) != ERROR_OK)
/* We read while the target was busy. Slow down and try again.
* Clear sbbusyerror, as well as readondata or readonaddr. */
if (dm_write(target, DM_SBCS, DM_SBCS_SBBUSYERROR) != ERROR_OK)
return ERROR_FAIL;
next_address = sb_read_address(target);

if (get_field(sbcs_read, DM_SBCS_SBERROR) == DM_SBCS_SBERROR_NONE) {
/* Read the address whose read was last completed. */
next_address = sb_read_address(target);

/* Read the value for the last address. It's
* sitting in the register for us, but we read it
* too early (sbbusyerror became set). */
target_addr_t current_address = next_address - (increment ? size : 0);
if (read_memory_bus_word(target, current_address, size,
buffer + current_address - address) != ERROR_OK)
return ERROR_FAIL;
}

info->bus_master_read_delay += info->bus_master_read_delay / 10 + 1;
LOG_TARGET_DEBUG(target, "Increasing bus_master_read_delay to %d.",
info->bus_master_read_delay);
continue;
}

unsigned error = get_field(sbcs_read, DM_SBCS_SBERROR);
if (error == 0) {
if (error == DM_SBCS_SBERROR_NONE) {
next_address = end_address;
} else {
/* Some error indicating the bus access failed, but not because of
Expand Down

0 comments on commit 08182bf

Please sign in to comment.