From ffe6bc82201ff3dceea193af530738d868258b0b Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Mon, 27 Jan 2020 18:45:10 +0100 Subject: [PATCH] swim: add new transport Add SWIM and STM8 to documentation and update TODO file. Introduce transport "swim" and command "swim newtap". Switch in swim.c from HLA API to the new SWIM API. Implement in stlink driver the SWIM APIs as wrappers of existing HLA functions. Remove any SWIM related reference from HLA files. Update stm8 config files and stlink-dap interface config file. Change-Id: I2bb9f58d52900f6eb4df05f979f7ef11fd439c24 Signed-off-by: Antonio Borneo Reviewed-on: http://openocd.zylin.com/5530 Tested-by: jenkins --- TODO | 3 +- doc/openocd.texi | 24 +++++++ src/jtag/core.c | 9 ++- src/jtag/drivers/stlink_usb.c | 39 +++++++++-- src/jtag/hla/hla_transport.c | 14 +--- src/jtag/hla/hla_transport.h | 1 - src/jtag/interface.h | 4 ++ src/jtag/swim.c | 124 +++++++++++++++++++++++++++++++--- src/transport/transport.h | 1 + tcl/interface/stlink-dap.cfg | 11 +-- tcl/target/stm8l.cfg | 4 +- tcl/target/stm8s.cfg | 4 +- 12 files changed, 197 insertions(+), 41 deletions(-) diff --git a/TODO b/TODO index c73d772e23..ebb6c99808 100644 --- a/TODO +++ b/TODO @@ -59,8 +59,7 @@ changes pending in gerrit. - tap_set_state(TAP_RESET) is already done in src/jtag/core.c. No need to replicate it in the drivers, apart in case the driver sets TRST independently -- separate SWIM from HLA and make it independent -- add .hla_ops and .swim_ops to "adapter" +- add .hla_ops to "adapter" - HLA is a API level (.hla_ops). Transport should simply be {jtag,swd}, not {hla_jtag,hla_swd}. diff --git a/doc/openocd.texi b/doc/openocd.texi index ef77993ec8..1ddf09ffab 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -3304,6 +3304,24 @@ The Serial Peripheral Interface (SPI) is a general purpose transport which uses four wire signaling. Some processors use it as part of a solution for flash programming. +@anchor{swimtransport} +@subsection SWIM Transport +@cindex SWIM +@cindex Single Wire Interface Module +The Single Wire Interface Module (SWIM) is a low-pin-count debug protocol used +by the STMicroelectronics MCU family STM8 and documented in the +@uref{https://www.st.com/resource/en/user_manual/cd00173911.pdf, User Manual UM470}. + +SWIM does not support boundary scan testing nor multiple cores. + +The SWIM transport is selected with the command @command{transport select swim}. + +The concept of TAPs does not fit in the protocol since SWIM does not implement +a scan chain. Nevertheless, the current SW model of OpenOCD requires defining a +virtual SWIM TAP through the command @command{swim newtap basename tap_type}. +The TAP definition must precede the target definition command +@command{target create target_name stm8 -chain-position basename.tap_type}. + @anchor{jtagspeed} @section JTAG Speed JTAG clock setup is part of system setup. @@ -9831,6 +9849,12 @@ This command is similar to @command{arc jtag get-aux-reg} but is for core registers. @end deffn +@section STM8 Architecture +@uref{http://st.com/stm8/, STM8} is a 8-bit microcontroller platform from +STMicroelectronics, based on a proprietary 8-bit core architecture. + +OpenOCD supports debugging STM8 through the STMicroelectronics debug +protocol SWIM, @pxref{swimtransport,,SWIM}. @anchor{softwaredebugmessagesandtracing} @section Software Debug Messages and Tracing diff --git a/src/jtag/core.c b/src/jtag/core.c index d83f19503c..1d424b2e42 100644 --- a/src/jtag/core.c +++ b/src/jtag/core.c @@ -2027,7 +2027,8 @@ int adapter_resets(int trst, int srst) jtag_execute_queue(); return ERROR_OK; } else if (transport_is_swd() || transport_is_hla() || - transport_is_dapdirect_swd() || transport_is_dapdirect_jtag()) { + transport_is_dapdirect_swd() || transport_is_dapdirect_jtag() || + transport_is_swim()) { if (trst == TRST_ASSERT) { LOG_ERROR("transport %s has no trst signal", get_current_transport()->name); @@ -2060,7 +2061,8 @@ int adapter_assert_reset(void) jtag_add_reset(0, 1); return ERROR_OK; } else if (transport_is_swd() || transport_is_hla() || - transport_is_dapdirect_jtag() || transport_is_dapdirect_swd()) + transport_is_dapdirect_jtag() || transport_is_dapdirect_swd() || + transport_is_swim()) return adapter_system_reset(1); else if (get_current_transport() != NULL) LOG_ERROR("reset is not supported on %s", @@ -2076,7 +2078,8 @@ int adapter_deassert_reset(void) jtag_add_reset(0, 0); return ERROR_OK; } else if (transport_is_swd() || transport_is_hla() || - transport_is_dapdirect_jtag() || transport_is_dapdirect_swd()) + transport_is_dapdirect_jtag() || transport_is_dapdirect_swd() || + transport_is_swim()) return adapter_system_reset(0); else if (get_current_transport() != NULL) LOG_ERROR("reset is not supported on %s", diff --git a/src/jtag/drivers/stlink_usb.c b/src/jtag/drivers/stlink_usb.c index 485a95c6b6..4c5081c9e3 100644 --- a/src/jtag/drivers/stlink_usb.c +++ b/src/jtag/drivers/stlink_usb.c @@ -1288,8 +1288,6 @@ static enum stlink_mode stlink_get_mode(enum hl_transports t) return STLINK_MODE_DEBUG_SWD; case HL_TRANSPORT_JTAG: return STLINK_MODE_DEBUG_JTAG; - case HL_TRANSPORT_SWIM: - return STLINK_MODE_DEBUG_SWIM; default: return STLINK_MODE_UNKNOWN; } @@ -3546,6 +3544,28 @@ static void stlink_dap_op_quit(struct adiv5_dap *dap) LOG_ERROR("Error closing APs"); } +static int stlink_swim_op_srst(void) +{ + return stlink_usb_reset(stlink_dap_handle); +} + +static int stlink_swim_op_read_mem(uint32_t addr, uint32_t size, + uint32_t count, uint8_t *buffer) +{ + return stlink_usb_read_mem(stlink_dap_handle, addr, size, count, buffer); +} + +static int stlink_swim_op_write_mem(uint32_t addr, uint32_t size, + uint32_t count, const uint8_t *buffer) +{ + return stlink_usb_write_mem(stlink_dap_handle, addr, size, count, buffer); +} + +static int stlink_swim_op_reconnect(void) +{ + return stlink_usb_state(stlink_dap_handle); +} + static int stlink_dap_config_trace(bool enabled, enum tpiu_pin_protocol pin_protocol, uint32_t port_size, unsigned int *trace_freq, unsigned int traceclkin_freq, @@ -3656,6 +3676,8 @@ static int stlink_dap_init(void) mode = STLINK_MODE_DEBUG_SWD; else if (transport_is_dapdirect_jtag()) mode = STLINK_MODE_DEBUG_JTAG; + else if (transport_is_swim()) + mode = STLINK_MODE_DEBUG_SWIM; else { LOG_ERROR("Unsupported transport"); return ERROR_FAIL; @@ -3665,7 +3687,8 @@ static int stlink_dap_init(void) if (retval != ERROR_OK) return retval; - if (!(stlink_dap_handle->version.flags & STLINK_F_HAS_DAP_REG)) { + if ((mode != STLINK_MODE_DEBUG_SWIM) && + !(stlink_dap_handle->version.flags & STLINK_F_HAS_DAP_REG)) { LOG_ERROR("ST-Link version does not support DAP direct transport"); return ERROR_FAIL; } @@ -3737,7 +3760,14 @@ static const struct dap_ops stlink_dap_ops = { .quit = stlink_dap_op_quit, /* optional */ }; -static const char *const stlink_dap_transport[] = { "dapdirect_jtag", "dapdirect_swd", NULL }; +static const struct swim_driver stlink_swim_ops = { + .srst = stlink_swim_op_srst, + .read_mem = stlink_swim_op_read_mem, + .write_mem = stlink_swim_op_write_mem, + .reconnect = stlink_swim_op_reconnect, +}; + +static const char *const stlink_dap_transport[] = { "dapdirect_jtag", "dapdirect_swd", "swim", NULL }; struct adapter_driver stlink_dap_adapter_driver = { .name = "st-link", @@ -3755,4 +3785,5 @@ struct adapter_driver stlink_dap_adapter_driver = { .dap_jtag_ops = &stlink_dap_ops, .dap_swd_ops = &stlink_dap_ops, + .swim_ops = &stlink_swim_ops, }; diff --git a/src/jtag/hla/hla_transport.c b/src/jtag/hla/hla_transport.c index ddacea36aa..fbdddfd651 100644 --- a/src/jtag/hla/hla_transport.c +++ b/src/jtag/hla/hla_transport.c @@ -175,8 +175,6 @@ static int hl_transport_init(struct command_context *cmd_ctx) tr = HL_TRANSPORT_SWD; else if (strcmp(transport->name, "hla_jtag") == 0) tr = HL_TRANSPORT_JTAG; - else if (strcmp(transport->name, "stlink_swim") == 0) - tr = HL_TRANSPORT_SWIM; int retval = hl_interface_open(tr); @@ -218,26 +216,18 @@ static struct transport hl_jtag_transport = { .override_target = hl_interface_override_target, }; -static struct transport stlink_swim_transport = { - .name = "stlink_swim", - .select = hl_transport_select, - .init = hl_transport_init, -}; - -const char *hl_transports[] = { "hla_swd", "hla_jtag", "stlink_swim", NULL }; +const char *hl_transports[] = { "hla_swd", "hla_jtag", NULL }; static void hl_constructor(void) __attribute__ ((constructor)); static void hl_constructor(void) { transport_register(&hl_swd_transport); transport_register(&hl_jtag_transport); - transport_register(&stlink_swim_transport); } bool transport_is_hla(void) { struct transport *t; t = get_current_transport(); - return t == &hl_swd_transport || t == &hl_jtag_transport - || t == &stlink_swim_transport; + return t == &hl_swd_transport || t == &hl_jtag_transport; } diff --git a/src/jtag/hla/hla_transport.h b/src/jtag/hla/hla_transport.h index 07eb751e2a..0e0bea25f4 100644 --- a/src/jtag/hla/hla_transport.h +++ b/src/jtag/hla/hla_transport.h @@ -26,7 +26,6 @@ enum hl_transports { HL_TRANSPORT_UNKNOWN = 0, HL_TRANSPORT_SWD, HL_TRANSPORT_JTAG, - HL_TRANSPORT_SWIM }; #endif /* OPENOCD_JTAG_HLA_HLA_TRANSPORT_H */ diff --git a/src/jtag/interface.h b/src/jtag/interface.h index 91291dbd1d..a471aa96df 100644 --- a/src/jtag/interface.h +++ b/src/jtag/interface.h @@ -26,6 +26,7 @@ #define OPENOCD_JTAG_INTERFACE_H #include +#include #include /* @file @@ -363,6 +364,9 @@ struct adapter_driver { /* DAP APIs over SWD transport */ const struct dap_ops *dap_swd_ops; + /* SWIM APIs */ + const struct swim_driver *swim_ops; + /* FIXME: helper to simplify transition of HLA drivers. To be removed */ struct hl_interface_s *hla_if; }; diff --git a/src/jtag/swim.c b/src/jtag/swim.c index 965018c270..936268b25a 100644 --- a/src/jtag/swim.c +++ b/src/jtag/swim.c @@ -14,38 +14,140 @@ #include "interface.h" #include "swim.h" -#include "jtag/hla/hla_transport.h" -#include "jtag/hla/hla_interface.h" -#include "jtag/hla/hla_layout.h" +#include +#include extern struct adapter_driver *adapter_driver; int swim_system_reset(void) { - assert(adapter_driver->hla_if); + assert(adapter_driver->swim_ops); - return adapter_driver->hla_if->layout->api->reset(adapter_driver->hla_if->handle); + return adapter_driver->swim_ops->srst(); } int swim_read_mem(uint32_t addr, uint32_t size, uint32_t count, uint8_t *buffer) { - assert(adapter_driver->hla_if); + assert(adapter_driver->swim_ops); - return adapter_driver->hla_if->layout->api->read_mem(adapter_driver->hla_if->handle, addr, size, count, buffer); + return adapter_driver->swim_ops->read_mem(addr, size, count, buffer); } int swim_write_mem(uint32_t addr, uint32_t size, uint32_t count, const uint8_t *buffer) { - assert(adapter_driver->hla_if); + assert(adapter_driver->swim_ops); - return adapter_driver->hla_if->layout->api->write_mem(adapter_driver->hla_if->handle, addr, size, count, buffer); + return adapter_driver->swim_ops->write_mem(addr, size, count, buffer); } int swim_reconnect(void) { - assert(adapter_driver->hla_if); + assert(adapter_driver->swim_ops); - return adapter_driver->hla_if->layout->api->state(adapter_driver->hla_if->handle); + return adapter_driver->swim_ops->reconnect(); +} + +COMMAND_HANDLER(handle_swim_newtap_command) +{ + struct jtag_tap *tap; + + /* + * only need "basename" and "tap_type", but for backward compatibility + * ignore extra parameters + */ + if (CMD_ARGC < 2) + return ERROR_COMMAND_SYNTAX_ERROR; + + tap = calloc(1, sizeof(*tap)); + if (!tap) { + LOG_ERROR("Out of memory"); + return ERROR_FAIL; + } + + tap->chip = strdup(CMD_ARGV[0]); + tap->tapname = strdup(CMD_ARGV[1]); + tap->dotted_name = alloc_printf("%s.%s", CMD_ARGV[0], CMD_ARGV[1]); + if (!tap->chip || !tap->tapname || !tap->dotted_name) { + LOG_ERROR("Out of memory"); + free(tap->dotted_name); + free(tap->tapname); + free(tap->chip); + free(tap); + return ERROR_FAIL; + } + + LOG_DEBUG("Creating new SWIM \"tap\", Chip: %s, Tap: %s, Dotted: %s", + tap->chip, tap->tapname, tap->dotted_name); + + /* default is enabled-after-reset */ + tap->enabled = true; + + jtag_tap_init(tap); + return ERROR_OK; +} + +static const struct command_registration swim_transport_subcommand_handlers[] = { + { + .name = "newtap", + .handler = handle_swim_newtap_command, + .mode = COMMAND_CONFIG, + .help = "Create a new TAP instance named basename.tap_type, " + "and appends it to the scan chain.", + .usage = "basename tap_type", + }, + COMMAND_REGISTRATION_DONE +}; + +static const struct command_registration swim_transport_command_handlers[] = { + { + .name = "swim", + .mode = COMMAND_ANY, + .help = "perform swim adapter actions", + .usage = "", + .chain = swim_transport_subcommand_handlers, + }, + COMMAND_REGISTRATION_DONE +}; + +static int swim_transport_select(struct command_context *cmd_ctx) +{ + LOG_DEBUG(__func__); + + return register_commands(cmd_ctx, NULL, swim_transport_command_handlers); +} + +static int swim_transport_init(struct command_context *cmd_ctx) +{ + enum reset_types jtag_reset_config = jtag_get_reset_config(); + + LOG_DEBUG(__func__); + + if (jtag_reset_config & RESET_CNCT_UNDER_SRST) { + if (jtag_reset_config & RESET_SRST_NO_GATING) + adapter_assert_reset(); + else + LOG_WARNING("\'srst_nogate\' reset_config option is required"); + } else + adapter_deassert_reset(); + + return ERROR_OK; +} + +static struct transport swim_transport = { + .name = "swim", + .select = swim_transport_select, + .init = swim_transport_init, +}; + +static void swim_constructor(void) __attribute__ ((constructor)); +static void swim_constructor(void) +{ + transport_register(&swim_transport); +} + +bool transport_is_swim(void) +{ + return get_current_transport() == &swim_transport; } diff --git a/src/transport/transport.h b/src/transport/transport.h index 4effca5d5e..809564e789 100644 --- a/src/transport/transport.h +++ b/src/transport/transport.h @@ -98,6 +98,7 @@ bool transport_is_jtag(void); bool transport_is_swd(void); bool transport_is_dapdirect_jtag(void); bool transport_is_dapdirect_swd(void); +bool transport_is_swim(void); #if BUILD_HLADAPTER bool transport_is_hla(void); diff --git a/tcl/interface/stlink-dap.cfg b/tcl/interface/stlink-dap.cfg index 4576ad388e..ac4de18f9b 100644 --- a/tcl/interface/stlink-dap.cfg +++ b/tcl/interface/stlink-dap.cfg @@ -1,16 +1,19 @@ # -# STMicroelectronics ST-LINK/V2, ST-LINK/V2-1, STLINK-V3 in-circuit +# STMicroelectronics ST-LINK/V1, ST-LINK/V2, ST-LINK/V2-1, STLINK-V3 in-circuit # debugger/programmer # -# This new interface driver creates a ST-Link wrapper for ARM-DAP -# Old ST-LINK/V1 and ST-LINK/V2 pre version V2J24 don't support this method +# This new interface driver creates a ST-Link wrapper for ARM-DAP named "dapdirect" +# Old ST-LINK/V1 and ST-LINK/V2 pre version V2J24 don't support "dapdirect" +# +# SWIM transport is natively supported # adapter driver st-link -st-link vid_pid 0x0483 0x3748 0x0483 0x374b 0x0483 0x374d 0x0483 0x374e 0x0483 0x374f 0x0483 0x3752 0x0483 0x3753 +st-link vid_pid 0x0483 0x3744 0x0483 0x3748 0x0483 0x374b 0x0483 0x374d 0x0483 0x374e 0x0483 0x374f 0x0483 0x3752 0x0483 0x3753 # transport select dapdirect_jtag # transport select dapdirect_swd +# transport select swim # Optionally specify the serial number of usb device # e.g. diff --git a/tcl/target/stm8l.cfg b/tcl/target/stm8l.cfg index f3c94280ae..782350f785 100644 --- a/tcl/target/stm8l.cfg +++ b/tcl/target/stm8l.cfg @@ -4,7 +4,7 @@ # stm8 devices support SWIM transports only. # -transport select stlink_swim +transport select swim if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME @@ -62,7 +62,7 @@ if { [info exists BLOCKSIZE] } { set _BLOCKSIZE 0x80 } -hla newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id 0 +swim newtap $_CHIPNAME cpu set _TARGETNAME $_CHIPNAME.cpu diff --git a/tcl/target/stm8s.cfg b/tcl/target/stm8s.cfg index 5d52aea12b..277cdc9fb2 100644 --- a/tcl/target/stm8s.cfg +++ b/tcl/target/stm8s.cfg @@ -4,7 +4,7 @@ # stm8 devices support SWIM transports only. # -transport select stlink_swim +transport select swim if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME @@ -62,7 +62,7 @@ if { [info exists BLOCKSIZE] } { set _BLOCKSIZE 0x80 } -hla newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id 0 +swim newtap $_CHIPNAME cpu set _TARGETNAME $_CHIPNAME.cpu -- 2.30.2