This is an automated email from Gerrit. Paul Fertser (fercer...@gmail.com) just uploaded a new patch set to Gerrit, which you can find at http://openocd.zylin.com/2538
-- gerrit commit 39b2b968ea2e48cc99799caf124e22560dd7c06a Author: Paul Fertser <fercer...@gmail.com> Date: Mon Feb 9 17:04:52 2015 +0300 armv7m: add generic trace support (TPIU, ITM, etc.) This intends to provide support for various trace-related subsystems in a generic and expandable way. I plan to add STLink, EDBG and JLink support later. I follow "release early, release often" methodology here, posting this mostly to get feedback on overall design and UI rather than intending to merge this as is. External (using additional hardware) trace capture is tested as follows (you can use just about any USB UART by selecting appropriate TPIU async clock prescaler): 1. STM32L152 board is programmed with an application that configures PLL to provide core clock with 24MHz frequency; to use ITM output it's enough to: ... ITM_STIM8(0) = c; ... (the most obvious way is to use the first stimulus port for printf, so this ITM_STIM8 assignment can be used inside _write()) 2. An FT2232H UART is connected to the SWO pin of the board; 3. Commands to configure UART for 12MHz baud rate: $ setserial /dev/ttyUSB1 spd_cust divisor 5 $ stty -F /dev/ttyUSB1 38400 (FT2232H's base frequency is 60MHz, spd_cust allows to alias 38400 baud with our custom divisor to get 12MHz) 4. itmdump -f /dev/ttyUSB1 -d 1 5. ~/openocd/tcl $ valgrind --vgdb=yes --vgdb-error=1 ../build-native/src/openocd -f interface/stlink-v2-1.cfg -c "transport select hla_swd" -f target/stm32l1.cfg -c "tpiu config external uart 0 0 2" (use prescaler 2 to get 24MHz/2 = 12MHz SWO baud rate) 6. Connect with telnet and issue "itm port 0 0" and "itm port 0 1" commands to see how individual ITM stimuli can be manipulated runtime. 7. Use reset button and Vcc jumper to check the target is properly reinitialised and SWO continues to pump data even after power-cycling. Change-Id: I3a27fa7b8cfb111753088bb8c3d760dd12d1395f Signed-off-by: Paul Fertser <fercer...@gmail.com> diff --git a/src/jtag/drivers/stlink_usb.c b/src/jtag/drivers/stlink_usb.c index 4959f97..4988337 100644 --- a/src/jtag/drivers/stlink_usb.c +++ b/src/jtag/drivers/stlink_usb.c @@ -1031,16 +1031,16 @@ static int stlink_configure_target_trace_port(void *handle) if (res != ERROR_OK) goto out; /* set the TPI clock prescaler */ - res = stlink_usb_write_debug_reg(handle, TPI_ACPR, h->trace.prescale); + res = stlink_usb_write_debug_reg(handle, TPIU_ACPR, h->trace.prescale); if (res != ERROR_OK) goto out; /* select the pin protocol. The STLinkv2 only supports asynchronous * UART emulation (NRZ) mode, so that's what we pick. */ - res = stlink_usb_write_debug_reg(handle, TPI_SPPR, 0x02); + res = stlink_usb_write_debug_reg(handle, TPIU_SPPR, 0x02); if (res != ERROR_OK) goto out; /* disable continuous formatting */ - res = stlink_usb_write_debug_reg(handle, TPI_FFCR, (1<<8)); + res = stlink_usb_write_debug_reg(handle, TPIU_FFCR, (1<<8)); if (res != ERROR_OK) goto out; @@ -1059,7 +1059,7 @@ static int stlink_configure_target_trace_port(void *handle) if (res != ERROR_OK) goto out; /* trace port enable (port 0) */ - res = stlink_usb_write_debug_reg(handle, ITM_TER, (1<<0)); + res = stlink_usb_write_debug_reg(handle, ITM_TER0, (1<<0)); if (res != ERROR_OK) goto out; diff --git a/src/target/Makefile.am b/src/target/Makefile.am index bf80c64..c591103 100644 --- a/src/target/Makefile.am +++ b/src/target/Makefile.am @@ -79,6 +79,7 @@ ARMV6_SRC = \ ARMV7_SRC = \ armv7m.c \ + armv7m_trace.c \ cortex_m.c \ armv7a.c \ cortex_a.c @@ -155,6 +156,7 @@ noinst_HEADERS = \ armv4_5_cache.h \ armv7a.h \ armv7m.h \ + armv7m_trace.h \ avrt.h \ dsp563xx.h \ dsp563xx_once.h \ diff --git a/src/target/armv7m.c b/src/target/armv7m.c index 99af3a8..03fca3c 100644 --- a/src/target/armv7m.c +++ b/src/target/armv7m.c @@ -578,6 +578,9 @@ int armv7m_init_arch_info(struct target *target, struct armv7m_common *armv7m) armv7m->common_magic = ARMV7M_COMMON_MAGIC; armv7m->fp_feature = FP_NONE; + armv7m->trace_config.trace_bus_id = 1; + /* Enable stimulus port #0 by default */ + armv7m->trace_config.itm_ter[0] = 1; arm->core_type = ARM_MODE_THREAD; arm->arch_info = armv7m; diff --git a/src/target/armv7m.h b/src/target/armv7m.h index 86c9aee..747637f 100644 --- a/src/target/armv7m.h +++ b/src/target/armv7m.h @@ -29,6 +29,7 @@ #include "arm_adi_v5.h" #include "arm.h" +#include "armv7m_trace.h" extern const int armv7m_psp_reg_map[]; extern const int armv7m_msp_reg_map[]; @@ -152,6 +153,8 @@ struct armv7m_common { /* stlink is a high level adapter, does not support all functions */ bool stlink; + struct armv7m_trace_config trace_config; + /* Direct processor core register read and writes */ int (*load_core_reg_u32)(struct target *target, uint32_t num, uint32_t *value); int (*store_core_reg_u32)(struct target *target, uint32_t num, uint32_t value); diff --git a/src/target/armv7m_trace.c b/src/target/armv7m_trace.c new file mode 100644 index 0000000..4093b78 --- /dev/null +++ b/src/target/armv7m_trace.c @@ -0,0 +1,222 @@ +/*************************************************************************** + * Copyright (C) 2015 Paul Fertser <fercer...@gmail.com> * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + ***************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "target.h" +#include "armv7m.h" +#include "cortex_m.h" +#include "armv7m_trace.h" + +int armv7m_trace_tpiu_config(struct target *target) +{ + struct armv7m_common *armv7m = target_to_armv7m(target); + struct armv7m_trace_config *trace_config = &armv7m->trace_config; + int retval; + + retval = target_write_u32(target, TPIU_CSPSR, 1 << trace_config->port_size); + if (retval != ERROR_OK) + return retval; + + retval = target_write_u32(target, TPIU_ACPR, trace_config->prescaler - 1); + if (retval != ERROR_OK) + return retval; + + retval = target_write_u32(target, TPIU_SPPR, trace_config->pin_protocol); + if (retval != ERROR_OK) + return retval; + + uint32_t ffcr; + retval = target_read_u32(target, TPIU_FFCR, &ffcr); + if (retval != ERROR_OK) + return retval; + if (trace_config->formatter) + ffcr |= (1 << 1); + else + ffcr &= ~(1 << 1); + retval = target_write_u32(target, TPIU_FFCR, ffcr); + if (retval != ERROR_OK) + return retval; + + return ERROR_OK; +} + +int armv7m_trace_itm_config(struct target *target) +{ + struct armv7m_common *armv7m = target_to_armv7m(target); + struct armv7m_trace_config *trace_config = &armv7m->trace_config; + int retval; + + retval = target_write_u32(target, ITM_LAR, ITM_LAR_KEY); + if (retval != ERROR_OK) + return retval; + + /* Enable ITM and set TraceBusID */ + retval = target_write_u32(target, ITM_TCR, (1 << 0) | + (trace_config->trace_bus_id << 16)); + if (retval != ERROR_OK) + return retval; + + for (unsigned int i = 0; i < 8; i++) { + retval = target_write_u32(target, ITM_TER0 + i * 4, + trace_config->itm_ter[i]); + if (retval != ERROR_OK) + return retval; + } + + return ERROR_OK; +} + +COMMAND_HANDLER(handle_tpiu_config_command) +{ + struct target *target = get_current_target(CMD_CTX); + struct armv7m_common *armv7m = target_to_armv7m(target); + + unsigned int cmd_idx = 0; + + if (CMD_ARGC == cmd_idx) + return ERROR_COMMAND_SYNTAX_ERROR; + if (!strcmp(CMD_ARGV[cmd_idx], "disable")) { + if (CMD_ARGC == cmd_idx + 1) { + armv7m->trace_config.config_type = NONE; + return ERROR_OK; + } + } else if (!strcmp(CMD_ARGV[cmd_idx], "external") || + !strcmp(CMD_ARGV[cmd_idx], "internal")) { + if (!strcmp(CMD_ARGV[cmd_idx], "internal")) { + cmd_idx++; + if (CMD_ARGC == cmd_idx) + return ERROR_COMMAND_SYNTAX_ERROR; + + COMMAND_PARSE_NUMBER(uint, CMD_ARGV[cmd_idx], armv7m->trace_config.trace_freq); + + cmd_idx++; + if (CMD_ARGC == cmd_idx) + return ERROR_COMMAND_SYNTAX_ERROR; + + if (armv7m->trace_config.trace_file) + fclose(armv7m->trace_config.trace_file); + + armv7m->trace_config.trace_file = fopen(CMD_ARGV[cmd_idx], "ab"); + if (!armv7m->trace_config.trace_file) { + LOG_ERROR("Can't open trace destination file"); + return ERROR_FAIL; + } + } + cmd_idx++; + if (CMD_ARGC == cmd_idx) + return ERROR_COMMAND_SYNTAX_ERROR; + + if (!strcmp(CMD_ARGV[cmd_idx], "sync")) + armv7m->trace_config.pin_protocol = SYNC; + else if (!strcmp(CMD_ARGV[cmd_idx], "manchester")) + armv7m->trace_config.pin_protocol = ASYNC_MANCHESTER; + else if (!strcmp(CMD_ARGV[cmd_idx], "uart")) + armv7m->trace_config.pin_protocol = ASYNC_UART; + else + return ERROR_COMMAND_SYNTAX_ERROR; + + cmd_idx++; + if (CMD_ARGC == cmd_idx) + return ERROR_COMMAND_SYNTAX_ERROR; + + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[cmd_idx++], armv7m->trace_config.port_size); + if (CMD_ARGC == cmd_idx) + return ERROR_COMMAND_SYNTAX_ERROR; + COMMAND_PARSE_ON_OFF(CMD_ARGV[cmd_idx++], armv7m->trace_config.formatter); + if (CMD_ARGC == cmd_idx) + return ERROR_COMMAND_SYNTAX_ERROR; + COMMAND_PARSE_NUMBER(u16, CMD_ARGV[cmd_idx++], armv7m->trace_config.prescaler); + + if (CMD_ARGC == cmd_idx) { + if (CMD_CTX->mode == COMMAND_EXEC) + return armv7m_trace_tpiu_config(target); + else + return ERROR_OK; + } + } + + return ERROR_COMMAND_SYNTAX_ERROR; +} + +COMMAND_HANDLER(handle_itm_port_command) +{ + struct target *target = get_current_target(CMD_CTX); + struct armv7m_common *armv7m = target_to_armv7m(target); + unsigned int reg_idx; + uint8_t port; + bool enable; + + if (CMD_ARGC != 2) + return ERROR_COMMAND_SYNTAX_ERROR; + + COMMAND_PARSE_NUMBER(u8, CMD_ARGV[0], port); + COMMAND_PARSE_ON_OFF(CMD_ARGV[1], enable); + reg_idx = port / 8; + port = port % 8; + if (enable) + armv7m->trace_config.itm_ter[reg_idx] |= (1 << port); + else + armv7m->trace_config.itm_ter[reg_idx] &= ~(1 << port); + + if (CMD_CTX->mode == COMMAND_EXEC) + return armv7m_trace_itm_config(target); + else + return ERROR_OK; +} + +static const struct command_registration tpiu_command_handlers[] = { + { + .name = "config", + .handler = handle_tpiu_config_command, + .mode = COMMAND_ANY, + .help = "Configure TPIU features", + .usage = "(disable | " + "((external | internal <baud> <filename>) " + "(sync|manchester|uart) <port_size> <formatter_en> <prescaler>))", + }, + COMMAND_REGISTRATION_DONE +}; + +static const struct command_registration itm_command_handlers[] = { + { + .name = "port", + .handler = handle_itm_port_command, + .mode = COMMAND_ANY, + .help = "Enable or disable ITM stimulus port", + .usage = "<port> (on|off)", + }, + COMMAND_REGISTRATION_DONE +}; + +const struct command_registration armv7m_trace_command_handlers[] = { + { + .name = "tpiu", + .mode = COMMAND_ANY, + .help = "tpiu command group", + .usage = "", + .chain = tpiu_command_handlers, + }, + { + .name = "itm", + .mode = COMMAND_ANY, + .help = "itm command group", + .usage = "", + .chain = itm_command_handlers, + }, + COMMAND_REGISTRATION_DONE +}; diff --git a/src/target/armv7m_trace.h b/src/target/armv7m_trace.h new file mode 100644 index 0000000..f5632dd --- /dev/null +++ b/src/target/armv7m_trace.h @@ -0,0 +1,53 @@ +/*************************************************************************** + * Copyright (C) 2015 Paul Fertser <fercer...@gmail.com> * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + ***************************************************************************/ + +#ifndef ARMV7M_TRACE_H +#define ARMV7M_TRACE_H + +#include "command.h" + +enum trace_config_type { + NONE, + EXTERNAL, + INTERNAL +}; + +enum tpio_pin_protocol { + SYNC, + ASYNC_MANCHESTER, + ASYNC_UART +}; + +struct armv7m_trace_config { + enum trace_config_type config_type; + + enum tpio_pin_protocol pin_protocol; + bool formatter; + uint32_t port_size; + uint16_t prescaler; + + uint32_t itm_ter[8]; + unsigned int trace_bus_id; + + FILE *trace_file; + unsigned int trace_freq; +}; + +extern const struct command_registration armv7m_trace_command_handlers[]; + +int armv7m_trace_tpiu_config(struct target *target); +int armv7m_trace_itm_config(struct target *target); + +#endif diff --git a/src/target/cortex_m.c b/src/target/cortex_m.c index a5230b7..7f8f90c 100644 --- a/src/target/cortex_m.c +++ b/src/target/cortex_m.c @@ -1838,6 +1838,14 @@ int cortex_m_examine(struct target *target) armv7m->dap.tar_autoincr_block = (1 << 12); } + /* Configure trace modules */ + retval = target_write_u32(target, DCB_DEMCR, TRCENA | armv7m->demcr); + if (retval != ERROR_OK) + return retval; + + armv7m_trace_tpiu_config(target); + armv7m_trace_itm_config(target); + /* NOTE: FPB and DWT are both optional. */ /* Setup FPB */ diff --git a/src/target/cortex_m.h b/src/target/cortex_m.h index 8a284bd..5c61abb 100644 --- a/src/target/cortex_m.h +++ b/src/target/cortex_m.h @@ -33,10 +33,11 @@ #define SYSTEM_CONTROL_BASE 0x400FE000 -#define ITM_TER 0xE0000E00 +#define ITM_TER0 0xE0000E00 #define ITM_TPR 0xE0000E40 #define ITM_TCR 0xE0000E80 #define ITM_LAR 0xE0000FB0 +#define ITM_LAR_KEY 0xC5ACCE55 #define CPUID 0xE000ED00 /* Debug Control Block */ @@ -69,13 +70,13 @@ #define FPU_FPCAR 0xE000EF38 #define FPU_FPDSCR 0xE000EF3C -#define TPI_SSPSR 0xE0040000 -#define TPI_CSPSR 0xE0040004 -#define TPI_ACPR 0xE0040010 -#define TPI_SPPR 0xE00400F0 -#define TPI_FFSR 0xE0040300 -#define TPI_FFCR 0xE0040304 -#define TPI_FSCR 0xE0040308 +#define TPIU_SSPSR 0xE0040000 +#define TPIU_CSPSR 0xE0040004 +#define TPIU_ACPR 0xE0040010 +#define TPIU_SPPR 0xE00400F0 +#define TPIU_FFSR 0xE0040300 +#define TPIU_FFCR 0xE0040304 +#define TPIU_FSCR 0xE0040308 /* DCB_DHCSR bit and field definitions */ #define DBGKEY (0xA05F << 16) diff --git a/src/target/hla_target.c b/src/target/hla_target.c index efc0313..47ef764 100644 --- a/src/target/hla_target.c +++ b/src/target/hla_target.c @@ -37,6 +37,7 @@ #include "breakpoints.h" #include "target_type.h" #include "armv7m.h" +#include "armv7m_trace.h" #include "cortex_m.h" #include "arm_semihosting.h" #include "target_request.h" @@ -786,6 +787,9 @@ static const struct command_registration adapter_command_handlers[] = { { .chain = arm_command_handlers, }, + { + .chain = armv7m_trace_command_handlers, + }, COMMAND_REGISTRATION_DONE }; diff --git a/tcl/target/stm32l1.cfg b/tcl/target/stm32l1.cfg index 8591830..0b636c3 100644 --- a/tcl/target/stm32l1.cfg +++ b/tcl/target/stm32l1.cfg @@ -104,3 +104,10 @@ $_TARGETNAME configure -event reset-init { $_TARGETNAME configure -event reset-start { adapter_khz 300 } + +$_TARGETNAME configure -event examine-end { + # Set TRACE_IOEN and DBG_* bits to facilitate debug + # TRACE_MODE is set to async; when using sync change this value + # accordingly to configure trace pins assignment + mww 0xE0042004 0x00000023 +} -- ------------------------------------------------------------------------------ Dive into the World of Parallel Programming. The Go Parallel Website, sponsored by Intel and developed in partnership with Slashdot Media, is your hub for all things parallel software development, from weekly thought leadership blogs to news, videos, case studies, tutorials and more. Take a look and join the conversation now. http://goparallel.sourceforge.net/ _______________________________________________ OpenOCD-devel mailing list OpenOCD-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/openocd-devel