forked from auracaster/openocd
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:
+1
-1
@@ -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;
|
||||
|
||||
@@ -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++;
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 ***/
|
||||
|
||||
+1
-1
@@ -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
@@ -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);
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user