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
This commit is contained in:
Tim Newsome
2019-06-19 10:56:37 -07:00
committed by GitHub
parent c05ad1a92a
commit bb03f79bde
10 changed files with 413 additions and 21 deletions
+1 -1
View File
@@ -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;
+1 -5
View File
@@ -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++;
}
+20 -1
View File
@@ -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)
+93 -8
View File
@@ -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 ***/
+1 -1
View File
@@ -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;
+1 -1
View File
@@ -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);
/**