+static int handle_etm_tracemode_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+ target_t *target;
+ armv4_5_common_t *armv4_5;
+ arm7_9_common_t *arm7_9;
+ etmv1_tracemode_t tracemode;
+
+ target = get_current_target(cmd_ctx);
+
+ if (arm7_9_get_arch_pointers(target, &armv4_5, &arm7_9) != ERROR_OK)
+ {
+ command_print(cmd_ctx, "current target isn't an ARM7/ARM9 target");
+ return ERROR_OK;
+ }
+
+ if (!arm7_9->etm_ctx)
+ {
+ command_print(cmd_ctx, "current target doesn't have an ETM configured");
+ return ERROR_OK;
+ }
+
+ tracemode = arm7_9->etm_ctx->tracemode;
+
+ if (argc == 4)
+ {
+ if (strcmp(args[0], "none") == 0)
+ {
+ tracemode = ETMV1_TRACE_NONE;
+ }
+ else if (strcmp(args[0], "data") == 0)
+ {
+ tracemode = ETMV1_TRACE_DATA;
+ }
+ else if (strcmp(args[0], "address") == 0)
+ {
+ tracemode = ETMV1_TRACE_ADDR;
+ }
+ else if (strcmp(args[0], "all") == 0)
+ {
+ tracemode = ETMV1_TRACE_DATA | ETMV1_TRACE_ADDR;
+ }
+ else
+ {
+ command_print(cmd_ctx, "invalid option '%s'", args[0]);
+ return ERROR_OK;
+ }
+
+ switch (strtol(args[1], NULL, 0))
+ {
+ case 0:
+ tracemode |= ETMV1_CONTEXTID_NONE;
+ break;
+ case 8:
+ tracemode |= ETMV1_CONTEXTID_8;
+ break;
+ case 16:
+ tracemode |= ETMV1_CONTEXTID_16;
+ break;
+ case 32:
+ tracemode |= ETMV1_CONTEXTID_32;
+ break;
+ default:
+ command_print(cmd_ctx, "invalid option '%s'", args[1]);
+ return ERROR_OK;
+ }
+
+ if (strcmp(args[2], "enable") == 0)
+ {
+ tracemode |= ETMV1_CYCLE_ACCURATE;
+ }
+ else if (strcmp(args[2], "disable") == 0)
+ {
+ tracemode |= 0;
+ }
+ else
+ {
+ command_print(cmd_ctx, "invalid option '%s'", args[2]);
+ return ERROR_OK;
+ }
+
+ if (strcmp(args[3], "enable") == 0)
+ {
+ tracemode |= ETMV1_BRANCH_OUTPUT;
+ }
+ else if (strcmp(args[3], "disable") == 0)
+ {
+ tracemode |= 0;
+ }
+ else
+ {
+ command_print(cmd_ctx, "invalid option '%s'", args[2]);
+ return ERROR_OK;
+ }
+ }
+ else if (argc != 0)
+ {
+ command_print(cmd_ctx, "usage: configure trace mode <none | data | address | all> <context id bits> <cycle accurate> <branch output>");
+ return ERROR_OK;
+ }
+
+ command_print(cmd_ctx, "current tracemode configuration:");
+
+ switch (tracemode & ETMV1_TRACE_MASK)
+ {
+ case ETMV1_TRACE_NONE:
+ command_print(cmd_ctx, "data tracing: none");
+ break;
+ case ETMV1_TRACE_DATA:
+ command_print(cmd_ctx, "data tracing: data only");
+ break;
+ case ETMV1_TRACE_ADDR:
+ command_print(cmd_ctx, "data tracing: address only");
+ break;
+ case ETMV1_TRACE_DATA | ETMV1_TRACE_ADDR:
+ command_print(cmd_ctx, "data tracing: address and data");
+ break;
+ }
+
+ switch (tracemode & ETMV1_CONTEXTID_MASK)
+ {
+ case ETMV1_CONTEXTID_NONE:
+ command_print(cmd_ctx, "contextid tracing: none");
+ break;
+ case ETMV1_CONTEXTID_8:
+ command_print(cmd_ctx, "contextid tracing: 8 bit");
+ break;
+ case ETMV1_CONTEXTID_16:
+ command_print(cmd_ctx, "contextid tracing: 16 bit");
+ break;
+ case ETMV1_CONTEXTID_32:
+ command_print(cmd_ctx, "contextid tracing: 32 bit");
+ break;
+ }
+
+ if (tracemode & ETMV1_CYCLE_ACCURATE)
+ {
+ command_print(cmd_ctx, "cycle-accurate tracing enabled");
+ }
+ else
+ {
+ command_print(cmd_ctx, "cycle-accurate tracing disabled");
+ }
+
+ if (tracemode & ETMV1_BRANCH_OUTPUT)
+ {
+ command_print(cmd_ctx, "full branch address output enabled");
+ }
+ else
+ {
+ command_print(cmd_ctx, "full branch address output disabled");
+ }
+
+ /* only update ETM_CTRL register if tracemode changed */
+ if (arm7_9->etm_ctx->tracemode != tracemode)
+ {
+ reg_t *etm_ctrl_reg;
+
+ etm_ctrl_reg = etm_reg_lookup(arm7_9->etm_ctx, ETM_CTRL);
+ if (!etm_ctrl_reg)
+ return ERROR_OK;
+
+ etm_get_reg(etm_ctrl_reg);
+
+ buf_set_u32(etm_ctrl_reg->value, 2, 2, tracemode & ETMV1_TRACE_MASK);
+ buf_set_u32(etm_ctrl_reg->value, 14, 2, (tracemode & ETMV1_CONTEXTID_MASK) >> 4);
+ buf_set_u32(etm_ctrl_reg->value, 12, 1, (tracemode & ETMV1_CYCLE_ACCURATE) >> 8);
+ buf_set_u32(etm_ctrl_reg->value, 8, 1, (tracemode & ETMV1_BRANCH_OUTPUT) >> 9);
+ etm_store_reg(etm_ctrl_reg);
+
+ arm7_9->etm_ctx->tracemode = tracemode;
+
+ /* invalidate old trace data */
+ arm7_9->etm_ctx->capture_status = TRACE_IDLE;
+ if (arm7_9->etm_ctx->trace_depth > 0)
+ {
+ free(arm7_9->etm_ctx->trace_data);
+ arm7_9->etm_ctx->trace_data = NULL;
+ }
+ arm7_9->etm_ctx->trace_depth = 0;
+ }
+
+ return ERROR_OK;
+}
+
+static int handle_etm_config_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+ target_t *target;
+ armv4_5_common_t *armv4_5;
+ arm7_9_common_t *arm7_9;
+ etm_portmode_t portmode = 0x0;
+ etm_context_t *etm_ctx = malloc(sizeof(etm_context_t));
+ int i;
+
+ if (argc != 5)
+ {
+ free(etm_ctx);
+ return ERROR_COMMAND_SYNTAX_ERROR;
+ }
+
+ target = get_target(args[0]);
+ if (!target)
+ {
+ LOG_ERROR("target '%s' not defined", args[0]);
+ free(etm_ctx);
+ return ERROR_FAIL;
+ }
+
+ if (arm7_9_get_arch_pointers(target, &armv4_5, &arm7_9) != ERROR_OK)
+ {
+ command_print(cmd_ctx, "current target isn't an ARM7/ARM9 target");
+ free(etm_ctx);
+ return ERROR_FAIL;
+ }
+
+ switch (strtoul(args[1], NULL, 0))
+ {
+ case 4:
+ portmode |= ETM_PORT_4BIT;
+ break;
+ case 8:
+ portmode |= ETM_PORT_8BIT;
+ break;
+ case 16:
+ portmode |= ETM_PORT_16BIT;
+ break;
+ default:
+ command_print(cmd_ctx, "unsupported ETM port width '%s', must be 4, 8 or 16", args[1]);
+ free(etm_ctx);
+ return ERROR_FAIL;
+ }
+
+ if (strcmp("normal", args[2]) == 0)
+ {
+ portmode |= ETM_PORT_NORMAL;
+ }
+ else if (strcmp("multiplexed", args[2]) == 0)
+ {
+ portmode |= ETM_PORT_MUXED;
+ }
+ else if (strcmp("demultiplexed", args[2]) == 0)
+ {
+ portmode |= ETM_PORT_DEMUXED;
+ }
+ else
+ {
+ command_print(cmd_ctx, "unsupported ETM port mode '%s', must be 'normal', 'multiplexed' or 'demultiplexed'", args[2]);
+ free(etm_ctx);
+ return ERROR_FAIL;
+ }
+
+ if (strcmp("half", args[3]) == 0)
+ {
+ portmode |= ETM_PORT_HALF_CLOCK;
+ }
+ else if (strcmp("full", args[3]) == 0)
+ {
+ portmode |= ETM_PORT_FULL_CLOCK;
+ }
+ else
+ {
+ command_print(cmd_ctx, "unsupported ETM port clocking '%s', must be 'full' or 'half'", args[3]);
+ free(etm_ctx);
+ return ERROR_FAIL;
+ }
+
+ for (i = 0; etm_capture_drivers[i]; i++)
+ {
+ if (strcmp(args[4], etm_capture_drivers[i]->name) == 0)
+ {
+ int retval;
+ if ((retval = etm_capture_drivers[i]->register_commands(cmd_ctx)) != ERROR_OK)
+ {
+ free(etm_ctx);
+ return retval;
+ }
+
+ etm_ctx->capture_driver = etm_capture_drivers[i];
+
+ break;
+ }
+ }
+
+ if (!etm_capture_drivers[i])
+ {
+ /* no supported capture driver found, don't register an ETM */
+ free(etm_ctx);
+ LOG_ERROR("trace capture driver '%s' not found", args[4]);
+ return ERROR_FAIL;
+ }
+
+ etm_ctx->target = target;
+ etm_ctx->trigger_percent = 50;
+ etm_ctx->trace_data = NULL;
+ etm_ctx->trace_depth = 0;
+ etm_ctx->portmode = portmode;
+ etm_ctx->tracemode = 0x0;
+ etm_ctx->core_state = ARMV4_5_STATE_ARM;
+ etm_ctx->image = NULL;
+ etm_ctx->pipe_index = 0;
+ etm_ctx->data_index = 0;
+ etm_ctx->current_pc = 0x0;
+ etm_ctx->pc_ok = 0;
+ etm_ctx->last_branch = 0x0;
+ etm_ctx->last_branch_reason = 0x0;
+ etm_ctx->last_ptr = 0x0;
+ etm_ctx->ptr_ok = 0x0;
+ etm_ctx->last_instruction = 0;
+
+ arm7_9->etm_ctx = etm_ctx;
+
+ return etm_register_user_commands(cmd_ctx);
+}
+
+static int handle_etm_info_command(struct command_context_s *cmd_ctx,
+ char *cmd, char **args, int argc)
+{
+ target_t *target;
+ armv4_5_common_t *armv4_5;
+ arm7_9_common_t *arm7_9;
+ etm_context_t *etm;
+ reg_t *etm_sys_config_reg;
+
+ int max_port_size;
+
+ target = get_current_target(cmd_ctx);
+
+ if (arm7_9_get_arch_pointers(target, &armv4_5, &arm7_9) != ERROR_OK)
+ {
+ command_print(cmd_ctx, "current target isn't an ARM7/ARM9 target");
+ return ERROR_OK;
+ }
+
+ etm = arm7_9->etm_ctx;
+ if (!etm)
+ {
+ command_print(cmd_ctx, "current target doesn't have an ETM configured");
+ return ERROR_OK;
+ }
+
+ command_print(cmd_ctx, "ETM v%d.%d",
+ etm->bcd_vers >> 4, etm->bcd_vers & 0xf);
+ command_print(cmd_ctx, "pairs of address comparators: %i",
+ (int) (etm->config >> 0) & 0x0f);
+ command_print(cmd_ctx, "data comparators: %i",
+ (int) (etm->config >> 4) & 0x0f);
+ command_print(cmd_ctx, "memory map decoders: %i",
+ (int) (etm->config >> 8) & 0x1f);
+ command_print(cmd_ctx, "number of counters: %i",
+ (int) (etm->config >> 13) & 0x07);
+ command_print(cmd_ctx, "sequencer %spresent",
+ (int) (etm->config & (1 << 16)) ? "" : "not ");
+ command_print(cmd_ctx, "number of ext. inputs: %i",
+ (int) (etm->config >> 17) & 0x07);
+ command_print(cmd_ctx, "number of ext. outputs: %i",
+ (int) (etm->config >> 20) & 0x07);
+ command_print(cmd_ctx, "FIFO full %spresent",
+ (int) (etm->config & (1 << 23)) ? "" : "not ");
+ if (etm->bcd_vers < 0x20)
+ command_print(cmd_ctx, "protocol version: %i",
+ (int) (etm->config >> 28) & 0x07);
+ else {
+ command_print(cmd_ctx, "trace start/stop %spresent",
+ (etm->config & (1 << 26)) ? "" : "not ");
+ command_print(cmd_ctx, "number of context comparators: %i",
+ (int) (etm->config >> 24) & 0x03);
+ }
+
+ /* SYS_CONFIG isn't present before ETMv1.2 */
+ etm_sys_config_reg = etm_reg_lookup(etm, ETM_SYS_CONFIG);
+ if (!etm_sys_config_reg)
+ return ERROR_OK;
+
+ etm_get_reg(etm_sys_config_reg);
+
+ switch (buf_get_u32(etm_sys_config_reg->value, 0, 3))
+ {
+ case 0:
+ max_port_size = 4;
+ break;
+ case 1:
+ max_port_size = 8;
+ break;
+ case 2:
+ max_port_size = 16;
+ break;
+ default:
+ LOG_ERROR("Illegal max_port_size");
+ exit(-1);
+ }
+ command_print(cmd_ctx, "max. port size: %i", max_port_size);
+
+ command_print(cmd_ctx, "half-rate clocking %ssupported",
+ (buf_get_u32(etm_sys_config_reg->value, 3, 1) == 1) ? "" : "not ");
+ command_print(cmd_ctx, "full-rate clocking %ssupported",
+ (buf_get_u32(etm_sys_config_reg->value, 4, 1) == 1) ? "" : "not ");
+ command_print(cmd_ctx, "normal trace format %ssupported",
+ (buf_get_u32(etm_sys_config_reg->value, 5, 1) == 1) ? "" : "not ");
+ command_print(cmd_ctx, "multiplex trace format %ssupported",
+ (buf_get_u32(etm_sys_config_reg->value, 6, 1) == 1) ? "" : "not ");
+ command_print(cmd_ctx, "demultiplex trace format %ssupported",
+ (buf_get_u32(etm_sys_config_reg->value, 7, 1) == 1) ? "" : "not ");
+ command_print(cmd_ctx, "FIFO full %ssupported",
+ (buf_get_u32(etm_sys_config_reg->value, 8, 1) == 1) ? "" : "not ");
+
+ return ERROR_OK;
+}
+
+static int handle_etm_status_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+ target_t *target;
+ armv4_5_common_t *armv4_5;
+ arm7_9_common_t *arm7_9;
+ etm_context_t *etm;
+ trace_status_t trace_status;
+
+ target = get_current_target(cmd_ctx);
+
+ if (arm7_9_get_arch_pointers(target, &armv4_5, &arm7_9) != ERROR_OK)
+ {
+ command_print(cmd_ctx, "current target isn't an ARM7/ARM9 target");
+ return ERROR_OK;
+ }
+
+ if (!arm7_9->etm_ctx)
+ {
+ command_print(cmd_ctx, "current target doesn't have an ETM configured");
+ return ERROR_OK;
+ }
+ etm = arm7_9->etm_ctx;
+
+ /* ETM status */
+ if (etm->bcd_vers >= 0x11) {
+ reg_t *reg;
+
+ reg = etm_reg_lookup(etm, ETM_STATUS);
+ if (!reg)
+ return ERROR_OK;
+ if (etm_get_reg(reg) == ERROR_OK) {
+ unsigned s = buf_get_u32(reg->value, 0, reg->size);
+
+ command_print(cmd_ctx, "etm: %s%s%s%s",
+ /* bit(1) == progbit */
+ (etm->bcd_vers >= 0x12)
+ ? ((s & (1 << 1))
+ ? "disabled" : "enabled")
+ : "?",
+ ((s & (1 << 3)) && etm->bcd_vers >= 0x31)
+ ? " triggered" : "",
+ ((s & (1 << 2)) && etm->bcd_vers >= 0x12)
+ ? " start/stop" : "",
+ ((s & (1 << 0)) && etm->bcd_vers >= 0x11)
+ ? " untraced-overflow" : "");
+ } /* else ignore and try showing trace port status */
+ }
+
+ /* Trace Port Driver status */
+ trace_status = etm->capture_driver->status(etm);
+ if (trace_status == TRACE_IDLE)
+ {
+ command_print(cmd_ctx, "%s: idle", etm->capture_driver->name);
+ }
+ else
+ {
+ static char *completed = " completed";
+ static char *running = " is running";
+ static char *overflowed = ", overflowed";
+ static char *triggered = ", triggered";
+
+ command_print(cmd_ctx, "%s: trace collection%s%s%s",
+ etm->capture_driver->name,
+ (trace_status & TRACE_RUNNING) ? running : completed,
+ (trace_status & TRACE_OVERFLOWED) ? overflowed : "",
+ (trace_status & TRACE_TRIGGERED) ? triggered : "");
+
+ if (etm->trace_depth > 0)
+ {
+ command_print(cmd_ctx, "%i frames of trace data read",
+ (int)(etm->trace_depth));
+ }
+ }
+
+ return ERROR_OK;
+}
+
+static int handle_etm_image_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+ target_t *target;
+ armv4_5_common_t *armv4_5;
+ arm7_9_common_t *arm7_9;
+ etm_context_t *etm_ctx;
+
+ if (argc < 1)
+ {
+ command_print(cmd_ctx, "usage: etm image <file> [base address] [type]");
+ return ERROR_OK;
+ }
+
+ target = get_current_target(cmd_ctx);
+
+ if (arm7_9_get_arch_pointers(target, &armv4_5, &arm7_9) != ERROR_OK)
+ {
+ command_print(cmd_ctx, "current target isn't an ARM7/ARM9 target");
+ return ERROR_OK;
+ }
+
+ if (!(etm_ctx = arm7_9->etm_ctx))
+ {
+ command_print(cmd_ctx, "current target doesn't have an ETM configured");
+ return ERROR_OK;
+ }
+
+ if (etm_ctx->image)
+ {
+ image_close(etm_ctx->image);
+ free(etm_ctx->image);
+ command_print(cmd_ctx, "previously loaded image found and closed");
+ }
+
+ etm_ctx->image = malloc(sizeof(image_t));
+ etm_ctx->image->base_address_set = 0;
+ etm_ctx->image->start_address_set = 0;
+
+ /* a base address isn't always necessary, default to 0x0 (i.e. don't relocate) */
+ if (argc >= 2)
+ {
+ etm_ctx->image->base_address_set = 1;
+ etm_ctx->image->base_address = strtoul(args[1], NULL, 0);
+ }
+ else
+ {
+ etm_ctx->image->base_address_set = 0;
+ }
+
+ if (image_open(etm_ctx->image, args[0], (argc >= 3) ? args[2] : NULL) != ERROR_OK)
+ {
+ free(etm_ctx->image);
+ etm_ctx->image = NULL;
+ return ERROR_OK;
+ }
+
+ return ERROR_OK;
+}
+
+static int handle_etm_dump_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+ fileio_t file;
+ target_t *target;
+ armv4_5_common_t *armv4_5;
+ arm7_9_common_t *arm7_9;
+ etm_context_t *etm_ctx;
+ uint32_t i;
+
+ if (argc != 1)
+ {
+ command_print(cmd_ctx, "usage: etm dump <file>");
+ return ERROR_OK;
+ }
+
+ target = get_current_target(cmd_ctx);
+
+ if (arm7_9_get_arch_pointers(target, &armv4_5, &arm7_9) != ERROR_OK)
+ {
+ command_print(cmd_ctx, "current target isn't an ARM7/ARM9 target");
+ return ERROR_OK;
+ }
+
+ if (!(etm_ctx = arm7_9->etm_ctx))
+ {
+ command_print(cmd_ctx, "current target doesn't have an ETM configured");
+ return ERROR_OK;
+ }
+
+ if (etm_ctx->capture_driver->status == TRACE_IDLE)
+ {
+ command_print(cmd_ctx, "trace capture wasn't enabled, no trace data captured");
+ return ERROR_OK;
+ }
+
+ if (etm_ctx->capture_driver->status(etm_ctx) & TRACE_RUNNING)
+ {
+ /* TODO: if on-the-fly capture is to be supported, this needs to be changed */
+ command_print(cmd_ctx, "trace capture not completed");
+ return ERROR_OK;
+ }
+
+ /* read the trace data if it wasn't read already */
+ if (etm_ctx->trace_depth == 0)
+ etm_ctx->capture_driver->read_trace(etm_ctx);
+
+ if (fileio_open(&file, args[0], FILEIO_WRITE, FILEIO_BINARY) != ERROR_OK)
+ {
+ return ERROR_OK;
+ }
+
+ fileio_write_u32(&file, etm_ctx->capture_status);
+ fileio_write_u32(&file, etm_ctx->portmode);
+ fileio_write_u32(&file, etm_ctx->tracemode);
+ fileio_write_u32(&file, etm_ctx->trace_depth);
+
+ for (i = 0; i < etm_ctx->trace_depth; i++)
+ {
+ fileio_write_u32(&file, etm_ctx->trace_data[i].pipestat);
+ fileio_write_u32(&file, etm_ctx->trace_data[i].packet);
+ fileio_write_u32(&file, etm_ctx->trace_data[i].flags);
+ }
+
+ fileio_close(&file);
+
+ return ERROR_OK;
+}
+
+static int handle_etm_load_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+ fileio_t file;
+ target_t *target;
+ armv4_5_common_t *armv4_5;
+ arm7_9_common_t *arm7_9;
+ etm_context_t *etm_ctx;
+ uint32_t i;
+
+ if (argc != 1)
+ {
+ command_print(cmd_ctx, "usage: etm load <file>");
+ return ERROR_OK;
+ }
+
+ target = get_current_target(cmd_ctx);
+
+ if (arm7_9_get_arch_pointers(target, &armv4_5, &arm7_9) != ERROR_OK)
+ {
+ command_print(cmd_ctx, "current target isn't an ARM7/ARM9 target");
+ return ERROR_OK;
+ }
+
+ if (!(etm_ctx = arm7_9->etm_ctx))
+ {
+ command_print(cmd_ctx, "current target doesn't have an ETM configured");
+ return ERROR_OK;
+ }
+
+ if (etm_ctx->capture_driver->status(etm_ctx) & TRACE_RUNNING)
+ {
+ command_print(cmd_ctx, "trace capture running, stop first");
+ return ERROR_OK;
+ }
+
+ if (fileio_open(&file, args[0], FILEIO_READ, FILEIO_BINARY) != ERROR_OK)
+ {
+ return ERROR_OK;
+ }
+
+ if (file.size % 4)
+ {
+ command_print(cmd_ctx, "size isn't a multiple of 4, no valid trace data");
+ fileio_close(&file);
+ return ERROR_OK;
+ }
+
+ if (etm_ctx->trace_depth > 0)
+ {
+ free(etm_ctx->trace_data);
+ etm_ctx->trace_data = NULL;
+ }
+
+ {
+ uint32_t tmp;
+ fileio_read_u32(&file, &tmp); etm_ctx->capture_status = tmp;
+ fileio_read_u32(&file, &tmp); etm_ctx->portmode = tmp;
+ fileio_read_u32(&file, &tmp); etm_ctx->tracemode = tmp;
+ fileio_read_u32(&file, &etm_ctx->trace_depth);
+ }
+ etm_ctx->trace_data = malloc(sizeof(etmv1_trace_data_t) * etm_ctx->trace_depth);
+ if (etm_ctx->trace_data == NULL)
+ {
+ command_print(cmd_ctx, "not enough memory to perform operation");
+ fileio_close(&file);
+ return ERROR_OK;
+ }
+
+ for (i = 0; i < etm_ctx->trace_depth; i++)
+ {
+ uint32_t pipestat, packet, flags;
+ fileio_read_u32(&file, &pipestat);
+ fileio_read_u32(&file, &packet);
+ fileio_read_u32(&file, &flags);
+ etm_ctx->trace_data[i].pipestat = pipestat & 0xff;
+ etm_ctx->trace_data[i].packet = packet & 0xffff;
+ etm_ctx->trace_data[i].flags = flags;
+ }
+
+ fileio_close(&file);
+
+ return ERROR_OK;
+}
+
+static int handle_etm_trigger_percent_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+ target_t *target;
+ armv4_5_common_t *armv4_5;
+ arm7_9_common_t *arm7_9;
+ etm_context_t *etm_ctx;
+
+ target = get_current_target(cmd_ctx);
+
+ if (arm7_9_get_arch_pointers(target, &armv4_5, &arm7_9) != ERROR_OK)
+ {
+ command_print(cmd_ctx, "current target isn't an ARM7/ARM9 target");
+ return ERROR_OK;
+ }
+
+ if (!(etm_ctx = arm7_9->etm_ctx))
+ {
+ command_print(cmd_ctx, "current target doesn't have an ETM configured");
+ return ERROR_OK;
+ }
+
+ if (argc > 0)
+ {
+ uint32_t new_value = strtoul(args[0], NULL, 0);
+
+ if ((new_value < 2) || (new_value > 100))
+ {
+ command_print(cmd_ctx, "valid settings are 2%% to 100%%");
+ }
+ else
+ {
+ etm_ctx->trigger_percent = new_value;
+ }
+ }
+
+ command_print(cmd_ctx, "%i percent of the tracebuffer reserved for after the trigger", ((int)(etm_ctx->trigger_percent)));
+
+ return ERROR_OK;
+}
+
+static int handle_etm_start_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+ target_t *target;
+ armv4_5_common_t *armv4_5;
+ arm7_9_common_t *arm7_9;
+ etm_context_t *etm_ctx;
+ reg_t *etm_ctrl_reg;
+
+ target = get_current_target(cmd_ctx);
+
+ if (arm7_9_get_arch_pointers(target, &armv4_5, &arm7_9) != ERROR_OK)
+ {
+ command_print(cmd_ctx, "current target isn't an ARM7/ARM9 target");
+ return ERROR_OK;
+ }
+
+ if (!(etm_ctx = arm7_9->etm_ctx))
+ {
+ command_print(cmd_ctx, "current target doesn't have an ETM configured");
+ return ERROR_OK;
+ }
+
+ /* invalidate old tracing data */
+ arm7_9->etm_ctx->capture_status = TRACE_IDLE;
+ if (arm7_9->etm_ctx->trace_depth > 0)
+ {
+ free(arm7_9->etm_ctx->trace_data);
+ arm7_9->etm_ctx->trace_data = NULL;
+ }
+ arm7_9->etm_ctx->trace_depth = 0;
+
+ etm_ctrl_reg = etm_reg_lookup(etm_ctx, ETM_CTRL);
+ if (!etm_ctrl_reg)
+ return ERROR_OK;
+
+ etm_get_reg(etm_ctrl_reg);
+
+ /* Clear programming bit (10), set port selection bit (11) */
+ buf_set_u32(etm_ctrl_reg->value, 10, 2, 0x2);
+
+ etm_store_reg(etm_ctrl_reg);
+ jtag_execute_queue();
+
+ etm_ctx->capture_driver->start_capture(etm_ctx);
+
+ return ERROR_OK;
+}
+
+static int handle_etm_stop_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+ target_t *target;
+ armv4_5_common_t *armv4_5;
+ arm7_9_common_t *arm7_9;
+ etm_context_t *etm_ctx;
+ reg_t *etm_ctrl_reg;
+
+ target = get_current_target(cmd_ctx);
+
+ if (arm7_9_get_arch_pointers(target, &armv4_5, &arm7_9) != ERROR_OK)
+ {
+ command_print(cmd_ctx, "current target isn't an ARM7/ARM9 target");
+ return ERROR_OK;
+ }
+
+ if (!(etm_ctx = arm7_9->etm_ctx))
+ {
+ command_print(cmd_ctx, "current target doesn't have an ETM configured");
+ return ERROR_OK;
+ }
+
+ etm_ctrl_reg = etm_reg_lookup(etm_ctx, ETM_CTRL);
+ if (!etm_ctrl_reg)
+ return ERROR_OK;
+
+ etm_get_reg(etm_ctrl_reg);
+
+ /* Set programming bit (10), clear port selection bit (11) */
+ buf_set_u32(etm_ctrl_reg->value, 10, 2, 0x1);
+
+ etm_store_reg(etm_ctrl_reg);
+ jtag_execute_queue();
+
+ etm_ctx->capture_driver->stop_capture(etm_ctx);
+
+ return ERROR_OK;
+}
+
+static int handle_etm_analyze_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+ target_t *target;
+ armv4_5_common_t *armv4_5;
+ arm7_9_common_t *arm7_9;
+ etm_context_t *etm_ctx;
+ int retval;
+
+ target = get_current_target(cmd_ctx);
+
+ if (arm7_9_get_arch_pointers(target, &armv4_5, &arm7_9) != ERROR_OK)
+ {
+ command_print(cmd_ctx, "current target isn't an ARM7/ARM9 target");
+ return ERROR_OK;
+ }
+
+ if (!(etm_ctx = arm7_9->etm_ctx))
+ {
+ command_print(cmd_ctx, "current target doesn't have an ETM configured");
+ return ERROR_OK;
+ }
+
+ if ((retval = etmv1_analyze_trace(etm_ctx, cmd_ctx)) != ERROR_OK)
+ {
+ switch (retval)
+ {
+ case ERROR_ETM_ANALYSIS_FAILED:
+ command_print(cmd_ctx, "further analysis failed (corrupted trace data or just end of data");
+ break;
+ case ERROR_TRACE_INSTRUCTION_UNAVAILABLE:
+ command_print(cmd_ctx, "no instruction for current address available, analysis aborted");
+ break;
+ case ERROR_TRACE_IMAGE_UNAVAILABLE:
+ command_print(cmd_ctx, "no image available for trace analysis");
+ break;
+ default:
+ command_print(cmd_ctx, "unknown error: %i", retval);
+ }
+ }
+
+ return ERROR_OK;
+}
+
+int etm_register_commands(struct command_context_s *cmd_ctx)
+{
+ etm_cmd = register_command(cmd_ctx, NULL, "etm", NULL, COMMAND_ANY, "Embedded Trace Macrocell");
+
+ register_command(cmd_ctx, etm_cmd, "config", handle_etm_config_command,
+ COMMAND_CONFIG, "etm config <target> <port_width> <port_mode> <clocking> <capture_driver>");
+
+ return ERROR_OK;
+}
+
+static int etm_register_user_commands(struct command_context_s *cmd_ctx)
+{
+ register_command(cmd_ctx, etm_cmd, "tracemode", handle_etm_tracemode_command,
+ COMMAND_EXEC, "configure/display trace mode: "
+ "<none | data | address | all> "
+ "<context_id_bits> <cycle_accurate> <branch_output>");
+
+ register_command(cmd_ctx, etm_cmd, "info", handle_etm_info_command,
+ COMMAND_EXEC, "display info about the current target's ETM");
+
+ register_command(cmd_ctx, etm_cmd, "trigger_percent", handle_etm_trigger_percent_command,
+ COMMAND_EXEC, "amount (<percent>) of trace buffer to be filled after the trigger occured");
+ register_command(cmd_ctx, etm_cmd, "status", handle_etm_status_command,
+ COMMAND_EXEC, "display current target's ETM status");
+ register_command(cmd_ctx, etm_cmd, "start", handle_etm_start_command,
+ COMMAND_EXEC, "start ETM trace collection");
+ register_command(cmd_ctx, etm_cmd, "stop", handle_etm_stop_command,
+ COMMAND_EXEC, "stop ETM trace collection");
+
+ register_command(cmd_ctx, etm_cmd, "analyze", handle_etm_analyze_command,
+ COMMAND_EXEC, "anaylze collected ETM trace");
+
+ register_command(cmd_ctx, etm_cmd, "image", handle_etm_image_command,
+ COMMAND_EXEC, "load image from <file> [base address]");
+
+ register_command(cmd_ctx, etm_cmd, "dump", handle_etm_dump_command,
+ COMMAND_EXEC, "dump captured trace data <file>");
+ register_command(cmd_ctx, etm_cmd, "load", handle_etm_load_command,
+ COMMAND_EXEC, "load trace data for analysis <file>");
+
+ return ERROR_OK;
+}