diff options
author | Tim Newsome <tim@sifive.com> | 2019-06-19 10:56:37 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-06-19 10:56:37 -0700 |
commit | bb03f79bde8eb3d3a2a5147876d42af7cebc247e (patch) | |
tree | 78081c386272d5255da9d7f03d8c415eccd2f58b /src | |
parent | c05ad1a92a9379295f2e0eef481e88e89e4eff6f (diff) | |
download | riscv-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.c | 2 | ||||
-rw-r--r-- | src/target/riscv/batch.c | 6 | ||||
-rw-r--r-- | src/target/riscv/riscv-013.c | 21 | ||||
-rw-r--r-- | src/target/riscv/riscv.c | 101 | ||||
-rw-r--r-- | src/target/target.c | 2 | ||||
-rw-r--r-- | src/target/target.h | 2 |
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(®_params[0], "a0", xlen, PARAM_IN_OUT); + init_reg_param(®_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(®_params[0]); + destroy_reg_param(®_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); /** |