* Copyright (C) 2005 by Dominic Rath *
* Dominic.Rath@gmx.de *
* *
- * Copyright (C) 2007,2008 Øyvind Harboe *
+ * Copyright (C) 2007,2008 Øyvind Harboe *
* oyvind.harboe@zylin.com *
* *
* Copyright (C) 2008, Duane Ellis *
* openocd@duaneeellis.com *
* *
+ * Copyright (C) 2008 by Spencer Oliver *
+ * spen@spen-soft.co.uk *
+ * *
+ * Copyright (C) 2008 by Rick Altherr *
+ * kc8apf@kc8apf.net> *
+ * *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
#include <fileio.h>
#include <image.h>
-static int USE_OLD_RESET = 0; // temp
-
int cli_target_callback_event_handler(struct target_s *target, enum target_event event, void *priv);
-
int handle_targets_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
-int handle_working_area_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
-
int handle_reg_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
int handle_poll_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
int handle_halt_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
int handle_wait_halt_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
-int handle_NEWreset_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
int handle_reset_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
int handle_soft_reset_halt_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
int handle_resume_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
int handle_rwp_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
int handle_virt2phys_command(command_context_t *cmd_ctx, char *cmd, char **args, int argc);
int handle_profile_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
+int handle_fast_load_image_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
+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_mem2array(Jim_Interp *interp, int argc, Jim_Obj *const *argv);
static int jim_target( Jim_Interp *interp, int argc, Jim_Obj *const *argv);
static int target_array2mem(Jim_Interp *interp, target_t *target, int argc, Jim_Obj *const *argv);
static int target_mem2array(Jim_Interp *interp, target_t *target, int argc, Jim_Obj *const *argv);
-
-
/* targets */
extern target_type_t arm7tdmi_target;
extern target_type_t arm720t_target;
}
const Jim_Nvp nvp_target_event[] = {
- { .value = TARGET_EVENT_OLD_pre_reset , .name = "old-pre_reset" },
{ .value = TARGET_EVENT_OLD_gdb_program_config , .name = "old-gdb_program_config" },
- { .value = TARGET_EVENT_OLD_post_reset , .name = "old-post_reset" },
{ .value = TARGET_EVENT_OLD_pre_resume , .name = "old-pre_resume" },
-
+ { .value = TARGET_EVENT_EARLY_HALTED, .name = "early-halted" },
{ .value = TARGET_EVENT_HALTED, .name = "halted" },
{ .value = TARGET_EVENT_RESUMED, .name = "resumed" },
{ .value = TARGET_EVENT_RESUME_START, .name = "resume-start" },
{ .value = TARGET_EVENT_RESUME_END, .name = "resume-end" },
+ { .name = "gdb-start", .value = TARGET_EVENT_GDB_START },
+ { .name = "gdb-end", .value = TARGET_EVENT_GDB_END },
+
/* historical name */
{ .value = TARGET_EVENT_RESET_START, .name = "reset-start" },
{ .value = TARGET_EVENT_RESET_INIT , .name = "reset-init" },
{ .value = TARGET_EVENT_RESET_END, .name = "reset-end" },
-
-
-
-
{ .value = TARGET_EVENT_EXAMINE_START, .name = "examine-start" },
- { .value = TARGET_EVENT_EXAMINE_START, .name = "examine-end" },
-
+ { .value = TARGET_EVENT_EXAMINE_END, .name = "examine-end" },
{ .value = TARGET_EVENT_DEBUG_HALTED, .name = "debug-halted" },
{ .value = TARGET_EVENT_DEBUG_RESUMED, .name = "debug-resumed" },
{ .value = TARGET_EVENT_GDB_ATTACH, .name = "gdb-attach" },
{ .value = TARGET_EVENT_GDB_DETACH, .name = "gdb-detach" },
-
{ .value = TARGET_EVENT_GDB_FLASH_WRITE_START, .name = "gdb-flash-write-start" },
{ .value = TARGET_EVENT_GDB_FLASH_WRITE_END , .name = "gdb-flash-write-end" },
{ .name = NULL, .value = -1 },
};
-
const Jim_Nvp nvp_target_debug_reason [] = {
{ .name = "debug-request" , .value = DBG_REASON_DBGRQ },
{ .name = "breakpoint" , .value = DBG_REASON_BREAKPOINT },
{ .name = NULL, .value = -1 },
};
-
const Jim_Nvp nvp_target_endian[] = {
{ .name = "big", .value = TARGET_BIG_ENDIAN },
{ .name = "little", .value = TARGET_LITTLE_ENDIAN },
{ .name = "be", .value = TARGET_BIG_ENDIAN },
- { .name = "le", .value = TARGET_LITTLE_ENDIAN },
+ { .name = "le", .value = TARGET_LITTLE_ENDIAN },
{ .name = NULL, .value = -1 },
};
{ .name = NULL , .value = -1 },
};
-static int
-max_target_number( void )
+static int max_target_number(void)
{
target_t *t;
int x;
}
/* determine the number of the new target */
-static int
-new_target_number( void )
+static int new_target_number(void)
{
target_t *t;
int x;
return target;
}
-
int target_poll(struct target_s *target)
{
/* We can't poll until after examine */
return retval;
}
-
-static int NEW_target_process_reset(struct command_context_s *cmd_ctx, enum target_reset_mode reset_mode)
+int target_process_reset(struct command_context_s *cmd_ctx, enum target_reset_mode reset_mode)
{
char buf[100];
+ int retval;
Jim_Nvp *n;
n = Jim_Nvp_value2name_simple( nvp_reset_modes, reset_mode );
if( n->name == NULL ){
}
sprintf( buf, "ocd_process_reset %s", n->name );
- Jim_Eval( interp, buf );
-
- /* We want any events to be processed before the prompt */
- target_call_timer_callbacks_now();
-
- return ERROR_OK;
-}
+ retval = Jim_Eval( interp, buf );
-// Next patch - this turns into TCL...
-static int OLD_target_process_reset(struct command_context_s *cmd_ctx, enum target_reset_mode reset_mode)
-{
- int retval = ERROR_OK;
- target_t *target;
-
- target = all_targets;
-
- target_all_handle_event( TARGET_EVENT_OLD_pre_reset );
-
- if ((retval = jtag_init_reset(cmd_ctx)) != ERROR_OK)
- return retval;
-
- keep_alive(); /* we might be running on a very slow JTAG clk */
-
- /* First time this is executed after launching OpenOCD, it will read out
- * the type of CPU, etc. and init Embedded ICE registers in host
- * memory.
- *
- * It will also set up ICE registers in the target.
- *
- * However, if we assert TRST later, we need to set up the registers again.
- *
- * For the "reset halt/init" case we must only set up the registers here.
- */
- if ((retval = target_examine()) != ERROR_OK)
- return retval;
-
- keep_alive(); /* we might be running on a very slow JTAG clk */
-
- target = all_targets;
- while (target)
- {
- /* we have no idea what state the target is in, so we
- * have to drop working areas
- */
- target_free_all_working_areas_restore(target, 0);
- target->reset_halt=((reset_mode==RESET_HALT)||(reset_mode==RESET_INIT));
- if ((retval = target->type->assert_reset(target))!=ERROR_OK)
- return retval;
- target = target->next;
- }
-
- target = all_targets;
- while (target)
- {
- if ((retval = target->type->deassert_reset(target))!=ERROR_OK)
- return retval;
- target = target->next;
- }
-
- target = all_targets;
- while (target)
- {
- /* We can fail to bring the target into the halted state, try after reset has been deasserted */
- if (target->reset_halt)
- {
- /* wait up to 1 second for halt. */
- target_wait_state(target, TARGET_HALTED, 1000);
- if (target->state != TARGET_HALTED)
- {
- LOG_WARNING("Failed to reset target into halted mode - issuing halt");
- if ((retval = target->type->halt(target))!=ERROR_OK)
- return retval;
- }
- }
-
- target = target->next;
- }
-
-
- LOG_DEBUG("Waiting for halted stated as appropriate");
-
- if ((reset_mode == RESET_HALT) || (reset_mode == RESET_INIT))
- {
- target = all_targets;
- while (target)
- {
- /* Wait for reset to complete, maximum 5 seconds. */
- if (((retval=target_wait_state(target, TARGET_HALTED, 5000)))==ERROR_OK)
- {
- if (reset_mode == RESET_INIT){
- target_handle_event( target, TARGET_EVENT_OLD_post_reset );
- }
-
- }
- target = target->next;
- }
+ if(retval != JIM_OK) {
+ Jim_PrintErrorMessage(interp);
+ return ERROR_FAIL;
}
/* We want any events to be processed before the prompt */
- target_call_timer_callbacks_now();
+ retval = target_call_timer_callbacks_now();
return retval;
}
-int target_process_reset(struct command_context_s *cmd_ctx, enum target_reset_mode reset_mode)
-{
- if( USE_OLD_RESET ){
- return OLD_target_process_reset( cmd_ctx, reset_mode );
- } else {
- return NEW_target_process_reset( cmd_ctx, reset_mode );
- }
-}
-
-
static int default_virt2phys(struct target_s *target, u32 virtual, u32 *physical)
{
*physical = virtual;
return ERROR_OK;
}
-
/* Targets that correctly implement init+examine, i.e.
* no communication with target during init:
*
int target_init(struct command_context_s *cmd_ctx)
{
target_t *target = all_targets;
+ int retval;
while (target)
{
target->type->examine = default_examine;
}
- if (target->type->init_target(cmd_ctx, target) != ERROR_OK)
+ if ((retval = target->type->init_target(cmd_ctx, target)) != ERROR_OK)
{
LOG_ERROR("target '%s' init failed", target->type->name);
- exit(-1);
+ return retval;
}
/* Set up default functions if none are provided by target */
target->type->run_algorithm_imp = target->type->run_algorithm;
target->type->run_algorithm = target_run_algorithm_imp;
-
if (target->type->mmu == NULL)
{
target->type->mmu = default_mmu;
if (all_targets)
{
- target_register_user_commands(cmd_ctx);
- target_register_timer_callback(handle_target, 100, 1, NULL);
+ if((retval = target_register_user_commands(cmd_ctx)) != ERROR_OK)
+ return retval;
+ if((retval = target_register_timer_callback(handle_target, 100, 1, NULL)) != ERROR_OK)
+ return retval;
}
return ERROR_OK;
target_event_callback_t *callback = target_event_callbacks;
target_event_callback_t *next_callback;
+ if (event == TARGET_EVENT_HALTED)
+ {
+ /* execute early halted first */
+ target_call_event_callbacks(target, TARGET_EVENT_EARLY_HALTED);
+ }
+
LOG_DEBUG("target event %i (%s)",
event,
Jim_Nvp_value2name_simple( nvp_target_event, event )->name );
}
}
else
- target_unregister_timer_callback(callback->callback, callback->priv);
+ {
+ int retval;
+ if((retval = target_unregister_timer_callback(callback->callback, callback->priv)) != ERROR_OK)
+ return retval;
+ }
}
}
if (target->backup_working_area)
{
+ int retval;
new_wa->backup = malloc(new_wa->size);
- target->type->read_memory(target, new_wa->address, 4, new_wa->size / 4, new_wa->backup);
+ if((retval = target->type->read_memory(target, new_wa->address, 4, new_wa->size / 4, new_wa->backup)) != ERROR_OK)
+ {
+ free(new_wa->backup);
+ free(new_wa);
+ return retval;
+ }
}
else
{
return ERROR_OK;
if (restore&&target->backup_working_area)
- target->type->write_memory(target, area->address, 4, area->size / 4, area->backup);
+ {
+ int retval;
+ if((retval = target->type->write_memory(target, area->address, 4, area->size / 4, area->backup)) != ERROR_OK)
+ return retval;
+ }
area->free = 1;
return target_free_working_area_restore(target, area, 1);
}
-int target_free_all_working_areas_restore(struct target_s *target, int restore)
+/* free resources and restore memory, if restoring memory fails,
+ * free up resources anyway
+ */
+void target_free_all_working_areas_restore(struct target_s *target, int restore)
{
working_area_t *c = target->working_areas;
}
target->working_areas = NULL;
-
- return ERROR_OK;
}
-int target_free_all_working_areas(struct target_s *target)
+void target_free_all_working_areas(struct target_s *target)
{
- return target_free_all_working_areas_restore(target, 1);
+ target_free_all_working_areas_restore(target, 1);
}
int target_register_commands(struct command_context_s *cmd_ctx)
{
- register_command(cmd_ctx, NULL, "targets", handle_targets_command, COMMAND_EXEC, NULL);
- register_command(cmd_ctx, NULL, "working_area", handle_working_area_command, COMMAND_ANY, "working_area <target#> <address> <size> <'backup'|'nobackup'> [virtual address]");
- register_command(cmd_ctx, NULL, "virt2phys", handle_virt2phys_command, COMMAND_ANY, "virt2phys <virtual address>");
- register_command(cmd_ctx, NULL, "profile", handle_profile_command, COMMAND_EXEC, "PRELIMINARY! - profile <seconds> <gmon.out>");
+ register_command(cmd_ctx, NULL, "targets", handle_targets_command, COMMAND_EXEC, "change the current command line target (one parameter) or lists targets (with no parameter)");
+ register_command(cmd_ctx, NULL, "virt2phys", handle_virt2phys_command, COMMAND_ANY, "translate a virtual address into a physical address");
+ register_command(cmd_ctx, NULL, "profile", handle_profile_command, COMMAND_EXEC, "profiling samples the CPU PC");
+
+ 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");
+
+ register_command(cmd_ctx, NULL, "fast_load", handle_fast_load_command, COMMAND_ANY,
+ "loads active fast load image to current target - mainly for profiling purposes");
+
+
register_jim(cmd_ctx, "target", jim_target, "configure target" );
return ERROR_OK;
}
-
/* Single aligned words are guaranteed to use 16 or 32 bit access
* mode respectively, otherwise data is handled as quickly as
* possible
}
if ((retval = target->type->checksum_memory(target, address,
- size, &checksum)) == ERROR_TARGET_RESOURCE_NOT_AVAILABLE)
+ size, &checksum)) != ERROR_OK)
{
buffer = malloc(size);
if (buffer == NULL)
LOG_DEBUG("address: 0x%8.8x, value: 0x%2.2x", address, value);
- if ((retval = target->type->read_memory(target, address, 1, 1, &value)) != ERROR_OK)
+ if ((retval = target->type->write_memory(target, address, 1, 1, &value)) != ERROR_OK)
{
LOG_DEBUG("failed: %i", retval);
}
int target_register_user_commands(struct command_context_s *cmd_ctx)
{
- register_command(cmd_ctx, NULL, "reg", handle_reg_command, COMMAND_EXEC, NULL);
+ int retval = ERROR_OK;
+ register_command(cmd_ctx, NULL, "reg", handle_reg_command, COMMAND_EXEC, "display or set a register");
register_command(cmd_ctx, NULL, "poll", handle_poll_command, COMMAND_EXEC, "poll target state");
register_command(cmd_ctx, NULL, "wait_halt", handle_wait_halt_command, COMMAND_EXEC, "wait for target halt [time (s)]");
register_command(cmd_ctx, NULL, "halt", handle_halt_command, COMMAND_EXEC, "halt target");
register_command(cmd_ctx, NULL, "resume", handle_resume_command, COMMAND_EXEC, "resume target [addr]");
register_command(cmd_ctx, NULL, "step", handle_step_command, COMMAND_EXEC, "step one instruction from current PC or [addr]");
- register_command(cmd_ctx, NULL, "NEWreset", handle_NEWreset_command, COMMAND_EXEC, "reset target [run|halt|init] - default is run");
- register_command(cmd_ctx, NULL, "reset", handle_reset_command, COMMAND_EXEC, "OLDreset target [run|halt|init] - default is run");
+ 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, "dump_image", handle_dump_image_command, COMMAND_EXEC, "dump_image <file> <address> <size>");
register_command(cmd_ctx, NULL, "verify_image", handle_verify_image_command, COMMAND_EXEC, "verify_image <file> [offset] [type]");
- target_request_register_commands(cmd_ctx);
- trace_register_commands(cmd_ctx);
+ if((retval = target_request_register_commands(cmd_ctx)) != ERROR_OK)
+ return retval;
+ if((retval = trace_register_commands(cmd_ctx)) != ERROR_OK)
+ return retval;
- return ERROR_OK;
+ return retval;
}
int handle_targets_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
if (argc == 1)
{
/* try as tcltarget name */
- for( target = all_targets ; target ; target++ ){
+ for( target = all_targets ; target ; target = target->next ){
if( target->cmd_name ){
if( 0 == strcmp( args[0], target->cmd_name ) ){
/* MATCH */
cmd_ctx->current_target = target->target_number;
return ERROR_OK;
}
- DumpTargets:
+DumpTargets:
- command_print(cmd_ctx, " CmdName Type Endian ChainPos State ");
- command_print(cmd_ctx, "-- ---------- ---------- ---------- -------- ----------");
+ target = all_targets;
+ command_print(cmd_ctx, " CmdName Type Endian AbsChainPos Name State ");
+ command_print(cmd_ctx, "-- ---------- ---------- ---------- ----------- ------------- ----------");
while (target)
{
/* XX: abcdefghij abcdefghij abcdefghij abcdefghij */
- command_print(cmd_ctx, "%2d: %-10s %-10s %-10s %8d %s",
+ command_print(cmd_ctx, "%2d: %-10s %-10s %-10s %10d %14s %s",
target->target_number,
target->cmd_name,
target->type->name,
Jim_Nvp_value2name_simple( nvp_target_endian, target->endianness )->name,
- target->chain_position,
+ target->tap->abs_chain_position,
+ target->tap->dotted_name,
Jim_Nvp_value2name_simple( nvp_target_state, target->state )->name );
target = target->next;
}
return ERROR_OK;
}
+/* every 300ms we check for reset & powerdropout and issue a "reset halt" if so. */
+
+static int powerDropout;
+static int srstAsserted;
+static int runPowerRestore;
+static int runPowerDropout;
+static int runSrstAsserted;
+static int runSrstDeasserted;
-int handle_working_area_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+static int sense_handler(void)
{
- target_t *target = NULL;
+ static int prevSrstAsserted = 0;
+ static int prevPowerdropout = 0;
- if ((argc < 4) || (argc > 5))
- {
- return ERROR_COMMAND_SYNTAX_ERROR;
- }
+ int retval;
+ if ((retval=jtag_power_dropout(&powerDropout))!=ERROR_OK)
+ return retval;
- target = get_target_by_num(strtoul(args[0], NULL, 0));
- if (!target)
+ int powerRestored;
+ powerRestored = prevPowerdropout && !powerDropout;
+ if (powerRestored)
{
- return ERROR_COMMAND_SYNTAX_ERROR;
+ runPowerRestore = 1;
}
- target_free_all_working_areas(target);
- target->working_area_phys = target->working_area_virt = strtoul(args[1], NULL, 0);
- if (argc == 5)
+ long long current = timeval_ms();
+ static long long lastPower = 0;
+ int waitMore = lastPower + 2000 > current;
+ if (powerDropout && !waitMore)
{
- target->working_area_virt = strtoul(args[4], NULL, 0);
+ runPowerDropout = 1;
+ lastPower = current;
}
- target->working_area_size = strtoul(args[2], NULL, 0);
- if (strcmp(args[3], "backup") == 0)
+ if ((retval=jtag_srst_asserted(&srstAsserted))!=ERROR_OK)
+ return retval;
+
+ int srstDeasserted;
+ srstDeasserted = prevSrstAsserted && !srstAsserted;
+
+ static long long lastSrst = 0;
+ waitMore = lastSrst + 2000 > current;
+ if (srstDeasserted && !waitMore)
{
- target->backup_working_area = 1;
+ runSrstDeasserted = 1;
+ lastSrst = current;
}
- else if (strcmp(args[3], "nobackup") == 0)
+
+ if (!prevSrstAsserted && srstAsserted)
{
- target->backup_working_area = 0;
+ runSrstAsserted = 1;
}
- else
+
+ prevSrstAsserted = srstAsserted;
+ prevPowerdropout = powerDropout;
+
+ if (srstDeasserted || powerRestored)
{
- LOG_ERROR("unrecognized <backup|nobackup> argument (%s)", args[3]);
- return ERROR_COMMAND_SYNTAX_ERROR;
+ /* Other than logging the event we can't do anything here.
+ * Issuing a reset is a particularly bad idea as we might
+ * be inside a reset already.
+ */
}
return ERROR_OK;
}
-
/* process target state changes */
int handle_target(void *priv)
{
+ int retval = ERROR_OK;
+
+ /* we do not want to recurse here... */
+ static int recursive = 0;
+ if (! recursive)
+ {
+ recursive = 1;
+ sense_handler();
+ /* danger! running these procedures can trigger srst assertions and power dropouts.
+ * We need to avoid an infinite loop/recursion here and we do that by
+ * clearing the flags after running these events.
+ */
+ int did_something = 0;
+ if (runSrstAsserted)
+ {
+ Jim_Eval( interp, "srst_asserted");
+ did_something = 1;
+ }
+ if (runSrstDeasserted)
+ {
+ Jim_Eval( interp, "srst_deasserted");
+ did_something = 1;
+ }
+ if (runPowerDropout)
+ {
+ Jim_Eval( interp, "power_dropout");
+ did_something = 1;
+ }
+ if (runPowerRestore)
+ {
+ Jim_Eval( interp, "power_restore");
+ did_something = 1;
+ }
+
+ if (did_something)
+ {
+ /* clear detect flags */
+ sense_handler();
+ }
+
+ /* clear action flags */
+
+ runSrstAsserted=0;
+ runSrstDeasserted=0;
+ runPowerRestore=0;
+ runPowerDropout=0;
+
+ recursive = 0;
+ }
+
target_t *target = all_targets;
while (target)
{
- if (target_continous_poll)
+
+ /* only poll target if we've got power and srst isn't asserted */
+ if (target_continous_poll&&!powerDropout&&!srstAsserted)
{
/* polling may fail silently until the target has been examined */
- target_poll(target);
+ if((retval = target_poll(target)) != ERROR_OK)
+ return retval;
}
target = target->next;
}
- return ERROR_OK;
+ return retval;
}
int handle_reg_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
if (reg->valid == 0)
{
reg_arch_type_t *arch_type = register_get_arch_type(reg->arch_type);
- if (arch_type == NULL)
- {
- LOG_ERROR("BUG: encountered unregistered arch type");
- return ERROR_OK;
- }
arch_type->get(reg);
}
value = buf_to_str(reg->value, reg->size, 16);
str_to_buf(args[1], strlen(args[1]), buf, reg->size, 0);
reg_arch_type_t *arch_type = register_get_arch_type(reg->arch_type);
- if (arch_type == NULL)
- {
- LOG_ERROR("BUG: encountered unregistered arch type");
- return ERROR_OK;
- }
-
arch_type->set(reg, buf);
value = buf_to_str(reg->value, reg->size, 16);
return ERROR_OK;
}
-
int handle_poll_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
{
+ int retval = ERROR_OK;
target_t *target = get_current_target(cmd_ctx);
if (argc == 0)
{
- target_poll(target);
- target_arch_state(target);
+ if((retval = target_poll(target)) != ERROR_OK)
+ return retval;
+ if((retval = target_arch_state(target)) != ERROR_OK)
+ return retval;
+
}
- else
+ else if (argc==1)
{
if (strcmp(args[0], "on") == 0)
{
{
command_print(cmd_ctx, "arg is \"on\" or \"off\"");
}
+ } else
+ {
+ return ERROR_COMMAND_SYNTAX_ERROR;
}
-
- return ERROR_OK;
+ return retval;
}
int handle_wait_halt_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
{
once=0;
LOG_DEBUG("waiting for target %s...",
- Jim_Nvp_value2name_simple(nvp_target_state,state)->name);
+ Jim_Nvp_value2name_simple(nvp_target_state,state)->name);
}
gettimeofday(&now, NULL);
if ((now.tv_sec > timeout.tv_sec) || ((now.tv_sec == timeout.tv_sec) && (now.tv_usec >= timeout.tv_usec)))
{
LOG_ERROR("timed out while waiting for target %s",
- Jim_Nvp_value2name_simple(nvp_target_state,state)->name);
+ Jim_Nvp_value2name_simple(nvp_target_state,state)->name);
return ERROR_FAIL;
}
}
return target_process_reset(cmd_ctx, reset_mode);
}
-int handle_NEWreset_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
-{
- int x;
- char *cp;
-
- if (argc >= 1){
- x = strtol( args[0], &cp, 0 );
- if( *cp != 0 ){
- command_print( cmd_ctx, "Not numeric: %s\n", args[0] );
- return ERROR_COMMAND_SYNTAX_ERROR;
- }
- USE_OLD_RESET = !!x;
- }
- command_print( cmd_ctx, "reset method: %d (%s)\n",
- USE_OLD_RESET,
- USE_OLD_RESET ? "old-method" : "new-method" );
- return ERROR_OK;
-}
int handle_resume_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
{
LOG_DEBUG("-");
if (argc == 0)
- target->type->step(target, 1, 0, 1); /* current pc, addr = 0, handle breakpoints */
+ return target->type->step(target, 1, 0, 1); /* current pc, addr = 0, handle breakpoints */
if (argc == 1)
- target->type->step(target, 0, strtoul(args[0], NULL, 0), 1); /* addr = args[0], handle breakpoints */
+ return target->type->step(target, 0, strtoul(args[0], NULL, 0), 1); /* addr = args[0], handle breakpoints */
return ERROR_OK;
}
address = strtoul(args[0], NULL, 0);
-
switch (cmd[2])
{
case 'w':
default:
return ERROR_OK;
}
+ keep_alive();
+
if (retval!=ERROR_OK)
{
return retval;
u32 min_address=0;
u32 max_address=0xffffffff;
int i;
- int retval;
+ int retval, retvaltemp;
image_t image;
return ERROR_COMMAND_SYNTAX_ERROR;
}
-
duration_start_measure(&duration);
if (image_open(&image, args[0], (argc >= 3) ? args[2] : NULL) != ERROR_OK)
u32 offset=0;
u32 length=buf_cnt;
-
/* DANGER!!! beware of unsigned comparision here!!! */
if ((image.sections[i].base_address+buf_cnt>=min_address)&&
free(buffer);
}
- duration_stop_measure(&duration, &duration_text);
+ if((retvaltemp = duration_stop_measure(&duration, &duration_text)) != ERROR_OK)
+ {
+ image_close(&image);
+ return retvaltemp;
+ }
+
if (retval==ERROR_OK)
{
command_print(cmd_ctx, "downloaded %u byte in %s", image_size, duration_text);
u32 address;
u32 size;
u8 buffer[560];
- int retval=ERROR_OK;
+ int retval=ERROR_OK, retvaltemp;
duration_t duration;
char *duration_text;
address += this_run_size;
}
- fileio_close(&fileio);
+ if((retvaltemp = fileio_close(&fileio)) != ERROR_OK)
+ return retvaltemp;
+
+ if((retvaltemp = duration_stop_measure(&duration, &duration_text)) != ERROR_OK)
+ return retvaltemp;
- duration_stop_measure(&duration, &duration_text);
if (retval==ERROR_OK)
{
command_print(cmd_ctx, "dumped %"PRIi64" byte in %s", fileio.size, duration_text);
u32 buf_cnt;
u32 image_size;
int i;
- int retval;
+ int retval, retvaltemp;
u32 checksum = 0;
u32 mem_checksum = 0;
retval=ERROR_FAIL;
goto done;
}
+ if ((t%16384)==0)
+ {
+ keep_alive();
+ }
}
}
image_size += buf_cnt;
}
done:
- duration_stop_measure(&duration, &duration_text);
+
+ if((retvaltemp = duration_stop_measure(&duration, &duration_text)) != ERROR_OK)
+ {
+ image_close(&image);
+ return retvaltemp;
+ }
+
if (retval==ERROR_OK)
{
command_print(cmd_ctx, "verified %u bytes in %s", image_size, duration_text);
}
return retval;
}
+
static void writeLong(FILE *f, int l)
{
int i;
}
}
+
static void writeString(FILE *f, char *s)
{
fwrite(s, 1, strlen(s), f);
}
-
-
-// Dump a gmon.out histogram file.
+/* Dump a gmon.out histogram file. */
static void writeGmon(u32 *samples, int sampleNum, char *filename)
{
int i;
if (f==NULL)
return;
fwrite("gmon", 1, 4, f);
- writeLong(f, 0x00000001); // Version
- writeLong(f, 0); // padding
- writeLong(f, 0); // padding
- writeLong(f, 0); // padding
+ writeLong(f, 0x00000001); /* Version */
+ writeLong(f, 0); /* padding */
+ writeLong(f, 0); /* padding */
+ writeLong(f, 0); /* padding */
- fwrite("", 1, 1, f); // GMON_TAG_TIME_HIST
+ fwrite("", 1, 1, f); /* GMON_TAG_TIME_HIST */
- // figure out bucket size
+ /* figure out bucket size */
u32 min=samples[0];
u32 max=samples[0];
for (i=0; i<sampleNum; i++)
int addressSpace=(max-min+1);
- static int const maxBuckets=256*1024; // maximum buckets.
+ static int const maxBuckets=256*1024; /* maximum buckets. */
int length=addressSpace;
if (length > maxBuckets)
{
long long a=address-min;
long long b=length-1;
long long c=addressSpace-1;
- int index=(a*b)/c; // danger!!!! int32 overflows
+ int index=(a*b)/c; /* danger!!!! int32 overflows */
buckets[index]++;
}
- // append binary memory gmon.out &profile_hist_hdr ((char*)&profile_hist_hdr + sizeof(struct gmon_hist_hdr))
- writeLong(f, min); // low_pc
- writeLong(f, max); // high_pc
- writeLong(f, length); // # of samples
- writeLong(f, 64000000); // 64MHz
+ /* append binary memory gmon.out &profile_hist_hdr ((char*)&profile_hist_hdr + sizeof(struct gmon_hist_hdr)) */
+ writeLong(f, min); /* low_pc */
+ writeLong(f, max); /* high_pc */
+ writeLong(f, length); /* # of samples */
+ writeLong(f, 64000000); /* 64MHz */
writeString(f, "seconds");
for (i=0; i<(15-strlen("seconds")); i++)
{
- fwrite("", 1, 1, f); // padding
+ fwrite("", 1, 1, f); /* padding */
}
writeString(f, "s");
-// append binary memory gmon.out profile_hist_data (profile_hist_data + profile_hist_hdr.hist_size)
+ /*append binary memory gmon.out profile_hist_data (profile_hist_data + profile_hist_hdr.hist_size) */
char *data=malloc(2*length);
if (data!=NULL)
int numSamples=0;
int retval=ERROR_OK;
- // hopefully it is safe to cache! We want to stop/restart as quickly as possible.
+ /* hopefully it is safe to cache! We want to stop/restart as quickly as possible. */
reg_t *reg = register_get_by_name(target->reg_cache, "pc", 1);
for (;;)
samples[numSamples++]=t;
retval = target_resume(target, 1, 0, 0, 0); /* current pc, addr = 0, do not handle breakpoints, not debugging */
target_poll(target);
- alive_sleep(10); // sleep 10ms, i.e. <100 samples/second.
+ alive_sleep(10); /* sleep 10ms, i.e. <100 samples/second. */
} else if (target->state == TARGET_RUNNING)
{
- // We want to quickly sample the PC.
- target_halt(target);
+ /* We want to quickly sample the PC. */
+ if((retval = target_halt(target)) != ERROR_OK)
+ {
+ free(samples);
+ return retval;
+ }
} else
{
command_print(cmd_ctx, "Target not halted or running");
if ((numSamples>=maxSample) || ((now.tv_sec >= timeout.tv_sec) && (now.tv_usec >= timeout.tv_usec)))
{
command_print(cmd_ctx, "Profiling completed. %d samples.", numSamples);
- target_poll(target);
+ if((retval = target_poll(target)) != ERROR_OK)
+ {
+ free(samples);
+ return retval;
+ }
if (target->state == TARGET_HALTED)
{
target_resume(target, 1, 0, 0, 0); /* current pc, addr = 0, do not handle breakpoints, not debugging */
}
- target_poll(target);
+ if((retval = target_poll(target)) != ERROR_OK)
+ {
+ free(samples);
+ return retval;
+ }
writeGmon(samples, numSamples, args[1]);
command_print(cmd_ctx, "Wrote %s", args[1]);
break;
{
long l;
u32 width;
- u32 len;
+ int len;
u32 addr;
u32 count;
u32 v;
return target_array2mem( interp,target, argc, argv );
}
-
static int target_array2mem(Jim_Interp *interp, target_t *target, int argc, Jim_Obj *const *argv)
{
long l;
u32 width;
- u32 len;
+ int len;
u32 addr;
u32 count;
u32 v;
return JIM_ERR;
}
-
/* Transfer loop */
/* index counter */
return JIM_OK;
}
-void
-target_all_handle_event( enum target_event e )
+void target_all_handle_event( enum target_event e )
{
target_t *target;
-
LOG_DEBUG( "**all*targets: event: %d, %s",
- e,
- Jim_Nvp_value2name_simple( nvp_target_event, e )->name );
+ e,
+ Jim_Nvp_value2name_simple( nvp_target_event, e )->name );
target = all_targets;
while (target){
}
}
-void
-target_handle_event( target_t *target, enum target_event e )
+void target_handle_event( target_t *target, enum target_event e )
{
target_event_action_t *teap;
int done;
e,
Jim_Nvp_value2name_simple( nvp_target_event, e )->name,
Jim_GetString( teap->body, NULL ) );
- Jim_EvalObj( interp, teap->body );
+ if (Jim_EvalObj( interp, teap->body )!=JIM_OK)
+ {
+ Jim_PrintErrorMessage(interp);
+ }
}
teap = teap->next;
}
TCFG_CHAIN_POSITION,
};
-
static Jim_Nvp nvp_config_opts[] = {
{ .name = "-type", .value = TCFG_TYPE },
{ .name = "-event", .value = TCFG_EVENT },
{ .name = NULL, .value = -1 }
};
-
-static int
-target_configure( Jim_GetOptInfo *goi,
- target_t *target )
+static int target_configure( Jim_GetOptInfo *goi, target_t *target )
{
Jim_Nvp *n;
Jim_Obj *o;
char *cp;
int e;
-
/* parse config or cget options ... */
while( goi->argc > 0 ){
Jim_SetEmptyResult( goi->interp );
- //Jim_GetOpt_Debug( goi );
+ /* Jim_GetOpt_Debug( goi ); */
if( target->type->target_jim_configure ){
/* target defines a configure function */
}
if( goi->isconfigure ){
- if( goi->argc == 0 ){
+ if( goi->argc != 1 ){
Jim_WrongNumArgs( goi->interp, goi->argc, goi->argv, "-event ?event-name? ?EVENT-BODY?");
return JIM_ERR;
}
}
}
-
{
target_event_action_t *teap;
break;
case TCFG_CHAIN_POSITION:
if( goi->isconfigure ){
+ Jim_Obj *o;
+ jtag_tap_t *tap;
target_free_all_working_areas(target);
- e = Jim_GetOpt_Wide( goi, &w );
+ e = Jim_GetOpt_Obj( goi, &o );
if( e != JIM_OK ){
return e;
}
+ tap = jtag_TapByJimObj( goi->interp, o );
+ if( tap == NULL ){
+ return JIM_ERR;
+ }
/* make this exactly 1 or 0 */
- target->chain_position = w;
+ target->tap = tap;
} else {
if( goi->argc != 0 ){
goto no_params;
}
}
- Jim_SetResult( interp, Jim_NewIntObj( goi->interp, target->chain_position ) );
+ Jim_SetResultString( interp, target->tap->dotted_name, -1 );
/* loop for more e*/
break;
}
} /* while( goi->argc ) */
+
+
/* done - we return */
return JIM_OK;
}
-
/** this is the 'tcl' handler for the target specific command */
-static int
-tcl_target_func( Jim_Interp *interp,
- int argc,
- Jim_Obj *const *argv )
+static int tcl_target_func( Jim_Interp *interp, int argc, Jim_Obj *const *argv )
{
Jim_GetOptInfo goi;
jim_wide a,b,c;
struct command_context_s *cmd_ctx;
int e;
-
enum {
TS_CMD_CONFIGURE,
TS_CMD_CGET,
{ .name = NULL, .value = -1 },
};
-
/* go past the "command" */
Jim_GetOpt_Setup( &goi, interp, argc-1, argv+1 );
Jim_GetOpt_NvpUnknown( &goi, target_options, 0 );
return e;
}
- // Assume blank result
+ /* Assume blank result */
Jim_SetEmptyResult( goi.interp );
switch( n->value ){
Jim_GetOpt_NvpUnknown( &goi, nvp_assert, 1 );
return e;
}
- // the halt or not param
+ /* the halt or not param */
e = Jim_GetOpt_Wide( &goi, &a);
if( e != JIM_OK ){
return e;
}
- // determine if we should halt or not.
+ /* determine if we should halt or not. */
target->reset_halt = !!a;
- // When this happens - all workareas are invalid.
+ /* When this happens - all workareas are invalid. */
target_free_all_working_areas_restore(target, 0);
- // do the assert
+ /* do the assert */
if( n->value == NVP_ASSERT ){
target->type->assert_reset( target );
} else {
target->type->halt( target );
return JIM_OK;
case TS_CMD_WAITSTATE:
- // params: <name> statename timeoutmsecs
+ /* params: <name> statename timeoutmsecs */
if( goi.argc != 2 ){
Jim_SetResult_sprintf( goi.interp, "%s STATENAME TIMEOUTMSECS", n->name );
return JIM_ERR;
"target: %s wait %s fails (%d) %s",
target->cmd_name,
n->name,
- e, target_strerror_safe(e) );
+ e, target_strerror_safe(e) );
return JIM_ERR;
} else {
return JIM_OK;
return JIM_ERR;
}
-
-static int
-target_create( Jim_GetOptInfo *goi )
+static int target_create( Jim_GetOptInfo *goi )
{
-
Jim_Obj *new_cmd;
Jim_Cmd *cmd;
const char *cp;
return JIM_ERR;
}
-
/* Create it */
target = calloc(1,sizeof(target_t));
/* set target number */
target->next = NULL;
target->arch_info = NULL;
+ target->display = 1;
+
/* initialize trace information */
target->trace_info = malloc(sizeof(trace_t));
target->trace_info->num_trace_points = 0;
/* Do the rest as "configure" options */
goi->isconfigure = 1;
e = target_configure( goi, target);
+
+ if (target->tap == NULL)
+ {
+ Jim_SetResultString( interp, "-chain-position required when creating target", -1);
+ e=JIM_ERR;
+ }
+
if( e != JIM_OK ){
free( target->type );
free( target );
target->endianness = TARGET_LITTLE_ENDIAN;
}
+ /* incase variant is not set */
+ if (!target->variant)
+ target->variant = strdup("");
+
/* create the target specific commands */
if( target->type->register_commands ){
(*(target->type->register_commands))( cmd_ctx );
target, /* private data */
NULL ); /* no del proc */
- (*(target->type->target_create))( target, goi->interp );
return e;
}
-static int
-jim_target( Jim_Interp *interp, int argc, Jim_Obj *const *argv )
+static int jim_target( Jim_Interp *interp, int argc, Jim_Obj *const *argv )
{
int x,r,e;
jim_wide w;
struct command_context_s *cmd_ctx;
- const char *cp;
target_t *target;
Jim_GetOptInfo goi;
enum tcmd {
const char *target_cmds[] = {
"create", "types", "names", "current", "number",
"count",
- NULL // terminate
+ NULL /* terminate */
};
LOG_DEBUG("Target command params:");
return JIM_ERR;
}
- /* is this old syntax? */
- /* To determine: We have to peek at argv[0]*/
- cp = Jim_GetString( goi.argv[0], NULL );
- for( x = 0 ; target_types[x] ; x++ ){
- if( 0 == strcmp(cp,target_types[x]->name) ){
- break;
- }
- }
- if( target_types[x] ){
- /* YES IT IS OLD SYNTAX */
- Jim_Obj *new_argv[10];
- int new_argc;
-
- /* target_old_syntax
- *
- * argv[0] typename (above)
- * argv[1] endian
- * argv[2] reset method, deprecated/ignored
- * argv[3] = old param
- * argv[4] = old param
- *
- * We will combine all "old params" into a single param.
- * Then later, split them again.
- */
- if( argc < 4 ){
- Jim_WrongNumArgs( interp, 1, argv, "[OLDSYNTAX] ?TYPE? ?ENDIAN? ?RESET? ?old-params?");
- return JIM_ERR;
- }
- /* the command */
- new_argv[0] = argv[0];
- new_argv[1] = Jim_NewStringObj( interp, "create", -1 );
- {
- char buf[ 30 ];
- sprintf( buf, "target%d", new_target_number() );
- new_argv[2] = Jim_NewStringObj( interp, buf , -1 );
- }
- new_argv[3] = goi.argv[0]; /* typename */
- new_argv[4] = Jim_NewStringObj( interp, "-endian", -1 );
- new_argv[5] = goi.argv[1];
- new_argv[6] = Jim_NewStringObj( interp, "-chain-position", -1 );
- new_argv[7] = goi.argv[2];
- new_argv[8] = Jim_NewStringObj( interp, "-variant", -1 );
- new_argv[9] = goi.argv[3];
- new_argc = 10;
- /*
- * new arg syntax:
- * argv[0] = command
- * argv[1] = create
- * argv[2] = cmdname
- * argv[3] = typename
- * argv[4] = **FIRST** "configure" option.
- *
- * Here, we make them:
- *
- * argv[4] = -endian
- * argv[5] = little
- * argv[6] = -position
- * argv[7] = NUMBER
- * argv[8] = -variant
- * argv[9] = "somestring"
- */
-
- /* don't let these be released */
- for( x = 0 ; x < new_argc ; x++ ){
- Jim_IncrRefCount( new_argv[x]);
- }
- /* call our self */
- LOG_DEBUG("Target OLD SYNTAX - converted to new syntax");
-
- r = jim_target( goi.interp, new_argc, new_argv );
-
- /* release? these items */
- for( x = 0 ; x < new_argc ; x++ ){
- Jim_DecrRefCount( interp, new_argv[x] );
- }
- return r;
- }
-
- //Jim_GetOpt_Debug( &goi );
+ /* Jim_GetOpt_Debug( &goi ); */
r = Jim_GetOpt_Enum( &goi, target_cmds, &x );
if( r != JIM_OK ){
return r;
}
+struct FastLoad
+{
+ u32 address;
+ u8 *data;
+ int length;
-/*
- * Local Variables: ***
- * c-basic-offset: 4 ***
- * tab-width: 4 ***
- * End: ***
- */
+};
+
+static int fastload_num;
+static struct FastLoad *fastload;
+
+static void free_fastload(void)
+{
+ if (fastload!=NULL)
+ {
+ int i;
+ for (i=0; i<fastload_num; i++)
+ {
+ if (fastload[i].data)
+ free(fastload[i].data);
+ }
+ free(fastload);
+ fastload=NULL;
+ }
+}
+
+
+
+
+int handle_fast_load_image_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+ u8 *buffer;
+ u32 buf_cnt;
+ u32 image_size;
+ u32 min_address=0;
+ u32 max_address=0xffffffff;
+ int i;
+ int retval;
+
+ image_t image;
+
+ duration_t duration;
+ char *duration_text;
+
+ if ((argc < 1)||(argc > 5))
+ {
+ return ERROR_COMMAND_SYNTAX_ERROR;
+ }
+
+ /* a base address isn't always necessary, default to 0x0 (i.e. don't relocate) */
+ if (argc >= 2)
+ {
+ image.base_address_set = 1;
+ image.base_address = strtoul(args[1], NULL, 0);
+ }
+ else
+ {
+ image.base_address_set = 0;
+ }
+
+
+ image.start_address_set = 0;
+
+ if (argc>=4)
+ {
+ min_address=strtoul(args[3], NULL, 0);
+ }
+ if (argc>=5)
+ {
+ max_address=strtoul(args[4], NULL, 0)+min_address;
+ }
+
+ if (min_address>max_address)
+ {
+ return ERROR_COMMAND_SYNTAX_ERROR;
+ }
+
+ duration_start_measure(&duration);
+
+ if (image_open(&image, args[0], (argc >= 3) ? args[2] : NULL) != ERROR_OK)
+ {
+ return ERROR_OK;
+ }
+
+ image_size = 0x0;
+ retval = ERROR_OK;
+ fastload_num=image.num_sections;
+ fastload=(struct FastLoad *)malloc(sizeof(struct FastLoad)*image.num_sections);
+ if (fastload==NULL)
+ {
+ image_close(&image);
+ return ERROR_FAIL;
+ }
+ memset(fastload, 0, sizeof(struct FastLoad)*image.num_sections);
+ for (i = 0; i < image.num_sections; i++)
+ {
+ buffer = malloc(image.sections[i].size);
+ if (buffer == NULL)
+ {
+ command_print(cmd_ctx, "error allocating buffer for section (%d bytes)", image.sections[i].size);
+ break;
+ }
+
+ if ((retval = image_read_section(&image, i, 0x0, image.sections[i].size, buffer, &buf_cnt)) != ERROR_OK)
+ {
+ free(buffer);
+ break;
+ }
+
+ u32 offset=0;
+ u32 length=buf_cnt;
+
+
+ /* DANGER!!! beware of unsigned comparision here!!! */
+
+ if ((image.sections[i].base_address+buf_cnt>=min_address)&&
+ (image.sections[i].base_address<max_address))
+ {
+ if (image.sections[i].base_address<min_address)
+ {
+ /* clip addresses below */
+ offset+=min_address-image.sections[i].base_address;
+ length-=offset;
+ }
+
+ if (image.sections[i].base_address+buf_cnt>max_address)
+ {
+ length-=(image.sections[i].base_address+buf_cnt)-max_address;
+ }
+
+ fastload[i].address=image.sections[i].base_address+offset;
+ fastload[i].data=malloc(length);
+ if (fastload[i].data==NULL)
+ {
+ free(buffer);
+ break;
+ }
+ memcpy(fastload[i].data, buffer+offset, length);
+ fastload[i].length=length;
+
+ image_size += length;
+ command_print(cmd_ctx, "%u byte written at address 0x%8.8x", length, image.sections[i].base_address+offset);
+ }
+
+ free(buffer);
+ }
+
+ duration_stop_measure(&duration, &duration_text);
+ if (retval==ERROR_OK)
+ {
+ command_print(cmd_ctx, "Loaded %u bytes in %s", image_size, duration_text);
+ command_print(cmd_ctx, "NB!!! image has not been loaded to target, issue a subsequent 'fast_load' to do so.");
+ }
+ free(duration_text);
+
+ image_close(&image);
+
+ if (retval!=ERROR_OK)
+ {
+ free_fastload();
+ }
+
+ return retval;
+}
+
+int handle_fast_load_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+ if (argc>0)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+ if (fastload==NULL)
+ {
+ LOG_ERROR("No image in memory");
+ return ERROR_FAIL;
+ }
+ int i;
+ int ms=timeval_ms();
+ int size=0;
+ for (i=0; i<fastload_num;i++)
+ {
+ int retval;
+ target_t *target = get_current_target(cmd_ctx);
+ if ((retval = target_write_buffer(target, fastload[i].address, fastload[i].length, fastload[i].data)) != ERROR_OK)
+ {
+ return retval;
+ }
+ size+=fastload[i].length;
+ }
+ int after=timeval_ms();
+ command_print(cmd_ctx, "Loaded image %f kBytes/s", (float)(size/1024.0)/((float)(after-ms)/1000.0));
+ return ERROR_OK;
+}