diff --git a/TODO b/TODO index c73d772e2..ebb6c9980 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 ef77993ec..1ddf09ffa 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 d83f19503..1d424b2e4 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 485a95c6b..4c5081c9e 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 ddacea36a..fbdddfd65 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 07eb751e2..0e0bea25f 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 91291dbd1..a471aa96d 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 965018c27..936268b25 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 4effca5d5..809564e78 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 4576ad388..ac4de18f9 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 f3c94280a..782350f78 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 5d52aea12..277cdc9fb 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