summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authordbrownell <dbrownell@b42882b7-edfa-0310-969c-e2dbd0fdcd60>2009-09-23 21:52:40 +0000
committerdbrownell <dbrownell@b42882b7-edfa-0310-969c-e2dbd0fdcd60>2009-09-23 21:52:40 +0000
commit22045fa6f28813f9e7b17c052f4c7a6c8355178d (patch)
tree4c02321d98f6b7ecba3b4ed7416f08be914ff289 /src
parentd9ce8a2f60ece3b98a6d99b0e5aff8d4adef29fa (diff)
downloadopenocd+libswd-22045fa6f28813f9e7b17c052f4c7a6c8355178d.tar.gz
openocd+libswd-22045fa6f28813f9e7b17c052f4c7a6c8355178d.tar.bz2
openocd+libswd-22045fa6f28813f9e7b17c052f4c7a6c8355178d.tar.xz
openocd+libswd-22045fa6f28813f9e7b17c052f4c7a6c8355178d.zip
When setting up an ETM, cache its ETM_CONFIG register. Then
only expose the registers which are actually present. They could be missing for two basic reasons: - This version might not support them at all; e.g. ETMv1.1 doesn't have some control/status registers. (My sample of ARM9 boards shows all with ETMv1.3 support, FWIW.) - The configuration on this chip may not populate as many registers as possible; e.g. only two data value comparators instead of eight. Includes a bugfix in the "etm info" command: only one of the two registers is missing on older silicon, so show the first one before bailing. Update ETM usage docs to explain that those registers need to be written to configure what is traced, and that some ETM configs are not yet handled. Also, give some examples of the kinds of constrained trace which could be arranged. git-svn-id: svn://svn.berlios.de/openocd/trunk@2752 b42882b7-edfa-0310-969c-e2dbd0fdcd60
Diffstat (limited to 'src')
-rw-r--r--src/target/etm.c227
-rw-r--r--src/target/etm.h2
2 files changed, 178 insertions, 51 deletions
diff --git a/src/target/etm.c b/src/target/etm.c
index cc80b685..91c73a23 100644
--- a/src/target/etm.c
+++ b/src/target/etm.c
@@ -71,10 +71,14 @@ struct etm_reg_info {
* 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", },
@@ -86,16 +90,25 @@ static const struct etm_reg_info reg[] = {
{ 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", },
-
/* 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", },
+ /* 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, \
@@ -120,7 +133,9 @@ static const struct etm_reg_info reg[] = {
ADDR_COMPARATOR(14),
ADDR_COMPARATOR(15),
#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, \
@@ -136,8 +151,9 @@ static const struct etm_reg_info reg[] = {
DATA_COMPARATOR(6),
DATA_COMPARATOR(7),
#undef DATA_COMPARATOR
+};
- /* Counters */
+static const struct etm_reg_info etm_counters[] = {
#define COUNTER(i) \
{ ETM_COUNTER_RELOAD_VALUE + (i), 16, WO, 0x10, \
"ETM_COUNTER_RELOAD_VALUE" #i, }, \
@@ -152,8 +168,9 @@ static const struct etm_reg_info reg[] = {
COUNTER(2),
COUNTER(3),
#undef COUNTER
+};
- /* Sequencers */
+static const struct etm_reg_info etm_sequencer[] = {
#define SEQ(i) \
{ ETM_SEQUENCER_EVENT + (i), 17, WO, 0x10, \
"ETM_SEQUENCER_EVENT" #i, }
@@ -166,7 +183,9 @@ static const struct etm_reg_info reg[] = {
#undef SEQ
/* 0x66 reserved */
{ ETM_SEQUENCER_STATE, 2, RO, 0x10, "ETM_SEQUENCER_STATE", },
+};
+static const struct etm_reg_info etm_outputs[] = {
#define OUT(i) \
{ ETM_EXTERNAL_OUTPUT + (i), 17, WO, 0x10, \
"ETM_EXTERNAL_OUTPUT" #i, }
@@ -176,6 +195,7 @@ static const struct etm_reg_info reg[] = {
OUT(2),
OUT(3),
#undef OUT
+};
#if 0
/* registers from 0x6c..0x7f were added after ETMv1.3 */
@@ -185,11 +205,7 @@ static const struct etm_reg_info reg[] = {
{ 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", },
#endif
-};
static int etm_reg_arch_type = -1;
@@ -224,43 +240,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 +381,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;
}
@@ -1362,7 +1473,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 +1486,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",
+ (etm->config >> 0) & 0x0f);
+ command_print(cmd_ctx, "data comparators: %i",
+ (etm->config >> 4) & 0x0f);
+ command_print(cmd_ctx, "memory map decoders: %i",
+ (etm->config >> 8) & 0x1f);
+ command_print(cmd_ctx, "number of counters: %i",
+ (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));
+ (etm->config & (1 << 16)) ? "" : "not ");
+ command_print(cmd_ctx, "number of ext. inputs: %i",
+ (etm->config >> 17) & 0x07);
+ command_print(cmd_ctx, "number of ext. outputs: %i",
+ (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));
+ (etm->config & (1 << 23)) ? "" : "not ");
+ if (etm->bcd_vers < 0x20)
+ command_print(cmd_ctx, "protocol version: %i",
+ (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",
+ (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);
diff --git a/src/target/etm.h b/src/target/etm.h
index 6b4938aa..b2426c74 100644
--- a/src/target/etm.h
+++ b/src/target/etm.h
@@ -165,6 +165,8 @@ typedef struct etm_context_s
bool data_half; /* port half on a 16 bit port */
bool pc_ok; /* full PC has been acquired */
bool ptr_ok; /* whether last_ptr is valid */
+ uint8_t bcd_vers; /* e.g. 0x13 == ETMv1.3 */
+ uint32_t config; /* cache of ETM_CONFIG value */
uint32_t current_pc; /* current program counter */
uint32_t last_branch; /* last branch address output */
uint32_t last_branch_reason; /* type of last branch encountered */