Improve ETM tracemode update command.
[openocd.git] / src / target / etm.c
index cc80b68590e56dd6a0addfaaffd23807a50cbdd3..8229bb07d0b154943149655201d3c70764c38703 100644 (file)
@@ -68,41 +68,54 @@ struct etm_reg_info {
 
 /*
  * Registers 0..0x7f are JTAG-addressable using scanchain 6.
+ * (Or on some processors, through coprocessor operations.)
  * Newer versions of ETM make some W/O registers R/W, and
  * provide definitions for some previously-unused bits.
  */
-static const struct etm_reg_info reg[] = {
+
+/* basic registers that are always there given the right ETM version */
+static const struct etm_reg_info etm_core[] = {
+       /* NOTE: we "know" ETM_CONFIG is listed first */
+       { ETM_CONFIG, 32, RO, 0x10, "ETM_config", },
+
        /* ETM Trace Registers */
-       { ETM_CTRL, 32, RW, 0x10, "ETM_CTRL", },
-       { ETM_CONFIG, 32, RO, 0x10, "ETM_CONFIG", },
-       { ETM_TRIG_EVENT, 17, WO, 0x10, "ETM_TRIG_EVENT", },
-       { ETM_ASIC_CTRL,  8, WO, 0x10, "ETM_ASIC_CTRL", },
-       { ETM_STATUS,  3, RO, 0x11, "ETM_STATUS", },
-       { ETM_SYS_CONFIG,  9, RO, 0x12, "ETM_SYS_CONFIG", },
+       { ETM_CTRL, 32, RW, 0x10, "ETM_ctrl", },
+       { ETM_TRIG_EVENT, 17, WO, 0x10, "ETM_trig_event", },
+       { ETM_ASIC_CTRL,  8, WO, 0x10, "ETM_asic_ctrl", },
+       { ETM_STATUS,  3, RO, 0x11, "ETM_status", },
+       { ETM_SYS_CONFIG,  9, RO, 0x12, "ETM_sys_config", },
 
        /* TraceEnable configuration */
-       { ETM_TRACE_RESOURCE_CTRL, 32, WO, 0x12, "ETM_TRACE_RESOURCE_CTRL", },
-       { ETM_TRACE_EN_CTRL2, 16, WO, 0x12, "ETM_TRACE_EN_CTRL2", },
-       { ETM_TRACE_EN_EVENT, 17, WO, 0x10, "ETM_TRACE_EN_EVENT", },
-       { ETM_TRACE_EN_CTRL1, 26, WO, 0x10, "ETM_TRACE_EN_CTRL1", },
-
-       /* FIFOFULL configuration */
-       { ETM_FIFOFULL_REGION, 25, WO, 0x10, "ETM_FIFOFULL_REGION", },
-       { ETM_FIFOFULL_LEVEL,  8, WO, 0x10, "ETM_FIFOFULL_LEVEL", },
+       { ETM_TRACE_RESOURCE_CTRL, 32, WO, 0x12, "ETM_trace_resource_ctrl", },
+       { ETM_TRACE_EN_CTRL2, 16, WO, 0x12, "ETM_trace_en_ctrl2", },
+       { ETM_TRACE_EN_EVENT, 17, WO, 0x10, "ETM_trace_en_event", },
+       { ETM_TRACE_EN_CTRL1, 26, WO, 0x10, "ETM_trace_en_ctrl1", },
 
        /* ViewData configuration (data trace) */
-       { ETM_VIEWDATA_EVENT, 17, WO, 0x10, "ETM_VIEWDATA_EVENT", },
-       { ETM_VIEWDATA_CTRL1, 32, WO, 0x10, "ETM_VIEWDATA_CTRL1", },
-       { ETM_VIEWDATA_CTRL2, 32, WO, 0x10, "ETM_VIEWDATA_CTRL2", },
-       { ETM_VIEWDATA_CTRL3, 17, WO, 0x10, "ETM_VIEWDATA_CTRL3", },
+       { ETM_VIEWDATA_EVENT, 17, WO, 0x10, "ETM_viewdata_event", },
+       { ETM_VIEWDATA_CTRL1, 32, WO, 0x10, "ETM_viewdata_ctrl1", },
+       { ETM_VIEWDATA_CTRL2, 32, WO, 0x10, "ETM_viewdata_ctrl2", },
+       { ETM_VIEWDATA_CTRL3, 17, WO, 0x10, "ETM_viewdata_ctrl3", },
+
+       /* REVISIT exclude VIEWDATA_CTRL2 when it's not there */
+
+       { 0x78, 12, WO, 0x20, "ETM_sync_freq", },
+       { 0x79, 32, RO, 0x20, "ETM_id", },
+};
+
+static const struct etm_reg_info etm_fifofull[] = {
+       /* FIFOFULL configuration */
+       { ETM_FIFOFULL_REGION, 25, WO, 0x10, "ETM_fifofull_region", },
+       { ETM_FIFOFULL_LEVEL,  8, WO, 0x10, "ETM_fifofull_level", },
+};
 
+static const struct etm_reg_info etm_addr_comp[] = {
        /* Address comparator register pairs */
 #define ADDR_COMPARATOR(i) \
-               { ETM_ADDR_COMPARATOR_VALUE + (i), 32, WO, 0x10, \
-                               "ETM_ADDR_COMPARATOR_VALUE" #i, }, \
-               { ETM_ADDR_ACCESS_TYPE + (i),  7, WO, 0x10, \
-                               "ETM_ADDR_ACCESS_TYPE" #i, }
-       ADDR_COMPARATOR(0),
+               { ETM_ADDR_COMPARATOR_VALUE + (i) - 1, 32, WO, 0x10, \
+                               "ETM_addr_" #i "_comparator_value", }, \
+               { ETM_ADDR_ACCESS_TYPE + (i) - 1,  7, WO, 0x10, \
+                               "ETM_addr_" #i "_access_type", }
        ADDR_COMPARATOR(1),
        ADDR_COMPARATOR(2),
        ADDR_COMPARATOR(3),
@@ -110,8 +123,8 @@ static const struct etm_reg_info reg[] = {
        ADDR_COMPARATOR(5),
        ADDR_COMPARATOR(6),
        ADDR_COMPARATOR(7),
-
        ADDR_COMPARATOR(8),
+
        ADDR_COMPARATOR(9),
        ADDR_COMPARATOR(10),
        ADDR_COMPARATOR(11),
@@ -119,15 +132,17 @@ static const struct etm_reg_info reg[] = {
        ADDR_COMPARATOR(13),
        ADDR_COMPARATOR(14),
        ADDR_COMPARATOR(15),
+       ADDR_COMPARATOR(16),
 #undef ADDR_COMPARATOR
+};
 
+static const struct etm_reg_info etm_data_comp[] = {
        /* Data Value Comparators (NOTE: odd addresses are reserved) */
 #define DATA_COMPARATOR(i) \
-               { ETM_DATA_COMPARATOR_VALUE + 2*(i), 32, WO, 0x10, \
-                               "ETM_DATA_COMPARATOR_VALUE" #i, }, \
-               { ETM_DATA_COMPARATOR_MASK + 2*(i), 32, WO, 0x10, \
-                               "ETM_DATA_COMPARATOR_MASK" #i, }
-       DATA_COMPARATOR(0),
+               { ETM_DATA_COMPARATOR_VALUE + 2*(i) - 1, 32, WO, 0x10, \
+                               "ETM_data_" #i "_comparator_value", }, \
+               { ETM_DATA_COMPARATOR_MASK + 2*(i) - 1, 32, WO, 0x10, \
+                               "ETM_data_" #i "_comparator_mask", }
        DATA_COMPARATOR(1),
        DATA_COMPARATOR(2),
        DATA_COMPARATOR(3),
@@ -135,61 +150,63 @@ static const struct etm_reg_info reg[] = {
        DATA_COMPARATOR(5),
        DATA_COMPARATOR(6),
        DATA_COMPARATOR(7),
+       DATA_COMPARATOR(8),
 #undef DATA_COMPARATOR
+};
+
+static const struct etm_reg_info etm_counters[] = {
+#define ETM_COUNTER(i) \
+               { ETM_COUNTER_RELOAD_VALUE + (i) - 1, 16, WO, 0x10, \
+                               "ETM_counter_" #i "_reload_value", }, \
+               { ETM_COUNTER_ENABLE + (i) - 1, 18, WO, 0x10, \
+                               "ETM_counter_" #i "_enable", }, \
+               { ETM_COUNTER_RELOAD_EVENT + (i) - 1, 17, WO, 0x10, \
+                               "ETM_counter_" #i "_reload_event", }, \
+               { ETM_COUNTER_VALUE + (i) - 1, 16, RO, 0x10, \
+                               "ETM_counter_" #i "_value", }
+       ETM_COUNTER(1),
+       ETM_COUNTER(2),
+       ETM_COUNTER(3),
+       ETM_COUNTER(4),
+#undef ETM_COUNTER
+};
 
-       /* Counters */
-#define COUNTER(i) \
-               { ETM_COUNTER_RELOAD_VALUE + (i), 16, WO, 0x10, \
-                               "ETM_COUNTER_RELOAD_VALUE" #i, }, \
-               { ETM_COUNTER_ENABLE + (i), 18, WO, 0x10, \
-                               "ETM_COUNTER_ENABLE" #i, }, \
-               { ETM_COUNTER_RELOAD_EVENT + (i), 17, WO, 0x10, \
-                               "ETM_COUNTER_RELOAD_EVENT" #i, }, \
-               { ETM_COUNTER_VALUE + (i), 16, RO, 0x10, \
-                               "ETM_COUNTER_VALUE" #i, }
-       COUNTER(0),
-       COUNTER(1),
-       COUNTER(2),
-       COUNTER(3),
-#undef COUNTER
-
-       /* Sequencers */
-#define SEQ(i) \
+static const struct etm_reg_info etm_sequencer[] = {
+#define ETM_SEQ(i) \
                { ETM_SEQUENCER_EVENT + (i), 17, WO, 0x10, \
-                               "ETM_SEQUENCER_EVENT" #i, }
-       SEQ(0),                         /* 1->2 */
-       SEQ(1),                         /* 2->1 */
-       SEQ(2),                         /* 2->3 */
-       SEQ(3),                         /* 3->1 */
-       SEQ(4),                         /* 3->2 */
-       SEQ(5),                         /* 1->3 */
-#undef SEQ
+                               "ETM_sequencer_event" #i, }
+       ETM_SEQ(0),                             /* 1->2 */
+       ETM_SEQ(1),                             /* 2->1 */
+       ETM_SEQ(2),                             /* 2->3 */
+       ETM_SEQ(3),                             /* 3->1 */
+       ETM_SEQ(4),                             /* 3->2 */
+       ETM_SEQ(5),                             /* 1->3 */
+#undef ETM_SEQ
        /* 0x66 reserved */
-       { ETM_SEQUENCER_STATE,  2, RO, 0x10, "ETM_SEQUENCER_STATE", },
+       { ETM_SEQUENCER_STATE,  2, RO, 0x10, "ETM_sequencer_state", },
+};
 
-#define OUT(i) \
-               { ETM_EXTERNAL_OUTPUT + (i), 17, WO, 0x10, \
-                               "ETM_EXTERNAL_OUTPUT" #i, }
+static const struct etm_reg_info etm_outputs[] = {
+#define ETM_OUTPUT(i) \
+               { ETM_EXTERNAL_OUTPUT + (i) - 1, 17, WO, 0x10, \
+                               "ETM_external_output" #i, }
 
-       OUT(0),
-       OUT(1),
-       OUT(2),
-       OUT(3),
-#undef OUT
+       ETM_OUTPUT(1),
+       ETM_OUTPUT(2),
+       ETM_OUTPUT(3),
+       ETM_OUTPUT(4),
+#undef ETM_OUTPUT
+};
 
 #if 0
        /* registers from 0x6c..0x7f were added after ETMv1.3 */
 
        /* Context ID Comparators */
-       { 0x6c, 32, RO, 0x20, "ETM_CONTEXTID_COMPARATOR_VALUE1", }
-       { 0x6d, 32, RO, 0x20, "ETM_CONTEXTID_COMPARATOR_VALUE1", }
-       { 0x6e, 32, RO, 0x20, "ETM_CONTEXTID_COMPARATOR_VALUE1", }
-       { 0x6f, 32, RO, 0x20, "ETM_CONTEXTID_COMPARATOR_MASK", }
-
-       { 0x78, 12, WO, 0x20, "ETM_SYNC_FREQ", },
-       { 0x79, 32, RO, 0x20, "ETM_ID", },
+       { 0x6c, 32, RO, 0x20, "ETM_contextid_comparator_value1", }
+       { 0x6d, 32, RO, 0x20, "ETM_contextid_comparator_value2", }
+       { 0x6e, 32, RO, 0x20, "ETM_contextid_comparator_value3", }
+       { 0x6f, 32, RO, 0x20, "ETM_contextid_comparator_mask", }
 #endif
-};
 
 static int etm_reg_arch_type = -1;
 
@@ -224,43 +241,137 @@ static reg_t *etm_reg_lookup(etm_context_t *etm_ctx, unsigned id)
        return NULL;
 }
 
+static void etm_reg_add(unsigned bcd_vers, arm_jtag_t *jtag_info,
+               reg_cache_t *cache, etm_reg_t *ereg,
+               const struct etm_reg_info *r, unsigned nreg)
+{
+       reg_t *reg = cache->reg_list;
+
+       reg += cache->num_regs;
+       ereg += cache->num_regs;
+
+       /* add up to "nreg" registers from "r", if supported by this
+        * version of the ETM, to the specified cache.
+        */
+       for (; nreg--; r++) {
+
+               /* this ETM may be too old to have some registers */
+               if (r->bcd_vers > bcd_vers)
+                       continue;
+
+               reg->name = r->name;
+               reg->size = r->size;
+               reg->value = &ereg->value;
+               reg->arch_info = ereg;
+               reg->arch_type = etm_reg_arch_type;
+               reg++;
+               cache->num_regs++;
+
+               ereg->reg_info = r;
+               ereg->jtag_info = jtag_info;
+               ereg++;
+       }
+}
+
 reg_cache_t *etm_build_reg_cache(target_t *target,
                arm_jtag_t *jtag_info, etm_context_t *etm_ctx)
 {
        reg_cache_t *reg_cache = malloc(sizeof(reg_cache_t));
        reg_t *reg_list = NULL;
        etm_reg_t *arch_info = NULL;
-       int num_regs = ARRAY_SIZE(reg);
-       int i;
+       unsigned bcd_vers, config;
 
        /* register a register arch-type for etm registers only once */
        if (etm_reg_arch_type == -1)
-               etm_reg_arch_type = register_reg_arch_type(etm_get_reg, etm_set_reg_w_exec);
+               etm_reg_arch_type = register_reg_arch_type(etm_get_reg,
+                               etm_set_reg_w_exec);
 
        /* the actual registers are kept in two arrays */
-       reg_list = calloc(num_regs, sizeof(reg_t));
-       arch_info = calloc(num_regs, sizeof(etm_reg_t));
+       reg_list = calloc(128, sizeof(reg_t));
+       arch_info = calloc(128, sizeof(etm_reg_t));
 
        /* fill in values for the reg cache */
        reg_cache->name = "etm registers";
        reg_cache->next = NULL;
        reg_cache->reg_list = reg_list;
-       reg_cache->num_regs = num_regs;
-
-       /* set up registers */
-       for (i = 0; i < num_regs; i++)
-       {
-               const struct etm_reg_info *r = reg + i;
-
-               reg_list[i].name = r->name;
-               reg_list[i].size = r->size;
-               reg_list[i].value = &arch_info[i].value;
-               reg_list[i].arch_info = &arch_info[i];
-               reg_list[i].arch_type = etm_reg_arch_type;
-
-               arch_info[i].reg_info = r;
-               arch_info[i].jtag_info = jtag_info;
+       reg_cache->num_regs = 0;
+
+       /* add ETM_CONFIG, then parse its values to see
+        * which other registers exist in this ETM
+        */
+       etm_reg_add(0x10, jtag_info, reg_cache, arch_info,
+                       etm_core, 1);
+
+       etm_get_reg(reg_list);
+       etm_ctx->config = buf_get_u32((void *)&arch_info->value, 0, 32);
+       config = etm_ctx->config;
+
+       /* figure ETM version then add base registers */
+       if (config & (1 << 31)) {
+               bcd_vers = 0x20;
+               LOG_WARNING("ETMv2+ support is incomplete");
+
+               /* REVISIT read ID register, distinguish ETMv3.3 etc;
+                * don't presume trace start/stop support is present;
+                * and include any context ID comparator registers.
+                */
+       } else {
+               switch (config >> 28) {
+               case 7:
+               case 5:
+               case 3:
+                       bcd_vers = 0x13;
+                       break;
+               case 4:
+               case 2:
+                       bcd_vers = 0x12;
+                       break;
+               case 1:
+                       bcd_vers = 0x11;
+                       break;
+               case 0:
+                       bcd_vers = 0x10;
+                       break;
+               default:
+                       LOG_WARNING("Bad ETMv1 protocol %d", config >> 28);
+                       free(reg_cache);
+                       free(reg_list);
+                       free(arch_info);
+                       return ERROR_OK;
+               }
        }
+       etm_ctx->bcd_vers = bcd_vers;
+       LOG_INFO("ETM v%d.%d", bcd_vers >> 4, bcd_vers & 0xf);
+
+       etm_reg_add(bcd_vers, jtag_info, reg_cache, arch_info,
+                       etm_core + 1, ARRAY_SIZE(etm_core) - 1);
+
+       /* address and data comparators; counters; outputs */
+       etm_reg_add(bcd_vers, jtag_info, reg_cache, arch_info,
+                       etm_addr_comp, 4 * (0x0f & (config >> 0)));
+       etm_reg_add(bcd_vers, jtag_info, reg_cache, arch_info,
+                       etm_data_comp, 2 * (0x0f & (config >> 4)));
+       etm_reg_add(bcd_vers, jtag_info, reg_cache, arch_info,
+                       etm_counters, 4 * (0x07 & (config >> 13)));
+       etm_reg_add(bcd_vers, jtag_info, reg_cache, arch_info,
+                       etm_outputs, (0x07 & (config >> 20)));
+
+       /* FIFOFULL presence is optional
+        * REVISIT for ETMv1.2 and later, don't bother adding this
+        * unless ETM_SYS_CONFIG says it's also *supported* ...
+        */
+       if (config & (1 << 23))
+               etm_reg_add(bcd_vers, jtag_info, reg_cache, arch_info,
+                               etm_fifofull, ARRAY_SIZE(etm_fifofull));
+
+       /* sequencer is optional (for state-dependant triggering) */
+       if (config & (1 << 16))
+               etm_reg_add(bcd_vers, jtag_info, reg_cache, arch_info,
+                               etm_sequencer, ARRAY_SIZE(etm_sequencer));
+
+       /* REVISIT could realloc and likely save half the memory
+        * in the two chunks we allocated...
+        */
 
        /* the ETM might have an ETB connected */
        if (strcmp(etm_ctx->capture_driver->name, "etb") == 0)
@@ -271,6 +382,7 @@ reg_cache_t *etm_build_reg_cache(target_t *target,
                {
                        LOG_ERROR("etb selected as etm capture driver, but no ETB configured");
                        free(reg_cache);
+                       free(reg_list);
                        free(arch_info);
                        return ERROR_OK;
                }
@@ -1043,103 +1155,108 @@ static int etmv1_analyze_trace(etm_context_t *ctx, struct command_context_s *cmd
        return ERROR_OK;
 }
 
-static int handle_etm_tracemode_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+static int handle_etm_tracemode_command_update(
+               struct command_context_s *cmd_ctx,
+               char **args, etmv1_tracemode_t *mode)
 {
-       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);
+       /* what parts of data access are traced? */
+       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;
+       }
 
-       if (arm7_9_get_arch_pointers(target, &armv4_5, &arm7_9) != ERROR_OK)
+       uint8_t context_id;
+       COMMAND_PARSE_NUMBER(u8, args[1], context_id);
+       switch (context_id)
+       {
+       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, "current target isn't an ARM7/ARM9 target");
+               command_print(cmd_ctx, "invalid option '%s'", args[2]);
                return ERROR_OK;
        }
 
-       if (!arm7_9->etm_ctx)
+       if (strcmp(args[3], "enable") == 0)
+               tracemode |= ETMV1_BRANCH_OUTPUT;
+       else if (strcmp(args[3], "disable") == 0)
+               tracemode |= 0;
+       else
        {
-               command_print(cmd_ctx, "current target doesn't have an ETM configured");
+               command_print(cmd_ctx, "invalid option '%s'", args[3]);
                return ERROR_OK;
        }
 
-       tracemode = arm7_9->etm_ctx->tracemode;
+       /* IGNORED:
+        *  - CPRT tracing (coprocessor register transfers)
+        *  - debug request (causes debug entry on trigger)
+        *  - stall on FIFOFULL (preventing tracedata lossage)
+        */
+       *mode = 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;
-               }
+       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;
-               }
+static int handle_etm_tracemode_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+       target_t *target = get_current_target(cmd_ctx);
 
-               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;
-               }
+       armv4_5_common_t *armv4_5;
+       arm7_9_common_t *arm7_9;
+       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 (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;
-               }
+       if (!arm7_9->etm_ctx)
+       {
+               command_print(cmd_ctx, "current target doesn't have an ETM configured");
+               return ERROR_OK;
        }
-       else if (argc != 0)
+
+       etmv1_tracemode_t tracemode = arm7_9->etm_ctx->tracemode;
+       switch (argc)
        {
-               command_print(cmd_ctx, "usage: configure trace mode <none | data | address | all> <context id bits> <cycle accurate> <branch output>");
+       case 0:
+               break;
+       case 4:
+               handle_etm_tracemode_command_update(cmd_ctx, args, &tracemode);
+               break;
+       default:
+               command_print(cmd_ctx, "usage: configure trace mode "
+                               "<none | data | address | all> "
+                               "<context id bits> <cycle accurate> <branch output>");
                return ERROR_OK;
        }
 
@@ -1257,7 +1374,9 @@ static int handle_etm_config_command(struct command_context_s *cmd_ctx, char *cm
                return ERROR_FAIL;
        }
 
-       switch (strtoul(args[1], NULL, 0))
+       uint8_t port_width;
+       COMMAND_PARSE_NUMBER(u8, args[1], port_width);
+       switch (port_width)
        {
                case 4:
                        portmode |= ETM_PORT_4BIT;
@@ -1362,7 +1481,7 @@ static int handle_etm_info_command(struct command_context_s *cmd_ctx,
        target_t *target;
        armv4_5_common_t *armv4_5;
        arm7_9_common_t *arm7_9;
-       reg_t *etm_config_reg;
+       etm_context_t *etm;
        reg_t *etm_sys_config_reg;
 
        int max_port_size;
@@ -1375,31 +1494,45 @@ static int handle_etm_info_command(struct command_context_s *cmd_ctx,
                return ERROR_OK;
        }
 
-       if (!arm7_9->etm_ctx)
+       etm = arm7_9->etm_ctx;
+       if (!etm)
        {
                command_print(cmd_ctx, "current target doesn't have an ETM configured");
                return ERROR_OK;
        }
 
-       etm_config_reg = etm_reg_lookup(arm7_9->etm_ctx, ETM_CONFIG);
-       if (!etm_config_reg)
-               return ERROR_OK;
-       etm_sys_config_reg = etm_reg_lookup(arm7_9->etm_ctx, ETM_SYS_CONFIG);
-       if (!etm_sys_config_reg)
-               return ERROR_OK;
-
-       etm_get_reg(etm_config_reg);
-       command_print(cmd_ctx, "pairs of address comparators: %i", (int)buf_get_u32(etm_config_reg->value, 0, 4));
-       command_print(cmd_ctx, "pairs of data comparators: %i", (int)buf_get_u32(etm_config_reg->value, 4, 4));
-       command_print(cmd_ctx, "memory map decoders: %i", (int)buf_get_u32(etm_config_reg->value, 8, 5));
-       command_print(cmd_ctx, "number of counters: %i", (int)buf_get_u32(etm_config_reg->value, 13, 3));
+       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",
-                       (buf_get_u32(etm_config_reg->value, 16, 1) == 1) ? "" : "not ");
-       command_print(cmd_ctx, "number of ext. inputs: %i", (int)buf_get_u32(etm_config_reg->value, 17, 3));
-       command_print(cmd_ctx, "number of ext. outputs: %i",(int) buf_get_u32(etm_config_reg->value, 20, 3));
+                       (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",
-                       (buf_get_u32(etm_config_reg->value, 23, 1) == 1) ? "" : "not ");
-       command_print(cmd_ctx, "protocol version: %i", (int)buf_get_u32(etm_config_reg->value, 28, 3));
+                       (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);
 
@@ -1441,6 +1574,7 @@ static int handle_etm_status_command(struct command_context_s *cmd_ctx, char *cm
        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);
@@ -1456,28 +1590,56 @@ static int handle_etm_status_command(struct command_context_s *cmd_ctx, char *cm
                command_print(cmd_ctx, "current target doesn't have an ETM configured");
                return ERROR_OK;
        }
+       etm = arm7_9->etm_ctx;
 
-       trace_status = arm7_9->etm_ctx->capture_driver->status(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, "tracing is idle");
+               command_print(cmd_ctx, "%s: idle", etm->capture_driver->name);
        }
        else
        {
                static char *completed = " completed";
                static char *running = " is running";
-               static char *overflowed = ", trace overflowed";
-               static char *triggered = ", trace triggered";
+               static char *overflowed = ", overflowed";
+               static char *triggered = ", triggered";
 
-               command_print(cmd_ctx, "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 : "",
                        (trace_status & TRACE_TRIGGERED) ? triggered : "");
 
-               if (arm7_9->etm_ctx->trace_depth > 0)
+               if (etm->trace_depth > 0)
                {
-                       command_print(cmd_ctx, "%i frames of trace data read", (int)(arm7_9->etm_ctx->trace_depth));
+                       command_print(cmd_ctx, "%i frames of trace data read",
+                                       (int)(etm->trace_depth));
                }
        }
 
@@ -1526,7 +1688,7 @@ static int handle_etm_image_command(struct command_context_s *cmd_ctx, char *cmd
        if (argc >= 2)
        {
                etm_ctx->image->base_address_set = 1;
-               etm_ctx->image->base_address = strtoul(args[1], NULL, 0);
+               COMMAND_PARSE_NUMBER(int, args[1], etm_ctx->image->base_address);
        }
        else
        {
@@ -1718,7 +1880,8 @@ static int handle_etm_trigger_percent_command(struct command_context_s *cmd_ctx,
 
        if (argc > 0)
        {
-               uint32_t new_value = strtoul(args[0], NULL, 0);
+               uint32_t new_value;
+               COMMAND_PARSE_NUMBER(u32, args[0], new_value);
 
                if ((new_value < 2) || (new_value > 100))
                {

Linking to existing account procedure

If you already have an account and want to add another login method you MUST first sign in with your existing account and then change URL to read https://review.openocd.org/login/?link to get to this page again but this time it'll work for linking. Thank you.

SSH host keys fingerprints

1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=..              |
|+o..   .         |
|*.o   . .        |
|+B . . .         |
|Bo. = o S        |
|Oo.+ + =         |
|oB=.* = . o      |
| =+=.+   + E     |
|. .=o   . o      |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)