From 0d74c8689d96d1f04344b5bebc84ac9069c5ee70 Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Mon, 14 Aug 2017 15:02:19 -0700 Subject: [PATCH 1/2] Fix block memory reads on slow targets. The interesting new code concerns ignore_prev_addr and this_is_last_read. Additionally, I tweaked some debug output, and optimized riscv_batch_run() when the batch is empty. --- src/target/riscv/batch.c | 5 +++++ src/target/riscv/riscv-013.c | 24 ++++++++++++++++-------- 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/src/target/riscv/batch.c b/src/target/riscv/batch.c index cb5a10856..d6e8b7941 100644 --- a/src/target/riscv/batch.c +++ b/src/target/riscv/batch.c @@ -44,6 +44,11 @@ bool riscv_batch_full(struct riscv_batch *batch) void riscv_batch_run(struct riscv_batch *batch) { + if (batch->used_scans == 0) { + LOG_DEBUG("Ignoring empty batch."); + return; + } + LOG_DEBUG("running a batch of %ld scans", (long)batch->used_scans); riscv_batch_add_nop(batch); diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c index 284f6a1ba..5fc3175ca 100644 --- a/src/target/riscv/riscv-013.c +++ b/src/target/riscv/riscv-013.c @@ -1353,7 +1353,7 @@ static int read_memory(struct target *target, target_addr_t address, riscv_addr_t cur_addr = 0xbadbeef; riscv_addr_t fin_addr = address + (count * size); riscv_addr_t prev_addr = ((riscv_addr_t) address) - size; - bool first = true; + bool ignore_prev_addr = true; bool this_is_last_read = false; LOG_DEBUG("reading until final address 0x%" PRIx64, fin_addr); while (count > 1 && !this_is_last_read) { @@ -1361,9 +1361,9 @@ static int read_memory(struct target *target, target_addr_t address, LOG_DEBUG("transferring burst starting at address 0x%" TARGET_PRIxADDR " (previous burst was 0x%" TARGET_PRIxADDR ")", cur_addr, prev_addr); - assert(first || prev_addr < cur_addr); - first = false; + assert(ignore_prev_addr || prev_addr < cur_addr); prev_addr = cur_addr; + ignore_prev_addr = false; riscv_addr_t start = (cur_addr - address) / size; assert (cur_addr >= address); struct riscv_batch *batch = riscv_batch_alloc( @@ -1409,10 +1409,11 @@ static int read_memory(struct target *target, target_addr_t address, info->cmderr = get_field(abstractcs, DMI_ABSTRACTCS_CMDERR); switch (info->cmderr) { case CMDERR_NONE: - LOG_DEBUG("successful (partial?) memory write"); + LOG_DEBUG("successful (partial?) memory read"); break; case CMDERR_BUSY: - LOG_DEBUG("memory write resulted in busy response"); + LOG_DEBUG("memory read resulted in busy response; " + "this_is_last_read=%d", this_is_last_read); riscv013_clear_abstract_error(target); increase_ac_busy_delay(target); retry_batch_transaction = true; @@ -1427,7 +1428,11 @@ static int read_memory(struct target *target, target_addr_t address, riscv_batch_free(batch); return ERROR_FAIL; } - if (retry_batch_transaction) continue; + if (retry_batch_transaction) { + this_is_last_read = false; + ignore_prev_addr = true; + continue; + } for (size_t i = start; i < start + reads; ++i) { riscv_addr_t offset = size*i; @@ -1437,8 +1442,11 @@ static int read_memory(struct target *target, target_addr_t address, if (this_is_last_read && i == start + reads - 1) { riscv013_set_autoexec(target, d_data, 0); - // access debug buffer without executing a program - this address logic was taken from program.c - int const off = (r_data - riscv_debug_buffer_addr(program.target)) / sizeof(program.debug_buffer[0]); + // Access debug buffer without executing a program. This + // address logic was taken from program.c. + int const off = (r_data - + riscv_debug_buffer_addr(program.target)) / + sizeof(program.debug_buffer[0]); value = riscv_read_debug_buffer(target, off); } else { uint64_t dmi_out = riscv_batch_get_dmi_read(batch, rereads); From 0ff4103a2659de06b76bcc6d96fe82afa5fd44cd Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Tue, 15 Aug 2017 15:47:35 -0700 Subject: [PATCH 2/2] Reset address if target was busy during bust write Improve Issue #98. DebugCompareSections is still failing for me (with an instrumented sometimes-slow spike), but MemTestBlock now passes reliably. --- src/target/riscv/riscv-013.c | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c index 5fc3175ca..d4cb51ced 100644 --- a/src/target/riscv/riscv-013.c +++ b/src/target/riscv/riscv-013.c @@ -1358,13 +1358,13 @@ static int read_memory(struct target *target, target_addr_t address, LOG_DEBUG("reading until final address 0x%" PRIx64, fin_addr); while (count > 1 && !this_is_last_read) { cur_addr = riscv_read_debug_buffer_x(target, d_addr); - LOG_DEBUG("transferring burst starting at address 0x%" TARGET_PRIxADDR - " (previous burst was 0x%" TARGET_PRIxADDR ")", cur_addr, - prev_addr); + riscv_addr_t start = (cur_addr - address) / size; + LOG_DEBUG("reading burst at address 0x%" TARGET_PRIxADDR + "; prev_addr=0x%" TARGET_PRIxADDR "; start=0x%" + TARGET_PRIxADDR, cur_addr, prev_addr, start); assert(ignore_prev_addr || prev_addr < cur_addr); prev_addr = cur_addr; ignore_prev_addr = false; - riscv_addr_t start = (cur_addr - address) / size; assert (cur_addr >= address); struct riscv_batch *batch = riscv_batch_alloc( target, @@ -1431,6 +1431,18 @@ static int read_memory(struct target *target, target_addr_t address, if (retry_batch_transaction) { this_is_last_read = false; ignore_prev_addr = true; + + switch (riscv_xlen(target)) { + case 64: + riscv013_write_debug_buffer(target, d_addr + 4, (cur_addr - size) >> 32); + case 32: + riscv013_write_debug_buffer(target, d_addr, (cur_addr - size)); + break; + default: + LOG_ERROR("unknown XLEN %d", riscv_xlen(target)); + return ERROR_FAIL; + } + continue; }