Minor ETB and ETM bugfixes and doc updates

- ETB
    * report _actual_ hardware status, not just expected status
    * add a missing diagnostic on a potential ETB setup error
    * prefix any diagnostics with "ETB"
 - ETM
    * make "etm status" show ETM hardware status too, instead of
      just traceport status (which previously was fake, sigh)
 - Docs
    * flesh out "etm tracemode" docs a bit
    * clarify "etm status" ... previously it was traceport status
    * explain "etm trigger_percent" as a *traceport* option

ETM+ETB tracing still isn't behaving, but now I can see that part of 
the reason is that the ETB turns itself off almost immediately after
being enabled, and before collecting any data.


git-svn-id: svn://svn.berlios.de/openocd/trunk@2790 b42882b7-edfa-0310-969c-e2dbd0fdcd60
This commit is contained in:
dbrownell 2009-10-02 09:19:03 +00:00
parent d340906476
commit 1033633321
3 changed files with 111 additions and 59 deletions

View File

@ -4891,7 +4891,7 @@ Displays information about the current target's ETM.
@end deffn @end deffn
@deffn Command {etm status} @deffn Command {etm status}
Displays status of the current target's ETM: Displays status of the current target's ETM and trace port driver:
is the ETM idle, or is it collecting data? is the ETM idle, or is it collecting data?
Did trace data overflow? Did trace data overflow?
Was it triggered? Was it triggered?
@ -4904,19 +4904,43 @@ When the configuration changes, tracing is stopped
and any buffered trace data is invalidated. and any buffered trace data is invalidated.
@itemize @itemize
@item @var{type} ... one of @item @var{type} ... describing how data accesses are traced,
when they pass any ViewData filtering that that was set up.
The value is one of
@option{none} (save nothing), @option{none} (save nothing),
@option{data} (save data), @option{data} (save data),
@option{address} (save addresses), @option{address} (save addresses),
@option{all} (save data and addresses) @option{all} (save data and addresses)
@item @var{context_id_bits} ... 0, 8, 16, or 32 @item @var{context_id_bits} ... 0, 8, 16, or 32
@item @var{cycle_accurate} ... @option{enable} or @option{disable} @item @var{cycle_accurate} ... @option{enable} or @option{disable}
@item @var{branch_output} ... @option{enable} or @option{disable} cycle-accurate instruction tracing.
Before ETMv3, enabling this causes much extra data to be recorded.
@item @var{branch_output} ... @option{enable} or @option{disable}.
Disable this unless you need to try reconstructing the instruction
trace stream without an image of the code.
@end itemize @end itemize
@end deffn @end deffn
@deffn Command {etm trigger_percent} percent @deffn Command {etm trigger_percent} [percent]
@emph{Buggy and effectively a NOP ... @var{percent} from 2..100} This displays, or optionally changes, the trace port driver's
behavior after the ETM's configured @emph{trigger} event fires.
It controls how much more trace data is saved after the (single)
trace trigger becomes active.
@itemize
@item The default corresponds to @emph{trace around} usage,
recording 50 percent data before the event and the rest
afterwards.
@item The minimum value of @var{percent} is 2 percent,
recording almost exclusively data before the trigger.
Such extreme @emph{trace before} usage can help figure out
what caused that event to happen.
@item The maximum value of @var{percent} is 100 percent,
recording data almost exclusively after the event.
This extreme @emph{trace after} usage might help sort out
how the event caused trouble.
@end itemize
@c REVISIT allow "break" too -- enter debug mode.
@end deffn @end deffn
@subsection ETM Trace Operation @subsection ETM Trace Operation

View File

@ -110,13 +110,13 @@ static int etb_get_reg(reg_t *reg)
if ((retval = etb_read_reg(reg)) != ERROR_OK) if ((retval = etb_read_reg(reg)) != ERROR_OK)
{ {
LOG_ERROR("BUG: error scheduling etm register read"); LOG_ERROR("BUG: error scheduling ETB register read");
return retval; return retval;
} }
if ((retval = jtag_execute_queue()) != ERROR_OK) if ((retval = jtag_execute_queue()) != ERROR_OK)
{ {
LOG_ERROR("register read failed"); LOG_ERROR("ETB register read failed");
return retval; return retval;
} }
@ -288,7 +288,7 @@ static int etb_set_reg(reg_t *reg, uint32_t value)
if ((retval = etb_write_reg(reg, value)) != ERROR_OK) if ((retval = etb_write_reg(reg, value)) != ERROR_OK)
{ {
LOG_ERROR("BUG: error scheduling etm register write"); LOG_ERROR("BUG: error scheduling ETB register write");
return retval; return retval;
} }
@ -307,7 +307,7 @@ static int etb_set_reg_w_exec(reg_t *reg, uint8_t *buf)
if ((retval = jtag_execute_queue()) != ERROR_OK) if ((retval = jtag_execute_queue()) != ERROR_OK)
{ {
LOG_ERROR("register write failed"); LOG_ERROR("ETB: register write failed");
return retval; return retval;
} }
return ERROR_OK; return ERROR_OK;
@ -378,20 +378,20 @@ static int handle_etb_config_command(struct command_context_s *cmd_ctx, char *cm
if (!target) if (!target)
{ {
LOG_ERROR("target '%s' not defined", args[0]); LOG_ERROR("ETB: target '%s' not defined", args[0]);
return ERROR_FAIL; return ERROR_FAIL;
} }
if (arm7_9_get_arch_pointers(target, &armv4_5, &arm7_9) != ERROR_OK) 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"); command_print(cmd_ctx, "ETB: current target isn't an ARM7/ARM9 target");
return ERROR_FAIL; return ERROR_FAIL;
} }
tap = jtag_tap_by_string(args[1]); tap = jtag_tap_by_string(args[1]);
if (tap == NULL) if (tap == NULL)
{ {
command_print(cmd_ctx, "Tap: %s does not exist", args[1]); command_print(cmd_ctx, "ETB: TAP %s does not exist", args[1]);
return ERROR_FAIL; return ERROR_FAIL;
} }
@ -409,7 +409,7 @@ static int handle_etb_config_command(struct command_context_s *cmd_ctx, char *cm
} }
else else
{ {
LOG_ERROR("target has no ETM defined, ETB left unconfigured"); LOG_ERROR("ETM: target has no ETM defined, ETB left unconfigured");
return ERROR_FAIL; return ERROR_FAIL;
} }
@ -436,56 +436,53 @@ static int etb_init(etm_context_t *etm_ctx)
static trace_status_t etb_status(etm_context_t *etm_ctx) static trace_status_t etb_status(etm_context_t *etm_ctx)
{ {
etb_t *etb = etm_ctx->capture_driver_priv; etb_t *etb = etm_ctx->capture_driver_priv;
reg_t *control = &etb->reg_cache->reg_list[ETB_CTRL];
reg_t *status = &etb->reg_cache->reg_list[ETB_STATUS];
trace_status_t retval = 0;
int etb_timeout = 100;
etb->etm_ctx = etm_ctx; etb->etm_ctx = etm_ctx;
/* if tracing is currently idle, return this information */ /* read control and status registers */
if (etm_ctx->capture_status == TRACE_IDLE) etb_read_reg(control);
{ etb_read_reg(status);
return etm_ctx->capture_status; jtag_execute_queue();
}
else if (etm_ctx->capture_status & TRACE_RUNNING)
{
reg_t *etb_status_reg = &etb->reg_cache->reg_list[ETB_STATUS];
int etb_timeout = 100;
/* trace is running, check the ETB status flags */ /* See if it's (still) active */
etb_get_reg(etb_status_reg); retval = buf_get_u32(control->value, 0, 1) ? TRACE_RUNNING : TRACE_IDLE;
/* check Full bit to identify an overflow */ /* check Full bit to identify wraparound/overflow */
if (buf_get_u32(etb_status_reg->value, 0, 1) == 1) if (buf_get_u32(status->value, 0, 1) == 1)
etm_ctx->capture_status |= TRACE_OVERFLOWED; retval |= TRACE_OVERFLOWED;
/* check Triggered bit to identify trigger condition */ /* check Triggered bit to identify trigger condition */
if (buf_get_u32(etb_status_reg->value, 1, 1) == 1) if (buf_get_u32(status->value, 1, 1) == 1)
etm_ctx->capture_status |= TRACE_TRIGGERED; retval |= TRACE_TRIGGERED;
/* check AcqComp to identify trace completion */ /* check AcqComp to see if trigger counter dropped to zero */
if (buf_get_u32(etb_status_reg->value, 2, 1) == 1) if (buf_get_u32(status->value, 2, 1) == 1) {
{ /* wait for DFEmpty */
while (etb_timeout-- && (buf_get_u32(etb_status_reg->value, 3, 1) == 0)) while (etb_timeout-- && buf_get_u32(status->value, 3, 1) == 0)
{ etb_get_reg(status);
/* wait for data formatter idle */
etb_get_reg(etb_status_reg);
}
if (etb_timeout == 0) if (etb_timeout == 0)
{ LOG_ERROR("ETB: DFEmpty won't go high, status 0x%02x",
LOG_ERROR("AcqComp set but DFEmpty won't go high, ETB status: 0x%" PRIx32 "", (unsigned) buf_get_u32(status->value, 0, 4));
buf_get_u32(etb_status_reg->value, 0, etb_status_reg->size));
}
if (!(etm_ctx->capture_status && TRACE_TRIGGERED)) if (!(etm_ctx->capture_status & TRACE_TRIGGERED))
{ LOG_WARNING("ETB: trace complete without triggering?");
LOG_ERROR("trace completed, but no trigger condition detected");
}
etm_ctx->capture_status &= ~TRACE_RUNNING; retval |= TRACE_COMPLETED;
etm_ctx->capture_status |= TRACE_COMPLETED;
}
} }
return etm_ctx->capture_status; /* NOTE: using a trigger is optional; and at least ETB11 has a mode
* where it can ignore the trigger counter.
*/
/* update recorded state */
etm_ctx->capture_status = retval;
return retval;
} }
static int etb_read_trace(etm_context_t *etm_ctx) static int etb_read_trace(etm_context_t *etm_ctx)
@ -654,8 +651,10 @@ static int etb_start_capture(etm_context_t *etm_ctx)
etb_ctrl_value |= 0x2; etb_ctrl_value |= 0x2;
} }
if ((etm_ctx->portmode & ETM_PORT_MODE_MASK) == ETM_PORT_MUXED) if ((etm_ctx->portmode & ETM_PORT_MODE_MASK) == ETM_PORT_MUXED) {
LOG_ERROR("ETB: can't run in multiplexed mode");
return ERROR_ETM_PORTMODE_NOT_SUPPORTED; return ERROR_ETM_PORTMODE_NOT_SUPPORTED;
}
trigger_count = (etb->ram_depth * etm_ctx->trigger_percent) / 100; trigger_count = (etb->ram_depth * etm_ctx->trigger_percent) / 100;

View File

@ -1567,6 +1567,7 @@ static int handle_etm_status_command(struct command_context_s *cmd_ctx, char *cm
target_t *target; target_t *target;
armv4_5_common_t *armv4_5; armv4_5_common_t *armv4_5;
arm7_9_common_t *arm7_9; arm7_9_common_t *arm7_9;
etm_context_t *etm;
trace_status_t trace_status; trace_status_t trace_status;
target = get_current_target(cmd_ctx); target = get_current_target(cmd_ctx);
@ -1582,28 +1583,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"); command_print(cmd_ctx, "current target doesn't have an ETM configured");
return ERROR_OK; 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) if (trace_status == TRACE_IDLE)
{ {
command_print(cmd_ctx, "tracing is idle"); command_print(cmd_ctx, "%s: idle", etm->capture_driver->name);
} }
else else
{ {
static char *completed = " completed"; static char *completed = " completed";
static char *running = " is running"; static char *running = " is running";
static char *overflowed = ", trace overflowed"; static char *overflowed = ", overflowed";
static char *triggered = ", trace triggered"; 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_RUNNING) ? running : completed,
(trace_status & TRACE_OVERFLOWED) ? overflowed : "", (trace_status & TRACE_OVERFLOWED) ? overflowed : "",
(trace_status & TRACE_TRIGGERED) ? triggered : ""); (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));
} }
} }