aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorTim Newsome <tim@sifive.com>2019-06-19 10:56:37 -0700
committerGitHub <noreply@github.com>2019-06-19 10:56:37 -0700
commitbb03f79bde8eb3d3a2a5147876d42af7cebc247e (patch)
tree78081c386272d5255da9d7f03d8c415eccd2f58b /src
parentc05ad1a92a9379295f2e0eef481e88e89e4eff6f (diff)
downloadriscv-openocd-bb03f79bde8eb3d3a2a5147876d42af7cebc247e.zip
riscv-openocd-bb03f79bde8eb3d3a2a5147876d42af7cebc247e.tar.gz
riscv-openocd-bb03f79bde8eb3d3a2a5147876d42af7cebc247e.tar.bz2
Improve block read and checksum speed (#381)
* Cache program buffer writes. Speeds up flash program by 3%, flash verify by 2%. Change-Id: I19f8f44f560a1111fa8f4e4fc04ce6de3c94999a * Remove nop from batch reads. program @ 22.123 KiB/s, verify @ 47.654 KiB/s (up from program @ 20.287 KiB/s, verify @ 23.148 KiB/s originally). Change-Id: I7ee19d967b1080336b0088d20e1fc30828afd935 * Use "algorithm" to compute CRC on RISC-V targets. Use the C compiler to generate the algorithm code. It's better at assembly than I am. We need separate RV32 and RV64 binaries to handle shift instructions. I used the code from gdb (libiberty really) because it returns the correct result. I'm not sure if the table is worth it since we do have to save/download/restore more bytes now. riscv_run_algorithm() now properly saves and reads back all registers used for parameters. It also doesn't check final_pc if exit_point is 0. Using gdb means I don't know the exact address where the code will end. Small target.[ch] change to be able to run algorithms at 64-bit addresses. Flashing an arty board now: ``` wrote 2228224 bytes from file /media/sf_tnewsome/SiFive/arty_images/arty.E21TraceFPGAEvaluationConfig.mcs in 105.589180s (20.608 KiB/s) verified 2192012 bytes in 7.037476s (304.177 KiB/s) 9.87user 16.16system 1:53.16elapsed 23%CPU (0avgtext+0avgdata 24768maxresident)k ``` Change-Id: I6696bd4cda7c89ac5ccd21b2ff3aa1663d7d7190 * Clean up formatting. Change-Id: I7f2d792a2b9432a04209272abb00d8136ee01025
Diffstat (limited to 'src')
-rw-r--r--src/target/image.c2
-rw-r--r--src/target/riscv/batch.c6
-rw-r--r--src/target/riscv/riscv-013.c21
-rw-r--r--src/target/riscv/riscv.c101
-rw-r--r--src/target/target.c2
-rw-r--r--src/target/target.h2
6 files changed, 117 insertions, 17 deletions
diff --git a/src/target/image.c b/src/target/image.c
index 9bd8f6b..1038a74 100644
--- a/src/target/image.c
+++ b/src/target/image.c
@@ -1071,7 +1071,7 @@ int image_calculate_checksum(uint8_t *buffer, uint32_t nbytes, uint32_t *checksu
keep_alive();
}
- LOG_DEBUG("Calculating checksum done");
+ LOG_DEBUG("Calculating checksum done; checksum=0x%x", crc);
*checksum = crc;
return ERROR_OK;
diff --git a/src/target/riscv/batch.c b/src/target/riscv/batch.c
index d041ed1..1ce4882 100644
--- a/src/target/riscv/batch.c
+++ b/src/target/riscv/batch.c
@@ -92,11 +92,7 @@ size_t riscv_batch_add_dmi_read(struct riscv_batch *batch, unsigned address)
batch->last_scan = RISCV_SCAN_TYPE_READ;
batch->used_scans++;
- /* FIXME We get the read response back on the next scan. For now I'm
- * just sticking a NOP in there, but this should be coalesced away. */
- riscv_batch_add_nop(batch);
-
- batch->read_keys[batch->read_keys_used] = batch->used_scans - 1;
+ batch->read_keys[batch->read_keys_used] = batch->used_scans;
return batch->read_keys_used++;
}
diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c
index 0b60399..05c108b 100644
--- a/src/target/riscv/riscv-013.c
+++ b/src/target/riscv/riscv-013.c
@@ -159,6 +159,10 @@ typedef struct {
/* The currently selected hartid on this DM. */
int current_hartid;
bool hasel_supported;
+
+ /* The program buffer stores executable code. 0 is an illegal instruction,
+ * so we use 0 to mean the cached value is invalid. */
+ uint32_t progbuf_cache[16];
} dm013_info_t;
typedef struct {
@@ -1814,6 +1818,13 @@ static int assert_reset(struct target *target)
target->state = TARGET_RESET;
+ dm013_info_t *dm = get_dm(target);
+
+ /* The DM might have gotten reset if OpenOCD called us in some reset that
+ * involves SRST being toggled. So clear our cache which may be out of
+ * date. */
+ memset(dm->progbuf_cache, 0, sizeof(dm->progbuf_cache));
+
return ERROR_OK;
}
@@ -3223,7 +3234,15 @@ static enum riscv_halt_reason riscv013_halt_reason(struct target *target)
int riscv013_write_debug_buffer(struct target *target, unsigned index, riscv_insn_t data)
{
- return dmi_write(target, DMI_PROGBUF0 + index, data);
+ dm013_info_t *dm = get_dm(target);
+ if (dm->progbuf_cache[index] != data) {
+ if (dmi_write(target, DMI_PROGBUF0 + index, data) != ERROR_OK)
+ return ERROR_FAIL;
+ dm->progbuf_cache[index] = data;
+ } else {
+ LOG_DEBUG("cache hit for 0x%x @%d", data, index);
+ }
+ return ERROR_OK;
}
riscv_insn_t riscv013_read_debug_buffer(struct target *target, unsigned index)
diff --git a/src/target/riscv/riscv.c b/src/target/riscv/riscv.c
index 1f4883c..f864b14 100644
--- a/src/target/riscv/riscv.c
+++ b/src/target/riscv/riscv.c
@@ -1414,9 +1414,6 @@ static int riscv_run_algorithm(struct target *target, int num_mem_params,
uint64_t saved_regs[32];
for (int i = 0; i < num_reg_params; i++) {
- if (reg_params[i].direction == PARAM_IN)
- continue;
-
LOG_DEBUG("save %s", reg_params[i].reg_name);
struct reg *r = register_get_by_name(target->reg_cache, reg_params[i].reg_name, 0);
if (!r) {
@@ -1438,8 +1435,11 @@ static int riscv_run_algorithm(struct target *target, int num_mem_params,
if (r->type->get(r) != ERROR_OK)
return ERROR_FAIL;
saved_regs[r->number] = buf_get_u64(r->value, 0, r->size);
- if (r->type->set(r, reg_params[i].value) != ERROR_OK)
- return ERROR_FAIL;
+
+ if (reg_params[i].direction == PARAM_OUT || reg_params[i].direction == PARAM_IN_OUT) {
+ if (r->type->set(r, reg_params[i].value) != ERROR_OK)
+ return ERROR_FAIL;
+ }
}
@@ -1489,7 +1489,7 @@ static int riscv_run_algorithm(struct target *target, int num_mem_params,
if (reg_pc->type->get(reg_pc) != ERROR_OK)
return ERROR_FAIL;
uint64_t final_pc = buf_get_u64(reg_pc->value, 0, reg_pc->size);
- if (final_pc != exit_point) {
+ if (exit_point && final_pc != exit_point) {
LOG_ERROR("PC ended up at 0x%" PRIx64 " instead of 0x%"
TARGET_PRIxADDR, final_pc, exit_point);
return ERROR_FAIL;
@@ -1507,6 +1507,13 @@ static int riscv_run_algorithm(struct target *target, int num_mem_params,
return ERROR_FAIL;
for (int i = 0; i < num_reg_params; i++) {
+ if (reg_params[i].direction == PARAM_IN ||
+ reg_params[i].direction == PARAM_IN_OUT) {
+ struct reg *r = register_get_by_name(target->reg_cache, reg_params[i].reg_name, 0);
+ if (r->type->get(r) != ERROR_OK)
+ return ERROR_FAIL;
+ buf_cpy(r->value, reg_params[i].value, reg_params[i].size);
+ }
LOG_DEBUG("restore %s", reg_params[i].reg_name);
struct reg *r = register_get_by_name(target->reg_cache, reg_params[i].reg_name, 0);
buf_set_u64(buf, 0, info->xlen[0], saved_regs[r->number]);
@@ -1525,8 +1532,86 @@ static int riscv_checksum_memory(struct target *target,
target_addr_t address, uint32_t count,
uint32_t *checksum)
{
- *checksum = 0xFFFFFFFF;
- return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+ struct working_area *crc_algorithm;
+ struct reg_param reg_params[2];
+ int retval;
+
+ LOG_DEBUG("address=0x%" TARGET_PRIxADDR "; count=0x%x", address, count);
+
+ static const uint8_t riscv32_crc_code[] = {
+#include "../../contrib/loaders/checksum/riscv32_crc.inc"
+ };
+ static const uint8_t riscv64_crc_code[] = {
+#include "../../contrib/loaders/checksum/riscv64_crc.inc"
+ };
+
+ static const uint8_t *crc_code;
+
+ int xlen = riscv_xlen(target);
+ unsigned crc_code_size;
+ if (xlen == 32) {
+ crc_code = riscv32_crc_code;
+ crc_code_size = sizeof(riscv32_crc_code);
+ } else {
+ crc_code = riscv64_crc_code;
+ crc_code_size = sizeof(riscv64_crc_code);
+ }
+
+ if (count < crc_code_size * 4) {
+ /* Don't use the algorithm for relatively small buffers. It's faster
+ * just to read the memory. target_checksum_memory() will take care of
+ * that if we fail. */
+ return ERROR_FAIL;
+ }
+
+ retval = target_alloc_working_area(target, crc_code_size, &crc_algorithm);
+ if (retval != ERROR_OK)
+ return retval;
+
+ if (crc_algorithm->address + crc_algorithm->size > address &&
+ crc_algorithm->address < address + count) {
+ /* Region to checksum overlaps with the work area we've been assigned.
+ * Bail. (Would be better to manually checksum what we read there, and
+ * use the algorithm for the rest.) */
+ target_free_working_area(target, crc_algorithm);
+ return ERROR_FAIL;
+ }
+
+ retval = target_write_buffer(target, crc_algorithm->address, crc_code_size,
+ crc_code);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("Failed to write code to " TARGET_ADDR_FMT ": %d",
+ crc_algorithm->address, retval);
+ target_free_working_area(target, crc_algorithm);
+ return retval;
+ }
+
+ init_reg_param(&reg_params[0], "a0", xlen, PARAM_IN_OUT);
+ init_reg_param(&reg_params[1], "a1", xlen, PARAM_OUT);
+ buf_set_u64(reg_params[0].value, 0, xlen, address);
+ buf_set_u64(reg_params[1].value, 0, xlen, count);
+
+ /* 20 second timeout/megabyte */
+ int timeout = 20000 * (1 + (count / (1024 * 1024)));
+
+ retval = target_run_algorithm(target, 0, NULL, 2, reg_params,
+ crc_algorithm->address,
+ 0, /* Leave exit point unspecified because we don't know. */
+ timeout, NULL);
+
+ if (retval == ERROR_OK)
+ *checksum = buf_get_u32(reg_params[0].value, 0, 32);
+ else
+ LOG_ERROR("error executing RISC-V CRC algorithm");
+
+ destroy_reg_param(&reg_params[0]);
+ destroy_reg_param(&reg_params[1]);
+
+ target_free_working_area(target, crc_algorithm);
+
+ LOG_DEBUG("checksum=0x%x, result=%d", *checksum, retval);
+
+ return retval;
}
/*** OpenOCD Helper Functions ***/
diff --git a/src/target/target.c b/src/target/target.c
index a99e981..36e63f9 100644
--- a/src/target/target.c
+++ b/src/target/target.c
@@ -796,7 +796,7 @@ static int target_soft_reset_halt(struct target *target)
int target_run_algorithm(struct target *target,
int num_mem_params, struct mem_param *mem_params,
int num_reg_params, struct reg_param *reg_param,
- uint32_t entry_point, uint32_t exit_point,
+ target_addr_t entry_point, target_addr_t exit_point,
int timeout_ms, void *arch_info)
{
int retval = ERROR_FAIL;
diff --git a/src/target/target.h b/src/target/target.h
index 8dde03d..160ac4a 100644
--- a/src/target/target.h
+++ b/src/target/target.h
@@ -533,7 +533,7 @@ int target_step(struct target *target,
int target_run_algorithm(struct target *target,
int num_mem_params, struct mem_param *mem_params,
int num_reg_params, struct reg_param *reg_param,
- uint32_t entry_point, uint32_t exit_point,
+ target_addr_t entry_point, target_addr_t exit_point,
int timeout_ms, void *arch_info);
/**