swim: abstract the transport in stm8 target

SWIM is implemented by (ab)using the HLA API. This was acceptable
when OpenOCD code did not provided a clear separation between
transports and related APIs. Still today SWIM in OpenOCD is only
supported by STLink, so the decision to re-use the HLA API was the
simpler way to implement it.
After commit efd1d64222 ("adapter: switch from struct
jtag_interface to adapter_driver") the transports API are better
split and SWIM can be implemented as a separate set of API. This
would open the possibility to extend OpenOCD for other adapters
that provide SWIM, e.g. versaloon, or through SPI emulation [1].

Introduce a new set of files swim.[ch] to handle the SWIM API.
Beside the API that almost match the transport low-level data
communication (system_reset, read_mem, write_mem), add a further
API reconnect. Today, inside HLA STLink code, the reconnect is
implemented by hacking the HLA API state(). Please notice that
due to this hack the return type is incorrect; stlink_usb_state()
returns ERROR_OK in SWIM mode, while its return type is enum
target_state. Ignore the type mismatch and still call the HLA API
state in the new SWIM API reconnect. Further commit will fix it.

[1] http://kuku.eu.org/?projects/stm8spi/stm8spi

Change-Id: I52018e1e2200cbd41af8e5031f7b35dc761b61d6
Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com>
Reviewed-on: http://openocd.zylin.com/5528
Tested-by: jenkins
This commit is contained in:
Antonio Borneo 2020-01-26 17:00:55 +01:00
parent 93c4c0fcbe
commit ac18e960ce
4 changed files with 134 additions and 53 deletions

View File

@ -56,6 +56,7 @@ endif
%D%/interface.c \ %D%/interface.c \
%D%/interfaces.c \ %D%/interfaces.c \
%D%/tcl.c \ %D%/tcl.c \
%D%/swim.c \
%D%/commands.h \ %D%/commands.h \
%D%/driver.h \ %D%/driver.h \
%D%/interface.h \ %D%/interface.h \
@ -65,6 +66,7 @@ endif
%D%/minidriver/minidriver_imp.h \ %D%/minidriver/minidriver_imp.h \
%D%/minidummy/jtag_minidriver.h \ %D%/minidummy/jtag_minidriver.h \
%D%/swd.h \ %D%/swd.h \
%D%/swim.h \
%D%/tcl.h \ %D%/tcl.h \
$(JTAG_SRCS) $(JTAG_SRCS)

51
src/jtag/swim.c Normal file
View File

@ -0,0 +1,51 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Copyright (C) 2020 by Antonio Borneo <borneo.antonio@gmail.com
*
* SWIM (Single Wire Interface Module) is a low-pin-count debug protocol
* used by STMicroelectronics MCU family STM8 and documented in UM470
* https://www.st.com/resource/en/user_manual/cd00173911.pdf
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "interface.h"
#include "swim.h"
#include "jtag/hla/hla_transport.h"
#include "jtag/hla/hla_interface.h"
#include "jtag/hla/hla_layout.h"
extern struct adapter_driver *adapter_driver;
int swim_system_reset(void)
{
assert(adapter_driver->hla_if);
return adapter_driver->hla_if->layout->api->reset(adapter_driver->hla_if->handle);
}
int swim_read_mem(uint32_t addr, uint32_t size, uint32_t count,
uint8_t *buffer)
{
assert(adapter_driver->hla_if);
return adapter_driver->hla_if->layout->api->read_mem(adapter_driver->hla_if->handle, 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);
return adapter_driver->hla_if->layout->api->write_mem(adapter_driver->hla_if->handle, addr, size, count, buffer);
}
int swim_reconnect(void)
{
assert(adapter_driver->hla_if);
return adapter_driver->hla_if->layout->api->state(adapter_driver->hla_if->handle);
}

65
src/jtag/swim.h Normal file
View File

@ -0,0 +1,65 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Copyright (C) 2020 by Antonio Borneo <borneo.antonio@gmail.com
*/
/**
* @file
* This file implements support for STMicroelectronics debug protocol SWIM
* (Single Wire Interface Module).
*/
#ifndef OPENOCD_JTAG_SWIM_H
#define OPENOCD_JTAG_SWIM_H
struct swim_driver {
/**
* Send SRST (system reset) command to target.
*
* @return ERROR_OK on success, else a fault code.
*/
int (*srst)(void);
/**
* Read target memory through ROTF (read on-the-fly) command.
*
* @param addr Start address to read data from target memory.
* @param size Size in bytes of data units, 1, 2 or 4.
* @param count Number of units (size units, not bytes) to read.
* @param buffer Data buffer to receive data.
* @return ERROR_OK on success, else a fault code.
*/
int (*read_mem)(uint32_t addr, uint32_t size, uint32_t count,
uint8_t *buffer);
/**
* Write target memory through WOTF (write on-the-fly) command.
*
* @param addr Start address to write data to target memory.
* @param size Size in bytes of data units, 1, 2 or 4.
* @param count Number of units (size units, not bytes) to write.
* @param buffer Data buffer to write.
* @return ERROR_OK on success, else a fault code.
*/
int (*write_mem)(uint32_t addr, uint32_t size, uint32_t count,
const uint8_t *buffer);
/**
* Reconnect to the target.
* Should be reworked to be more generic and not linked to current
* implementation in stlink driver.
*
* @return ERROR_OK on success, else a fault code.
*/
int (*reconnect)(void);
};
int swim_system_reset(void);
int swim_read_mem(uint32_t addr, uint32_t size, uint32_t count,
uint8_t *buffer);
int swim_write_mem(uint32_t addr, uint32_t size, uint32_t count,
const uint8_t *buffer);
int swim_reconnect(void);
#endif /* OPENOCD_JTAG_SWIM_H */

View File

@ -27,9 +27,7 @@
#include "hello.h" #include "hello.h"
#include "jtag/interface.h" #include "jtag/interface.h"
#include "jtag/jtag.h" #include "jtag/jtag.h"
#include "jtag/hla/hla_transport.h" #include "jtag/swim.h"
#include "jtag/hla/hla_interface.h"
#include "jtag/hla/hla_layout.h"
#include "register.h" #include "register.h"
#include "breakpoints.h" #include "breakpoints.h"
#include "algorithm.h" #include "algorithm.h"
@ -180,68 +178,31 @@ struct stm8_comparator {
enum hw_break_type type; enum hw_break_type type;
}; };
static inline struct hl_interface_s *target_to_adapter(struct target *target)
{
return target->tap->priv;
}
static int stm8_adapter_read_memory(struct target *target, static int stm8_adapter_read_memory(struct target *target,
uint32_t addr, int size, int count, void *buf) uint32_t addr, int size, int count, void *buf)
{ {
int ret; return swim_read_mem(addr, size, count, buf);
struct hl_interface_s *adapter = target_to_adapter(target);
ret = adapter->layout->api->read_mem(adapter->handle,
addr, size, count, buf);
if (ret != ERROR_OK)
return ret;
return ERROR_OK;
} }
static int stm8_adapter_write_memory(struct target *target, static int stm8_adapter_write_memory(struct target *target,
uint32_t addr, int size, int count, const void *buf) uint32_t addr, int size, int count, const void *buf)
{ {
int ret; return swim_write_mem(addr, size, count, buf);
struct hl_interface_s *adapter = target_to_adapter(target);
ret = adapter->layout->api->write_mem(adapter->handle,
addr, size, count, buf);
if (ret != ERROR_OK)
return ret;
return ERROR_OK;
} }
static int stm8_write_u8(struct target *target, static int stm8_write_u8(struct target *target,
uint32_t addr, uint8_t val) uint32_t addr, uint8_t val)
{ {
int ret;
uint8_t buf[1]; uint8_t buf[1];
struct hl_interface_s *adapter = target_to_adapter(target);
buf[0] = val; buf[0] = val;
ret = adapter->layout->api->write_mem(adapter->handle, addr, 1, 1, buf); return swim_write_mem(addr, 1, 1, buf);
if (ret != ERROR_OK)
return ret;
return ERROR_OK;
} }
static int stm8_read_u8(struct target *target, static int stm8_read_u8(struct target *target,
uint32_t addr, uint8_t *val) uint32_t addr, uint8_t *val)
{ {
int ret; return swim_read_mem(addr, 1, 1, val);
struct hl_interface_s *adapter = target_to_adapter(target);
ret = adapter->layout->api->read_mem(adapter->handle, addr, 1, 1, val);
if (ret != ERROR_OK)
return ret;
return ERROR_OK;
}
static int stm8_set_speed(struct target *target, int speed)
{
struct hl_interface_s *adapter = target_to_adapter(target);
adapter->layout->api->speed(adapter->handle, speed, 0);
return ERROR_OK;
} }
/* /*
@ -924,7 +885,6 @@ static int stm8_halt(struct target *target)
static int stm8_reset_assert(struct target *target) static int stm8_reset_assert(struct target *target)
{ {
int res = ERROR_OK; int res = ERROR_OK;
struct hl_interface_s *adapter = target_to_adapter(target);
struct stm8_common *stm8 = target_to_stm8(target); struct stm8_common *stm8 = target_to_stm8(target);
bool use_srst_fallback = true; bool use_srst_fallback = true;
@ -942,7 +902,7 @@ static int stm8_reset_assert(struct target *target)
if (use_srst_fallback) { if (use_srst_fallback) {
LOG_DEBUG("Hardware srst not supported, falling back to swim reset"); LOG_DEBUG("Hardware srst not supported, falling back to swim reset");
res = adapter->layout->api->reset(adapter->handle); res = swim_system_reset();
if (res != ERROR_OK) if (res != ERROR_OK)
return res; return res;
} }
@ -1696,7 +1656,7 @@ static int stm8_examine(struct target *target)
uint8_t csr1, csr2; uint8_t csr1, csr2;
/* get pointers to arch-specific information */ /* get pointers to arch-specific information */
struct stm8_common *stm8 = target_to_stm8(target); struct stm8_common *stm8 = target_to_stm8(target);
struct hl_interface_s *adapter = target_to_adapter(target); enum reset_types jtag_reset_config = jtag_get_reset_config();
if (!target_was_examined(target)) { if (!target_was_examined(target)) {
if (!stm8->swim_configured) { if (!stm8->swim_configured) {
@ -1710,20 +1670,23 @@ static int stm8_examine(struct target *target)
retval = stm8_write_u8(target, SWIM_CSR, SAFE_MASK + SWIM_DM + HS); retval = stm8_write_u8(target, SWIM_CSR, SAFE_MASK + SWIM_DM + HS);
if (retval != ERROR_OK) if (retval != ERROR_OK)
return retval; return retval;
retval = stm8_set_speed(target, 1); jtag_config_khz(1);
if (retval == ERROR_OK) stm8->swim_configured = true;
stm8->swim_configured = true;
/* /*
Now is the time to deassert reset if connect_under_reset. Now is the time to deassert reset if connect_under_reset.
Releasing reset line will cause the option bytes to load. Releasing reset line will cause the option bytes to load.
The core will still be stalled. The core will still be stalled.
*/ */
if (adapter->param.connect_under_reset) if (jtag_reset_config & RESET_CNCT_UNDER_SRST) {
stm8_reset_deassert(target); if (jtag_reset_config & RESET_SRST_NO_GATING)
stm8_reset_deassert(target);
else
LOG_WARNING("\'srst_nogate\' reset_config option is required");
}
} else { } else {
LOG_INFO("trying to reconnect"); LOG_INFO("trying to reconnect");
retval = adapter->layout->api->state(adapter->handle); retval = swim_reconnect();
if (retval != ERROR_OK) { if (retval != ERROR_OK) {
LOG_ERROR("reconnect failed"); LOG_ERROR("reconnect failed");
return ERROR_FAIL; return ERROR_FAIL;