+// SPDX-License-Identifier: GPL-2.0-or-later
+
/*
- OpenOCD STM8 target driver
- Copyright (C) 2017 Ake Rehnman
- ake.rehnman(at)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 3 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.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>.
+* OpenOCD STM8 target driver
+* Copyright (C) 2017 Ake Rehnman
+* ake.rehnman(at)gmail.com
*/
#ifdef HAVE_CONFIG_H
#include "target.h"
#include "target_type.h"
#include "hello.h"
+#include "jtag/interface.h"
#include "jtag/jtag.h"
-#include "jtag/hla/hla_transport.h"
-#include "jtag/hla/hla_interface.h"
-#include "jtag/hla/hla_layout.h"
+#include "jtag/swim.h"
#include "register.h"
#include "breakpoints.h"
#include "algorithm.h"
static void stm8_enable_watchpoints(struct target *target);
static int stm8_unset_watchpoint(struct target *target,
struct watchpoint *watchpoint);
+static int (*adapter_speed)(int speed);
+extern struct adapter_driver *adapter_driver;
static const struct {
unsigned id;
struct stm8_core_reg {
uint32_t num;
struct target *target;
- struct stm8_common *stm8_common;
};
enum hw_break_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,
uint32_t addr, int size, int count, void *buf)
{
- int ret;
- 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;
+ return swim_read_mem(addr, size, count, buf);
}
static int stm8_adapter_write_memory(struct target *target,
uint32_t addr, int size, int count, const void *buf)
{
- int ret;
- 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;
+ return swim_write_mem(addr, size, count, buf);
}
static int stm8_write_u8(struct target *target,
uint32_t addr, uint8_t val)
{
- int ret;
uint8_t buf[1];
- struct hl_interface_s *adapter = target_to_adapter(target);
buf[0] = val;
- ret = adapter->layout->api->write_mem(adapter->handle, addr, 1, 1, buf);
- if (ret != ERROR_OK)
- return ret;
- return ERROR_OK;
+ return swim_write_mem(addr, 1, 1, buf);
}
static int stm8_read_u8(struct target *target,
uint32_t addr, uint8_t *val)
{
- int ret;
- 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;
+ return swim_read_mem(addr, 1, 1, val);
}
/*
if ((comparator_list[0].type != HWBRK_EXEC)
&& (comparator_list[1].type != HWBRK_EXEC)) {
- if ((comparator_list[0].type != comparator_list[1].type)) {
+ if (comparator_list[0].type != comparator_list[1].type) {
LOG_ERROR("data hw breakpoints must be of same type");
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
}
return retval;
}
+static int stm8_speed(int speed)
+{
+ int retval;
+ uint8_t csr;
+
+ LOG_DEBUG("stm8_speed: %d", speed);
+
+ csr = SAFE_MASK | SWIM_DM;
+ if (speed >= SWIM_FREQ_HIGH)
+ csr |= HS;
+
+ LOG_DEBUG("writing B0 to SWIM_CSR (SAFE_MASK + SWIM_DM + HS:%d)", csr & HS ? 1 : 0);
+ retval = stm8_write_u8(NULL, SWIM_CSR, csr);
+ if (retval != ERROR_OK)
+ return retval;
+ return adapter_speed(speed);
+}
+
static int stm8_init(struct command_context *cmd_ctx, struct target *target)
{
+ /*
+ * FIXME: this is a temporarily hack that needs better implementation.
+ * Being the only overwrite of adapter_driver, it prevents declaring const
+ * the struct adapter_driver.
+ * intercept adapter_driver->speed() calls
+ */
+ adapter_speed = adapter_driver->speed;
+ adapter_driver->speed = stm8_speed;
+
stm8_build_reg_cache(target);
return ERROR_OK;
static int stm8_reset_assert(struct target *target)
{
int res = ERROR_OK;
- struct hl_interface_s *adapter = target_to_adapter(target);
struct stm8_common *stm8 = target_to_stm8(target);
bool use_srst_fallback = true;
enum reset_types jtag_reset_config = jtag_get_reset_config();
if (jtag_reset_config & RESET_HAS_SRST) {
- jtag_add_reset(0, 1);
- res = adapter->layout->api->assert_srst(adapter->handle, 0);
-
+ res = adapter_assert_reset();
if (res == ERROR_OK)
/* hardware srst supported */
use_srst_fallback = false;
if (use_srst_fallback) {
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)
return res;
}
static int stm8_reset_deassert(struct target *target)
{
int res;
- struct hl_interface_s *adapter = target_to_adapter(target);
-
enum reset_types jtag_reset_config = jtag_get_reset_config();
if (jtag_reset_config & RESET_HAS_SRST) {
- res = adapter->layout->api->assert_srst(adapter->handle, 1);
+ res = adapter_deassert_reset();
if ((res != ERROR_OK) && (res != ERROR_COMMAND_NOTFOUND))
return res;
}
- /* virtual deassert reset, we need it for the internal
- * jtag state machine
- */
- jtag_add_reset(0, 0);
-
/* The cpu should now be stalled. If halt was requested
let poll detect the stall */
if (target->reset_halt)
return ERROR_OK;
- /* Instead of going thrugh saving context, polling and
+ /* Instead of going through saving context, polling and
then resuming target again just clear stall and proceed. */
target->state = TARGET_RUNNING;
return stm8_exit_debug(target);
return ERROR_COMMAND_SYNTAX_ERROR;
reg_value = stm8->core_regs[num];
- LOG_DEBUG("read core reg %i value 0x%" PRIx32 "", num , reg_value);
+ LOG_DEBUG("read core reg %i value 0x%" PRIx32 "", num, reg_value);
buf_set_u32(stm8->core_cache->reg_list[num].value, 0, 32, reg_value);
stm8->core_cache->reg_list[num].valid = true;
stm8->core_cache->reg_list[num].dirty = false;
reg_value = buf_get_u32(stm8->core_cache->reg_list[num].value, 0, 32);
stm8->core_regs[num] = reg_value;
- LOG_DEBUG("write core reg %i value 0x%" PRIx32 "", num , reg_value);
+ LOG_DEBUG("write core reg %i value 0x%" PRIx32 "", num, reg_value);
stm8->core_cache->reg_list[num].valid = true;
stm8->core_cache->reg_list[num].dirty = false;
for (i = 0; i < num_regs; i++) {
arch_info[i].num = stm8_regs[i].id;
arch_info[i].target = target;
- arch_info[i].stm8_common = stm8;
reg_list[i].name = stm8_regs[i].name;
reg_list[i].size = stm8_regs[i].bits;
static int stm8_step(struct target *target, int current,
target_addr_t address, int handle_breakpoints)
{
- LOG_DEBUG("%" PRIx32 " " TARGET_ADDR_FMT " %" PRIx32,
+ LOG_DEBUG("%x " TARGET_ADDR_FMT " %x",
current, address, handle_breakpoints);
/* get pointers to arch-specific information */
/* set any pending breakpoints */
while (breakpoint) {
- if (breakpoint->set == 0)
+ if (!breakpoint->is_set)
stm8_set_breakpoint(target, breakpoint);
breakpoint = breakpoint->next;
}
struct stm8_comparator *comparator_list = stm8->hw_break_list;
int retval;
- if (breakpoint->set) {
+ if (breakpoint->is_set) {
LOG_WARNING("breakpoint already set");
return ERROR_OK;
}
breakpoint->unique_id);
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
}
- breakpoint->set = bp_num + 1;
+ breakpoint_hw_set(breakpoint, bp_num);
comparator_list[bp_num].used = true;
comparator_list[bp_num].bp_value = breakpoint->address;
comparator_list[bp_num].type = HWBRK_EXEC;
} else {
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
}
- breakpoint->set = 1; /* Any nice value but 0 */
+ breakpoint->is_set = true;
}
return ERROR_OK;
struct stm8_comparator *comparator_list = stm8->hw_break_list;
int retval;
- if (!breakpoint->set) {
+ if (!breakpoint->is_set) {
LOG_WARNING("breakpoint not set");
return ERROR_OK;
}
if (breakpoint->type == BKPT_HARD) {
- int bp_num = breakpoint->set - 1;
- if ((bp_num < 0) || (bp_num >= stm8->num_hw_bpoints)) {
+ int bp_num = breakpoint->number;
+ if (bp_num >= stm8->num_hw_bpoints) {
LOG_DEBUG("Invalid comparator number in breakpoint (bpid: %" PRIu32 ")",
breakpoint->unique_id);
return ERROR_OK;
} else
return ERROR_FAIL;
}
- breakpoint->set = 0;
+ breakpoint->is_set = false;
return ERROR_OK;
}
return ERROR_TARGET_NOT_HALTED;
}
- if (breakpoint->set)
+ if (breakpoint->is_set)
stm8_unset_breakpoint(target, breakpoint);
if (breakpoint->type == BKPT_HARD)
int wp_num = 0;
int ret;
- if (watchpoint->set) {
+ if (watchpoint->is_set) {
LOG_WARNING("watchpoint already set");
return ERROR_OK;
}
return ret;
}
- watchpoint->set = wp_num + 1;
+ watchpoint_set(watchpoint, wp_num);
LOG_DEBUG("wp_num %i bp_value 0x%" PRIx32 "",
wp_num,
/* set any pending watchpoints */
while (watchpoint) {
- if (watchpoint->set == 0)
+ if (!watchpoint->is_set)
stm8_set_watchpoint(target, watchpoint);
watchpoint = watchpoint->next;
}
struct stm8_common *stm8 = target_to_stm8(target);
struct stm8_comparator *comparator_list = stm8->hw_break_list;
- if (!watchpoint->set) {
+ if (!watchpoint->is_set) {
LOG_WARNING("watchpoint not set");
return ERROR_OK;
}
- int wp_num = watchpoint->set - 1;
- if ((wp_num < 0) || (wp_num >= stm8->num_hw_bpoints)) {
+ int wp_num = watchpoint->number;
+ if (wp_num >= stm8->num_hw_bpoints) {
LOG_DEBUG("Invalid hw comparator number in watchpoint");
return ERROR_OK;
}
comparator_list[wp_num].used = false;
- watchpoint->set = 0;
+ watchpoint->is_set = false;
stm8_set_hwbreak(target, comparator_list);
return ERROR_TARGET_NOT_HALTED;
}
- if (watchpoint->set)
+ if (watchpoint->is_set)
stm8_unset_watchpoint(target, watchpoint);
stm8->num_hw_bpoints_avail++;
uint8_t csr1, csr2;
/* get pointers to arch-specific information */
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 (!stm8->swim_configured) {
- /* set SWIM_CSR = 0xa0 (enable mem access & mask reset) */
- LOG_DEBUG("writing A0 to SWIM_CSR (SAFE_MASK + SWIM_DM)");
- retval = stm8_write_u8(target, SWIM_CSR, SAFE_MASK + SWIM_DM);
- if (retval != ERROR_OK)
- return retval;
- /* set high speed */
- LOG_DEBUG("writing B0 to SWIM_CSR (SAFE_MASK + SWIM_DM + HS)");
- retval = stm8_write_u8(target, SWIM_CSR, SAFE_MASK + SWIM_DM + HS);
- if (retval != ERROR_OK)
- return retval;
- retval = stm8_set_speed(target, 1);
- if (retval == ERROR_OK)
- stm8->swim_configured = true;
+ stm8->swim_configured = true;
/*
Now is the time to deassert reset if connect_under_reset.
Releasing reset line will cause the option bytes to load.
The core will still be stalled.
*/
- if (adapter->param.connect_under_reset)
- stm8_reset_deassert(target);
+ if (jtag_reset_config & RESET_CNCT_UNDER_SRST) {
+ if (jtag_reset_config & RESET_SRST_NO_GATING)
+ stm8_reset_deassert(target);
+ else
+ LOG_WARNING("\'srst_nogate\' reset_config option is required");
+ }
} else {
LOG_INFO("trying to reconnect");
- retval = adapter->layout->api->state(adapter->handle);
+ retval = swim_reconnect();
if (retval != ERROR_OK) {
LOG_ERROR("reconnect failed");
return ERROR_FAIL;
continue;
struct reg *reg = register_get_by_name(stm8->core_cache,
- reg_params[i].reg_name, 0);
+ reg_params[i].reg_name, false);
if (!reg) {
LOG_ERROR("BUG: register '%s' not found", reg_params[i].reg_name);
for (int i = 0; i < num_reg_params; i++) {
if (reg_params[i].direction != PARAM_OUT) {
struct reg *reg = register_get_by_name(stm8->core_cache,
- reg_params[i].reg_name, 0);
+ reg_params[i].reg_name, false);
if (!reg) {
LOG_ERROR("BUG: register '%s' not found",
reg_params[i].reg_name);
return ERROR_OK;
}
-int stm8_jim_configure(struct target *target, Jim_GetOptInfo *goi)
+static int stm8_jim_configure(struct target *target, struct jim_getopt_info *goi)
{
struct stm8_common *stm8 = target_to_stm8(target);
jim_wide w;
arg = Jim_GetString(goi->argv[0], NULL);
if (!strcmp(arg, "-blocksize")) {
- e = Jim_GetOpt_String(goi, &arg, NULL);
+ e = jim_getopt_string(goi, &arg, NULL);
if (e != JIM_OK)
return e;
return JIM_ERR;
}
- e = Jim_GetOpt_Wide(goi, &w);
+ e = jim_getopt_wide(goi, &w);
if (e != JIM_OK)
return e;
stm8->blocksize = w;
- LOG_DEBUG("blocksize=%8.8x", stm8->blocksize);
+ LOG_DEBUG("blocksize=%8.8" PRIx32, stm8->blocksize);
return JIM_OK;
}
if (!strcmp(arg, "-flashstart")) {
- e = Jim_GetOpt_String(goi, &arg, NULL);
+ e = jim_getopt_string(goi, &arg, NULL);
if (e != JIM_OK)
return e;
return JIM_ERR;
}
- e = Jim_GetOpt_Wide(goi, &w);
+ e = jim_getopt_wide(goi, &w);
if (e != JIM_OK)
return e;
stm8->flashstart = w;
- LOG_DEBUG("flashstart=%8.8x", stm8->flashstart);
+ LOG_DEBUG("flashstart=%8.8" PRIx32, stm8->flashstart);
return JIM_OK;
}
if (!strcmp(arg, "-flashend")) {
- e = Jim_GetOpt_String(goi, &arg, NULL);
+ e = jim_getopt_string(goi, &arg, NULL);
if (e != JIM_OK)
return e;
return JIM_ERR;
}
- e = Jim_GetOpt_Wide(goi, &w);
+ e = jim_getopt_wide(goi, &w);
if (e != JIM_OK)
return e;
stm8->flashend = w;
- LOG_DEBUG("flashend=%8.8x", stm8->flashend);
+ LOG_DEBUG("flashend=%8.8" PRIx32, stm8->flashend);
return JIM_OK;
}
if (!strcmp(arg, "-eepromstart")) {
- e = Jim_GetOpt_String(goi, &arg, NULL);
+ e = jim_getopt_string(goi, &arg, NULL);
if (e != JIM_OK)
return e;
return JIM_ERR;
}
- e = Jim_GetOpt_Wide(goi, &w);
+ e = jim_getopt_wide(goi, &w);
if (e != JIM_OK)
return e;
stm8->eepromstart = w;
- LOG_DEBUG("eepromstart=%8.8x", stm8->eepromstart);
+ LOG_DEBUG("eepromstart=%8.8" PRIx32, stm8->eepromstart);
return JIM_OK;
}
if (!strcmp(arg, "-eepromend")) {
- e = Jim_GetOpt_String(goi, &arg, NULL);
+ e = jim_getopt_string(goi, &arg, NULL);
if (e != JIM_OK)
return e;
return JIM_ERR;
}
- e = Jim_GetOpt_Wide(goi, &w);
+ e = jim_getopt_wide(goi, &w);
if (e != JIM_OK)
return e;
stm8->eepromend = w;
- LOG_DEBUG("eepromend=%8.8x", stm8->eepromend);
+ LOG_DEBUG("eepromend=%8.8" PRIx32, stm8->eepromend);
return JIM_OK;
}
if (!strcmp(arg, "-optionstart")) {
- e = Jim_GetOpt_String(goi, &arg, NULL);
+ e = jim_getopt_string(goi, &arg, NULL);
if (e != JIM_OK)
return e;
return JIM_ERR;
}
- e = Jim_GetOpt_Wide(goi, &w);
+ e = jim_getopt_wide(goi, &w);
if (e != JIM_OK)
return e;
stm8->optionstart = w;
- LOG_DEBUG("optionstart=%8.8x", stm8->optionstart);
+ LOG_DEBUG("optionstart=%8.8" PRIx32, stm8->optionstart);
return JIM_OK;
}
if (!strcmp(arg, "-optionend")) {
- e = Jim_GetOpt_String(goi, &arg, NULL);
+ e = jim_getopt_string(goi, &arg, NULL);
if (e != JIM_OK)
return e;
return JIM_ERR;
}
- e = Jim_GetOpt_Wide(goi, &w);
+ e = jim_getopt_wide(goi, &w);
if (e != JIM_OK)
return e;
stm8->optionend = w;
- LOG_DEBUG("optionend=%8.8x", stm8->optionend);
+ LOG_DEBUG("optionend=%8.8" PRIx32, stm8->optionend);
return JIM_OK;
}
if (!strcmp(arg, "-enable_step_irq")) {
- e = Jim_GetOpt_String(goi, &arg, NULL);
+ e = jim_getopt_string(goi, &arg, NULL);
if (e != JIM_OK)
return e;
return JIM_OK;
}
if (!strcmp(arg, "-enable_stm8l")) {
- e = Jim_GetOpt_String(goi, &arg, NULL);
+ e = jim_getopt_string(goi, &arg, NULL);
if (e != JIM_OK)
return e;
COMMAND_REGISTRATION_DONE
};
-const struct command_registration stm8_command_handlers[] = {
+static const struct command_registration stm8_command_handlers[] = {
{
.name = "stm8",
.mode = COMMAND_ANY,