]> git.sur5r.net Git - openocd/blobdiff - src/target/target.c
Overhaul time support API
[openocd] / src / target / target.c
index 7689c5e64ae1bb3e088ebc84c8eb910f71958c94..3e4c00d0b96007dcaa20fe62228b4ba276ab2ac4 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);
 
@@ -84,6 +85,7 @@ extern target_type_t arm966e_target;
 extern target_type_t arm926ejs_target;
 extern target_type_t fa526_target;
 extern target_type_t feroceon_target;
+extern target_type_t dragonite_target;
 extern target_type_t xscale_target;
 extern target_type_t cortexm3_target;
 extern target_type_t cortexa8_target;
@@ -101,6 +103,7 @@ target_type_t *target_types[] =
        &arm926ejs_target,
        &fa526_target,
        &feroceon_target,
+       &dragonite_target,
        &xscale_target,
        &cortexm3_target,
        &cortexa8_target,
@@ -155,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" },
@@ -267,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)
 {
@@ -378,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)
@@ -434,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);
@@ -461,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;
 }
 
@@ -567,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)
 {
@@ -640,6 +694,114 @@ 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;
+       }
+
+       if (op1 > 7)
+       {
+               LOG_ERROR("Illegal op1");
+               return ERROR_FAIL;
+       }
+
+       if (op2 > 7)
+       {
+               LOG_ERROR("Illegal op2");
+               return ERROR_FAIL;
+       }
+
+       if (CRn > 15)
+       {
+               LOG_ERROR("Illegal CRn");
+               return ERROR_FAIL;
+       }
+
+       if (CRm > 15)
+       {
+               LOG_ERROR("Illegal CRm");
+               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;
@@ -664,7 +826,39 @@ 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;
+               } else
+               {
+                       /* FIX! multiple targets will generally register global commands
+                        * multiple times. Only register this one if *one* of the
+                        * targets need the command. Hmm... make it a command on the
+                        * Jim Tcl target object?
+                        */
+                       register_jim(cmd_ctx, "mcr", jim_mcrmrc, "write coprocessor <cpnum> <op1> <op2> <CRn> <CRm> <value>");
+               }
+
+               if (target->type->mrc == NULL)
+               {
+                       target->type->mrc = default_mrc;
+               } else
+               {
+                       register_jim(cmd_ctx, "mrc", jim_mcrmrc, "read coprocessor <cpnum> <op1> <op2> <CRn> <CRm>");
+               }
+
+
                /* a non-invasive way(in terms of patches) to add some code that
                 * runs before the type->write/read_memory implementation
                 */
@@ -681,6 +875,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;
        }
 
@@ -819,7 +1017,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)",
@@ -917,18 +1115,35 @@ int target_alloc_working_area(struct target_s *target, uint32_t size, working_ar
        {
                int retval;
                int enabled;
+
                retval = target->type->mmu(target, &enabled);
                if (retval != ERROR_OK)
                {
                        return retval;
                }
-               if (enabled)
-               {
-                       target->working_area = target->working_area_virt;
-               }
-               else
-               {
-                       target->working_area = target->working_area_phys;
+
+               if (!enabled) {
+                       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 {
+                       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;
+                       }
                }
        }
 
@@ -957,8 +1172,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)
                {
@@ -975,6 +1188,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;
@@ -1239,7 +1454,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)
        {
@@ -1498,13 +1713,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,
@@ -1656,6 +1871,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)
 {
@@ -1674,6 +1898,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;
                }
@@ -1684,6 +1909,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;
                }
@@ -1713,7 +1939,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)
@@ -1724,7 +1950,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;
+                       }
                }
        }
 
@@ -1752,6 +1981,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++)
@@ -1784,9 +2015,7 @@ static int handle_reg_command(struct command_context_s *cmd_ctx, char *cmd, char
        if ((args[0][0] >= '0') && (args[0][0] <= '9'))
        {
                unsigned num;
-               int retval = parse_uint(args[0], &num);
-               if (ERROR_OK != retval)
-                       return ERROR_COMMAND_SYNTAX_ERROR;
+               COMMAND_PARSE_NUMBER(uint, args[0], num);
 
                reg_cache_t *cache = target->reg_cache;
                count = 0;
@@ -1870,7 +2099,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");
@@ -1886,11 +2115,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
                {
@@ -2040,9 +2269,7 @@ static int handle_resume_command(struct command_context_s *cmd_ctx, char *cmd, c
        uint32_t addr = 0;
        if (argc == 1)
        {
-               int retval = parse_u32(args[0], &addr);
-               if (ERROR_OK != retval)
-                       return retval;
+               COMMAND_PARSE_NUMBER(u32, args[0], addr);
                current = 0;
        }
 
@@ -2063,9 +2290,7 @@ static int handle_step_command(struct command_context_s *cmd_ctx, char *cmd, cha
        int current_pc = 1;
        if (argc == 1)
        {
-               int retval = parse_u32(args[0], &addr);
-               if (ERROR_OK != retval)
-                       return retval;
+               COMMAND_PARSE_NUMBER(u32, args[0], addr);
                current_pc = 0;
        }
 
@@ -2136,24 +2361,34 @@ 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)
-               return retval;
+       COMMAND_PARSE_NUMBER(u32, args[0], address);
 
        unsigned count = 1;
        if (argc == 2)
-       {
-               retval = parse_uint(args[1], &count);
-               if (ERROR_OK != retval)
-                       return retval;
-       }
+               COMMAND_PARSE_NUMBER(uint, args[1], count);
 
        uint8_t *buffer = calloc(count, size);
 
        target_t *target = get_current_target(cmd_ctx);
-       retval = target_read_memory(target,
-                               address, size, count, buffer);
+       int retval = fn(target, address, size, count, buffer);
        if (ERROR_OK == retval)
                handle_md_output(cmd_ctx, target, address, size, count, buffer);
 
@@ -2164,26 +2399,34 @@ 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;
-       int retval = parse_u32(args[0], &address);
-       if (ERROR_OK != retval)
-               return retval;
+       COMMAND_PARSE_NUMBER(u32, args[0], address);
 
        uint32_t value;
-       retval = parse_u32(args[1], &value);
-       if (ERROR_OK != retval)
-               return retval;
+       COMMAND_PARSE_NUMBER(u32, args[1], value);
 
        unsigned count = 1;
        if (argc == 3)
-       {
-               retval = parse_uint(args[2], &count);
-               if (ERROR_OK != retval)
-                       return retval;
-       }
+               COMMAND_PARSE_NUMBER(uint, args[2], count);
 
        target_t *target = get_current_target(cmd_ctx);
        unsigned wordsize;
@@ -2207,7 +2450,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,
+               int retval = fn(target,
                                address + i * wordsize, wordsize, 1, value_buf);
                if (ERROR_OK != retval)
                        return retval;
@@ -2218,8 +2461,9 @@ static int handle_mw_command(struct command_context_s *cmd_ctx, char *cmd, char
 
 }
 
-static int parse_load_image_command_args(char **args, int argc,
-               image_t *image, uint32_t *min_address, uint32_t *max_address)
+static int parse_load_image_command_args(struct command_context_s *cmd_ctx,
+               char **args, int argc, image_t *image,
+               uint32_t *min_address, uint32_t *max_address)
 {
        if (argc < 1 || argc > 5)
                return ERROR_COMMAND_SYNTAX_ERROR;
@@ -2229,9 +2473,7 @@ static int parse_load_image_command_args(char **args, int argc,
        if (argc >= 2)
        {
                uint32_t addr;
-               int retval = parse_u32(args[1], &addr);
-               if (ERROR_OK != retval)
-                       return ERROR_COMMAND_SYNTAX_ERROR;
+               COMMAND_PARSE_NUMBER(u32, args[1], addr);
                image->base_address = addr;
                image->base_address_set = 1;
        }
@@ -2242,15 +2484,11 @@ static int parse_load_image_command_args(char **args, int argc,
 
        if (argc >= 4)
        {
-               int retval = parse_u32(args[3], min_address);
-               if (ERROR_OK != retval)
-                       return ERROR_COMMAND_SYNTAX_ERROR;
+               COMMAND_PARSE_NUMBER(u32, args[3], *min_address);
        }
        if (argc == 5)
        {
-               int retval = parse_u32(args[4], max_address);
-               if (ERROR_OK != retval)
-                       return ERROR_COMMAND_SYNTAX_ERROR;
+               COMMAND_PARSE_NUMBER(u32, args[4], *max_address);
                // use size (given) to find max (required)
                *max_address += *min_address;
        }
@@ -2269,20 +2507,17 @@ static int handle_load_image_command(struct command_context_s *cmd_ctx, char *cm
        uint32_t min_address = 0;
        uint32_t max_address = 0xffffffff;
        int i;
-       int retvaltemp;
-
        image_t image;
 
-       duration_t duration;
-       char *duration_text;
-
-       int retval = parse_load_image_command_args(args, argc,
+       int retval = parse_load_image_command_args(cmd_ctx, args, argc,
                        &image, &min_address, &max_address);
        if (ERROR_OK != retval)
                return retval;
 
        target_t *target = get_current_target(cmd_ctx);
-       duration_start_measure(&duration);
+
+       struct duration bench;
+       duration_start(&bench);
 
        if (image_open(&image, args[0], (argc >= 3) ? args[2] : NULL) != ERROR_OK)
        {
@@ -2342,20 +2577,13 @@ static int handle_load_image_command(struct command_context_s *cmd_ctx, char *cm
                free(buffer);
        }
 
-       if ((retvaltemp = duration_stop_measure(&duration, &duration_text)) != ERROR_OK)
+       if ((ERROR_OK == retval) && (duration_measure(&bench) == ERROR_OK))
        {
-               image_close(&image);
-               return retvaltemp;
+               command_print(cmd_ctx, "downloaded %" PRIu32 " bytes "
+                               "in %fs (%0.3f kb/s)", image_size,
+                               duration_elapsed(&bench), duration_kbps(&bench, image_size));
        }
 
-       if (retval == ERROR_OK)
-       {
-               command_print(cmd_ctx, "downloaded %u byte in %s",
-                                         (unsigned int)image_size,
-                                         duration_text);
-       }
-       free(duration_text);
-
        image_close(&image);
 
        return retval;
@@ -2369,8 +2597,6 @@ static int handle_dump_image_command(struct command_context_s *cmd_ctx, char *cm
        uint8_t buffer[560];
        int retvaltemp;
 
-       duration_t duration;
-       char *duration_text;
 
        target_t *target = get_current_target(cmd_ctx);
 
@@ -2381,27 +2607,23 @@ static int handle_dump_image_command(struct command_context_s *cmd_ctx, char *cm
        }
 
        uint32_t address;
-       int retval = parse_u32(args[1], &address);
-       if (ERROR_OK != retval)
-               return retval;
-
+       COMMAND_PARSE_NUMBER(u32, args[1], address);
        uint32_t size;
-       retval = parse_u32(args[2], &size);
-       if (ERROR_OK != retval)
-               return retval;
+       COMMAND_PARSE_NUMBER(u32, args[2], size);
 
        if (fileio_open(&fileio, args[0], FILEIO_WRITE, FILEIO_BINARY) != ERROR_OK)
        {
                return ERROR_OK;
        }
 
-       duration_start_measure(&duration);
+       struct duration bench;
+       duration_start(&bench);
 
+       int retval = ERROR_OK;
        while (size > 0)
        {
                uint32_t size_written;
                uint32_t this_run_size = (size > 560) ? 560 : size;
-
                retval = target_read_buffer(target, address, this_run_size, buffer);
                if (retval != ERROR_OK)
                {
@@ -2421,14 +2643,11 @@ static int handle_dump_image_command(struct command_context_s *cmd_ctx, char *cm
        if ((retvaltemp = fileio_close(&fileio)) != ERROR_OK)
                return retvaltemp;
 
-       if ((retvaltemp = duration_stop_measure(&duration, &duration_text)) != ERROR_OK)
-               return retvaltemp;
-
-       if (retval == ERROR_OK)
+       if ((ERROR_OK == retval) && (duration_measure(&bench) == ERROR_OK))
        {
-               command_print(cmd_ctx, "dumped %lld byte in %s",
-                               fileio.size, duration_text);
-               free(duration_text);
+               command_print(cmd_ctx,
+                               "dumped %lld bytes in %fs (%0.3f kb/s)", fileio.size,
+                               duration_elapsed(&bench), duration_kbps(&bench, fileio.size));
        }
 
        return retval;
@@ -2440,15 +2659,12 @@ static int handle_verify_image_command_internal(struct command_context_s *cmd_ct
        uint32_t buf_cnt;
        uint32_t image_size;
        int i;
-       int retval, retvaltemp;
+       int retval;
        uint32_t checksum = 0;
        uint32_t mem_checksum = 0;
 
        image_t image;
 
-       duration_t duration;
-       char *duration_text;
-
        target_t *target = get_current_target(cmd_ctx);
 
        if (argc < 1)
@@ -2462,14 +2678,13 @@ static int handle_verify_image_command_internal(struct command_context_s *cmd_ct
                return ERROR_FAIL;
        }
 
-       duration_start_measure(&duration);
+       struct duration bench;
+       duration_start(&bench);
 
        if (argc >= 2)
        {
                uint32_t addr;
-               retval = parse_u32(args[1], &addr);
-               if (ERROR_OK != retval)
-                       return ERROR_COMMAND_SYNTAX_ERROR;
+               COMMAND_PARSE_NUMBER(u32, args[1], addr);
                image.base_address = addr;
                image.base_address_set = 1;
        }
@@ -2571,20 +2786,12 @@ static int handle_verify_image_command_internal(struct command_context_s *cmd_ct
                image_size += buf_cnt;
        }
 done:
-
-       if ((retvaltemp = duration_stop_measure(&duration, &duration_text)) != ERROR_OK)
-       {
-               image_close(&image);
-               return retvaltemp;
-       }
-
-       if (retval == ERROR_OK)
+       if ((ERROR_OK == retval) && (duration_measure(&bench) == ERROR_OK))
        {
-               command_print(cmd_ctx, "verified %u bytes in %s",
-                                         (unsigned int)image_size,
-                                         duration_text);
+               command_print(cmd_ctx, "verified %" PRIu32 " bytes "
+                               "in %fs (%0.3f kb/s)", image_size,
+                               duration_elapsed(&bench), duration_kbps(&bench, image_size));
        }
-       free(duration_text);
 
        image_close(&image);
 
@@ -2654,14 +2861,9 @@ static int handle_bp_command(struct command_context_s *cmd_ctx,
        }
 
        uint32_t addr;
-       int retval = parse_u32(args[0], &addr);
-       if (ERROR_OK != retval)
-               return retval;
-
+       COMMAND_PARSE_NUMBER(u32, args[0], addr);
        uint32_t length;
-       retval = parse_u32(args[1], &length);
-       if (ERROR_OK != retval)
-               return retval;
+       COMMAND_PARSE_NUMBER(u32, args[1], length);
 
        int hw = BKPT_SOFT;
        if (argc == 3)
@@ -2681,9 +2883,7 @@ static int handle_rbp_command(struct command_context_s *cmd_ctx, char *cmd, char
                return ERROR_COMMAND_SYNTAX_ERROR;
 
        uint32_t addr;
-       int retval = parse_u32(args[0], &addr);
-       if (ERROR_OK != retval)
-               return retval;
+       COMMAND_PARSE_NUMBER(u32, args[0], addr);
 
        target_t *target = get_current_target(cmd_ctx);
        breakpoint_remove(target, addr);
@@ -2718,19 +2918,14 @@ static int handle_wp_command(struct command_context_s *cmd_ctx, char *cmd, char
        uint32_t length = 0;
        uint32_t data_value = 0x0;
        uint32_t data_mask = 0xffffffff;
-       int retval;
 
        switch (argc)
        {
        case 5:
-               retval = parse_u32(args[4], &data_mask);
-               if (ERROR_OK != retval)
-                       return retval;
+               COMMAND_PARSE_NUMBER(u32, args[4], data_mask);
                // fall through
        case 4:
-               retval = parse_u32(args[3], &data_value);
-               if (ERROR_OK != retval)
-                       return retval;
+               COMMAND_PARSE_NUMBER(u32, args[3], data_value);
                // fall through
        case 3:
                switch (args[2][0])
@@ -2750,20 +2945,17 @@ static int handle_wp_command(struct command_context_s *cmd_ctx, char *cmd, char
                }
                // fall through
        case 2:
-               retval = parse_u32(args[1], &length);
-               if (ERROR_OK != retval)
-                       return retval;
-               retval = parse_u32(args[0], &addr);
-               if (ERROR_OK != retval)
-                       return retval;
+               COMMAND_PARSE_NUMBER(u32, args[1], length);
+               COMMAND_PARSE_NUMBER(u32, args[0], addr);
                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;
        }
 
-       retval = watchpoint_add(target, addr, length, type,
+       int retval = watchpoint_add(target, addr, length, type,
                        data_value, data_mask);
        if (ERROR_OK != retval)
                LOG_ERROR("Failure setting watchpoints");
@@ -2777,9 +2969,7 @@ static int handle_rwp_command(struct command_context_s *cmd_ctx, char *cmd, char
                return ERROR_COMMAND_SYNTAX_ERROR;
 
        uint32_t addr;
-       int retval = parse_u32(args[0], &addr);
-       if (ERROR_OK != retval)
-               return retval;
+       COMMAND_PARSE_NUMBER(u32, args[0], addr);
 
        target_t *target = get_current_target(cmd_ctx);
        watchpoint_remove(target, addr);
@@ -2801,13 +2991,11 @@ static int handle_virt2phys_command(command_context_t *cmd_ctx,
                return ERROR_COMMAND_SYNTAX_ERROR;
 
        uint32_t va;
-       int retval = parse_u32(args[0], &va);
-       if (ERROR_OK != retval)
-               return retval;
+       COMMAND_PARSE_NUMBER(u32, args[0], va);
        uint32_t pa;
 
        target_t *target = get_current_target(cmd_ctx);
-       retval = target->type->virt2phys(target, va, &pa);
+       int retval = target->type->virt2phys(target, va, &pa);
        if (retval == ERROR_OK)
                command_print(cmd_ctx, "Physical address 0x%08" PRIx32 "", pa);
 
@@ -2942,9 +3130,7 @@ static int handle_profile_command(struct command_context_s *cmd_ctx, char *cmd,
                return ERROR_COMMAND_SYNTAX_ERROR;
        }
        unsigned offset;
-       int retval = parse_uint(args[0], &offset);
-       if (ERROR_OK != retval)
-               return retval;
+       COMMAND_PARSE_NUMBER(uint, args[0], offset);
 
        timeval_add_time(&timeout, offset, 0);
 
@@ -2961,6 +3147,7 @@ static int handle_profile_command(struct command_context_s *cmd_ctx, char *cmd,
 
        for (;;)
        {
+               int retval;
                target_poll(target);
                if (target->state == TARGET_HALTED)
                {
@@ -3251,7 +3438,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;
@@ -3404,17 +3590,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,
@@ -3427,12 +3612,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);
        }
 }
 
@@ -3598,6 +3777,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;
@@ -3615,6 +3795,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;
@@ -4026,7 +4207,8 @@ static int tcl_target_func(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
                break;
        case TS_CMD_RESET:
                if (goi.argc != 2) {
-                       Jim_WrongNumArgs(interp, 2, argv, "t | f|assert | deassert BOOL");
+                       Jim_WrongNumArgs(interp, 2, argv,
+                                       "([tT]|[fF]|assert|deassert) BOOL");
                        return JIM_ERR;
                }
                e = Jim_GetOpt_Nvp(&goi, nvp_assert, &n);
@@ -4055,11 +4237,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]");
@@ -4067,8 +4249,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) {
@@ -4231,6 +4413,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;
@@ -4464,15 +4648,13 @@ static int handle_fast_load_image_command(struct command_context_s *cmd_ctx, cha
 
        image_t image;
 
-       duration_t duration;
-       char *duration_text;
-
-       int retval = parse_load_image_command_args(args, argc,
+       int retval = parse_load_image_command_args(cmd_ctx, args, argc,
                        &image, &min_address, &max_address);
        if (ERROR_OK != retval)
                return retval;
 
-       duration_start_measure(&duration);
+       struct duration bench;
+       duration_start(&bench);
 
        if (image_open(&image, args[0], (argc >= 3) ? args[2] : NULL) != ERROR_OK)
        {
@@ -4545,13 +4727,16 @@ static int handle_fast_load_image_command(struct command_context_s *cmd_ctx, cha
                free(buffer);
        }
 
-       duration_stop_measure(&duration, &duration_text);
-       if (retval == ERROR_OK)
+       if ((ERROR_OK == retval) && (duration_measure(&bench) == ERROR_OK))
        {
-               command_print(cmd_ctx, "Loaded %u bytes in %s", (unsigned int)image_size, duration_text);
-               command_print(cmd_ctx, "NB!!! image has not been loaded to target, issue a subsequent 'fast_load' to do so.");
+               command_print(cmd_ctx, "Loaded %" PRIu32 " bytes "
+                               "in %fs (%0.3f kb/s)", image_size, 
+                               duration_elapsed(&bench), duration_kbps(&bench, image_size));
+
+               command_print(cmd_ctx,
+                               "WARNING: image has not been loaded to target!"
+                               "You can issue a 'fast_load' to finish loading.");
        }
-       free(duration_text);
 
        image_close(&image);
 
@@ -4593,10 +4778,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;
+       }
+       CRn = l;
+
+       e = Jim_GetLong(interp, argv[4], &l);
+       if (e != JIM_OK) {
+               return e;
+       }
+       CRm = l;
+
+       e = Jim_GetLong(interp, argv[5], &l);
+       if (e != JIM_OK) {
+               return e;
+       }
+       op2 = 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;
+}