watchpoint_add() cleanup
[openocd.git] / src / target / target.c
index 16e36816b22c18b5a4b89aaff23af54f028d3d64..55fc2c8237ead31961d1a83aa5583bbcb2e5aeb9 100644 (file)
@@ -69,6 +69,7 @@ static int handle_fast_load_image_command(struct command_context_s *cmd_ctx, cha
 static int handle_fast_load_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
 
 static int jim_array2mem(Jim_Interp *interp, int argc, Jim_Obj *const *argv);
+static int jim_mcrmrc(Jim_Interp *interp, int argc, Jim_Obj *const *argv);
 static int jim_mem2array(Jim_Interp *interp, int argc, Jim_Obj *const *argv);
 static int jim_target(Jim_Interp *interp, int argc, Jim_Obj *const *argv);
 
@@ -157,7 +158,7 @@ static const Jim_Nvp nvp_target_event[] = {
        { .value = TARGET_EVENT_OLD_gdb_program_config , .name = "old-gdb_program_config" },
        { .value = TARGET_EVENT_OLD_pre_resume         , .name = "old-pre_resume" },
 
-       { .value = TARGET_EVENT_EARLY_HALTED, .name = "early-halted" },
+       { .value = TARGET_EVENT_GDB_HALT, .name = "gdb-halt" },
        { .value = TARGET_EVENT_HALTED, .name = "halted" },
        { .value = TARGET_EVENT_RESUMED, .name = "resumed" },
        { .value = TARGET_EVENT_RESUME_START, .name = "resume-start" },
@@ -269,8 +270,6 @@ static int new_target_number(void)
        return x + 1;
 }
 
-static int target_continuous_poll = 1;
-
 /* read a uint32_t from a buffer in target memory endianness */
 uint32_t target_buffer_get_u32(target_t *target, const uint8_t *buffer)
 {
@@ -380,24 +379,57 @@ target_t* get_current_target(command_context_t *cmd_ctx)
 
 int target_poll(struct target_s *target)
 {
+       int retval;
+
        /* We can't poll until after examine */
        if (!target_was_examined(target))
        {
                /* Fail silently lest we pollute the log */
                return ERROR_FAIL;
        }
-       return target->type->poll(target);
+
+       retval = target->type->poll(target);
+       if (retval != ERROR_OK)
+               return retval;
+
+       if (target->halt_issued)
+       {
+               if (target->state == TARGET_HALTED)
+               {
+                       target->halt_issued = false;
+               } else
+               {
+                       long long t = timeval_ms() - target->halt_issued_time;
+                       if (t>1000)
+                       {
+                               target->halt_issued = false;
+                               LOG_INFO("Halt timed out, wake up GDB.");
+                               target_call_event_callbacks(target, TARGET_EVENT_GDB_HALT);
+                       }
+               }
+       }
+
+       return ERROR_OK;
 }
 
 int target_halt(struct target_s *target)
 {
+       int retval;
        /* We can't poll until after examine */
        if (!target_was_examined(target))
        {
                LOG_ERROR("Target not examined yet");
                return ERROR_FAIL;
        }
-       return target->type->halt(target);
+
+       retval = target->type->halt(target);
+       if (retval != ERROR_OK)
+               return retval;
+
+       target->halt_issued = true;
+       target->halt_issued_time = timeval_ms();
+
+       return ERROR_OK;
 }
 
 int target_resume(struct target_s *target, int current, uint32_t address, int handle_breakpoints, int debug_execution)
@@ -436,13 +468,14 @@ int target_process_reset(struct command_context_s *cmd_ctx, enum target_reset_mo
         * more predictable, i.e. dr/irscan & pathmove in events will
         * not have JTAG operations injected into the middle of a sequence.
         */
-       int save_poll = target_continuous_poll;
-       target_continuous_poll = 0;
+       bool save_poll = jtag_poll_get_enabled();
+
+       jtag_poll_set_enabled(false);
 
        sprintf(buf, "ocd_process_reset %s", n->name);
        retval = Jim_Eval(interp, buf);
 
-       target_continuous_poll = save_poll;
+       jtag_poll_set_enabled(save_poll);
 
        if (retval != JIM_OK) {
                Jim_PrintErrorMessage(interp);
@@ -463,7 +496,13 @@ static int default_virt2phys(struct target_s *target, uint32_t virtual, uint32_t
 
 static int default_mmu(struct target_s *target, int *enabled)
 {
-       *enabled = 0;
+       LOG_ERROR("Not implemented.");
+       return ERROR_FAIL;
+}
+
+static int default_has_mmu(struct target_s *target, bool *has_mmu)
+{
+       *has_mmu = true;
        return ERROR_OK;
 }
 
@@ -569,11 +608,24 @@ int target_read_memory(struct target_s *target,
        return target->type->read_memory(target, address, size, count, buffer);
 }
 
+int target_read_phys_memory(struct target_s *target,
+               uint32_t address, uint32_t size, uint32_t count, uint8_t *buffer)
+{
+       return target->type->read_phys_memory(target, address, size, count, buffer);
+}
+
 int target_write_memory(struct target_s *target,
                uint32_t address, uint32_t size, uint32_t count, uint8_t *buffer)
 {
        return target->type->write_memory(target, address, size, count, buffer);
 }
+
+int target_write_phys_memory(struct target_s *target,
+               uint32_t address, uint32_t size, uint32_t count, uint8_t *buffer)
+{
+       return target->type->write_phys_memory(target, address, size, count, buffer);
+}
+
 int target_bulk_write_memory(struct target_s *target,
                uint32_t address, uint32_t count, uint8_t *buffer)
 {
@@ -642,6 +694,90 @@ void target_reset_examined(struct target_s *target)
 }
 
 
+
+static int default_mrc(struct target_s *target, int cpnum, uint32_t op1, uint32_t op2, uint32_t CRn, uint32_t CRm, uint32_t *value)
+{
+       LOG_ERROR("Not implemented");
+       return ERROR_FAIL;
+}
+
+static int default_mcr(struct target_s *target, int cpnum, uint32_t op1, uint32_t op2, uint32_t CRn, uint32_t CRm, uint32_t value)
+{
+       LOG_ERROR("Not implemented");
+       return ERROR_FAIL;
+}
+
+static int arm_cp_check(struct target_s *target, int cpnum, uint32_t op1, uint32_t op2, uint32_t CRn, uint32_t CRm)
+{
+       /* basic check */
+       if (!target_was_examined(target))
+       {
+               LOG_ERROR("Target not examined yet");
+               return ERROR_FAIL;
+       }
+
+       if ((cpnum <0) || (cpnum > 15))
+       {
+               LOG_ERROR("Illegal co-processor %d", cpnum);
+               return ERROR_FAIL;
+       }
+
+       return ERROR_OK;
+}
+
+int target_mrc(struct target_s *target, int cpnum, uint32_t op1, uint32_t op2, uint32_t CRn, uint32_t CRm, uint32_t *value)
+{
+       int retval;
+
+       retval = arm_cp_check(target, cpnum, op1, op2, CRn, CRm);
+       if (retval != ERROR_OK)
+               return retval;
+
+       return target->type->mrc(target, cpnum, op1, op2, CRn, CRm, value);
+}
+
+int target_mcr(struct target_s *target, int cpnum, uint32_t op1, uint32_t op2, uint32_t CRn, uint32_t CRm, uint32_t value)
+{
+       int retval;
+
+       retval = arm_cp_check(target, cpnum, op1, op2, CRn, CRm);
+       if (retval != ERROR_OK)
+               return retval;
+
+       return target->type->mcr(target, cpnum, op1, op2, CRn, CRm, value);
+}
+
+static int default_read_phys_memory(struct target_s *target, uint32_t address, uint32_t size, uint32_t count, uint8_t *buffer)
+{
+       int retval;
+       bool mmu;
+       retval = target->type->has_mmu(target, &mmu);
+       if (retval != ERROR_OK)
+               return retval;
+       if (mmu)
+       {
+               LOG_ERROR("Not implemented");
+               return ERROR_FAIL;
+       }
+       return target_read_memory(target, address, size, count, buffer);
+}
+
+static int default_write_phys_memory(struct target_s *target, uint32_t address, uint32_t size, uint32_t count, uint8_t *buffer)
+{
+       int retval;
+       bool mmu;
+       retval = target->type->has_mmu(target, &mmu);
+       if (retval != ERROR_OK)
+               return retval;
+       if (mmu)
+       {
+               LOG_ERROR("Not implemented");
+               return ERROR_FAIL;
+       }
+       return target_write_memory(target, address, size, count, buffer);
+}
+
+
 int target_init(struct command_context_s *cmd_ctx)
 {
        target_t *target = all_targets;
@@ -666,7 +802,28 @@ int target_init(struct command_context_s *cmd_ctx)
                {
                        target->type->virt2phys = default_virt2phys;
                }
-               target->type->virt2phys = default_virt2phys;
+
+               if (target->type->read_phys_memory == NULL)
+               {
+                       target->type->read_phys_memory = default_read_phys_memory;
+               }
+
+               if (target->type->write_phys_memory == NULL)
+               {
+                       target->type->write_phys_memory = default_write_phys_memory;
+               }
+
+               if (target->type->mcr == NULL)
+               {
+                       target->type->mcr = default_mcr;
+               }
+
+               if (target->type->mrc == NULL)
+               {
+                       target->type->mrc = default_mrc;
+               }
+
+
                /* a non-invasive way(in terms of patches) to add some code that
                 * runs before the type->write/read_memory implementation
                 */
@@ -683,6 +840,10 @@ int target_init(struct command_context_s *cmd_ctx)
                {
                        target->type->mmu = default_mmu;
                }
+               if (target->type->has_mmu == NULL)
+               {
+                       target->type->has_mmu = default_has_mmu;
+               }
                target = target->next;
        }
 
@@ -821,7 +982,7 @@ int target_call_event_callbacks(target_t *target, enum target_event event)
        if (event == TARGET_EVENT_HALTED)
        {
                /* execute early halted first */
-               target_call_event_callbacks(target, TARGET_EVENT_EARLY_HALTED);
+               target_call_event_callbacks(target, TARGET_EVENT_GDB_HALT);
        }
 
        LOG_DEBUG("target event %i (%s)",
@@ -924,13 +1085,29 @@ int target_alloc_working_area(struct target_s *target, uint32_t size, working_ar
                {
                        return retval;
                }
+
                if (enabled)
                {
-                       target->working_area = target->working_area_virt;
-               }
-               else
+                       if (target->working_area_phys_spec)
+                       {
+                               LOG_DEBUG("MMU disabled, using physical address for working memory 0x%08x", (unsigned)target->working_area_phys);
+                               target->working_area = target->working_area_phys;
+                       } else
+                       {
+                               LOG_ERROR("No working memory available. Specify -work-area-phys to target.");
+                               return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+                       }
+               } else
                {
-                       target->working_area = target->working_area_phys;
+                       if (target->working_area_virt_spec)
+                       {
+                               LOG_DEBUG("MMU enabled, using virtual address for working memory 0x%08x", (unsigned)target->working_area_virt);
+                               target->working_area = target->working_area_virt;
+                       } else
+                       {
+                               LOG_ERROR("No working memory available. Specify -work-area-virt to target.");
+                               return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+                       }
                }
        }
 
@@ -959,8 +1136,6 @@ int target_alloc_working_area(struct target_s *target, uint32_t size, working_ar
                uint32_t first_free = target->working_area;
                uint32_t free_size = target->working_area_size;
 
-               LOG_DEBUG("allocating new working area");
-
                c = target->working_areas;
                while (c)
                {
@@ -977,6 +1152,8 @@ int target_alloc_working_area(struct target_s *target, uint32_t size, working_ar
                        return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
                }
 
+               LOG_DEBUG("allocated new working area at address 0x%08x", (unsigned)first_free);
+
                new_wa = malloc(sizeof(working_area_t));
                new_wa->next = NULL;
                new_wa->size = size;
@@ -1241,7 +1418,7 @@ int target_read_buffer(struct target_s *target, uint32_t address, uint32_t size,
                address += aligned;
                size -= aligned;
        }
-       
+
        /*prevent byte access when possible (avoid AHB access limitations in some cases)*/
        if(size >=2)
        {
@@ -1483,6 +1660,9 @@ int target_register_user_commands(struct command_context_s *cmd_ctx)
        register_jim(cmd_ctx, "ocd_mem2array", jim_mem2array, "read memory and return as a TCL array for script processing <ARRAYNAME> <WIDTH = 32/16/8> <ADDRESS> <COUNT>");
        register_jim(cmd_ctx, "ocd_array2mem", jim_array2mem, "convert a TCL array to memory locations and write the values  <ARRAYNAME> <WIDTH = 32/16/8> <ADDRESS> <COUNT>");
 
+       register_jim(cmd_ctx, "mrc", jim_mcrmrc, "read coprocessor <cpnum> <op1> <op2> <CRn> <CRm>");
+       register_jim(cmd_ctx, "mcr", jim_mcrmrc, "write coprocessor <cpnum> <op1> <op2> <CRn> <CRm> <value>");
+
        register_command(cmd_ctx, NULL, "fast_load_image", handle_fast_load_image_command, COMMAND_ANY,
                        "same args as load_image, image stored in memory - mainly for profiling purposes");
 
@@ -1500,13 +1680,13 @@ int target_register_user_commands(struct command_context_s *cmd_ctx)
        register_command(cmd_ctx,  NULL, "reset", handle_reset_command, COMMAND_EXEC, "reset target [run | halt | init] - default is run");
        register_command(cmd_ctx,  NULL, "soft_reset_halt", handle_soft_reset_halt_command, COMMAND_EXEC, "halt the target and do a soft reset");
 
-       register_command(cmd_ctx,  NULL, "mdw", handle_md_command, COMMAND_EXEC, "display memory words <addr> [count]");
-       register_command(cmd_ctx,  NULL, "mdh", handle_md_command, COMMAND_EXEC, "display memory half-words <addr> [count]");
-       register_command(cmd_ctx,  NULL, "mdb", handle_md_command, COMMAND_EXEC, "display memory bytes <addr> [count]");
+       register_command(cmd_ctx,  NULL, "mdw", handle_md_command, COMMAND_EXEC, "display memory words [phys] <addr> [count]");
+       register_command(cmd_ctx,  NULL, "mdh", handle_md_command, COMMAND_EXEC, "display memory half-words [phys] <addr> [count]");
+       register_command(cmd_ctx,  NULL, "mdb", handle_md_command, COMMAND_EXEC, "display memory bytes [phys] <addr> [count]");
 
-       register_command(cmd_ctx,  NULL, "mww", handle_mw_command, COMMAND_EXEC, "write memory word <addr> <value> [count]");
-       register_command(cmd_ctx,  NULL, "mwh", handle_mw_command, COMMAND_EXEC, "write memory half-word <addr> <value> [count]");
-       register_command(cmd_ctx,  NULL, "mwb", handle_mw_command, COMMAND_EXEC, "write memory byte <addr> <value> [count]");
+       register_command(cmd_ctx,  NULL, "mww", handle_mw_command, COMMAND_EXEC, "write memory word [phys]  <addr> <value> [count]");
+       register_command(cmd_ctx,  NULL, "mwh", handle_mw_command, COMMAND_EXEC, "write memory half-word [phys]  <addr> <value> [count]");
+       register_command(cmd_ctx,  NULL, "mwb", handle_mw_command, COMMAND_EXEC, "write memory byte [phys] <addr> <value> [count]");
 
        register_command(cmd_ctx,  NULL, "bp",
                        handle_bp_command, COMMAND_EXEC,
@@ -1658,6 +1838,15 @@ static int sense_handler(void)
        return ERROR_OK;
 }
 
+static void target_call_event_callbacks_all(enum target_event e) {
+       target_t *target;
+       target = all_targets;
+       while (target) {
+               target_call_event_callbacks(target, e);
+               target = target->next;
+       }
+}
+
 /* process target state changes */
 int handle_target(void *priv)
 {
@@ -1676,6 +1865,7 @@ int handle_target(void *priv)
                int did_something = 0;
                if (runSrstAsserted)
                {
+                       target_call_event_callbacks_all(TARGET_EVENT_GDB_HALT);
                        Jim_Eval(interp, "srst_asserted");
                        did_something = 1;
                }
@@ -1686,6 +1876,7 @@ int handle_target(void *priv)
                }
                if (runPowerDropout)
                {
+                       target_call_event_callbacks_all(TARGET_EVENT_GDB_HALT);
                        Jim_Eval(interp, "power_dropout");
                        did_something = 1;
                }
@@ -1715,7 +1906,7 @@ int handle_target(void *priv)
         * Skip targets that are currently disabled.
         */
        for (target_t *target = all_targets;
-                       target_continuous_poll && target;
+                       is_jtag_poll_safe() && target;
                        target = target->next)
        {
                if (!target->tap->enabled)
@@ -1726,7 +1917,10 @@ int handle_target(void *priv)
                {
                        /* polling may fail silently until the target has been examined */
                        if ((retval = target_poll(target)) != ERROR_OK)
+                       {
+                               target_call_event_callbacks(target, TARGET_EVENT_GDB_HALT);
                                return retval;
+                       }
                }
        }
 
@@ -1754,6 +1948,8 @@ static int handle_reg_command(struct command_context_s *cmd_ctx, char *cmd, char
                {
                        int i;
 
+                       command_print(cmd_ctx, "===== %s", cache->name);
+
                        for (i = 0, reg = cache->reg_list;
                                        i < cache->num_regs;
                                        i++, reg++, count++)
@@ -1872,7 +2068,7 @@ static int handle_poll_command(struct command_context_s *cmd_ctx, char *cmd, cha
        if (argc == 0)
        {
                command_print(cmd_ctx, "background polling: %s",
-                               target_continuous_poll ?  "on" : "off");
+                               jtag_poll_get_enabled() ? "on" : "off");
                command_print(cmd_ctx, "TAP: %s (%s)",
                                target->tap->dotted_name,
                                target->tap->enabled ? "enabled" : "disabled");
@@ -1888,11 +2084,11 @@ static int handle_poll_command(struct command_context_s *cmd_ctx, char *cmd, cha
        {
                if (strcmp(args[0], "on") == 0)
                {
-                       target_continuous_poll = 1;
+                       jtag_poll_set_enabled(true);
                }
                else if (strcmp(args[0], "off") == 0)
                {
-                       target_continuous_poll = 0;
+                       jtag_poll_set_enabled(false);
                }
                else
                {
@@ -2138,6 +2334,22 @@ static int handle_md_command(struct command_context_s *cmd_ctx, char *cmd, char
        default: return ERROR_COMMAND_SYNTAX_ERROR;
        }
 
+       bool physical=strcmp(args[0], "phys")==0;
+       int (*fn)(struct target_s *target,
+                       uint32_t address, uint32_t size, uint32_t count, uint8_t *buffer);
+       if (physical)
+       {
+               argc--;
+               args++;
+               fn=target_read_phys_memory;
+       } else
+       {
+               fn=target_read_memory;
+       }
+       if ((argc < 1) || (argc > 2))
+       {
+               return ERROR_COMMAND_SYNTAX_ERROR;
+       }
        uint32_t address;
        int retval = parse_u32(args[0], &address);
        if (ERROR_OK != retval)
@@ -2154,8 +2366,7 @@ static int handle_md_command(struct command_context_s *cmd_ctx, char *cmd, char
        uint8_t *buffer = calloc(count, size);
 
        target_t *target = get_current_target(cmd_ctx);
-       retval = target_read_memory(target,
-                               address, size, count, buffer);
+       retval = fn(target, address, size, count, buffer);
        if (ERROR_OK == retval)
                handle_md_output(cmd_ctx, target, address, size, count, buffer);
 
@@ -2166,7 +2377,23 @@ static int handle_md_command(struct command_context_s *cmd_ctx, char *cmd, char
 
 static int handle_mw_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
 {
-        if ((argc < 2) || (argc > 3))
+       if (argc < 2)
+       {
+               return ERROR_COMMAND_SYNTAX_ERROR;
+       }
+       bool physical=strcmp(args[0], "phys")==0;
+       int (*fn)(struct target_s *target,
+                       uint32_t address, uint32_t size, uint32_t count, uint8_t *buffer);
+       if (physical)
+       {
+               argc--;
+               args++;
+               fn=target_write_phys_memory;
+       } else
+       {
+               fn=target_write_memory;
+       }
+       if ((argc < 2) || (argc > 3))
                return ERROR_COMMAND_SYNTAX_ERROR;
 
        uint32_t address;
@@ -2209,7 +2436,7 @@ static int handle_mw_command(struct command_context_s *cmd_ctx, char *cmd, char
        }
        for (unsigned i = 0; i < count; i++)
        {
-               retval = target_write_memory(target,
+               retval = fn(target,
                                address + i * wordsize, wordsize, 1, value_buf);
                if (ERROR_OK != retval)
                        return retval;
@@ -2761,7 +2988,8 @@ static int handle_wp_command(struct command_context_s *cmd_ctx, char *cmd, char
                break;
 
        default:
-               command_print(cmd_ctx, "usage: wp <address> <length> [r/w/a] [value] [mask]");
+               command_print(cmd_ctx, "usage: wp [address length "
+                               "[(r|w|a) [value [mask]]]]");
                return ERROR_COMMAND_SYNTAX_ERROR;
        }
 
@@ -3253,7 +3481,6 @@ static int jim_array2mem(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
 
        return target_array2mem(interp,target, argc-1, argv + 1);
 }
-
 static int target_array2mem(Jim_Interp *interp, target_t *target, int argc, Jim_Obj *const *argv)
 {
        long l;
@@ -3406,17 +3633,16 @@ void target_all_handle_event(enum target_event e)
        }
 }
 
+
+/* FIX? should we propagate errors here rather than printing them
+ * and continuing?
+ */
 void target_handle_event(target_t *target, enum target_event e)
 {
        target_event_action_t *teap;
-       int done;
-
-       teap = target->event_action;
 
-       done = 0;
-       while (teap) {
+       for (teap = target->event_action; teap != NULL; teap = teap->next) {
                if (teap->event == e) {
-                       done = 1;
                        LOG_DEBUG("target: (%d) %s (%s) event: %d (%s) action: %s",
                                           target->target_number,
                                           target->cmd_name,
@@ -3429,12 +3655,6 @@ void target_handle_event(target_t *target, enum target_event e)
                                Jim_PrintErrorMessage(interp);
                        }
                }
-               teap = teap->next;
-       }
-       if (!done) {
-               LOG_DEBUG("event: %d %s - no action",
-                                  e,
-                                  Jim_Nvp_value2name_simple(nvp_target_event, e)->name);
        }
 }
 
@@ -3600,6 +3820,7 @@ static int target_configure(Jim_GetOptInfo *goi, target_t *target)
                                        return e;
                                }
                                target->working_area_virt = w;
+                               target->working_area_virt_spec = true;
                        } else {
                                if (goi->argc != 0) {
                                        goto no_params;
@@ -3617,6 +3838,7 @@ static int target_configure(Jim_GetOptInfo *goi, target_t *target)
                                        return e;
                                }
                                target->working_area_phys = w;
+                               target->working_area_phys_spec = true;
                        } else {
                                if (goi->argc != 0) {
                                        goto no_params;
@@ -4058,11 +4280,11 @@ static int tcl_target_func(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
 
                /* do the assert */
                if (n->value == NVP_ASSERT) {
-                       target->type->assert_reset(target);
+                       e = target->type->assert_reset(target);
                } else {
-                       target->type->deassert_reset(target);
+                       e = target->type->deassert_reset(target);
                }
-               return JIM_OK;
+               return (e == ERROR_OK) ? JIM_OK : JIM_ERR;
        case TS_CMD_HALT:
                if (goi.argc) {
                        Jim_WrongNumArgs(goi.interp, 0, argv, "halt [no parameters]");
@@ -4070,8 +4292,8 @@ static int tcl_target_func(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
                }
                if (!target->tap->enabled)
                        goto err_tap_disabled;
-               target->type->halt(target);
-               return JIM_OK;
+               e = target->type->halt(target);
+               return (e == ERROR_OK) ? JIM_OK : JIM_ERR;
        case TS_CMD_WAITSTATE:
                /* params:  <name>  statename timeoutmsecs */
                if (goi.argc != 2) {
@@ -4234,6 +4456,8 @@ static int target_create(Jim_GetOptInfo *goi)
 
        target->display             = 1;
 
+       target->halt_issued                     = false;
+
        /* initialize trace information */
        target->trace_info = malloc(sizeof(trace_t));
        target->trace_info->num_trace_points         = 0;
@@ -4596,10 +4820,88 @@ static int handle_fast_load_command(struct command_context_s *cmd_ctx, char *cmd
        return retval;
 }
 
+static int jim_mcrmrc(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+       command_context_t *context;
+       target_t *target;
+       int retval;
 
-/*
- * Local Variables:
- * c-basic-offset: 4
- * tab-width: 4
- * End:
- */
+       context = Jim_GetAssocData(interp, "context");
+       if (context == NULL) {
+               LOG_ERROR("array2mem: no command context");
+               return JIM_ERR;
+       }
+       target = get_current_target(context);
+       if (target == NULL) {
+               LOG_ERROR("array2mem: no current target");
+               return JIM_ERR;
+       }
+
+       if ((argc < 6) || (argc > 7))
+       {
+               return JIM_ERR;
+       }
+
+       int cpnum;
+       uint32_t op1;
+       uint32_t op2;
+       uint32_t CRn;
+       uint32_t CRm;
+       uint32_t value;
+
+       int e;
+       long l;
+       e = Jim_GetLong(interp, argv[1], &l);
+       if (e != JIM_OK) {
+               return e;
+       }
+       cpnum = l;
+
+       e = Jim_GetLong(interp, argv[2], &l);
+       if (e != JIM_OK) {
+               return e;
+       }
+       op1 = l;
+
+       e = Jim_GetLong(interp, argv[3], &l);
+       if (e != JIM_OK) {
+               return e;
+       }
+       op2 = l;
+
+       e = Jim_GetLong(interp, argv[4], &l);
+       if (e != JIM_OK) {
+               return e;
+       }
+       CRn = l;
+
+       e = Jim_GetLong(interp, argv[5], &l);
+       if (e != JIM_OK) {
+               return e;
+       }
+       CRm = l;
+
+       value = 0;
+
+       if (argc == 7)
+       {
+               e = Jim_GetLong(interp, argv[6], &l);
+               if (e != JIM_OK) {
+                       return e;
+               }
+               value = l;
+
+               retval = target_mcr(target, cpnum, op1, op2, CRn, CRm, value);
+               if (retval != ERROR_OK)
+                       return JIM_ERR;
+       } else
+       {
+               retval = target_mrc(target, cpnum, op1, op2, CRn, CRm, &value);
+               if (retval != ERROR_OK)
+                       return JIM_ERR;
+
+               Jim_SetResult(interp, Jim_NewIntObj(interp, value));
+       }
+
+       return JIM_OK;
+}

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)