X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=src%2Ftarget%2Fetm.c;h=3126efc2f211f597be37d5bc6b1572005f399238;hb=d91941d5a01ca0b9d43571edc03ba18741076cca;hp=72e8b3d21fe422b0f7b58da5e8863db8f36fe91f;hpb=23402315ce01071f30d7ec0c5ca7563ce41f1cc6;p=openocd diff --git a/src/target/etm.c b/src/target/etm.c index 72e8b3d2..3126efc2 100644 --- a/src/target/etm.c +++ b/src/target/etm.c @@ -21,12 +21,17 @@ #include "config.h" #endif -#include "armv4_5.h" +#include "arm.h" #include "etm.h" #include "etb.h" #include "image.h" #include "arm_disassembler.h" #include "register.h" +#include "etm_dummy.h" + +#if BUILD_OOCD_TRACE == 1 +#include "oocd_trace.h" +#endif /* @@ -221,8 +226,6 @@ static int etm_register_user_commands(struct command_context *cmd_ctx); static int etm_set_reg_w_exec(struct reg *reg, uint8_t *buf); static int etm_write_reg(struct reg *reg, uint32_t value); -static struct command *etm_cmd; - static const struct reg_arch_type etm_scan6_type = { .get = etm_get_reg, .set = etm_set_reg_w_exec, @@ -234,7 +237,7 @@ static const struct reg_arch_type etm_scan6_type = { static struct reg *etm_reg_lookup(struct etm_context *etm_ctx, unsigned id) { struct reg_cache *cache = etm_ctx->reg_cache; - int i; + unsigned i; for (i = 0; i < cache->num_regs; i++) { struct etm_reg *reg = cache->reg_list[i].arch_info; @@ -432,10 +435,10 @@ int etm_setup(struct target *target) /* initialize some ETM control register settings */ etm_get_reg(etm_ctrl_reg); - etm_ctrl_value = buf_get_u32(etm_ctrl_reg->value, 0, etm_ctrl_reg->size); + etm_ctrl_value = buf_get_u32(etm_ctrl_reg->value, 0, 32); /* clear the ETM powerdown bit (0) */ - etm_ctrl_value &= ~0x1; + etm_ctrl_value &= ~ETM_CTRL_POWERDOWN; /* configure port width (21,6:4), mode (13,17:16) and * for older modules clocking (13) @@ -443,12 +446,15 @@ int etm_setup(struct target *target) etm_ctrl_value = (etm_ctrl_value & ~ETM_PORT_WIDTH_MASK & ~ETM_PORT_MODE_MASK + & ~ETM_CTRL_DBGRQ & ~ETM_PORT_CLOCK_MASK) - | etm_ctx->portmode; + | etm_ctx->control; - buf_set_u32(etm_ctrl_reg->value, 0, etm_ctrl_reg->size, etm_ctrl_value); + buf_set_u32(etm_ctrl_reg->value, 0, 32, etm_ctrl_value); etm_store_reg(etm_ctrl_reg); + etm_ctx->control = etm_ctrl_value; + if ((retval = jtag_execute_queue()) != ERROR_OK) return retval; @@ -615,13 +621,7 @@ static int etm_write_reg(struct reg *reg, uint32_t value) } -/* ETM trace analysis functionality - * - */ -extern struct etm_capture_driver etm_dummy_capture_driver; -#if BUILD_OOCD_TRACE == 1 -extern struct etm_capture_driver oocd_trace_capture_driver; -#endif +/* ETM trace analysis functionality */ static struct etm_capture_driver *etm_capture_drivers[] = { @@ -661,7 +661,7 @@ static int etm_read_instruction(struct etm_context *ctx, struct arm_instruction return ERROR_TRACE_INSTRUCTION_UNAVAILABLE; } - if (ctx->core_state == ARMV4_5_STATE_ARM) + if (ctx->core_state == ARM_STATE_ARM) { uint8_t buf[4]; if ((retval = image_read_section(ctx->image, section, @@ -674,7 +674,7 @@ static int etm_read_instruction(struct etm_context *ctx, struct arm_instruction opcode = target_buffer_get_u32(ctx->target, buf); arm_evaluate_opcode(opcode, ctx->current_pc, instruction); } - else if (ctx->core_state == ARMV4_5_STATE_THUMB) + else if (ctx->core_state == ARM_STATE_THUMB) { uint8_t buf[2]; if ((retval = image_read_section(ctx->image, section, @@ -687,7 +687,7 @@ static int etm_read_instruction(struct etm_context *ctx, struct arm_instruction opcode = target_buffer_get_u16(ctx->target, buf); thumb_evaluate_opcode(opcode, ctx->current_pc, instruction); } - else if (ctx->core_state == ARMV4_5_STATE_JAZELLE) + else if (ctx->core_state == ARM_STATE_JAZELLE) { LOG_ERROR("BUG: tracing of jazelle code not supported"); return ERROR_FAIL; @@ -730,7 +730,8 @@ static int etmv1_next_packet(struct etm_context *ctx, uint8_t *packet, int apo) continue; } - if ((ctx->portmode & ETM_PORT_WIDTH_MASK) == ETM_PORT_16BIT) + /* FIXME there are more port widths than these... */ + if ((ctx->control & ETM_PORT_WIDTH_MASK) == ETM_PORT_16BIT) { if (ctx->data_half == 0) { @@ -744,7 +745,7 @@ static int etmv1_next_packet(struct etm_context *ctx, uint8_t *packet, int apo) ctx->data_index++; } } - else if ((ctx->portmode & ETM_PORT_WIDTH_MASK) == ETM_PORT_8BIT) + else if ((ctx->control & ETM_PORT_WIDTH_MASK) == ETM_PORT_8BIT) { *packet = ctx->trace_data[ctx->data_index].packet & 0xff; ctx->data_index++; @@ -831,7 +832,7 @@ static int etmv1_branch_address(struct etm_context *ctx) /* if a full address was output, we might have branched into Jazelle state */ if ((shift == 32) && (packet & 0x80)) { - ctx->core_state = ARMV4_5_STATE_JAZELLE; + ctx->core_state = ARM_STATE_JAZELLE; } else { @@ -839,12 +840,12 @@ static int etmv1_branch_address(struct etm_context *ctx) * encoded in bit 0 of the branch target address */ if (ctx->last_branch & 0x1) { - ctx->core_state = ARMV4_5_STATE_THUMB; + ctx->core_state = ARM_STATE_THUMB; ctx->last_branch &= ~0x1; } else { - ctx->core_state = ARMV4_5_STATE_ARM; + ctx->core_state = ARM_STATE_ARM; ctx->last_branch &= ~0x3; } } @@ -1061,7 +1062,7 @@ static int etmv1_analyze_trace(struct etm_context *ctx, struct command_context * ctx->data_half = old_data_half; } - if (ctx->tracemode & ETMV1_TRACE_ADDR) + if (ctx->control & ETM_CTRL_TRACE_ADDR) { uint8_t packet; int shift = 0; @@ -1083,7 +1084,7 @@ static int etmv1_analyze_trace(struct etm_context *ctx, struct command_context * } } - if (ctx->tracemode & ETMV1_TRACE_DATA) + if (ctx->control & ETM_CTRL_TRACE_DATA) { if ((instruction.type == ARM_LDM) || (instruction.type == ARM_STM)) { @@ -1128,12 +1129,12 @@ static int etmv1_analyze_trace(struct etm_context *ctx, struct command_context * } else { - next_pc += (ctx->core_state == ARMV4_5_STATE_ARM) ? 4 : 2; + next_pc += (ctx->core_state == ARM_STATE_ARM) ? 4 : 2; } } else if (pipestat == STAT_IN) { - next_pc += (ctx->core_state == ARMV4_5_STATE_ARM) ? 4 : 2; + next_pc += (ctx->core_state == ARM_STATE_ARM) ? 4 : 2; } if ((pipestat != STAT_TD) && (pipestat != STAT_WT)) @@ -1143,7 +1144,7 @@ static int etmv1_analyze_trace(struct etm_context *ctx, struct command_context * /* if the trace was captured with cycle accurate tracing enabled, * output the number of cycles since the last executed instruction */ - if (ctx->tracemode & ETMV1_CYCLE_ACCURATE) + if (ctx->control & ETM_CTRL_CYCLE_ACCURATE) { snprintf(cycles_text, 32, " (%i %s)", (int)cycles, @@ -1174,22 +1175,22 @@ static int etmv1_analyze_trace(struct etm_context *ctx, struct command_context * } static COMMAND_HELPER(handle_etm_tracemode_command_update, - etmv1_tracemode_t *mode) + uint32_t *mode) { - etmv1_tracemode_t tracemode; + uint32_t tracemode; /* what parts of data access are traced? */ if (strcmp(CMD_ARGV[0], "none") == 0) - tracemode = ETMV1_TRACE_NONE; + tracemode = 0; else if (strcmp(CMD_ARGV[0], "data") == 0) - tracemode = ETMV1_TRACE_DATA; + tracemode = ETM_CTRL_TRACE_DATA; else if (strcmp(CMD_ARGV[0], "address") == 0) - tracemode = ETMV1_TRACE_ADDR; + tracemode = ETM_CTRL_TRACE_ADDR; else if (strcmp(CMD_ARGV[0], "all") == 0) - tracemode = ETMV1_TRACE_DATA | ETMV1_TRACE_ADDR; + tracemode = ETM_CTRL_TRACE_DATA | ETM_CTRL_TRACE_ADDR; else { - command_print(cmd_ctx, "invalid option '%s'", CMD_ARGV[0]); + command_print(CMD_CTX, "invalid option '%s'", CMD_ARGV[0]); return ERROR_INVALID_ARGUMENTS; } @@ -1198,41 +1199,31 @@ static COMMAND_HELPER(handle_etm_tracemode_command_update, switch (context_id) { case 0: - tracemode |= ETMV1_CONTEXTID_NONE; + tracemode |= ETM_CTRL_CONTEXTID_NONE; break; case 8: - tracemode |= ETMV1_CONTEXTID_8; + tracemode |= ETM_CTRL_CONTEXTID_8; break; case 16: - tracemode |= ETMV1_CONTEXTID_16; + tracemode |= ETM_CTRL_CONTEXTID_16; break; case 32: - tracemode |= ETMV1_CONTEXTID_32; + tracemode |= ETM_CTRL_CONTEXTID_32; break; default: - command_print(cmd_ctx, "invalid option '%s'", CMD_ARGV[1]); + command_print(CMD_CTX, "invalid option '%s'", CMD_ARGV[1]); return ERROR_INVALID_ARGUMENTS; } - if (strcmp(CMD_ARGV[2], "enable") == 0) - tracemode |= ETMV1_CYCLE_ACCURATE; - else if (strcmp(CMD_ARGV[2], "disable") == 0) - tracemode |= 0; - else - { - command_print(cmd_ctx, "invalid option '%s'", CMD_ARGV[2]); - return ERROR_INVALID_ARGUMENTS; - } + bool etmv1_cycle_accurate; + COMMAND_PARSE_ENABLE(CMD_ARGV[2], etmv1_cycle_accurate); + if (etmv1_cycle_accurate) + tracemode |= ETM_CTRL_CYCLE_ACCURATE; - if (strcmp(CMD_ARGV[3], "enable") == 0) - tracemode |= ETMV1_BRANCH_OUTPUT; - else if (strcmp(CMD_ARGV[3], "disable") == 0) - tracemode |= 0; - else - { - command_print(cmd_ctx, "invalid option '%s'", CMD_ARGV[3]); - return ERROR_INVALID_ARGUMENTS; - } + bool etmv1_branch_output; + COMMAND_PARSE_ENABLE(CMD_ARGV[3], etmv1_branch_output); + if (etmv1_branch_output) + tracemode |= ETM_CTRL_BRANCH_OUTPUT; /* IGNORED: * - CPRT tracing (coprocessor register transfers) @@ -1246,34 +1237,38 @@ static COMMAND_HELPER(handle_etm_tracemode_command_update, COMMAND_HANDLER(handle_etm_tracemode_command) { - struct target *target = get_current_target(cmd_ctx); + struct target *target = get_current_target(CMD_CTX); struct arm *arm = target_to_arm(target); struct etm_context *etm; if (!is_arm(arm)) { - command_print(cmd_ctx, "ETM: current target isn't an ARM"); + command_print(CMD_CTX, "ETM: current target isn't an ARM"); return ERROR_FAIL; } etm = arm->etm; if (!etm) { - command_print(cmd_ctx, "current target doesn't have an ETM configured"); + command_print(CMD_CTX, "current target doesn't have an ETM configured"); return ERROR_FAIL; } - etmv1_tracemode_t tracemode = etm->tracemode; + uint32_t tracemode = etm->control; switch (CMD_ARGC) { case 0: break; case 4: - CALL_COMMAND_HANDLER(handle_etm_tracemode_command_update, &tracemode); + CALL_COMMAND_HANDLER(handle_etm_tracemode_command_update, + &tracemode); break; default: - command_print(cmd_ctx, "usage: configure trace mode " - " " - " "); + command_print(CMD_CTX, "usage: tracemode " + "('none'|'data'|'address'|'all') " + "context_id_bits " + "('enable'|'disable') " + "('enable'|'disable')" + ); return ERROR_FAIL; } @@ -1282,60 +1277,67 @@ COMMAND_HANDLER(handle_etm_tracemode_command) * or couldn't be written; display actual hardware state... */ - command_print(cmd_ctx, "current tracemode configuration:"); + command_print(CMD_CTX, "current tracemode configuration:"); - switch (tracemode & ETMV1_TRACE_MASK) + switch (tracemode & ETM_CTRL_TRACE_MASK) { - case ETMV1_TRACE_NONE: - command_print(cmd_ctx, "data tracing: none"); + default: + command_print(CMD_CTX, "data tracing: none"); break; - case ETMV1_TRACE_DATA: - command_print(cmd_ctx, "data tracing: data only"); + case ETM_CTRL_TRACE_DATA: + command_print(CMD_CTX, "data tracing: data only"); break; - case ETMV1_TRACE_ADDR: - command_print(cmd_ctx, "data tracing: address only"); + case ETM_CTRL_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"); + case ETM_CTRL_TRACE_DATA | ETM_CTRL_TRACE_ADDR: + command_print(CMD_CTX, "data tracing: address and data"); break; } - switch (tracemode & ETMV1_CONTEXTID_MASK) + switch (tracemode & ETM_CTRL_CONTEXTID_MASK) { - case ETMV1_CONTEXTID_NONE: - command_print(cmd_ctx, "contextid tracing: none"); + case ETM_CTRL_CONTEXTID_NONE: + command_print(CMD_CTX, "contextid tracing: none"); break; - case ETMV1_CONTEXTID_8: - command_print(cmd_ctx, "contextid tracing: 8 bit"); + case ETM_CTRL_CONTEXTID_8: + command_print(CMD_CTX, "contextid tracing: 8 bit"); break; - case ETMV1_CONTEXTID_16: - command_print(cmd_ctx, "contextid tracing: 16 bit"); + case ETM_CTRL_CONTEXTID_16: + command_print(CMD_CTX, "contextid tracing: 16 bit"); break; - case ETMV1_CONTEXTID_32: - command_print(cmd_ctx, "contextid tracing: 32 bit"); + case ETM_CTRL_CONTEXTID_32: + command_print(CMD_CTX, "contextid tracing: 32 bit"); break; } - if (tracemode & ETMV1_CYCLE_ACCURATE) + if (tracemode & ETM_CTRL_CYCLE_ACCURATE) { - command_print(cmd_ctx, "cycle-accurate tracing enabled"); + command_print(CMD_CTX, "cycle-accurate tracing enabled"); } else { - command_print(cmd_ctx, "cycle-accurate tracing disabled"); + command_print(CMD_CTX, "cycle-accurate tracing disabled"); } - if (tracemode & ETMV1_BRANCH_OUTPUT) + if (tracemode & ETM_CTRL_BRANCH_OUTPUT) { - command_print(cmd_ctx, "full branch address output enabled"); + command_print(CMD_CTX, "full branch address output enabled"); } else { - command_print(cmd_ctx, "full branch address output disabled"); + command_print(CMD_CTX, "full branch address output disabled"); } +#define TRACEMODE_MASK ( \ + ETM_CTRL_CONTEXTID_MASK \ + | ETM_CTRL_BRANCH_OUTPUT \ + | ETM_CTRL_CYCLE_ACCURATE \ + | ETM_CTRL_TRACE_MASK \ + ) + /* only update ETM_CTRL register if tracemode changed */ - if (etm->tracemode != tracemode) + if ((etm->control & TRACEMODE_MASK) != tracemode) { struct reg *etm_ctrl_reg; @@ -1343,16 +1345,12 @@ COMMAND_HANDLER(handle_etm_tracemode_command) if (!etm_ctrl_reg) return ERROR_FAIL; - etm_get_reg(etm_ctrl_reg); + etm->control &= ~TRACEMODE_MASK; + etm->control |= tracemode & TRACEMODE_MASK; - 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); + buf_set_u32(etm_ctrl_reg->value, 0, 32, etm->control); etm_store_reg(etm_ctrl_reg); - etm->tracemode = tracemode; - /* invalidate old trace data */ etm->capture_status = TRACE_IDLE; if (etm->trace_depth > 0) @@ -1363,6 +1361,8 @@ COMMAND_HANDLER(handle_etm_tracemode_command) etm->trace_depth = 0; } +#undef TRACEMODE_MASK + return ERROR_OK; } @@ -1370,7 +1370,7 @@ COMMAND_HANDLER(handle_etm_config_command) { struct target *target; struct arm *arm; - etm_portmode_t portmode = 0x0; + uint32_t portmode = 0x0; struct etm_context *etm_ctx; int i; @@ -1386,8 +1386,9 @@ COMMAND_HANDLER(handle_etm_config_command) arm = target_to_arm(target); if (!is_arm(arm)) { - command_print(cmd_ctx, "target '%s' is '%s'; not an ARM", - target->cmd_name, target_get_name(target)); + command_print(CMD_CTX, "target '%s' is '%s'; not an ARM", + target_name(target), + target_type_name(target)); return ERROR_FAIL; } @@ -1437,7 +1438,7 @@ COMMAND_HANDLER(handle_etm_config_command) portmode |= ETM_PORT_2BIT; break; default: - command_print(cmd_ctx, + command_print(CMD_CTX, "unsupported ETM port width '%s'", CMD_ARGV[1]); return ERROR_FAIL; } @@ -1456,7 +1457,7 @@ COMMAND_HANDLER(handle_etm_config_command) } else { - command_print(cmd_ctx, "unsupported ETM port mode '%s', must be 'normal', 'multiplexed' or 'demultiplexed'", CMD_ARGV[2]); + command_print(CMD_CTX, "unsupported ETM port mode '%s', must be 'normal', 'multiplexed' or 'demultiplexed'", CMD_ARGV[2]); return ERROR_FAIL; } @@ -1470,7 +1471,7 @@ COMMAND_HANDLER(handle_etm_config_command) } else { - command_print(cmd_ctx, "unsupported ETM port clocking '%s', must be 'full' or 'half'", CMD_ARGV[3]); + command_print(CMD_CTX, "unsupported ETM port clocking '%s', must be 'full' or 'half'", CMD_ARGV[3]); return ERROR_FAIL; } @@ -1484,8 +1485,9 @@ COMMAND_HANDLER(handle_etm_config_command) { if (strcmp(CMD_ARGV[4], etm_capture_drivers[i]->name) == 0) { - int retval; - if ((retval = etm_capture_drivers[i]->register_commands(cmd_ctx)) != ERROR_OK) + int retval = register_commands(CMD_CTX, NULL, + etm_capture_drivers[i]->commands); + if (ERROR_OK != retval) { free(etm_ctx); return retval; @@ -1506,14 +1508,13 @@ COMMAND_HANDLER(handle_etm_config_command) } etm_ctx->target = target; - etm_ctx->trigger_percent = 50; etm_ctx->trace_data = NULL; - etm_ctx->portmode = portmode; - etm_ctx->core_state = ARMV4_5_STATE_ARM; + etm_ctx->control = portmode; + etm_ctx->core_state = ARM_STATE_ARM; arm->etm = etm_ctx; - return etm_register_user_commands(cmd_ctx); + return etm_register_user_commands(CMD_CTX); } COMMAND_HANDLER(handle_etm_info_command) @@ -1525,49 +1526,49 @@ COMMAND_HANDLER(handle_etm_info_command) int max_port_size; uint32_t config; - target = get_current_target(cmd_ctx); + target = get_current_target(CMD_CTX); arm = target_to_arm(target); if (!is_arm(arm)) { - command_print(cmd_ctx, "ETM: current target isn't an ARM"); + command_print(CMD_CTX, "ETM: current target isn't an ARM"); return ERROR_FAIL; } etm = arm->etm; if (!etm) { - command_print(cmd_ctx, "current target doesn't have an ETM configured"); + command_print(CMD_CTX, "current target doesn't have an ETM configured"); return ERROR_FAIL; } - command_print(cmd_ctx, "ETM v%d.%d", + 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", + command_print(CMD_CTX, "pairs of address comparators: %i", (int) (etm->config >> 0) & 0x0f); - command_print(cmd_ctx, "data comparators: %i", + command_print(CMD_CTX, "data comparators: %i", (int) (etm->config >> 4) & 0x0f); - command_print(cmd_ctx, "memory map decoders: %i", + command_print(CMD_CTX, "memory map decoders: %i", (int) (etm->config >> 8) & 0x1f); - command_print(cmd_ctx, "number of counters: %i", + command_print(CMD_CTX, "number of counters: %i", (int) (etm->config >> 13) & 0x07); - command_print(cmd_ctx, "sequencer %spresent", + command_print(CMD_CTX, "sequencer %spresent", (int) (etm->config & (1 << 16)) ? "" : "not "); - command_print(cmd_ctx, "number of ext. inputs: %i", + command_print(CMD_CTX, "number of ext. inputs: %i", (int) (etm->config >> 17) & 0x07); - command_print(cmd_ctx, "number of ext. outputs: %i", + command_print(CMD_CTX, "number of ext. outputs: %i", (int) (etm->config >> 20) & 0x07); - command_print(cmd_ctx, "FIFO full %spresent", + 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", + command_print(CMD_CTX, "protocol version: %i", (int) (etm->config >> 28) & 0x07); else { - command_print(cmd_ctx, + command_print(CMD_CTX, "coprocessor and memory access %ssupported", (etm->config & (1 << 26)) ? "" : "not "); - command_print(cmd_ctx, "trace start/stop %spresent", + command_print(CMD_CTX, "trace start/stop %spresent", (etm->config & (1 << 26)) ? "" : "not "); - command_print(cmd_ctx, "number of context comparators: %i", + command_print(CMD_CTX, "number of context comparators: %i", (int) (etm->config >> 24) & 0x03); } @@ -1619,30 +1620,30 @@ COMMAND_HANDLER(handle_etm_info_command) LOG_ERROR("Illegal max_port_size"); return ERROR_FAIL; } - command_print(cmd_ctx, "max. port size: %i", max_port_size); + command_print(CMD_CTX, "max. port size: %i", max_port_size); if (etm->bcd_vers < 0x30) { - command_print(cmd_ctx, "half-rate clocking %ssupported", + command_print(CMD_CTX, "half-rate clocking %ssupported", (config & (1 << 3)) ? "" : "not "); - command_print(cmd_ctx, "full-rate clocking %ssupported", + command_print(CMD_CTX, "full-rate clocking %ssupported", (config & (1 << 4)) ? "" : "not "); - command_print(cmd_ctx, "normal trace format %ssupported", + command_print(CMD_CTX, "normal trace format %ssupported", (config & (1 << 5)) ? "" : "not "); - command_print(cmd_ctx, "multiplex trace format %ssupported", + command_print(CMD_CTX, "multiplex trace format %ssupported", (config & (1 << 6)) ? "" : "not "); - command_print(cmd_ctx, "demultiplex trace format %ssupported", + command_print(CMD_CTX, "demultiplex trace format %ssupported", (config & (1 << 7)) ? "" : "not "); } else { /* REVISIT show which size and format are selected ... */ - command_print(cmd_ctx, "current port size %ssupported", + command_print(CMD_CTX, "current port size %ssupported", (config & (1 << 10)) ? "" : "not "); - command_print(cmd_ctx, "current trace format %ssupported", + command_print(CMD_CTX, "current trace format %ssupported", (config & (1 << 11)) ? "" : "not "); } if (etm->bcd_vers >= 0x21) - command_print(cmd_ctx, "fetch comparisons %ssupported", + command_print(CMD_CTX, "fetch comparisons %ssupported", (config & (1 << 17)) ? "not " : ""); - command_print(cmd_ctx, "FIFO full %ssupported", + command_print(CMD_CTX, "FIFO full %ssupported", (config & (1 << 8)) ? "" : "not "); return ERROR_OK; @@ -1655,18 +1656,18 @@ COMMAND_HANDLER(handle_etm_status_command) struct etm_context *etm; trace_status_t trace_status; - target = get_current_target(cmd_ctx); + target = get_current_target(CMD_CTX); arm = target_to_arm(target); if (!is_arm(arm)) { - command_print(cmd_ctx, "ETM: current target isn't an ARM"); + command_print(CMD_CTX, "ETM: current target isn't an ARM"); return ERROR_FAIL; } etm = arm->etm; if (!etm) { - command_print(cmd_ctx, "current target doesn't have an ETM configured"); + command_print(CMD_CTX, "current target doesn't have an ETM configured"); return ERROR_FAIL; } @@ -1680,7 +1681,7 @@ COMMAND_HANDLER(handle_etm_status_command) 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", + command_print(CMD_CTX, "etm: %s%s%s%s", /* bit(1) == progbit */ (etm->bcd_vers >= 0x12) ? ((s & (1 << 1)) @@ -1699,7 +1700,7 @@ COMMAND_HANDLER(handle_etm_status_command) trace_status = etm->capture_driver->status(etm); if (trace_status == TRACE_IDLE) { - command_print(cmd_ctx, "%s: idle", etm->capture_driver->name); + command_print(CMD_CTX, "%s: idle", etm->capture_driver->name); } else { @@ -1708,7 +1709,7 @@ COMMAND_HANDLER(handle_etm_status_command) static char *overflowed = ", overflowed"; static char *triggered = ", triggered"; - command_print(cmd_ctx, "%s: trace collection%s%s%s", + 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 : "", @@ -1716,7 +1717,7 @@ COMMAND_HANDLER(handle_etm_status_command) if (etm->trace_depth > 0) { - command_print(cmd_ctx, "%i frames of trace data read", + command_print(CMD_CTX, "%i frames of trace data read", (int)(etm->trace_depth)); } } @@ -1732,22 +1733,22 @@ COMMAND_HANDLER(handle_etm_image_command) if (CMD_ARGC < 1) { - command_print(cmd_ctx, "usage: etm image [base address] [type]"); + command_print(CMD_CTX, "usage: etm image [base address] [type]"); return ERROR_FAIL; } - target = get_current_target(cmd_ctx); + target = get_current_target(CMD_CTX); arm = target_to_arm(target); if (!is_arm(arm)) { - command_print(cmd_ctx, "ETM: current target isn't an ARM"); + command_print(CMD_CTX, "ETM: current target isn't an ARM"); return ERROR_FAIL; } etm_ctx = arm->etm; if (!etm_ctx) { - command_print(cmd_ctx, "current target doesn't have an ETM configured"); + command_print(CMD_CTX, "current target doesn't have an ETM configured"); return ERROR_FAIL; } @@ -1755,7 +1756,7 @@ COMMAND_HANDLER(handle_etm_image_command) { image_close(etm_ctx->image); free(etm_ctx->image); - command_print(cmd_ctx, "previously loaded image found and closed"); + command_print(CMD_CTX, "previously loaded image found and closed"); } etm_ctx->image = malloc(sizeof(struct image)); @@ -1793,35 +1794,35 @@ COMMAND_HANDLER(handle_etm_dump_command) if (CMD_ARGC != 1) { - command_print(cmd_ctx, "usage: etm dump "); + command_print(CMD_CTX, "usage: etm dump "); return ERROR_FAIL; } - target = get_current_target(cmd_ctx); + target = get_current_target(CMD_CTX); arm = target_to_arm(target); if (!is_arm(arm)) { - command_print(cmd_ctx, "ETM: current target isn't an ARM"); + command_print(CMD_CTX, "ETM: current target isn't an ARM"); return ERROR_FAIL; } etm_ctx = arm->etm; if (!etm_ctx) { - command_print(cmd_ctx, "current target doesn't have an ETM configured"); + command_print(CMD_CTX, "current target doesn't have an ETM configured"); return ERROR_FAIL; } if (etm_ctx->capture_driver->status == TRACE_IDLE) { - command_print(cmd_ctx, "trace capture wasn't enabled, no trace data captured"); + 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"); + command_print(CMD_CTX, "trace capture not completed"); return ERROR_FAIL; } @@ -1835,8 +1836,7 @@ COMMAND_HANDLER(handle_etm_dump_command) } 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->control); fileio_write_u32(&file, etm_ctx->trace_depth); for (i = 0; i < etm_ctx->trace_depth; i++) @@ -1861,28 +1861,28 @@ COMMAND_HANDLER(handle_etm_load_command) if (CMD_ARGC != 1) { - command_print(cmd_ctx, "usage: etm load "); + command_print(CMD_CTX, "usage: etm load "); return ERROR_FAIL; } - target = get_current_target(cmd_ctx); + target = get_current_target(CMD_CTX); arm = target_to_arm(target); if (!is_arm(arm)) { - command_print(cmd_ctx, "ETM: current target isn't an ARM"); + command_print(CMD_CTX, "ETM: current target isn't an ARM"); return ERROR_FAIL; } etm_ctx = arm->etm; if (!etm_ctx) { - command_print(cmd_ctx, "current target doesn't have an ETM configured"); + command_print(CMD_CTX, "current target doesn't have an ETM configured"); return ERROR_FAIL; } if (etm_ctx->capture_driver->status(etm_ctx) & TRACE_RUNNING) { - command_print(cmd_ctx, "trace capture running, stop first"); + command_print(CMD_CTX, "trace capture running, stop first"); return ERROR_FAIL; } @@ -1893,7 +1893,7 @@ COMMAND_HANDLER(handle_etm_load_command) if (file.size % 4) { - command_print(cmd_ctx, "size isn't a multiple of 4, no valid trace data"); + command_print(CMD_CTX, "size isn't a multiple of 4, no valid trace data"); fileio_close(&file); return ERROR_FAIL; } @@ -1907,14 +1907,13 @@ COMMAND_HANDLER(handle_etm_load_command) { 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, &tmp); etm_ctx->control = tmp; fileio_read_u32(&file, &etm_ctx->trace_depth); } etm_ctx->trace_data = malloc(sizeof(struct etmv1_trace_data) * etm_ctx->trace_depth); if (etm_ctx->trace_data == NULL) { - command_print(cmd_ctx, "not enough memory to perform operation"); + command_print(CMD_CTX, "not enough memory to perform operation"); fileio_close(&file); return ERROR_FAIL; } @@ -1935,47 +1934,6 @@ COMMAND_HANDLER(handle_etm_load_command) return ERROR_OK; } -COMMAND_HANDLER(handle_etm_trigger_percent_command) -{ - struct target *target; - struct arm *arm; - struct etm_context *etm_ctx; - - target = get_current_target(cmd_ctx); - arm = target_to_arm(target); - if (!is_arm(arm)) - { - command_print(cmd_ctx, "ETM: current target isn't an ARM"); - return ERROR_FAIL; - } - - etm_ctx = arm->etm; - if (!etm_ctx) - { - command_print(cmd_ctx, "current target doesn't have an ETM configured"); - return ERROR_FAIL; - } - - if (CMD_ARGC > 0) - { - uint32_t new_value; - COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], new_value); - - 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; -} - COMMAND_HANDLER(handle_etm_start_command) { struct target *target; @@ -1983,18 +1941,18 @@ COMMAND_HANDLER(handle_etm_start_command) struct etm_context *etm_ctx; struct reg *etm_ctrl_reg; - target = get_current_target(cmd_ctx); + target = get_current_target(CMD_CTX); arm = target_to_arm(target); if (!is_arm(arm)) { - command_print(cmd_ctx, "ETM: current target isn't an ARM"); + command_print(CMD_CTX, "ETM: current target isn't an ARM"); return ERROR_FAIL; } etm_ctx = arm->etm; if (!etm_ctx) { - command_print(cmd_ctx, "current target doesn't have an ETM configured"); + command_print(CMD_CTX, "current target doesn't have an ETM configured"); return ERROR_FAIL; } @@ -2031,18 +1989,18 @@ COMMAND_HANDLER(handle_etm_stop_command) struct etm_context *etm_ctx; struct reg *etm_ctrl_reg; - target = get_current_target(cmd_ctx); + target = get_current_target(CMD_CTX); arm = target_to_arm(target); if (!is_arm(arm)) { - command_print(cmd_ctx, "ETM: current target isn't an ARM"); + command_print(CMD_CTX, "ETM: current target isn't an ARM"); return ERROR_FAIL; } etm_ctx = arm->etm; if (!etm_ctx) { - command_print(cmd_ctx, "current target doesn't have an ETM configured"); + command_print(CMD_CTX, "current target doesn't have an ETM configured"); return ERROR_FAIL; } @@ -2063,6 +2021,56 @@ COMMAND_HANDLER(handle_etm_stop_command) return ERROR_OK; } +COMMAND_HANDLER(handle_etm_trigger_debug_command) +{ + struct target *target; + struct arm *arm; + struct etm_context *etm; + + target = get_current_target(CMD_CTX); + arm = target_to_arm(target); + if (!is_arm(arm)) + { + command_print(CMD_CTX, "ETM: %s isn't an ARM", + target_name(target)); + return ERROR_FAIL; + } + + etm = arm->etm; + if (!etm) + { + command_print(CMD_CTX, "ETM: no ETM configured for %s", + target_name(target)); + return ERROR_FAIL; + } + + if (CMD_ARGC == 1) { + struct reg *etm_ctrl_reg; + bool dbgrq; + + etm_ctrl_reg = etm_reg_lookup(etm, ETM_CTRL); + if (!etm_ctrl_reg) + return ERROR_FAIL; + + COMMAND_PARSE_ENABLE(CMD_ARGV[0], dbgrq); + if (dbgrq) + etm->control |= ETM_CTRL_DBGRQ; + else + etm->control &= ~ETM_CTRL_DBGRQ; + + /* etm->control will be written to hardware + * the next time an "etm start" is issued. + */ + buf_set_u32(etm_ctrl_reg->value, 0, 32, etm->control); + } + + command_print(CMD_CTX, "ETM: %s debug halt", + (etm->control & ETM_CTRL_DBGRQ) + ? "triggers" + : "does not trigger"); + return ERROR_OK; +} + COMMAND_HANDLER(handle_etm_analyze_command) { struct target *target; @@ -2070,81 +2078,140 @@ COMMAND_HANDLER(handle_etm_analyze_command) struct etm_context *etm_ctx; int retval; - target = get_current_target(cmd_ctx); + target = get_current_target(CMD_CTX); arm = target_to_arm(target); if (!is_arm(arm)) { - command_print(cmd_ctx, "ETM: current target isn't an ARM"); + command_print(CMD_CTX, "ETM: current target isn't an ARM"); return ERROR_FAIL; } etm_ctx = arm->etm; if (!etm_ctx) { - command_print(cmd_ctx, "current target doesn't have an ETM configured"); + command_print(CMD_CTX, "current target doesn't have an ETM configured"); return ERROR_FAIL; } - if ((retval = etmv1_analyze_trace(etm_ctx, cmd_ctx)) != 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"); + 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"); + 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"); + command_print(CMD_CTX, "no image available for trace analysis"); break; default: - command_print(cmd_ctx, "unknown error: %i", retval); + command_print(CMD_CTX, "unknown error: %i", retval); } } return retval; } -int etm_register_commands(struct command_context *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 "); +static const struct command_registration etm_config_command_handlers[] = { + { + /* NOTE: with ADIv5, ETMs are accessed by DAP operations, + * possibly over SWD, not JTAG scanchain 6 of 'target'. + * + * Also, these parameters don't match ETM v3+ modules... + */ + .name = "config", + .handler = handle_etm_config_command, + .mode = COMMAND_CONFIG, + .help = "Set up ETM output port.", + .usage = "target port_width port_mode clocking capture_driver", + }, + COMMAND_REGISTRATION_DONE +}; +const struct command_registration etm_command_handlers[] = { + { + .name = "etm", + .mode = COMMAND_ANY, + .help = "Emebdded Trace Macrocell command group", + .chain = etm_config_command_handlers, + }, + COMMAND_REGISTRATION_DONE +}; - return ERROR_OK; -} +static const struct command_registration etm_exec_command_handlers[] = { + { + .name = "tracemode", + .handler = handle_etm_tracemode_command, + .mode = COMMAND_EXEC, + .help = "configure/display trace mode", + .usage = "('none'|'data'|'address'|'all') " + "context_id_bits " + "['enable'|'disable'] " + "['enable'|'disable']", + }, + { + .name = "info", + .handler = handle_etm_info_command, + .mode = COMMAND_EXEC, + .help = "display info about the current target's ETM", + }, + { + .name = "status", + .handler = handle_etm_status_command, + .mode = COMMAND_EXEC, + .help = "display current target's ETM status", + }, + { + .name = "start", + .handler = handle_etm_start_command, + .mode = COMMAND_EXEC, + .help = "start ETM trace collection", + }, + { + .name = "stop", + .handler = handle_etm_stop_command, + .mode = COMMAND_EXEC, + .help = "stop ETM trace collection", + }, + { + .name = "trigger_debug", + .handler = handle_etm_trigger_debug_command, + .mode = COMMAND_EXEC, + .help = "enable/disable debug entry on trigger", + .usage = "['enable'|'disable']", + }, + { + .name = "analyze", + .handler = handle_etm_analyze_command, + .mode = COMMAND_EXEC, + .help = "analyze collected ETM trace", + }, + { + .name = "image", + .handler = handle_etm_image_command, + .mode = COMMAND_EXEC, + .help = "load image from file with optional offset", + .usage = "filename [offset]", + }, + { + .name = "dump", + .handler = handle_etm_dump_command, + .mode = COMMAND_EXEC, + .help = "dump captured trace data to file", + .usage = "filename", + }, + { + .name = "load", + .handler = handle_etm_load_command, + .mode = COMMAND_EXEC, + .help = "load trace data for analysis ", + }, + COMMAND_REGISTRATION_DONE +}; static int etm_register_user_commands(struct command_context *cmd_ctx) { - register_command(cmd_ctx, etm_cmd, "tracemode", handle_etm_tracemode_command, - COMMAND_EXEC, "configure/display trace mode: " - " " - " "); - - 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 () 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 [base address]"); - - register_command(cmd_ctx, etm_cmd, "dump", handle_etm_dump_command, - COMMAND_EXEC, "dump captured trace data "); - register_command(cmd_ctx, etm_cmd, "load", handle_etm_load_command, - COMMAND_EXEC, "load trace data for analysis "); - - return ERROR_OK; + struct command *etm_cmd = command_find_in_context(cmd_ctx, "etm"); + return register_commands(cmd_ctx, etm_cmd, etm_exec_command_handlers); }