target: Add test bench for memory access functions
Change-Id: I86e6fe4d0b4d580389ae5e1d3f4813d1e25b2613 Signed-off-by: Andreas Fritiofson <andreas.fritiofson@gmail.com> Reviewed-on: http://openocd.zylin.com/1629 Tested-by: jenkins Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>__archive__
parent
cb6836f923
commit
e65817653f
|
@ -5642,6 +5642,198 @@ COMMAND_HANDLER(handle_ps_command)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void binprint(struct command_context *cmd_ctx, const char *text, const uint8_t *buf, int size)
|
||||||
|
{
|
||||||
|
if (text != NULL)
|
||||||
|
command_print_sameline(cmd_ctx, "%s", text);
|
||||||
|
for (int i = 0; i < size; i++)
|
||||||
|
command_print_sameline(cmd_ctx, " %02x", buf[i]);
|
||||||
|
command_print(cmd_ctx, " ");
|
||||||
|
}
|
||||||
|
|
||||||
|
COMMAND_HANDLER(handle_test_mem_access_command)
|
||||||
|
{
|
||||||
|
struct target *target = get_current_target(CMD_CTX);
|
||||||
|
uint32_t test_size;
|
||||||
|
int retval = ERROR_OK;
|
||||||
|
|
||||||
|
if (target->state != TARGET_HALTED) {
|
||||||
|
LOG_INFO("target not halted !!");
|
||||||
|
return ERROR_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (CMD_ARGC != 1)
|
||||||
|
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||||
|
|
||||||
|
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], test_size);
|
||||||
|
|
||||||
|
/* Test reads */
|
||||||
|
size_t num_bytes = test_size + 4;
|
||||||
|
|
||||||
|
struct working_area *wa = NULL;
|
||||||
|
retval = target_alloc_working_area(target, num_bytes, &wa);
|
||||||
|
if (retval != ERROR_OK) {
|
||||||
|
LOG_ERROR("Not enough working area");
|
||||||
|
return ERROR_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t *test_pattern = malloc(num_bytes);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < num_bytes; i++)
|
||||||
|
test_pattern[i] = rand();
|
||||||
|
|
||||||
|
retval = target_write_memory(target, wa->address, 1, num_bytes, test_pattern);
|
||||||
|
if (retval != ERROR_OK) {
|
||||||
|
LOG_ERROR("Test pattern write failed");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int host_offset = 0; host_offset <= 1; host_offset++) {
|
||||||
|
for (int size = 1; size <= 4; size *= 2) {
|
||||||
|
for (int offset = 0; offset < 4; offset++) {
|
||||||
|
uint32_t count = test_size / size;
|
||||||
|
size_t host_bufsiz = (count + 2) * size + host_offset;
|
||||||
|
uint8_t *read_ref = malloc(host_bufsiz);
|
||||||
|
uint8_t *read_buf = malloc(host_bufsiz);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < host_bufsiz; i++) {
|
||||||
|
read_ref[i] = rand();
|
||||||
|
read_buf[i] = read_ref[i];
|
||||||
|
}
|
||||||
|
command_print_sameline(CMD_CTX,
|
||||||
|
"Test read %d x %d @ %d to %saligned buffer: ", count,
|
||||||
|
size, offset, host_offset ? "un" : "");
|
||||||
|
|
||||||
|
struct duration bench;
|
||||||
|
duration_start(&bench);
|
||||||
|
|
||||||
|
retval = target_read_memory(target, wa->address + offset, size, count,
|
||||||
|
read_buf + size + host_offset);
|
||||||
|
|
||||||
|
duration_measure(&bench);
|
||||||
|
|
||||||
|
if (retval == ERROR_TARGET_UNALIGNED_ACCESS) {
|
||||||
|
command_print(CMD_CTX, "Unsupported alignment");
|
||||||
|
goto next;
|
||||||
|
} else if (retval != ERROR_OK) {
|
||||||
|
command_print(CMD_CTX, "Memory read failed");
|
||||||
|
goto next;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* replay on host */
|
||||||
|
memcpy(read_ref + size + host_offset, test_pattern + offset, count * size);
|
||||||
|
|
||||||
|
/* check result */
|
||||||
|
int result = memcmp(read_ref, read_buf, host_bufsiz);
|
||||||
|
if (result == 0) {
|
||||||
|
command_print(CMD_CTX, "Pass in %fs (%0.3f KiB/s)",
|
||||||
|
duration_elapsed(&bench),
|
||||||
|
duration_kbps(&bench, count * size));
|
||||||
|
} else {
|
||||||
|
command_print(CMD_CTX, "Compare failed");
|
||||||
|
binprint(CMD_CTX, "ref:", read_ref, host_bufsiz);
|
||||||
|
binprint(CMD_CTX, "buf:", read_buf, host_bufsiz);
|
||||||
|
}
|
||||||
|
next:
|
||||||
|
free(read_ref);
|
||||||
|
free(read_buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
free(test_pattern);
|
||||||
|
|
||||||
|
if (wa != NULL)
|
||||||
|
target_free_working_area(target, wa);
|
||||||
|
|
||||||
|
/* Test writes */
|
||||||
|
num_bytes = test_size + 4 + 4 + 4;
|
||||||
|
|
||||||
|
retval = target_alloc_working_area(target, num_bytes, &wa);
|
||||||
|
if (retval != ERROR_OK) {
|
||||||
|
LOG_ERROR("Not enough working area");
|
||||||
|
return ERROR_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
test_pattern = malloc(num_bytes);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < num_bytes; i++)
|
||||||
|
test_pattern[i] = rand();
|
||||||
|
|
||||||
|
for (int host_offset = 0; host_offset <= 1; host_offset++) {
|
||||||
|
for (int size = 1; size <= 4; size *= 2) {
|
||||||
|
for (int offset = 0; offset < 4; offset++) {
|
||||||
|
uint32_t count = test_size / size;
|
||||||
|
size_t host_bufsiz = count * size + host_offset;
|
||||||
|
uint8_t *read_ref = malloc(num_bytes);
|
||||||
|
uint8_t *read_buf = malloc(num_bytes);
|
||||||
|
uint8_t *write_buf = malloc(host_bufsiz);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < host_bufsiz; i++)
|
||||||
|
write_buf[i] = rand();
|
||||||
|
command_print_sameline(CMD_CTX,
|
||||||
|
"Test write %d x %d @ %d from %saligned buffer: ", count,
|
||||||
|
size, offset, host_offset ? "un" : "");
|
||||||
|
|
||||||
|
retval = target_write_memory(target, wa->address, 1, num_bytes, test_pattern);
|
||||||
|
if (retval != ERROR_OK) {
|
||||||
|
command_print(CMD_CTX, "Test pattern write failed");
|
||||||
|
goto nextw;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* replay on host */
|
||||||
|
memcpy(read_ref, test_pattern, num_bytes);
|
||||||
|
memcpy(read_ref + size + offset, write_buf + host_offset, count * size);
|
||||||
|
|
||||||
|
struct duration bench;
|
||||||
|
duration_start(&bench);
|
||||||
|
|
||||||
|
retval = target_write_memory(target, wa->address + size + offset, size, count,
|
||||||
|
write_buf + host_offset);
|
||||||
|
|
||||||
|
duration_measure(&bench);
|
||||||
|
|
||||||
|
if (retval == ERROR_TARGET_UNALIGNED_ACCESS) {
|
||||||
|
command_print(CMD_CTX, "Unsupported alignment");
|
||||||
|
goto nextw;
|
||||||
|
} else if (retval != ERROR_OK) {
|
||||||
|
command_print(CMD_CTX, "Memory write failed");
|
||||||
|
goto nextw;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* read back */
|
||||||
|
retval = target_read_memory(target, wa->address, 1, num_bytes, read_buf);
|
||||||
|
if (retval != ERROR_OK) {
|
||||||
|
command_print(CMD_CTX, "Test pattern write failed");
|
||||||
|
goto nextw;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* check result */
|
||||||
|
int result = memcmp(read_ref, read_buf, num_bytes);
|
||||||
|
if (result == 0) {
|
||||||
|
command_print(CMD_CTX, "Pass in %fs (%0.3f KiB/s)",
|
||||||
|
duration_elapsed(&bench),
|
||||||
|
duration_kbps(&bench, count * size));
|
||||||
|
} else {
|
||||||
|
command_print(CMD_CTX, "Compare failed");
|
||||||
|
binprint(CMD_CTX, "ref:", read_ref, num_bytes);
|
||||||
|
binprint(CMD_CTX, "buf:", read_buf, num_bytes);
|
||||||
|
}
|
||||||
|
nextw:
|
||||||
|
free(read_ref);
|
||||||
|
free(read_buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
free(test_pattern);
|
||||||
|
|
||||||
|
if (wa != NULL)
|
||||||
|
target_free_working_area(target, wa);
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
static const struct command_registration target_exec_command_handlers[] = {
|
static const struct command_registration target_exec_command_handlers[] = {
|
||||||
{
|
{
|
||||||
.name = "fast_load_image",
|
.name = "fast_load_image",
|
||||||
|
@ -5861,6 +6053,13 @@ static const struct command_registration target_exec_command_handlers[] = {
|
||||||
.help = "list all tasks ",
|
.help = "list all tasks ",
|
||||||
.usage = " ",
|
.usage = " ",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
.name = "test_mem_access",
|
||||||
|
.handler = handle_test_mem_access_command,
|
||||||
|
.mode = COMMAND_EXEC,
|
||||||
|
.help = "Test the target's memory access functions",
|
||||||
|
.usage = "size",
|
||||||
|
},
|
||||||
|
|
||||||
COMMAND_REGISTRATION_DONE
|
COMMAND_REGISTRATION_DONE
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue