ETM: add "etm trigger_debug" command
[fw/openocd] / src / target / etm.c
index 520e22f6089c9a20c5785992f4bd1a0e8abb3d8f..d22bc4070a6bc8086fc4f628fd2449cf6c273618 100644 (file)
 #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
 
 
 /*
@@ -430,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)
@@ -441,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;
 
@@ -613,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[] =
 {
@@ -659,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,
@@ -672,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,
@@ -685,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;
@@ -728,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)
                        {
@@ -742,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++;
@@ -829,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
        {
@@ -837,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;
                }
        }
@@ -1059,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;
@@ -1081,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))
                                {
@@ -1126,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))
@@ -1141,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,
@@ -1172,19 +1175,19 @@ 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]);
@@ -1196,16 +1199,16 @@ 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]);
@@ -1215,11 +1218,12 @@ static COMMAND_HELPER(handle_etm_tracemode_command_update,
        bool etmv1_cycle_accurate;
        COMMAND_PARSE_ENABLE(CMD_ARGV[2], etmv1_cycle_accurate);
        if (etmv1_cycle_accurate)
-               tracemode |= ETMV1_CYCLE_ACCURATE;
+               tracemode |= ETM_CTRL_CYCLE_ACCURATE;
 
        bool etmv1_branch_output;
        COMMAND_PARSE_ENABLE(CMD_ARGV[3], etmv1_branch_output);
-               tracemode |= ETMV1_BRANCH_OUTPUT;
+       if (etmv1_branch_output)
+               tracemode |= ETM_CTRL_BRANCH_OUTPUT;
 
        /* IGNORED:
         *  - CPRT tracing (coprocessor register transfers)
@@ -1248,7 +1252,7 @@ COMMAND_HANDLER(handle_etm_tracemode_command)
                return ERROR_FAIL;
        }
 
-       etmv1_tracemode_t tracemode = etm->tracemode;
+       uint32_t tracemode = etm->control;
 
        switch (CMD_ARGC)
        {
@@ -1271,39 +1275,39 @@ COMMAND_HANDLER(handle_etm_tracemode_command)
 
        command_print(CMD_CTX, "current tracemode configuration:");
 
-       switch (tracemode & ETMV1_TRACE_MASK)
+       switch (tracemode & ETM_CTRL_TRACE_MASK)
        {
-               case ETMV1_TRACE_NONE:
+               default:
                        command_print(CMD_CTX, "data tracing: none");
                        break;
-               case ETMV1_TRACE_DATA:
+               case ETM_CTRL_TRACE_DATA:
                        command_print(CMD_CTX, "data tracing: data only");
                        break;
-               case ETMV1_TRACE_ADDR:
+               case ETM_CTRL_TRACE_ADDR:
                        command_print(CMD_CTX, "data tracing: address only");
                        break;
-               case ETMV1_TRACE_DATA | ETMV1_TRACE_ADDR:
+               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:
+               case ETM_CTRL_CONTEXTID_NONE:
                        command_print(CMD_CTX, "contextid tracing: none");
                        break;
-               case ETMV1_CONTEXTID_8:
+               case ETM_CTRL_CONTEXTID_8:
                        command_print(CMD_CTX, "contextid tracing: 8 bit");
                        break;
-               case ETMV1_CONTEXTID_16:
+               case ETM_CTRL_CONTEXTID_16:
                        command_print(CMD_CTX, "contextid tracing: 16 bit");
                        break;
-               case ETMV1_CONTEXTID_32:
+               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");
        }
@@ -1312,7 +1316,7 @@ COMMAND_HANDLER(handle_etm_tracemode_command)
                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");
        }
@@ -1321,8 +1325,15 @@ COMMAND_HANDLER(handle_etm_tracemode_command)
                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;
 
@@ -1330,16 +1341,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)
@@ -1350,6 +1357,8 @@ COMMAND_HANDLER(handle_etm_tracemode_command)
                etm->trace_depth = 0;
        }
 
+#undef TRACEMODE_MASK
+
        return ERROR_OK;
 }
 
@@ -1357,7 +1366,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;
 
@@ -1495,10 +1504,9 @@ 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;
 
@@ -1824,8 +1832,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++)
@@ -1896,8 +1903,7 @@ 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);
@@ -1924,47 +1930,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;
@@ -2052,6 +2017,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;
@@ -2129,13 +2144,6 @@ static const struct command_registration etm_exec_command_handlers[] = {
                .mode = COMMAND_EXEC,
                .help = "display info about the current target's ETM",
        },
-       {
-               .name = "trigger_percent",
-               .handler = &handle_etm_trigger_percent_command,
-               .mode = COMMAND_EXEC,
-               .help = "amount (<percent>) of trace buffer "
-                       "to be filled after the trigger occured",
-       },
        {
                .name = "status",
                .handler = &handle_etm_status_command,
@@ -2154,11 +2162,18 @@ static const struct command_registration etm_exec_command_handlers[] = {
                .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,
+               .handler = handle_etm_analyze_command,
                .mode = COMMAND_EXEC,
-               .help = "anaylze collected ETM trace",
+               .help = "analyze collected ETM trace",
        },
        {
                .name = "image",