Mac/PPC: Fix build.
[openocd.git] / src / target / target.c
index 942dbc1c38c1020fcbeee10fa4e1a5c75466fd0d..6f458bcebe63d378a3cda378a5c1957a84798a4a 100644 (file)
@@ -55,6 +55,7 @@
 #include "trace.h"
 #include "image.h"
 #include "rtos/rtos.h"
+#include "transport/transport.h"
 
 /* default halt wait timeout (ms) */
 #define DEFAULT_HALT_TIMEOUT 5000
@@ -88,7 +89,7 @@ extern struct target_type feroceon_target;
 extern struct target_type dragonite_target;
 extern struct target_type xscale_target;
 extern struct target_type cortexm_target;
-extern struct target_type cortexa8_target;
+extern struct target_type cortexa_target;
 extern struct target_type cortexr4_target;
 extern struct target_type arm11_target;
 extern struct target_type mips_m4k_target;
@@ -102,6 +103,7 @@ extern struct target_type nds32_v2_target;
 extern struct target_type nds32_v3_target;
 extern struct target_type nds32_v3m_target;
 extern struct target_type or1k_target;
+extern struct target_type quark_x10xx_target;
 
 static struct target_type *target_types[] = {
        &arm7tdmi_target,
@@ -116,7 +118,7 @@ static struct target_type *target_types[] = {
        &dragonite_target,
        &xscale_target,
        &cortexm_target,
-       &cortexa8_target,
+       &cortexa_target,
        &cortexr4_target,
        &arm11_target,
        &mips_m4k_target,
@@ -130,6 +132,7 @@ static struct target_type *target_types[] = {
        &nds32_v3_target,
        &nds32_v3m_target,
        &or1k_target,
+       &quark_x10xx_target,
        NULL,
 };
 
@@ -294,6 +297,15 @@ static int new_target_number(void)
        return x + 1;
 }
 
+/* read a uint64_t from a buffer in target memory endianness */
+uint64_t target_buffer_get_u64(struct target *target, const uint8_t *buffer)
+{
+       if (target->endianness == TARGET_LITTLE_ENDIAN)
+               return le_to_h_u64(buffer);
+       else
+               return be_to_h_u64(buffer);
+}
+
 /* read a uint32_t from a buffer in target memory endianness */
 uint32_t target_buffer_get_u32(struct target *target, const uint8_t *buffer)
 {
@@ -327,6 +339,15 @@ static uint8_t target_buffer_get_u8(struct target *target, const uint8_t *buffer
        return *buffer & 0x0ff;
 }
 
+/* write a uint64_t to a buffer in target memory endianness */
+void target_buffer_set_u64(struct target *target, uint8_t *buffer, uint64_t value)
+{
+       if (target->endianness == TARGET_LITTLE_ENDIAN)
+               h_u64_to_le(buffer, value);
+       else
+               h_u64_to_be(buffer, value);
+}
+
 /* write a uint32_t to a buffer in target memory endianness */
 void target_buffer_set_u32(struct target *target, uint8_t *buffer, uint32_t value)
 {
@@ -360,6 +381,14 @@ static void target_buffer_set_u8(struct target *target, uint8_t *buffer, uint8_t
        *buffer = value;
 }
 
+/* write a uint64_t array to a buffer in target memory endianness */
+void target_buffer_get_u64_array(struct target *target, const uint8_t *buffer, uint32_t count, uint64_t *dstbuf)
+{
+       uint32_t i;
+       for (i = 0; i < count; i++)
+               dstbuf[i] = target_buffer_get_u64(target, &buffer[i * 8]);
+}
+
 /* write a uint32_t array to a buffer in target memory endianness */
 void target_buffer_get_u32_array(struct target *target, const uint8_t *buffer, uint32_t count, uint32_t *dstbuf)
 {
@@ -376,8 +405,16 @@ void target_buffer_get_u16_array(struct target *target, const uint8_t *buffer, u
                dstbuf[i] = target_buffer_get_u16(target, &buffer[i * 2]);
 }
 
+/* write a uint64_t array to a buffer in target memory endianness */
+void target_buffer_set_u64_array(struct target *target, uint8_t *buffer, uint32_t count, const uint64_t *srcbuf)
+{
+       uint32_t i;
+       for (i = 0; i < count; i++)
+               target_buffer_set_u64(target, &buffer[i * 8], srcbuf[i]);
+}
+
 /* write a uint32_t array to a buffer in target memory endianness */
-void target_buffer_set_u32_array(struct target *target, uint8_t *buffer, uint32_t count, uint32_t *srcbuf)
+void target_buffer_set_u32_array(struct target *target, uint8_t *buffer, uint32_t count, const uint32_t *srcbuf)
 {
        uint32_t i;
        for (i = 0; i < count; i++)
@@ -385,7 +422,7 @@ void target_buffer_set_u32_array(struct target *target, uint8_t *buffer, uint32_
 }
 
 /* write a uint16_t array to a buffer in target memory endianness */
-void target_buffer_set_u16_array(struct target *target, uint8_t *buffer, uint32_t count, uint16_t *srcbuf)
+void target_buffer_set_u16_array(struct target *target, uint8_t *buffer, uint32_t count, const uint16_t *srcbuf)
 {
        uint32_t i;
        for (i = 0; i < count; i++)
@@ -817,7 +854,7 @@ done:
  */
 
 int target_run_flash_async_algorithm(struct target *target,
-               uint8_t *buffer, uint32_t count, int block_size,
+               const uint8_t *buffer, uint32_t count, int block_size,
                int num_mem_params, struct mem_param *mem_params,
                int num_reg_params, struct reg_param *reg_params,
                uint32_t buffer_start, uint32_t buffer_size,
@@ -826,6 +863,8 @@ int target_run_flash_async_algorithm(struct target *target,
        int retval;
        int timeout = 0;
 
+       const uint8_t *buffer_orig = buffer;
+
        /* Set up working area. First word is write pointer, second word is read pointer,
         * rest is fifo data area. */
        uint32_t wp_addr = buffer_start;
@@ -866,7 +905,8 @@ int target_run_flash_async_algorithm(struct target *target,
                        break;
                }
 
-               LOG_DEBUG("count 0x%" PRIx32 " wp 0x%" PRIx32 " rp 0x%" PRIx32, count, wp, rp);
+               LOG_DEBUG("offs 0x%zx count 0x%" PRIx32 " wp 0x%" PRIx32 " rp 0x%" PRIx32,
+                       (size_t) (buffer - buffer_orig), count, wp, rp);
 
                if (rp == 0) {
                        LOG_ERROR("flash write algorithm aborted by target");
@@ -1238,6 +1278,10 @@ COMMAND_HANDLER(handle_target_init_command)
        if (ERROR_OK != retval)
                return retval;
 
+       retval = command_run_line(CMD_CTX, "init_target_events");
+       if (ERROR_OK != retval)
+               return retval;
+
        retval = command_run_line(CMD_CTX, "init_board");
        if (ERROR_OK != retval)
                return retval;
@@ -1325,7 +1369,7 @@ int target_unregister_event_callback(int (*callback)(struct target *target,
        return ERROR_OK;
 }
 
-static int target_unregister_timer_callback(int (*callback)(void *priv), void *priv)
+int target_unregister_timer_callback(int (*callback)(void *priv), void *priv)
 {
        struct target_timer_callback **p = &target_timer_callbacks;
        struct target_timer_callback *c = target_timer_callbacks;
@@ -1796,7 +1840,7 @@ static int target_profiling_default(struct target *target, uint32_t *samples,
                gettimeofday(&now, NULL);
                if ((sample_count >= max_num_samples) ||
                        ((now.tv_sec >= timeout.tv_sec) && (now.tv_usec >= timeout.tv_usec))) {
-                       LOG_INFO("Profiling completed. %d samples.", sample_count);
+                       LOG_INFO("Profiling completed. %" PRIu32 " samples.", sample_count);
                        break;
                }
        }
@@ -1983,6 +2027,30 @@ int target_blank_check_memory(struct target *target, uint32_t address, uint32_t
        return retval;
 }
 
+int target_read_u64(struct target *target, uint64_t address, uint64_t *value)
+{
+       uint8_t value_buf[8];
+       if (!target_was_examined(target)) {
+               LOG_ERROR("Target not examined yet");
+               return ERROR_FAIL;
+       }
+
+       int retval = target_read_memory(target, address, 8, 1, value_buf);
+
+       if (retval == ERROR_OK) {
+               *value = target_buffer_get_u64(target, value_buf);
+               LOG_DEBUG("address: 0x%" PRIx64 ", value: 0x%16.16" PRIx64 "",
+                                 address,
+                                 *value);
+       } else {
+               *value = 0x0;
+               LOG_DEBUG("address: 0x%" PRIx64 " failed",
+                                 address);
+       }
+
+       return retval;
+}
+
 int target_read_u32(struct target *target, uint32_t address, uint32_t *value)
 {
        uint8_t value_buf[4];
@@ -2053,6 +2121,27 @@ int target_read_u8(struct target *target, uint32_t address, uint8_t *value)
        return retval;
 }
 
+int target_write_u64(struct target *target, uint64_t address, uint64_t value)
+{
+       int retval;
+       uint8_t value_buf[8];
+       if (!target_was_examined(target)) {
+               LOG_ERROR("Target not examined yet");
+               return ERROR_FAIL;
+       }
+
+       LOG_DEBUG("address: 0x%" PRIx64 ", value: 0x%16.16" PRIx64 "",
+                         address,
+                         value);
+
+       target_buffer_set_u64(target, value_buf, value);
+       retval = target_write_memory(target, address, 8, 1, value_buf);
+       if (retval != ERROR_OK)
+               LOG_DEBUG("failed: %i", retval);
+
+       return retval;
+}
+
 int target_write_u32(struct target *target, uint32_t address, uint32_t value)
 {
        int retval;
@@ -2298,6 +2387,10 @@ static int handle_target(void *priv)
        for (struct target *target = all_targets;
                        is_jtag_poll_safe() && target;
                        target = target->next) {
+
+               if (!target_was_examined(target))
+                       continue;
+
                if (!target->tap->enabled)
                        continue;
 
@@ -2329,8 +2422,18 @@ static int handle_target(void *priv)
                                return retval;
                        }
                        /* Since we succeeded, we reset backoff count */
-                       if (target->backoff.times > 0)
-                               LOG_USER("Polling target %s succeeded again", target_name(target));
+                       if (target->backoff.times > 0) {
+                               LOG_USER("Polling target %s succeeded again, trying to reexamine", target_name(target));
+                               target_reset_examined(target);
+                               retval = target_examine_one(target);
+                               /* Target examination could have failed due to unstable connection,
+                                * but we set the examined flag anyway to repoll it later */
+                               if (retval != ERROR_OK) {
+                                       target->examined = true;
+                                       return retval;
+                               }
+                       }
+
                        target->backoff.times = 0;
                }
        }
@@ -3101,7 +3204,7 @@ static COMMAND_HELPER(handle_verify_image_command_internal, int verify)
                                if (diffs == 0)
                                        LOG_ERROR("checksum mismatch - attempting binary compare");
 
-                               data = (uint8_t *)malloc(buf_cnt);
+                               data = malloc(buf_cnt);
 
                                /* Can we use 32bit word accesses? */
                                int size = 1;
@@ -3533,29 +3636,30 @@ COMMAND_HANDLER(handle_profile_command)
 
        const uint32_t MAX_PROFILE_SAMPLE_NUM = 10000;
        uint32_t offset;
-       uint32_t num_of_sampels;
+       uint32_t num_of_samples;
        int retval = ERROR_OK;
+
+       COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], offset);
+
        uint32_t *samples = malloc(sizeof(uint32_t) * MAX_PROFILE_SAMPLE_NUM);
        if (samples == NULL) {
                LOG_ERROR("No memory to store samples.");
                return ERROR_FAIL;
        }
 
-       COMMAND_PARSE_NUMBER(uint, CMD_ARGV[0], offset);
-
        /**
         * Some cores let us sample the PC without the
         * annoying halt/resume step; for example, ARMv7 PCSR.
         * Provide a way to use that more efficient mechanism.
         */
        retval = target_profiling(target, samples, MAX_PROFILE_SAMPLE_NUM,
-                               &num_of_sampels, offset);
+                               &num_of_samples, offset);
        if (retval != ERROR_OK) {
                free(samples);
                return retval;
        }
 
-       assert(num_of_sampels <= MAX_PROFILE_SAMPLE_NUM);
+       assert(num_of_samples <= MAX_PROFILE_SAMPLE_NUM);
 
        retval = target_poll(target);
        if (retval != ERROR_OK) {
@@ -3581,11 +3685,11 @@ COMMAND_HANDLER(handle_profile_command)
        bool with_range = false;
        if (CMD_ARGC == 4) {
                with_range = true;
-               COMMAND_PARSE_NUMBER(uint, CMD_ARGV[2], start_address);
-               COMMAND_PARSE_NUMBER(uint, CMD_ARGV[3], end_address);
+               COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], start_address);
+               COMMAND_PARSE_NUMBER(u32, CMD_ARGV[3], end_address);
        }
 
-       write_gmon(samples, num_of_sampels, CMD_ARGV[1],
+       write_gmon(samples, num_of_samples, CMD_ARGV[1],
                        with_range, start_address, end_address);
        command_print(CMD_CTX, "Wrote %s", CMD_ARGV[1]);
 
@@ -3767,6 +3871,7 @@ static int target_mem2array(Jim_Interp *interp, struct target *target, int argc,
                                new_int_array_element(interp, varname, n, v);
                        }
                        len -= count;
+                       addr += count * width;
                }
        }
 
@@ -3960,6 +4065,7 @@ static int target_array2mem(Jim_Interp *interp, struct target *target,
                        e = JIM_ERR;
                        break;
                }
+               addr += count * width;
        }
 
        free(buffer);
@@ -4015,7 +4121,6 @@ enum target_cfg_param {
        TCFG_WORK_AREA_SIZE,
        TCFG_WORK_AREA_BACKUP,
        TCFG_ENDIAN,
-       TCFG_VARIANT,
        TCFG_COREID,
        TCFG_CHAIN_POSITION,
        TCFG_DBGBASE,
@@ -4030,7 +4135,6 @@ static Jim_Nvp nvp_config_opts[] = {
        { .name = "-work-area-size",   .value = TCFG_WORK_AREA_SIZE },
        { .name = "-work-area-backup", .value = TCFG_WORK_AREA_BACKUP },
        { .name = "-endian" ,          .value = TCFG_ENDIAN },
-       { .name = "-variant",          .value = TCFG_VARIANT },
        { .name = "-coreid",           .value = TCFG_COREID },
        { .name = "-chain-position",   .value = TCFG_CHAIN_POSITION },
        { .name = "-dbgbase",          .value = TCFG_DBGBASE },
@@ -4043,7 +4147,6 @@ static int target_configure(Jim_GetOptInfo *goi, struct target *target)
        Jim_Nvp *n;
        Jim_Obj *o;
        jim_wide w;
-       char *cp;
        int e;
 
        /* parse config or cget options ... */
@@ -4252,28 +4355,6 @@ no_params:
                        /* loop for more */
                        break;
 
-               case TCFG_VARIANT:
-                       if (goi->isconfigure) {
-                               if (goi->argc < 1) {
-                                       Jim_SetResultFormatted(goi->interp,
-                                                                                  "%s ?STRING?",
-                                                                                  n->name);
-                                       return JIM_ERR;
-                               }
-                               if (target->variant)
-                                       free((void *)(target->variant));
-                               e = Jim_GetOpt_String(goi, &cp, NULL);
-                               if (e != JIM_OK)
-                                       return e;
-                               target->variant = strdup(cp);
-                       } else {
-                               if (goi->argc != 0)
-                                       goto no_params;
-                       }
-                       Jim_SetResultString(goi->interp, target->variant, -1);
-                       /* loop for more */
-                       break;
-
                case TCFG_COREID:
                        if (goi->isconfigure) {
                                e = Jim_GetOpt_Wide(goi, &w);
@@ -4971,6 +5052,15 @@ static int target_create(Jim_GetOptInfo *goi)
        if (e != JIM_OK)
                return e;
        cp = cp2;
+       struct transport *tr = get_current_transport();
+       if (tr->override_target) {
+               e = tr->override_target(&cp);
+               if (e != ERROR_OK) {
+                       LOG_ERROR("The selected transport doesn't support this target");
+                       return JIM_ERR;
+               }
+               LOG_INFO("The selected transport took over low-level target control. The results might differ compared to plain JTAG/SWD");
+       }
        /* now does target type exist */
        for (x = 0 ; target_types[x] ; x++) {
                if (0 == strcmp(cp, target_types[x]->name)) {
@@ -5009,9 +5099,10 @@ static int target_create(Jim_GetOptInfo *goi)
        target = calloc(1, sizeof(struct target));
        /* set target number */
        target->target_number = new_target_number();
+       cmd_ctx->current_target = target->target_number;
 
        /* allocate memory for each unique target type */
-       target->type = (struct target_type *)calloc(1, sizeof(struct target_type));
+       target->type = calloc(1, sizeof(struct target_type));
 
        memcpy(target->type, target_types[x], sizeof(struct target_type));
 
@@ -5076,10 +5167,6 @@ static int target_create(Jim_GetOptInfo *goi)
                target->endianness = TARGET_LITTLE_ENDIAN;
        }
 
-       /* incase variant is not set */
-       if (!target->variant)
-               target->variant = strdup("");
-
        cp = Jim_GetString(new_cmd, NULL);
        target->cmd_name = strdup(cp);
 
@@ -5397,7 +5484,7 @@ COMMAND_HANDLER(handle_fast_load_image_command)
        image_size = 0x0;
        retval = ERROR_OK;
        fastload_num = image.num_sections;
-       fastload = (struct FastLoad *)malloc(sizeof(struct FastLoad)*image.num_sections);
+       fastload = malloc(sizeof(struct FastLoad)*image.num_sections);
        if (fastload == NULL) {
                command_print(CMD_CTX, "out of memory");
                image_close(&image);
@@ -5439,7 +5526,7 @@ COMMAND_HANDLER(handle_fast_load_image_command)
                        fastload[i].data = malloc(length);
                        if (fastload[i].data == NULL) {
                                free(buffer);
-                               command_print(CMD_CTX, "error allocating buffer for section (%d bytes)",
+                               command_print(CMD_CTX, "error allocating buffer for section (%" PRIu32 " bytes)",
                                                          length);
                                retval = ERROR_FAIL;
                                break;
@@ -5562,6 +5649,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 %" PRIu32 " 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 %" PRIu32 " 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[] = {
        {
                .name = "fast_load_image",
@@ -5599,9 +5878,9 @@ static const struct command_registration target_exec_command_handlers[] = {
                .name = "reg",
                .handler = handle_reg_command,
                .mode = COMMAND_EXEC,
-               .help = "display or set a register; with no arguments, "
-                       "displays all registers and their values",
-               .usage = "[(register_name|register_number) [value]]",
+               .help = "display (reread from target with \"force\") or set a register; "
+                       "with no arguments, displays all registers and their values",
+               .usage = "[(register_number|register_name) [(value|'force')]]",
        },
        {
                .name = "poll",
@@ -5781,6 +6060,13 @@ static const struct command_registration target_exec_command_handlers[] = {
                .help = "list all tasks ",
                .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
 };

Linking to existing account procedure

If you already have an account and want to add another login method you MUST first sign in with your existing account and then change URL to read https://review.openocd.org/login/?link to get to this page again but this time it'll work for linking. Thank you.

SSH host keys fingerprints

1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=..              |
|+o..   .         |
|*.o   . .        |
|+B . . .         |
|Bo. = o S        |
|Oo.+ + =         |
|oB=.* = . o      |
| =+=.+   + E     |
|. .=o   . o      |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)