From 8d1dcf293a0cee71b264787c65749de3f6c4d8bc Mon Sep 17 00:00:00 2001 From: Erhan Kurubas Date: Thu, 25 Aug 2022 15:38:34 +0300 Subject: [PATCH 01/49] target/espressif: add application tracing functionality over JTAG This feature allows to transfer arbitrary data between host and ESP32 via JTAG. The main use cases: 1- Collecting application specific data 2- Lightweight logging to the host 3- System behaviour analysis with SEGGER SystemView 4- Source code coverage Signed-off-by: Erhan Kurubas Change-Id: I95dee00ac22891fa326915a3fcac3c088cbb2afc Reviewed-on: https://review.openocd.org/c/openocd/+/7163 Tested-by: jenkins Reviewed-by: Antonio Borneo --- doc/openocd.texi | 40 + src/target/espressif/Makefile.am | 4 + src/target/espressif/esp32.c | 5 + src/target/espressif/esp32_apptrace.c | 1376 ++++++++++++++++++++ src/target/espressif/esp32_apptrace.h | 126 ++ src/target/espressif/esp32s2.c | 5 + src/target/espressif/esp32s3.c | 5 + src/target/espressif/esp_xtensa.c | 2 + src/target/espressif/esp_xtensa.h | 2 + src/target/espressif/esp_xtensa_apptrace.c | 497 +++++++ src/target/espressif/esp_xtensa_apptrace.h | 37 + 11 files changed, 2099 insertions(+) create mode 100644 src/target/espressif/esp32_apptrace.c create mode 100644 src/target/espressif/esp32_apptrace.h create mode 100644 src/target/espressif/esp_xtensa_apptrace.c create mode 100644 src/target/espressif/esp_xtensa_apptrace.h diff --git a/doc/openocd.texi b/doc/openocd.texi index fe72cf5fa..4154e56b5 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -11137,6 +11137,46 @@ Stop current trace as started by the tracestart command. Dump trace memory to a file. @end deffn +@section Espressif Specific Commands + +@deffn {Command} {esp apptrace} (start [ [ [ [ []]]]]) +Starts +@uref{https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/app_trace.html#application-level-tracing-library, application level tracing}. +Data will be stored to specified destination. Available destinations are: +@itemize @bullet +@item @code{file://} - Save trace logs into file. +@item @code{tcp://:} - Send trace logs to tcp port on specified host. OpenOCD will act as a tcp client. +@item @code{con:} - Print trace logs to the stdout. +@end itemize +Other parameters will be same for each destination. +@itemize @bullet +@item @code{poll_period} - trace data polling period in ms. +@item @code{trace_size} - maximum trace data size. +Tracing will be stopped automatically when that amount is reached. +Use "-1" to disable the limitation. +@item @code{stop_tmo} - Data reception timeout in ms. +Tracing will be stopped automatically when no data is received within that period. +@item @code{wait4halt} - if non-zero then wait for target to be halted before tracing start. +@item @code{skip_size} - amount of tracing data to be skipped before writing it to destination. +@end itemize +@end deffn + +@deffn {Command} {esp apptrace} (stop) +Stops tracing started with above command. +@end deffn + +@deffn {Command} {esp apptrace} (status) +Requests ongoing tracing status. +@end deffn + +@deffn {Command} {esp apptrace} (dump file://) +Dumps tracing data from target buffer. It can be useful to dump the latest data +buffered on target for post-mortem analysis. For example when target starts tracing automatically +w/o OpenOCD command and keeps only the latest data window which fit into the buffer. +@uref{https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/app_trace.html#application-level-tracing-library, application level tracing}. +Data will be stored to specified destination. +@end deffn + @anchor{softwaredebugmessagesandtracing} @section Software Debug Messages and Tracing @cindex Linux-ARM DCC support diff --git a/src/target/espressif/Makefile.am b/src/target/espressif/Makefile.am index 8367a3881..c1759ed77 100644 --- a/src/target/espressif/Makefile.am +++ b/src/target/espressif/Makefile.am @@ -8,6 +8,10 @@ noinst_LTLIBRARIES += %D%/libespressif.la %D%/esp_xtensa_smp.h \ %D%/esp_xtensa_semihosting.c \ %D%/esp_xtensa_semihosting.h \ + %D%/esp_xtensa_apptrace.c \ + %D%/esp_xtensa_apptrace.h \ + %D%/esp32_apptrace.c \ + %D%/esp32_apptrace.h \ %D%/esp32.c \ %D%/esp32s2.c \ %D%/esp32s3.c \ diff --git a/src/target/espressif/esp32.c b/src/target/espressif/esp32.c index 63055cf18..74bbe50bd 100644 --- a/src/target/espressif/esp32.c +++ b/src/target/espressif/esp32.c @@ -440,6 +440,11 @@ static const struct command_registration esp32_command_handlers[] = { { .chain = esp_xtensa_smp_command_handlers, }, + { + .name = "esp", + .usage = "", + .chain = esp32_apptrace_command_handlers, + }, { .name = "esp32", .usage = "", diff --git a/src/target/espressif/esp32_apptrace.c b/src/target/espressif/esp32_apptrace.c new file mode 100644 index 000000000..dfeb79401 --- /dev/null +++ b/src/target/espressif/esp32_apptrace.c @@ -0,0 +1,1376 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/*************************************************************************** + * ESP32xx application tracing module for OpenOCD * + * Copyright (C) 2017 Espressif Systems Ltd. * + ***************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef HAVE_ARPA_INET_H +#include +#endif + +#ifdef HAVE_NETDB_H +#include +#endif + +#ifndef _WIN32 +#include +#include +#endif + +#include +#include +#include +#include +#include +#include +#include "esp_xtensa.h" +#include "esp_xtensa_smp.h" +#include "esp_xtensa_apptrace.h" +#include "esp32_apptrace.h" + +#define ESP32_APPTRACE_USER_BLOCK_CORE(_v_) ((_v_) >> 15) +#define ESP32_APPTRACE_USER_BLOCK_LEN(_v_) ((_v_) & ~BIT(15)) + +#define ESP32_APPTRACE_USER_BLOCK_HDR_SZ 4 + +#define ESP_APPTRACE_CMD_MODE_GEN 0 +#define ESP_APPTRACE_CMD_MODE_SYSVIEW 1 +#define ESP_APPTRACE_CMD_MODE_SYSVIEW_MCORE 2 +#define ESP_APPTRACE_CMD_MODE_SYNC 3 + +#define ESP32_APPTRACE_TGT_STATE_TMO 5000 +#define ESP_APPTRACE_BLOCKS_POOL_SZ 10 + +struct esp32_apptrace_dest_file_data { + int fout; +}; + +struct esp32_apptrace_dest_tcp_data { + int sockfd; +}; + +struct esp32_apptrace_target_state { + int running; + uint32_t block_id; + uint32_t data_len; +}; + +struct esp_apptrace_target2host_hdr { + uint16_t block_sz; + uint16_t wr_sz; +}; +#define APPTRACE_BLOCK_SIZE_OFFSET 0 +#define APPTRACE_WR_SIZE_OFFSET 2 + +struct esp32_apptrace_block { + struct list_head node; + uint8_t *data; + uint32_t data_len; +}; + +static int esp32_apptrace_data_processor(void *priv); +static int esp32_apptrace_get_data_info(struct esp32_apptrace_cmd_ctx *ctx, + struct esp32_apptrace_target_state *target_state, + uint32_t *fired_target_num); +static int esp32_apptrace_safe_halt_targets(struct esp32_apptrace_cmd_ctx *ctx, + struct esp32_apptrace_target_state *targets); +static struct esp32_apptrace_block *esp32_apptrace_free_block_get(struct esp32_apptrace_cmd_ctx *ctx); +static int esp32_apptrace_handle_trace_block(struct esp32_apptrace_cmd_ctx *ctx, + struct esp32_apptrace_block *block); + +static const bool s_time_stats_enable = true; + +/********************************************************************* +* Trace destination API +**********************************************************************/ + +static int esp32_apptrace_file_dest_write(void *priv, uint8_t *data, int size) +{ + struct esp32_apptrace_dest_file_data *dest_data = (struct esp32_apptrace_dest_file_data *)priv; + + int wr_sz = write(dest_data->fout, data, size); + if (wr_sz != size) { + LOG_ERROR("Failed to write %d bytes to out file (%d)! Written %d.", size, errno, wr_sz); + return ERROR_FAIL; + } + return ERROR_OK; +} + +static int esp32_apptrace_file_dest_cleanup(void *priv) +{ + struct esp32_apptrace_dest_file_data *dest_data = (struct esp32_apptrace_dest_file_data *)priv; + + if (dest_data->fout > 0) + close(dest_data->fout); + free(dest_data); + return ERROR_OK; +} + +static int esp32_apptrace_file_dest_init(struct esp32_apptrace_dest *dest, const char *dest_name) +{ + struct esp32_apptrace_dest_file_data *dest_data = calloc(1, sizeof(*dest_data)); + if (!dest_data) { + LOG_ERROR("Failed to alloc mem for file dest!"); + return ERROR_FAIL; + } + + LOG_INFO("Open file %s", dest_name); + dest_data->fout = open(dest_name, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0666); + if (dest_data->fout <= 0) { + LOG_ERROR("Failed to open file %s", dest_name); + free(dest_data); + return ERROR_FAIL; + } + + dest->priv = dest_data; + dest->write = esp32_apptrace_file_dest_write; + dest->clean = esp32_apptrace_file_dest_cleanup; + dest->log_progress = true; + + return ERROR_OK; +} + +static int esp32_apptrace_console_dest_write(void *priv, uint8_t *data, int size) +{ + LOG_USER_N("%.*s", size, data); + return ERROR_OK; +} + +static int esp32_apptrace_console_dest_cleanup(void *priv) +{ + return ERROR_OK; +} + +static int esp32_apptrace_console_dest_init(struct esp32_apptrace_dest *dest, const char *dest_name) +{ + dest->priv = NULL; + dest->write = esp32_apptrace_console_dest_write; + dest->clean = esp32_apptrace_console_dest_cleanup; + dest->log_progress = false; + + return ERROR_OK; +} + +static int esp32_apptrace_tcp_dest_write(void *priv, uint8_t *data, int size) +{ + struct esp32_apptrace_dest_tcp_data *dest_data = (struct esp32_apptrace_dest_tcp_data *)priv; + int wr_sz = write_socket(dest_data->sockfd, data, size); + if (wr_sz != size) { + LOG_ERROR("Failed to write %u bytes to out socket (%d)! Written %d.", size, errno, wr_sz); + return ERROR_FAIL; + } + return ERROR_OK; +} + +static int esp32_apptrace_tcp_dest_cleanup(void *priv) +{ + struct esp32_apptrace_dest_tcp_data *dest_data = (struct esp32_apptrace_dest_tcp_data *)priv; + + if (dest_data->sockfd > 0) + close_socket(dest_data->sockfd); + free(dest_data); + return ERROR_OK; +} + +static int esp32_apptrace_tcp_dest_init(struct esp32_apptrace_dest *dest, const char *dest_name) +{ + const char *port_sep = strchr(dest_name, ':'); + /* separator not found, or was the first or the last character */ + if (!port_sep || port_sep == dest_name || port_sep == dest_name + strlen(dest_name) - 1) { + LOG_ERROR("apptrace: Invalid connection URI, format should be tcp://host:port"); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + size_t hostname_len = port_sep - dest_name; + + char hostname[64] = { 0 }; + if (hostname_len >= sizeof(hostname)) { + LOG_ERROR("apptrace: Hostname too long"); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + memcpy(hostname, dest_name, hostname_len); + + const char *port_str = port_sep + 1; + struct addrinfo *ai; + int flags = 0; +#ifdef AI_NUMERICSERV + flags |= AI_NUMERICSERV; +#endif /* AI_NUMERICSERV */ + struct addrinfo hint = { + .ai_family = AF_UNSPEC, + .ai_socktype = SOCK_STREAM, + .ai_protocol = 0, + .ai_flags = flags + }; + int res = getaddrinfo(hostname, port_str, &hint, &ai); + if (res != 0) { + LOG_ERROR("apptrace: Failed to resolve host name: %s", hostname); + return ERROR_FAIL; + } + int sockfd = -1; + for (struct addrinfo *ai_it = ai; ai_it; ai_it = ai_it->ai_next) { + sockfd = socket(ai_it->ai_family, ai_it->ai_socktype, ai_it->ai_protocol); + if (sockfd < 0) { + LOG_DEBUG("apptrace: Failed to create socket (%d, %d, %d) (%s)", + ai_it->ai_family, + ai_it->ai_socktype, + ai_it->ai_protocol, + strerror(errno)); + continue; + } + + char cur_hostname[NI_MAXHOST]; + char cur_portname[NI_MAXSERV]; + res = + getnameinfo(ai_it->ai_addr, ai_it->ai_addrlen, cur_hostname, + sizeof(cur_hostname), + cur_portname, sizeof(cur_portname), + NI_NUMERICHOST | NI_NUMERICSERV); + if (res != 0) + continue; + + LOG_INFO("apptrace: Trying to connect to %s:%s", cur_hostname, cur_portname); + if (connect(sockfd, ai_it->ai_addr, ai_it->ai_addrlen) < 0) { + close_socket(sockfd); + sockfd = -1; + LOG_WARNING("apptrace: Connection failed (%s)", strerror(errno)); + continue; + } + break; + } + freeaddrinfo(ai); + if (sockfd < 0) { + LOG_ERROR("apptrace: Could not connect to %s:%s", hostname, port_str); + return ERROR_FAIL; + } + LOG_INFO("apptrace: Connected!"); + + struct esp32_apptrace_dest_tcp_data *dest_data = calloc(1, sizeof(struct esp32_apptrace_dest_tcp_data)); + if (!dest_data) { + LOG_ERROR("apptrace: Failed to alloc mem for tcp dest!"); + close_socket(sockfd); + return ERROR_FAIL; + } + + dest_data->sockfd = sockfd; + dest->priv = dest_data; + dest->write = esp32_apptrace_tcp_dest_write; + dest->clean = esp32_apptrace_tcp_dest_cleanup; + dest->log_progress = true; + + return ERROR_OK; +} + +int esp32_apptrace_dest_init(struct esp32_apptrace_dest dest[], const char *dest_paths[], unsigned int max_dests) +{ + int res; + unsigned int i; + + for (i = 0; i < max_dests; i++) { + if (strncmp(dest_paths[i], "file://", 7) == 0) + res = esp32_apptrace_file_dest_init(&dest[i], &dest_paths[i][7]); + else if (strncmp(dest_paths[i], "con:", 4) == 0) + res = esp32_apptrace_console_dest_init(&dest[i], NULL); + else if (strncmp(dest_paths[i], "tcp://", 6) == 0) + res = esp32_apptrace_tcp_dest_init(&dest[i], &dest_paths[i][6]); + else + break; + + if (res != ERROR_OK) { + LOG_ERROR("apptrace: Failed to init trace data destination '%s'!", dest_paths[i]); + return 0; + } + } + + return i; +} + +int esp32_apptrace_dest_cleanup(struct esp32_apptrace_dest dest[], unsigned int max_dests) +{ + for (unsigned int i = 0; i < max_dests; i++) { + if (dest[i].clean && dest[i].priv) { + int res = dest[i].clean(dest[i].priv); + dest[i].priv = NULL; + return res; + } + } + return ERROR_OK; +} + +/********************************************************************* +* Trace data blocks management API +**********************************************************************/ +static void esp32_apptrace_blocks_pool_cleanup(struct esp32_apptrace_cmd_ctx *ctx) +{ + struct esp32_apptrace_block *cur; + struct list_head *head = &ctx->free_trace_blocks; + struct list_head *tmp, *pos; + + list_for_each_safe(pos, tmp, head) { + cur = list_entry(pos, struct esp32_apptrace_block, node); + if (cur) { + list_del(&cur->node); + free(cur->data); + free(cur); + } + } + + head = &ctx->ready_trace_blocks; + + list_for_each_safe(pos, tmp, head) { + cur = list_entry(pos, struct esp32_apptrace_block, node); + if (cur) { + list_del(&cur->node); + free(cur->data); + free(cur); + } + } +} + +struct esp32_apptrace_block *esp32_apptrace_free_block_get(struct esp32_apptrace_cmd_ctx *ctx) +{ + struct esp32_apptrace_block *block = NULL; + + if (!list_empty(&ctx->free_trace_blocks)) { + /*get first */ + block = list_first_entry(&ctx->free_trace_blocks, struct esp32_apptrace_block, node); + list_del(&block->node); + } + + return block; +} + +static int esp32_apptrace_ready_block_put(struct esp32_apptrace_cmd_ctx *ctx, struct esp32_apptrace_block *block) +{ + LOG_DEBUG("esp32_apptrace_ready_block_put"); + /* add to ready blocks list */ + INIT_LIST_HEAD(&block->node); + list_add(&block->node, &ctx->ready_trace_blocks); + + return ERROR_OK; +} + +static struct esp32_apptrace_block *esp32_apptrace_ready_block_get(struct esp32_apptrace_cmd_ctx *ctx) +{ + struct esp32_apptrace_block *block = NULL; + + if (!list_empty(&ctx->ready_trace_blocks)) { + struct list_head *head = &ctx->ready_trace_blocks; + struct list_head *tmp, *pos; + + list_for_each_safe(pos, tmp, head) { + block = list_entry(pos, struct esp32_apptrace_block, node); + } + /* remove it from ready list */ + list_del(&block->node); + } + + return block; +} + +static int esp32_apptrace_block_free(struct esp32_apptrace_cmd_ctx *ctx, struct esp32_apptrace_block *block) +{ + /* add to free blocks list */ + INIT_LIST_HEAD(&block->node); + list_add(&block->node, &ctx->free_trace_blocks); + + return ERROR_OK; +} + +static int esp32_apptrace_wait_tracing_finished(struct esp32_apptrace_cmd_ctx *ctx) +{ + int64_t timeout = timeval_ms() + (LOG_LEVEL_IS(LOG_LVL_DEBUG) ? 70000 : 5000); + while (!list_empty(&ctx->ready_trace_blocks)) { + alive_sleep(100); + if (timeval_ms() >= timeout) { + LOG_ERROR("Failed to wait for pended trace blocks!"); + return ERROR_FAIL; + } + } + /* signal timer callback to stop */ + ctx->running = 0; + target_unregister_timer_callback(esp32_apptrace_data_processor, ctx); + return ERROR_OK; +} + +/********************************************************************* +* Trace commands +**********************************************************************/ + +int esp32_apptrace_cmd_ctx_init(struct esp32_apptrace_cmd_ctx *cmd_ctx, struct command_invocation *cmd, int mode) +{ + struct target *target = get_current_target(CMD_CTX); + + memset(cmd_ctx, 0, sizeof(struct esp32_apptrace_cmd_ctx)); + cmd_ctx->target = target; + cmd_ctx->mode = mode; + cmd_ctx->target_state = target->state; + cmd_ctx->cmd = cmd; + + if (target->smp) { + struct target_list *head; + struct target *curr; + unsigned int i = 0; + cmd_ctx->cores_num = 0; + foreach_smp_target(head, target->smp_targets) { + curr = head->target; + if (i == ESP32_APPTRACE_MAX_CORES_NUM) { + command_print(cmd, "Too many cores configured! Max %d cores are supported.", + ESP32_APPTRACE_MAX_CORES_NUM); + return ERROR_FAIL; + } + if (!target_was_examined(curr)) + continue; + cmd_ctx->cores_num++; + cmd_ctx->cpus[i++] = curr; + } + } else { + cmd_ctx->cores_num = 1; + cmd_ctx->cpus[0] = target; + } + /* some relies on ESP32_APPTRACE_MAX_CORES_NUM + * TODO: remove that dependency */ + assert(cmd_ctx->cores_num <= ESP32_APPTRACE_MAX_CORES_NUM && "Too many cores number!"); + + struct xtensa *xtensa = target->arch_info; + if (xtensa->common_magic == XTENSA_COMMON_MAGIC) { + cmd_ctx->hw = target_to_esp_xtensa(target)->apptrace.hw; + } else { /* TODO: riscv is not supported yet */ + command_print(cmd, "Unsupported target arch 0x%X", xtensa->common_magic); + return ERROR_FAIL; + } + + cmd_ctx->max_trace_block_sz = cmd_ctx->hw->max_block_size_get(cmd_ctx->cpus[0]); + if (cmd_ctx->max_trace_block_sz == 0) { + command_print(cmd, "Failed to get max trace block size!"); + return ERROR_FAIL; + } + LOG_INFO("Total trace memory: %" PRIu32 " bytes", cmd_ctx->max_trace_block_sz); + + INIT_LIST_HEAD(&cmd_ctx->ready_trace_blocks); + INIT_LIST_HEAD(&cmd_ctx->free_trace_blocks); + for (unsigned int i = 0; i < ESP_APPTRACE_BLOCKS_POOL_SZ; i++) { + struct esp32_apptrace_block *block = calloc(1, sizeof(struct esp32_apptrace_block)); + if (!block) { + command_print(cmd, "Failed to alloc trace buffer entry!"); + esp32_apptrace_blocks_pool_cleanup(cmd_ctx); + return ERROR_FAIL; + } + block->data = malloc(cmd_ctx->max_trace_block_sz); + if (!block->data) { + free(block); + command_print(cmd, "Failed to alloc trace buffer %" PRIu32 " bytes!", cmd_ctx->max_trace_block_sz); + esp32_apptrace_blocks_pool_cleanup(cmd_ctx); + return ERROR_FAIL; + } + INIT_LIST_HEAD(&block->node); + list_add(&block->node, &cmd_ctx->free_trace_blocks); + } + + cmd_ctx->running = 1; + if (cmd_ctx->mode != ESP_APPTRACE_CMD_MODE_SYNC) { + int res = target_register_timer_callback(esp32_apptrace_data_processor, + 0, + TARGET_TIMER_TYPE_PERIODIC, + cmd_ctx); + if (res != ERROR_OK) { + command_print(cmd, "Failed to start trace data timer callback (%d)!", res); + esp32_apptrace_blocks_pool_cleanup(cmd_ctx); + return ERROR_FAIL; + } + } + + if (s_time_stats_enable) { + cmd_ctx->stats.min_blk_read_time = 1000000.0; + cmd_ctx->stats.min_blk_proc_time = 1000000.0; + } + if (duration_start(&cmd_ctx->idle_time) != 0) { + command_print(cmd, "Failed to start idle time measurement!"); + esp32_apptrace_cmd_ctx_cleanup(cmd_ctx); + return ERROR_FAIL; + } + + return ERROR_OK; +} + +int esp32_apptrace_cmd_ctx_cleanup(struct esp32_apptrace_cmd_ctx *cmd_ctx) +{ + esp32_apptrace_blocks_pool_cleanup(cmd_ctx); + return ERROR_OK; +} + +#define ESP32_APPTRACE_CMD_NUM_ARG_CHECK(_cmd_, _arg_, _start_, _end_) \ + do { \ + if ((_arg_) == 0 && (_start_) == (_end_)) { \ + command_print(_cmd_, "Invalid '" # _arg_ "' arg!"); \ + return; \ + } \ + } while (0) + +void esp32_apptrace_cmd_args_parse(struct esp32_apptrace_cmd_ctx *cmd_ctx, + struct esp32_apptrace_cmd_data *cmd_data, + const char **argv, + int argc) +{ + char *end; + + cmd_data->poll_period = strtoul(argv[0], &end, 10); + ESP32_APPTRACE_CMD_NUM_ARG_CHECK(cmd_ctx->cmd, cmd_data->poll_period, argv[0], end); + if (argc > 1) { + cmd_data->max_len = strtoul(argv[1], &end, 10); + ESP32_APPTRACE_CMD_NUM_ARG_CHECK(cmd_ctx->cmd, cmd_data->max_len, argv[1], end); + if (argc > 2) { + int32_t tmo = strtol(argv[2], &end, 10); + ESP32_APPTRACE_CMD_NUM_ARG_CHECK(cmd_ctx->cmd, tmo, argv[2], end); + cmd_ctx->stop_tmo = 1.0 * tmo; + if (argc > 3) { + cmd_data->wait4halt = strtoul(argv[3], &end, 10); + ESP32_APPTRACE_CMD_NUM_ARG_CHECK(cmd_ctx->cmd, cmd_data->wait4halt, argv[3], end); + if (argc > 4) { + cmd_data->skip_len = strtoul(argv[4], &end, 10); + ESP32_APPTRACE_CMD_NUM_ARG_CHECK(cmd_ctx->cmd, cmd_data->skip_len, argv[4], end); + } + } + } + } +} + +static int esp32_apptrace_core_id_get(struct target *target, uint8_t *hdr_buf) +{ + return ESP32_APPTRACE_USER_BLOCK_CORE(target_buffer_get_u16(target, hdr_buf + APPTRACE_BLOCK_SIZE_OFFSET)); +} + +static uint32_t esp32_apptrace_usr_block_len_get(struct target *target, uint8_t *hdr_buf, uint32_t *wr_len) +{ + *wr_len = ESP32_APPTRACE_USER_BLOCK_LEN(target_buffer_get_u16(target, hdr_buf + APPTRACE_WR_SIZE_OFFSET)); + return ESP32_APPTRACE_USER_BLOCK_LEN(target_buffer_get_u16(target, hdr_buf + APPTRACE_BLOCK_SIZE_OFFSET)); +} + +static int esp32_apptrace_cmd_init(struct esp32_apptrace_cmd_ctx *cmd_ctx, + struct command_invocation *cmd, + int mode, + const char **argv, + int argc) +{ + struct esp32_apptrace_cmd_data *cmd_data; + + if (argc < 1) { + command_print(cmd, "Not enough args! Need trace data destination!"); + return ERROR_FAIL; + } + + int res = esp32_apptrace_cmd_ctx_init(cmd_ctx, cmd, mode); + if (res != ERROR_OK) + return res; + + cmd_data = calloc(1, sizeof(*cmd_data)); + assert(cmd_data && "No memory for command data!"); + cmd_ctx->cmd_priv = cmd_data; + + /*outfile1 [poll_period [trace_size [stop_tmo [wait4halt [skip_size]]]]] */ + res = esp32_apptrace_dest_init(&cmd_data->data_dest, argv, 1); + if (res != 1) { /* only one destination needs to be initialized */ + command_print(cmd, "Wrong args! Needs a trace data destination!"); + free(cmd_data); + goto on_error; + } + cmd_ctx->stop_tmo = -1.0; /* infinite */ + cmd_data->max_len = UINT32_MAX; + cmd_data->poll_period = 0 /*ms*/; + if (argc > 1) + /* parse remaining args */ + esp32_apptrace_cmd_args_parse(cmd_ctx, cmd_data, &argv[1], argc - 1); + + LOG_USER("App trace params: from %d cores, size %" PRId32 " bytes, stop_tmo %g s, poll period %" PRId32 + " ms, wait_rst %d, skip %" PRId32 " bytes", cmd_ctx->cores_num, + cmd_data->max_len, + cmd_ctx->stop_tmo, + cmd_data->poll_period, + cmd_data->wait4halt, + cmd_data->skip_len); + + cmd_ctx->trace_format.hdr_sz = ESP32_APPTRACE_USER_BLOCK_HDR_SZ; + cmd_ctx->trace_format.core_id_get = esp32_apptrace_core_id_get; + cmd_ctx->trace_format.usr_block_len_get = esp32_apptrace_usr_block_len_get; + return ERROR_OK; +on_error: + command_print(cmd, "Not enough args! Need %d trace data destinations!", cmd_ctx->cores_num); + cmd_ctx->running = 0; + esp32_apptrace_cmd_ctx_cleanup(cmd_ctx); + return res; +} + +static int esp32_apptrace_cmd_cleanup(struct esp32_apptrace_cmd_ctx *cmd_ctx) +{ + struct esp32_apptrace_cmd_data *cmd_data = cmd_ctx->cmd_priv; + + esp32_apptrace_dest_cleanup(&cmd_data->data_dest, 1); + free(cmd_data); + cmd_ctx->cmd_priv = NULL; + esp32_apptrace_cmd_ctx_cleanup(cmd_ctx); + return ERROR_OK; +} + +static void esp32_apptrace_print_stats(struct esp32_apptrace_cmd_ctx *ctx) +{ + struct esp32_apptrace_cmd_data *cmd_data = ctx->cmd_priv; + uint32_t trace_sz = 0; + + if (cmd_data) + trace_sz = ctx->tot_len > cmd_data->skip_len ? ctx->tot_len - cmd_data->skip_len : 0; + LOG_USER("Tracing is %s. Size is %" PRId32 " of %" PRId32 " @ %f (%f) KiB/s", + !ctx->running ? "STOPPED" : "RUNNING", + trace_sz, + cmd_data ? cmd_data->max_len : 0, + duration_kbps(&ctx->read_time, ctx->tot_len), + duration_kbps(&ctx->read_time, ctx->raw_tot_len)); + LOG_USER("Data: blocks incomplete %" PRId32 ", lost bytes: %" PRId32, + ctx->stats.incompl_blocks, + ctx->stats.lost_bytes); + if (s_time_stats_enable) { + LOG_USER("Block read time [%f..%f] ms", + 1000 * ctx->stats.min_blk_read_time, + 1000 * ctx->stats.max_blk_read_time); + LOG_USER("Block proc time [%f..%f] ms", + 1000 * ctx->stats.min_blk_proc_time, + 1000 * ctx->stats.max_blk_proc_time); + } +} + +static int esp32_apptrace_wait4halt(struct esp32_apptrace_cmd_ctx *ctx, struct target *target) +{ + LOG_USER("Wait for halt..."); + while (!openocd_is_shutdown_pending()) { + int res = target_poll(target); + if (res != ERROR_OK) + return res; + if (target->state == TARGET_HALTED) { + LOG_USER("%s: HALTED", target->cmd_name); + break; + } + alive_sleep(500); + } + return ERROR_OK; +} + +int esp32_apptrace_safe_halt_targets(struct esp32_apptrace_cmd_ctx *ctx, + struct esp32_apptrace_target_state *targets) +{ + int res = ERROR_OK; + + memset(targets, 0, ctx->cores_num * sizeof(struct esp32_apptrace_target_state)); + /* halt all CPUs */ + LOG_DEBUG("Halt all targets!"); + for (unsigned int k = 0; k < ctx->cores_num; k++) { + if (!target_was_examined(ctx->cpus[k])) + continue; + if (ctx->cpus[k]->state == TARGET_HALTED) + continue; + res = target_halt(ctx->cpus[k]); + if (res != ERROR_OK) { + LOG_ERROR("Failed to halt target (%d)!", res); + return res; + } + res = target_wait_state(ctx->cpus[k], TARGET_HALTED, ESP32_APPTRACE_TGT_STATE_TMO); + if (res != ERROR_OK) { + LOG_ERROR("Failed to wait halt target %s / %d (%d)!", + target_name(ctx->cpus[k]), + ctx->cpus[k]->state, + res); + return res; + } + } + /* read current block statuses from CPUs */ + LOG_DEBUG("Read current block statuses"); + for (unsigned int k = 0; k < ctx->cores_num; k++) { + uint32_t stat; + res = ctx->hw->status_reg_read(ctx->cpus[k], &stat); + if (res != ERROR_OK) { + LOG_ERROR("Failed to read trace status (%d)!", res); + return res; + } + /* check if some CPU stopped inside tracing regs update critical section */ + if (stat) { + if (ctx->hw->leave_trace_crit_section_start) { + res = ctx->hw->leave_trace_crit_section_start(ctx->cpus[k]); + if (res != ERROR_OK) + return res; + } + uint32_t bp_addr = stat; + res = breakpoint_add(ctx->cpus[k], bp_addr, 1, BKPT_HARD); + if (res != ERROR_OK) { + LOG_ERROR("Failed to set breakpoint (%d)!", res); + return res; + } + while (stat) { + /* allow this CPU to leave ERI write critical section */ + res = target_resume(ctx->cpus[k], 1, 0, 1, 0); + if (res != ERROR_OK) { + LOG_ERROR("Failed to resume target (%d)!", res); + breakpoint_remove(ctx->cpus[k], bp_addr); + return res; + } + /* wait for CPU to be halted on BP */ + enum target_debug_reason debug_reason = DBG_REASON_UNDEFINED; + while (debug_reason != DBG_REASON_BREAKPOINT) { + res = target_wait_state(ctx->cpus[k], TARGET_HALTED, + ESP32_APPTRACE_TGT_STATE_TMO); + if (res != ERROR_OK) { + LOG_ERROR("Failed to wait halt on bp (%d)!", res); + breakpoint_remove(ctx->cpus[k], bp_addr); + return res; + } + debug_reason = ctx->cpus[k]->debug_reason; + } + res = ctx->hw->status_reg_read(ctx->cpus[k], &stat); + if (res != ERROR_OK) { + LOG_ERROR("Failed to read trace status (%d)!", res); + breakpoint_remove(ctx->cpus[k], bp_addr); + return res; + } + } + breakpoint_remove(ctx->cpus[k], bp_addr); + if (ctx->hw->leave_trace_crit_section_stop) { + res = ctx->hw->leave_trace_crit_section_stop(ctx->cpus[k]); + if (res != ERROR_OK) + return res; + } + } + res = ctx->hw->data_len_read(ctx->cpus[k], &targets[k].block_id, &targets[k].data_len); + if (res != ERROR_OK) { + LOG_ERROR("Failed to read trace status (%d)!", res); + return res; + } + } + + return ERROR_OK; +} + +static int esp32_apptrace_connect_targets(struct esp32_apptrace_cmd_ctx *ctx, + bool conn, + bool resume_target) +{ + struct esp32_apptrace_target_state target_to_connect[ESP32_APPTRACE_MAX_CORES_NUM]; + + if (conn) + LOG_USER("Connect targets..."); + else + LOG_USER("Disconnect targets..."); + + int res = esp32_apptrace_safe_halt_targets(ctx, target_to_connect); + if (res != ERROR_OK) { + command_print(ctx->cmd, "Failed to halt targets (%d)!", res); + return res; + } + if (ctx->cores_num > 1) { + /* set block ids to the highest value */ + uint32_t max_id = 0; + for (unsigned int k = 0; k < ctx->cores_num; k++) { + if (target_to_connect[k].block_id > max_id) + max_id = target_to_connect[k].block_id; + } + for (unsigned int k = 0; k < ctx->cores_num; k++) + target_to_connect[k].block_id = max_id; + } + for (unsigned int k = 0; k < ctx->cores_num; k++) { + /* update host connected status */ + res = ctx->hw->ctrl_reg_write(ctx->cpus[k], + target_to_connect[k].block_id, + 0 /*ack target data*/, + conn, + false /*no host data*/); + if (res != ERROR_OK) { + command_print(ctx->cmd, "Failed to read trace status (%d)!", res); + return res; + } + } + if (resume_target) { + LOG_DEBUG("Resume targets"); + bool smp_resumed = false; + for (unsigned int k = 0; k < ctx->cores_num; k++) { + if (smp_resumed && ctx->cpus[k]->smp) { + /* in SMP mode we need to call target_resume for one core only */ + continue; + } + res = target_resume(ctx->cpus[k], 1, 0, 1, 0); + if (res != ERROR_OK) { + command_print(ctx->cmd, "Failed to resume target (%d)!", res); + return res; + } + if (ctx->cpus[k]->smp) + smp_resumed = true; + } + } + if (conn) + LOG_INFO("Targets connected."); + else + LOG_INFO("Targets disconnected."); + return ERROR_OK; +} + +int esp_apptrace_usr_block_write(const struct esp32_apptrace_hw *hw, struct target *target, + uint32_t block_id, + const uint8_t *data, + uint32_t size) +{ + struct esp_apptrace_host2target_hdr hdr = { .block_sz = size }; + uint32_t buf_sz[2] = { sizeof(hdr), size }; + const uint8_t *bufs[2] = { (const uint8_t *)&hdr, data }; + + if (size > hw->usr_block_max_size_get(target)) { + LOG_ERROR("Too large user block %" PRId32, size); + return ERROR_FAIL; + } + + return hw->buffs_write(target, + ARRAY_SIZE(buf_sz), + buf_sz, + bufs, + block_id, + true /*ack target data*/, + true /*host data*/); +} + +static uint32_t esp32_apptrace_usr_block_check(struct esp32_apptrace_cmd_ctx *ctx, uint8_t *hdr_buf) +{ + uint32_t wr_len = 0; + uint32_t usr_len = ctx->trace_format.usr_block_len_get(ctx->target, hdr_buf, &wr_len); + if (usr_len != wr_len) { + LOG_ERROR("Incomplete block sz %" PRId32 ", wr %" PRId32, usr_len, wr_len); + ctx->stats.incompl_blocks++; + ctx->stats.lost_bytes += usr_len - wr_len; + } + return usr_len; +} + +int esp32_apptrace_get_data_info(struct esp32_apptrace_cmd_ctx *ctx, + struct esp32_apptrace_target_state *target_state, + uint32_t *fired_target_num) +{ + if (fired_target_num) + *fired_target_num = UINT32_MAX; + + for (unsigned int i = 0; i < ctx->cores_num; i++) { + int res = ctx->hw->data_len_read(ctx->cpus[i], &target_state[i].block_id, &target_state[i].data_len); + if (res != ERROR_OK) { + LOG_ERROR("Failed to read data len on (%s)!", target_name(ctx->cpus[i])); + return res; + } + if (target_state[i].data_len) { + LOG_TARGET_DEBUG(ctx->cpus[i], "Block %" PRId32 ", len %" PRId32 " bytes on fired", + target_state[i].block_id, target_state[i].data_len); + if (fired_target_num) + *fired_target_num = i; + break; + } + } + return ERROR_OK; +} + +static int esp32_apptrace_process_data(struct esp32_apptrace_cmd_ctx *ctx, + unsigned int core_id, + uint8_t *data, + uint32_t data_len) +{ + struct esp32_apptrace_cmd_data *cmd_data = ctx->cmd_priv; + + LOG_DEBUG("Got block %" PRId32 " bytes [%x %x...%x %x]", data_len, data[12], data[13], + data[data_len - 2], data[data_len - 1]); + if (ctx->tot_len + data_len > cmd_data->skip_len) { + uint32_t wr_idx = 0, wr_chunk_len = data_len; + if (ctx->tot_len < cmd_data->skip_len) { + wr_chunk_len = (ctx->tot_len + wr_chunk_len) - cmd_data->skip_len; + wr_idx = cmd_data->skip_len - ctx->tot_len; + } + if (ctx->tot_len + wr_chunk_len > cmd_data->max_len) + wr_chunk_len -= (ctx->tot_len + wr_chunk_len - cmd_data->skip_len) - cmd_data->max_len; + if (wr_chunk_len > 0) { + int res = cmd_data->data_dest.write(cmd_data->data_dest.priv, data + wr_idx, wr_chunk_len); + if (res != ERROR_OK) { + LOG_ERROR("Failed to write %" PRId32 " bytes to dest 0!", data_len); + return res; + } + } + ctx->tot_len += wr_chunk_len; + } else { + ctx->tot_len += data_len; + } + + if (cmd_data->data_dest.log_progress) + LOG_USER("%" PRId32 " ", ctx->tot_len); + /* check for stop condition */ + if (ctx->tot_len > cmd_data->skip_len && (ctx->tot_len - cmd_data->skip_len >= cmd_data->max_len)) { + ctx->running = 0; + if (duration_measure(&ctx->read_time) != 0) { + LOG_ERROR("Failed to stop trace read time measure!"); + return ERROR_FAIL; + } + } + return ERROR_OK; +} + +static int esp32_apptrace_handle_trace_block(struct esp32_apptrace_cmd_ctx *ctx, + struct esp32_apptrace_block *block) +{ + uint32_t processed = 0; + uint32_t hdr_sz = ctx->trace_format.hdr_sz; + + LOG_DEBUG("Got block %" PRId32 " bytes", block->data_len); + /* process user blocks one by one */ + while (processed < block->data_len) { + LOG_DEBUG("Process usr block %" PRId32 "/%" PRId32, processed, block->data_len); + /* process user block */ + uint32_t usr_len = esp32_apptrace_usr_block_check(ctx, block->data + processed); + int core_id = ctx->trace_format.core_id_get(ctx->target, block->data + processed); + /* process user data */ + int res = ctx->process_data(ctx, core_id, block->data + processed + hdr_sz, usr_len); + if (res != ERROR_OK) { + LOG_ERROR("Failed to process %" PRId32 " bytes!", usr_len); + return res; + } + processed += usr_len + hdr_sz; + } + return ERROR_OK; +} + +static int esp32_apptrace_data_processor(void *priv) +{ + struct esp32_apptrace_cmd_ctx *ctx = (struct esp32_apptrace_cmd_ctx *)priv; + + if (!ctx->running) + return ERROR_OK; + + struct esp32_apptrace_block *block = esp32_apptrace_ready_block_get(ctx); + if (!block) + return ERROR_OK; + + int res = esp32_apptrace_handle_trace_block(ctx, block); + if (res != ERROR_OK) { + ctx->running = 0; + LOG_ERROR("Failed to process trace block %" PRId32 " bytes!", block->data_len); + return res; + } + res = esp32_apptrace_block_free(ctx, block); + if (res != ERROR_OK) { + ctx->running = 0; + LOG_ERROR("Failed to free ready block!"); + return res; + } + + return ERROR_OK; +} + +static int esp32_apptrace_check_connection(struct esp32_apptrace_cmd_ctx *ctx) +{ + if (!ctx) + return ERROR_FAIL; + + unsigned int busy_target_num = 0; + + for (unsigned int i = 0; i < ctx->cores_num; i++) { + bool conn = true; + int res = ctx->hw->ctrl_reg_read(ctx->cpus[i], NULL, NULL, &conn); + if (res != ERROR_OK) { + LOG_ERROR("Failed to read apptrace control reg for cpu(%d) res(%d)!", i, res); + return res; + } + if (!conn) { + uint32_t stat = 0; + LOG_TARGET_WARNING(ctx->cpus[i], "apptrace connection is lost. Re-connect."); + res = ctx->hw->status_reg_read(ctx->cpus[i], &stat); + if (res != ERROR_OK) { + LOG_ERROR("Failed to read trace status (%d)!", res); + return res; + } + if (stat) { + LOG_TARGET_WARNING(ctx->cpus[i], "in critical state. Retry in next poll"); + if (++busy_target_num == ctx->cores_num) { + LOG_WARNING("No available core"); + return ERROR_WAIT; + } + continue; + } + res = ctx->hw->ctrl_reg_write(ctx->cpus[i], + 0, + 0, + true /*host connected*/, + false /*no host data*/); + if (res != ERROR_OK) { + LOG_ERROR("Failed to write apptrace control reg for cpu(%d) res(%d)!", i, res); + return res; + } + if (ctx->stop_tmo != -1.0) { + /* re-start idle time measurement */ + if (duration_start(&ctx->idle_time) != 0) { + LOG_ERROR("Failed to re-start idle time measure!"); + return ERROR_FAIL; + } + } + } + } + + return ERROR_OK; +} + +static int esp32_apptrace_poll(void *priv) +{ + struct esp32_apptrace_cmd_ctx *ctx = (struct esp32_apptrace_cmd_ctx *)priv; + int res; + uint32_t fired_target_num = 0; + struct esp32_apptrace_target_state target_state[ESP32_APPTRACE_MAX_CORES_NUM]; + struct duration blk_proc_time; + + if (!ctx->running) { + if (ctx->auto_clean) + ctx->auto_clean(ctx); + return ERROR_FAIL; + } + + /* Check for connection is alive.For some reason target and therefore host_connected flag + * might have been reset */ + res = esp32_apptrace_check_connection(ctx); + if (res != ERROR_OK) { + if (res != ERROR_WAIT) + ctx->running = 0; + return res; + } + + /* check for data from target */ + res = esp32_apptrace_get_data_info(ctx, target_state, &fired_target_num); + if (res != ERROR_OK) { + ctx->running = 0; + LOG_ERROR("Failed to read data len!"); + return res; + } + /* LOG_DEBUG("Block %d (%d bytes) on target (%s)!", target_state[0].block_id, + * target_state[0].data_len, target_name(ctx->cpus[0])); */ + if (fired_target_num == UINT32_MAX) { + /* no data has been received, but block could be switched due to the data transferred + * from host to target */ + if (ctx->cores_num > 1) { + uint32_t max_block_id = 0, min_block_id = ctx->hw->max_block_id; + /* find maximum block ID and set the same ID in control reg for both cores + * */ + for (unsigned int i = 0; i < ctx->cores_num; i++) { + if (max_block_id < target_state[i].block_id) + max_block_id = target_state[i].block_id; + if (min_block_id > target_state[i].block_id) + min_block_id = target_state[i].block_id; + } + /* handle block ID overflow */ + if (max_block_id == ctx->hw->max_block_id && min_block_id == 0) + max_block_id = 0; + for (unsigned int i = 0; i < ctx->cores_num; i++) { + if (max_block_id != target_state[i].block_id) { + LOG_TARGET_DEBUG(ctx->cpus[i], "Ack empty block %" PRId32 "!", max_block_id); + res = ctx->hw->ctrl_reg_write(ctx->cpus[i], + max_block_id, + 0 /*all read*/, + true /*host connected*/, + false /*no host data*/); + if (res != ERROR_OK) { + ctx->running = 0; + LOG_TARGET_ERROR(ctx->cpus[i], "Failed to ack empty data block!"); + return res; + } + } + } + ctx->last_blk_id = max_block_id; + } + if (ctx->stop_tmo != -1.0) { + if (duration_measure(&ctx->idle_time) != 0) { + ctx->running = 0; + LOG_ERROR("Failed to measure idle time!"); + return ERROR_FAIL; + } + if (duration_elapsed(&ctx->idle_time) >= ctx->stop_tmo) { + ctx->running = 0; + LOG_ERROR("Data timeout!"); + return ERROR_FAIL; + } + } + return ERROR_OK;/* no data */ + } + /* sanity check */ + if (target_state[fired_target_num].data_len > ctx->max_trace_block_sz) { + ctx->running = 0; + LOG_ERROR("Too large block size %" PRId32 "!", target_state[fired_target_num].data_len); + return ERROR_FAIL; + } + if (ctx->tot_len == 0) { + if (duration_start(&ctx->read_time) != 0) { + ctx->running = 0; + LOG_ERROR("Failed to start trace read time measurement!"); + return ERROR_FAIL; + } + } + struct esp32_apptrace_block *block = esp32_apptrace_free_block_get(ctx); + if (!block) { + ctx->running = 0; + LOG_TARGET_ERROR(ctx->cpus[fired_target_num], "Failed to get free block for data!"); + return ERROR_FAIL; + } + if (s_time_stats_enable) { + /* read block */ + if (duration_start(&blk_proc_time) != 0) { + ctx->running = 0; + LOG_ERROR("Failed to start block read time measurement!"); + return ERROR_FAIL; + } + } + res = + ctx->hw->data_read(ctx->cpus[fired_target_num], + target_state[fired_target_num].data_len, + block->data, + target_state[fired_target_num].block_id, + /* do not ack target data in sync mode, + esp32_apptrace_handle_trace_block() can write response data and will do ack thereafter */ + ctx->mode != ESP_APPTRACE_CMD_MODE_SYNC); + if (res != ERROR_OK) { + ctx->running = 0; + LOG_TARGET_ERROR(ctx->cpus[fired_target_num], "Failed to read data!"); + return res; + } + ctx->last_blk_id = target_state[fired_target_num].block_id; + block->data_len = target_state[fired_target_num].data_len; + ctx->raw_tot_len += block->data_len; + if (s_time_stats_enable) { + if (duration_measure(&blk_proc_time) != 0) { + ctx->running = 0; + LOG_ERROR("Failed to measure block read time!"); + return ERROR_FAIL; + } + /* update stats */ + float brt = duration_elapsed(&blk_proc_time); + if (brt > ctx->stats.max_blk_read_time) + ctx->stats.max_blk_read_time = brt; + if (brt < ctx->stats.min_blk_read_time) + ctx->stats.min_blk_read_time = brt; + + if (duration_start(&blk_proc_time) != 0) { + ctx->running = 0; + LOG_ERROR("Failed to start block proc time measurement!"); + return ERROR_FAIL; + } + } + /* in sync mode do not ack target data on other cores, esp32_apptrace_handle_trace_block() can write response + * data and will do ack thereafter */ + if (ctx->mode != ESP_APPTRACE_CMD_MODE_SYNC) { + for (unsigned int i = 0; i < ctx->cores_num; i++) { + if (i == fired_target_num) + continue; + res = ctx->hw->ctrl_reg_write(ctx->cpus[i], + ctx->last_blk_id, + 0 /*all read*/, + true /*host connected*/, + false /*no host data*/); + if (res != ERROR_OK) { + ctx->running = 0; + LOG_TARGET_ERROR(ctx->cpus[i], "Failed to ack data!"); + return res; + } + LOG_TARGET_DEBUG(ctx->cpus[i], "Ack block %" PRId32, ctx->last_blk_id); + } + res = esp32_apptrace_ready_block_put(ctx, block); + if (res != ERROR_OK) { + ctx->running = 0; + LOG_TARGET_ERROR(ctx->cpus[fired_target_num], "Failed to put ready block of data!"); + return res; + } + } else { + res = esp32_apptrace_handle_trace_block(ctx, block); + if (res != ERROR_OK) { + ctx->running = 0; + LOG_ERROR("Failed to process trace block %" PRId32 " bytes!", block->data_len); + return res; + } + res = esp32_apptrace_block_free(ctx, block); + if (res != ERROR_OK) { + ctx->running = 0; + LOG_ERROR("Failed to free ready block!"); + return res; + } + } + if (ctx->stop_tmo != -1.0) { + /* start idle time measurement */ + if (duration_start(&ctx->idle_time) != 0) { + ctx->running = 0; + LOG_ERROR("Failed to start idle time measure!"); + return ERROR_FAIL; + } + } + if (s_time_stats_enable) { + if (duration_measure(&blk_proc_time) != 0) { + ctx->running = 0; + LOG_ERROR("Failed to stop block proc time measure!"); + return ERROR_FAIL; + } + /* update stats */ + float bt = duration_elapsed(&blk_proc_time); + if (bt > ctx->stats.max_blk_proc_time) + ctx->stats.max_blk_proc_time = bt; + if (bt < ctx->stats.min_blk_proc_time) + ctx->stats.min_blk_proc_time = bt; + } + return ERROR_OK; +} + +static void esp32_apptrace_cmd_stop(struct esp32_apptrace_cmd_ctx *ctx) +{ + if (duration_measure(&ctx->read_time) != 0) + LOG_ERROR("Failed to stop trace read time measurement!"); + int res = target_unregister_timer_callback(esp32_apptrace_poll, ctx); + if (res != ERROR_OK) + LOG_ERROR("Failed to unregister target timer handler (%d)!", res); + + /* data processor is alive, so wait for all received blocks to be processed */ + res = esp32_apptrace_wait_tracing_finished(ctx); + if (res != ERROR_OK) + LOG_ERROR("Failed to wait for pended blocks (%d)!", res); + res = esp32_apptrace_connect_targets(ctx, false, ctx->target_state == TARGET_RUNNING); + if (res != ERROR_OK) + LOG_ERROR("Failed to disconnect targets (%d)!", res); + esp32_apptrace_print_stats(ctx); + res = esp32_apptrace_cmd_cleanup(ctx); + if (res != ERROR_OK) + LOG_ERROR("Failed to cleanup cmd ctx (%d)!", res); +} + +int esp32_cmd_apptrace_generic(struct command_invocation *cmd, int mode, const char **argv, int argc) +{ + static struct esp32_apptrace_cmd_ctx s_at_cmd_ctx; + struct esp32_apptrace_cmd_data *cmd_data; + int res = ERROR_FAIL; + enum target_state old_state; + struct target *target = get_current_target(CMD_CTX); + + if (argc < 1) + return ERROR_COMMAND_SYNTAX_ERROR; + + /* command can be invoked on unexamined core, if so find examined one */ + if (target->smp && !target_was_examined(target)) { + struct target_list *head; + struct target *curr; + LOG_WARNING("Current target '%s' was not examined!", target_name(target)); + foreach_smp_target(head, target->smp_targets) { + curr = head->target; + if (target_was_examined(curr)) { + target = curr; + LOG_WARNING("Run command on target '%s'", target_name(target)); + break; + } + } + } + old_state = target->state; + + if (strcmp(argv[0], "start") == 0) { + res = esp32_apptrace_cmd_init(&s_at_cmd_ctx, + cmd, + mode, + &argv[1], + argc - 1); + if (res != ERROR_OK) { + command_print(cmd, "Failed to init cmd ctx (%d)!", res); + return res; + } + cmd_data = s_at_cmd_ctx.cmd_priv; + s_at_cmd_ctx.process_data = esp32_apptrace_process_data; + s_at_cmd_ctx.auto_clean = esp32_apptrace_cmd_stop; + if (cmd_data->wait4halt) { + res = esp32_apptrace_wait4halt(&s_at_cmd_ctx, target); + if (res != ERROR_OK) { + command_print(cmd, "Failed to wait for halt target (%d)!", res); + goto _on_start_error; + } + } + res = esp32_apptrace_connect_targets(&s_at_cmd_ctx, true, old_state == TARGET_RUNNING); + if (res != ERROR_OK) { + command_print(cmd, "Failed to connect to targets (%d)!", res); + goto _on_start_error; + } + res = target_register_timer_callback(esp32_apptrace_poll, + cmd_data->poll_period, + TARGET_TIMER_TYPE_PERIODIC, + &s_at_cmd_ctx); + if (res != ERROR_OK) { + command_print(cmd, "Failed to register target timer handler (%d)!", res); + goto _on_start_error; + } + } else if (strcmp(argv[0], "stop") == 0) { + if (!s_at_cmd_ctx.running) { + command_print(cmd, "Tracing is not running!"); + return ERROR_FAIL; + } + esp32_apptrace_cmd_stop(&s_at_cmd_ctx); + return ERROR_OK; + } else if (strcmp(argv[0], "status") == 0) { + if (s_at_cmd_ctx.running && duration_measure(&s_at_cmd_ctx.read_time) != 0) + LOG_ERROR("Failed to measure trace read time!"); + esp32_apptrace_print_stats(&s_at_cmd_ctx); + return ERROR_OK; + } else if (strcmp(argv[0], "dump") == 0) { + /* [dump outfile] - post-mortem dump without connection to targets */ + res = esp32_apptrace_cmd_init(&s_at_cmd_ctx, + cmd, + mode, + &argv[1], + argc - 1); + if (res != ERROR_OK) { + command_print(cmd, "Failed to init cmd ctx (%d)!", res); + return res; + } + s_at_cmd_ctx.stop_tmo = 0.01; /* use small stop tmo */ + s_at_cmd_ctx.process_data = esp32_apptrace_process_data; + /* check for exit signal and command completion */ + while (!openocd_is_shutdown_pending() && s_at_cmd_ctx.running) { + res = esp32_apptrace_poll(&s_at_cmd_ctx); + if (res != ERROR_OK) { + LOG_ERROR("Failed to poll target for trace data (%d)!", res); + break; + } + /* let registered timer callbacks to run */ + target_call_timer_callbacks(); + } + if (s_at_cmd_ctx.running) { + /* data processor is alive, so wait for all received blocks to be processed */ + res = esp32_apptrace_wait_tracing_finished(&s_at_cmd_ctx); + if (res != ERROR_OK) + LOG_ERROR("Failed to wait for pended blocks (%d)!", res); + } + esp32_apptrace_print_stats(&s_at_cmd_ctx); + res = esp32_apptrace_cmd_cleanup(&s_at_cmd_ctx); + if (res != ERROR_OK) + command_print(cmd, "Failed to cleanup cmd ctx (%d)!", res); + } else { + command_print(cmd, "Invalid action '%s'!", argv[0]); + } + + return res; + +_on_start_error: + s_at_cmd_ctx.running = 0; + esp32_apptrace_cmd_cleanup(&s_at_cmd_ctx); + return res; +} + +COMMAND_HANDLER(esp32_cmd_apptrace) +{ + return esp32_cmd_apptrace_generic(CMD, ESP_APPTRACE_CMD_MODE_GEN, CMD_ARGV, CMD_ARGC); +} + +const struct command_registration esp32_apptrace_command_handlers[] = { + { + .name = "apptrace", + .handler = esp32_cmd_apptrace, + .mode = COMMAND_EXEC, + .help = + "App Tracing: application level trace control. Starts, stops or queries tracing process status.", + .usage = + "[start [poll_period [trace_size [stop_tmo [wait4halt [skip_size]]]]] | [stop] | [status] | [dump ]", + }, + COMMAND_REGISTRATION_DONE +}; diff --git a/src/target/espressif/esp32_apptrace.h b/src/target/espressif/esp32_apptrace.h new file mode 100644 index 000000000..387334222 --- /dev/null +++ b/src/target/espressif/esp32_apptrace.h @@ -0,0 +1,126 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/*************************************************************************** + * ESP32 application trace module * + * Copyright (C) 2017-2019 Espressif Systems Ltd. * + ***************************************************************************/ + +#ifndef OPENOCD_TARGET_ESP32_APPTRACE_H +#define OPENOCD_TARGET_ESP32_APPTRACE_H + +#include +#include +#include + +#define ESP32_APPTRACE_MAX_CORES_NUM 2 + +struct esp32_apptrace_hw { + uint32_t max_block_id; + uint32_t (*max_block_size_get)(struct target *target); + int (*status_reg_read)(struct target *target, uint32_t *stat); + int (*ctrl_reg_write)(struct target *target, + uint32_t block_id, + uint32_t len, + bool conn, + bool data); + int (*ctrl_reg_read)(struct target *target, + uint32_t *block_id, + uint32_t *len, + bool *conn); + int (*data_len_read)(struct target *target, + uint32_t *block_id, + uint32_t *len); + int (*data_read)(struct target *target, + uint32_t size, + uint8_t *buffer, + uint32_t block_id, + bool ack); + uint32_t (*usr_block_max_size_get)(struct target *target); + int (*buffs_write)(struct target *target, + uint32_t bufs_num, + uint32_t buf_sz[], + const uint8_t *bufs[], + uint32_t block_id, + bool ack, + bool data); + int (*leave_trace_crit_section_start)(struct target *target); + int (*leave_trace_crit_section_stop)(struct target *target); +}; + +struct esp_apptrace_host2target_hdr { + uint16_t block_sz; +}; + +struct esp32_apptrace_dest { + void *priv; + int (*write)(void *priv, uint8_t *data, int size); + int (*clean)(void *priv); + bool log_progress; +}; + +struct esp32_apptrace_format { + uint32_t hdr_sz; + int (*core_id_get)(struct target *target, uint8_t *hdr_buf); + uint32_t (*usr_block_len_get)(struct target *target, uint8_t *hdr_buf, uint32_t *wr_len); +}; + +struct esp32_apptrace_cmd_stats { + uint32_t incompl_blocks; + uint32_t lost_bytes; + float min_blk_read_time; + float max_blk_read_time; + float min_blk_proc_time; + float max_blk_proc_time; +}; + +struct esp32_apptrace_cmd_ctx { + volatile int running; + int mode; + /* TODO: use subtargets from target arch info */ + struct target *cpus[ESP32_APPTRACE_MAX_CORES_NUM]; + /* TODO: use cores num from target */ + unsigned int cores_num; + const struct esp32_apptrace_hw *hw; + enum target_state target_state; + uint32_t last_blk_id; + struct list_head free_trace_blocks; + struct list_head ready_trace_blocks; + uint32_t max_trace_block_sz; + struct esp32_apptrace_format trace_format; + int (*process_data)(struct esp32_apptrace_cmd_ctx *ctx, unsigned int core_id, uint8_t *data, uint32_t data_len); + void (*auto_clean)(struct esp32_apptrace_cmd_ctx *ctx); + uint32_t tot_len; + uint32_t raw_tot_len; + float stop_tmo; + struct esp32_apptrace_cmd_stats stats; + struct duration read_time; + struct duration idle_time; + void *cmd_priv; + struct target *target; + struct command_invocation *cmd; +}; + +struct esp32_apptrace_cmd_data { + struct esp32_apptrace_dest data_dest; + uint32_t poll_period; + uint32_t max_len; + uint32_t skip_len; + bool wait4halt; +}; + +int esp32_apptrace_cmd_ctx_init(struct esp32_apptrace_cmd_ctx *cmd_ctx, struct command_invocation *cmd, int mode); +int esp32_apptrace_cmd_ctx_cleanup(struct esp32_apptrace_cmd_ctx *cmd_ctx); +void esp32_apptrace_cmd_args_parse(struct esp32_apptrace_cmd_ctx *cmd_ctx, + struct esp32_apptrace_cmd_data *cmd_data, + const char **argv, + int argc); +int esp32_apptrace_dest_init(struct esp32_apptrace_dest dest[], const char *dest_paths[], unsigned int max_dests); +int esp32_apptrace_dest_cleanup(struct esp32_apptrace_dest dest[], unsigned int max_dests); +int esp_apptrace_usr_block_write(const struct esp32_apptrace_hw *hw, struct target *target, + uint32_t block_id, + const uint8_t *data, + uint32_t size); + +extern const struct command_registration esp32_apptrace_command_handlers[]; + +#endif /* OPENOCD_TARGET_ESP32_APPTRACE_H */ diff --git a/src/target/espressif/esp32s2.c b/src/target/espressif/esp32s2.c index 64fa69057..a11d05f0f 100644 --- a/src/target/espressif/esp32s2.c +++ b/src/target/espressif/esp32s2.c @@ -496,6 +496,11 @@ static const struct command_registration esp32s2_command_handlers[] = { { .chain = xtensa_command_handlers, }, + { + .name = "esp", + .usage = "", + .chain = esp32_apptrace_command_handlers, + }, { .name = "arm", .mode = COMMAND_ANY, diff --git a/src/target/espressif/esp32s3.c b/src/target/espressif/esp32s3.c index 62b22b135..485567836 100644 --- a/src/target/espressif/esp32s3.c +++ b/src/target/espressif/esp32s3.c @@ -364,6 +364,11 @@ static const struct command_registration esp32s3_command_handlers[] = { .usage = "", .chain = esp_xtensa_smp_command_handlers, }, + { + .name = "esp", + .usage = "", + .chain = esp32_apptrace_command_handlers, + }, { .name = "esp32", .usage = "", diff --git a/src/target/espressif/esp_xtensa.c b/src/target/espressif/esp_xtensa.c index fcc340c82..44764aeca 100644 --- a/src/target/espressif/esp_xtensa.c +++ b/src/target/espressif/esp_xtensa.c @@ -12,6 +12,7 @@ #include #include #include +#include "esp_xtensa_apptrace.h" #include #include "esp_xtensa.h" #include "esp_semihosting.h" @@ -25,6 +26,7 @@ int esp_xtensa_init_arch_info(struct target *target, if (ret != ERROR_OK) return ret; esp_xtensa->semihost.ops = (struct esp_semihost_ops *)semihost_ops; + esp_xtensa->apptrace.hw = &esp_xtensa_apptrace_hw; return ERROR_OK; } diff --git a/src/target/espressif/esp_xtensa.h b/src/target/espressif/esp_xtensa.h index 1ad6c377f..8807f0c32 100644 --- a/src/target/espressif/esp_xtensa.h +++ b/src/target/espressif/esp_xtensa.h @@ -12,10 +12,12 @@ #include #include "esp_xtensa.h" #include "esp_semihosting.h" +#include "esp_xtensa_apptrace.h" struct esp_xtensa_common { struct xtensa xtensa; /* must be the first element */ struct esp_semihost_data semihost; + struct esp_xtensa_apptrace_info apptrace; }; static inline struct esp_xtensa_common *target_to_esp_xtensa(struct target *target) diff --git a/src/target/espressif/esp_xtensa_apptrace.c b/src/target/espressif/esp_xtensa_apptrace.c new file mode 100644 index 000000000..dfb846da0 --- /dev/null +++ b/src/target/espressif/esp_xtensa_apptrace.c @@ -0,0 +1,497 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/*************************************************************************** + * Xtensa application tracing module for OpenOCD * + * Copyright (C) 2017 Espressif Systems Ltd. * + ***************************************************************************/ + +/* + How it works? + https://github.com/espressif/esp-idf/blob/master/components/app_trace/port/xtensa/port.c#L8 +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include "esp_xtensa_apptrace.h" + +/* TRAX is disabled, so we use its registers for our own purposes + * | 31..XXXXXX..24 | 23 .(host_connect). 23 | 22 .(host_data). 22| 21..(block_id)..15 | 14..(block_len)..0 | + */ +#define XTENSA_APPTRACE_CTRL_REG XDMREG_DELAYCNT +#define XTENSA_APPTRACE_BLOCK_ID_MSK 0x7FUL +#define XTENSA_APPTRACE_BLOCK_ID_MAX XTENSA_APPTRACE_BLOCK_ID_MSK +/* if non-zero then apptrace code entered the critical section and the value is an address of the + * critical section's exit point */ +#define XTENSA_APPTRACE_STAT_REG XDMREG_TRIGGERPC + +#define XTENSA_APPTRACE_BLOCK_LEN_MSK 0x7FFFUL +#define XTENSA_APPTRACE_BLOCK_LEN(_l_) ((_l_) & XTENSA_APPTRACE_BLOCK_LEN_MSK) +#define XTENSA_APPTRACE_BLOCK_LEN_GET(_v_) ((_v_) & XTENSA_APPTRACE_BLOCK_LEN_MSK) +#define XTENSA_APPTRACE_BLOCK_ID(_id_) (((_id_) & XTENSA_APPTRACE_BLOCK_ID_MSK) << 15) +#define XTENSA_APPTRACE_BLOCK_ID_GET(_v_) (((_v_) >> 15) & XTENSA_APPTRACE_BLOCK_ID_MSK) +#define XTENSA_APPTRACE_HOST_DATA BIT(22) +#define XTENSA_APPTRACE_HOST_CONNECT BIT(23) + +static int esp_xtensa_apptrace_leave_crit_section_start(struct target *target); +static int esp_xtensa_apptrace_leave_crit_section_stop(struct target *target); +static int esp_xtensa_apptrace_buffs_write(struct target *target, + uint32_t bufs_num, + uint32_t buf_sz[], + const uint8_t *bufs[], + uint32_t block_id, + bool ack, + bool data); + +struct esp32_apptrace_hw esp_xtensa_apptrace_hw = { + .max_block_id = XTENSA_APPTRACE_BLOCK_ID_MAX, + .max_block_size_get = esp_xtensa_apptrace_block_max_size_get, + .status_reg_read = esp_xtensa_apptrace_status_reg_read, + .ctrl_reg_write = esp_xtensa_apptrace_ctrl_reg_write, + .ctrl_reg_read = esp_xtensa_apptrace_ctrl_reg_read, + .data_len_read = esp_xtensa_apptrace_data_len_read, + .data_read = esp_xtensa_apptrace_data_read, + .usr_block_max_size_get = esp_xtensa_apptrace_usr_block_max_size_get, + .buffs_write = esp_xtensa_apptrace_buffs_write, + .leave_trace_crit_section_start = esp_xtensa_apptrace_leave_crit_section_start, + .leave_trace_crit_section_stop = esp_xtensa_apptrace_leave_crit_section_stop, +}; + +uint32_t esp_xtensa_apptrace_block_max_size_get(struct target *target) +{ + struct xtensa *xtensa = target_to_xtensa(target); + struct xtensa_trace_status trace_status; + struct xtensa_trace_config trace_config; + uint32_t max_trace_block_sz; + + int res = xtensa_dm_trace_status_read(&xtensa->dbg_mod, &trace_status); + if (res != ERROR_OK) { + LOG_ERROR("Failed to read TRAX status (%d)!", res); + return 0; + } + + max_trace_block_sz = BIT(((trace_status.stat >> 8) & 0x1f) - 2) * 4; + res = xtensa_dm_trace_config_read(&xtensa->dbg_mod, &trace_config); + if (res != ERROR_OK) { + LOG_ERROR("Failed to read TRAX config (%d)!", res); + return 0; + } + LOG_DEBUG("ctrl=0x%" PRIx32 " memadrstart=0x%" PRIx32 " memadrend=0x%" PRIx32 " traxadr=0x%" PRIx32, + trace_config.ctrl, + trace_config.memaddr_start, + trace_config.memaddr_end, + trace_config.addr); + + return max_trace_block_sz; +} + +uint32_t esp_xtensa_apptrace_usr_block_max_size_get(struct target *target) +{ + return esp_xtensa_apptrace_block_max_size_get(target) - sizeof(struct esp_apptrace_host2target_hdr); +} + +int esp_xtensa_apptrace_data_len_read(struct target *target, + uint32_t *block_id, + uint32_t *len) +{ + return esp_xtensa_apptrace_ctrl_reg_read(target, block_id, len, NULL); +} + +int esp_xtensa_apptrace_usr_block_write(struct target *target, + uint32_t block_id, + const uint8_t *data, + uint32_t size) +{ + return esp_apptrace_usr_block_write(&esp_xtensa_apptrace_hw, target, block_id, data, size); +} + +static int esp_xtensa_apptrace_data_reverse_read(struct xtensa *xtensa, + uint32_t size, + uint8_t *buffer, + uint8_t *unal_bytes) +{ + int res = 0; + uint32_t rd_sz = ALIGN_UP(size, 4); + + res = xtensa_queue_dbg_reg_write(xtensa, XDMREG_TRAXADDR, (xtensa->core_config->trace.mem_sz - rd_sz) / 4); + if (res != ERROR_OK) + return res; + if (!IS_ALIGNED(size, 4)) { + res = xtensa_queue_dbg_reg_read(xtensa, XDMREG_TRAXDATA, unal_bytes); + if (res != ERROR_OK) + return res; + } + for (unsigned int i = size / 4; i != 0; i--) { + res = xtensa_queue_dbg_reg_read(xtensa, XDMREG_TRAXDATA, &buffer[(i - 1) * 4]); + if (res != ERROR_OK) + return res; + } + return ERROR_OK; +} + +static int esp_xtensa_apptrace_data_normal_read(struct xtensa *xtensa, + uint32_t size, + uint8_t *buffer, + uint8_t *unal_bytes) +{ + int res = xtensa_queue_dbg_reg_write(xtensa, XDMREG_TRAXADDR, 0); + if (res != ERROR_OK) + return res; + for (unsigned int i = 0; i < size / 4; i++) { + res = xtensa_queue_dbg_reg_read(xtensa, XDMREG_TRAXDATA, &buffer[i * 4]); + if (res != ERROR_OK) + return res; + } + if (!IS_ALIGNED(size, 4)) { + res = xtensa_queue_dbg_reg_read(xtensa, XDMREG_TRAXDATA, unal_bytes); + if (res != ERROR_OK) + return res; + } + return ERROR_OK; +} + +int esp_xtensa_apptrace_data_read(struct target *target, + uint32_t size, + uint8_t *buffer, + uint32_t block_id, + bool ack) +{ + struct xtensa *xtensa = target_to_xtensa(target); + int res; + uint32_t tmp = XTENSA_APPTRACE_HOST_CONNECT | XTENSA_APPTRACE_BLOCK_ID(block_id) | + XTENSA_APPTRACE_BLOCK_LEN(0); + uint8_t unal_bytes[4]; + + LOG_DEBUG("Read data on target (%s)", target_name(target)); + if (xtensa->core_config->trace.reversed_mem_access) + res = esp_xtensa_apptrace_data_reverse_read(xtensa, size, buffer, unal_bytes); + else + res = esp_xtensa_apptrace_data_normal_read(xtensa, size, buffer, unal_bytes); + if (res != ERROR_OK) + return res; + if (ack) { + LOG_DEBUG("Ack block %" PRIu32 " target (%s)!", block_id, target_name(target)); + res = xtensa_queue_dbg_reg_write(xtensa, XTENSA_APPTRACE_CTRL_REG, tmp); + if (res != ERROR_OK) + return res; + } + xtensa_dm_queue_tdi_idle(&xtensa->dbg_mod); + res = xtensa_dm_queue_execute(&xtensa->dbg_mod); + if (res != ERROR_OK) { + LOG_ERROR("Failed to exec JTAG queue!"); + return res; + } + if (!IS_ALIGNED(size, 4)) { + /* copy the last unaligned bytes */ + memcpy(buffer + ALIGN_DOWN(size, 4), unal_bytes, size & 0x3UL); + } + return ERROR_OK; +} + +int esp_xtensa_apptrace_ctrl_reg_write(struct target *target, + uint32_t block_id, + uint32_t len, + bool conn, + bool data) +{ + struct xtensa *xtensa = target_to_xtensa(target); + uint32_t tmp = (conn ? XTENSA_APPTRACE_HOST_CONNECT : 0) | + (data ? XTENSA_APPTRACE_HOST_DATA : 0) | XTENSA_APPTRACE_BLOCK_ID(block_id) | + XTENSA_APPTRACE_BLOCK_LEN(len); + + xtensa_queue_dbg_reg_write(xtensa, XTENSA_APPTRACE_CTRL_REG, tmp); + xtensa_dm_queue_tdi_idle(&xtensa->dbg_mod); + int res = xtensa_dm_queue_execute(&xtensa->dbg_mod); + if (res != ERROR_OK) { + LOG_ERROR("Failed to exec JTAG queue!"); + return res; + } + + return ERROR_OK; +} + +int esp_xtensa_apptrace_ctrl_reg_read(struct target *target, + uint32_t *block_id, + uint32_t *len, + bool *conn) +{ + struct xtensa *xtensa = target_to_xtensa(target); + uint8_t tmp[4]; + + xtensa_queue_dbg_reg_read(xtensa, XTENSA_APPTRACE_CTRL_REG, tmp); + xtensa_dm_queue_tdi_idle(&xtensa->dbg_mod); + int res = xtensa_dm_queue_execute(&xtensa->dbg_mod); + if (res != ERROR_OK) + return res; + uint32_t val = target_buffer_get_u32(target, tmp); + if (block_id) + *block_id = XTENSA_APPTRACE_BLOCK_ID_GET(val); + if (len) + *len = XTENSA_APPTRACE_BLOCK_LEN_GET(val); + if (conn) + *conn = val & XTENSA_APPTRACE_HOST_CONNECT; + return ERROR_OK; +} + +int esp_xtensa_apptrace_status_reg_read(struct target *target, uint32_t *stat) +{ + struct xtensa *xtensa = target_to_xtensa(target); + uint8_t tmp[4]; + + xtensa_queue_dbg_reg_read(xtensa, XTENSA_APPTRACE_STAT_REG, tmp); + xtensa_dm_queue_tdi_idle(&xtensa->dbg_mod); + int res = xtensa_dm_queue_execute(&xtensa->dbg_mod); + if (res != ERROR_OK) { + LOG_ERROR("Failed to exec JTAG queue!"); + return res; + } + *stat = buf_get_u32(tmp, 0, 32); + return ERROR_OK; +} + +int esp_xtensa_apptrace_status_reg_write(struct target *target, uint32_t stat) +{ + struct xtensa *xtensa = target_to_xtensa(target); + + xtensa_queue_dbg_reg_write(xtensa, XTENSA_APPTRACE_STAT_REG, stat); + xtensa_dm_queue_tdi_idle(&xtensa->dbg_mod); + int res = xtensa_dm_queue_execute(&xtensa->dbg_mod); + if (res != ERROR_OK) { + LOG_ERROR("Failed to exec JTAG queue!"); + return res; + } + return ERROR_OK; +} + +static int esp_xtensa_swdbg_activate(struct target *target, int enab) +{ + struct xtensa *xtensa = target_to_xtensa(target); + + xtensa_queue_dbg_reg_write(xtensa, enab ? XDMREG_DCRSET : XDMREG_DCRCLR, OCDDCR_DEBUGSWACTIVE); + xtensa_dm_queue_tdi_idle(&xtensa->dbg_mod); + int res = xtensa_dm_queue_execute(&xtensa->dbg_mod); + if (res != ERROR_OK) { + LOG_ERROR("%s: writing DCR failed!", target->cmd_name); + return res; + } + + return ERROR_OK; +} + +static int esp_xtensa_apptrace_leave_crit_section_start(struct target *target) +{ + /* TODO: not sure that we need this, but it seems that we fail to leave tracing critical + *section w/o this */ + int res = esp_xtensa_swdbg_activate(target, 1 /*enable*/); + if (res != ERROR_OK) { + LOG_ERROR("Failed to activate SW debug (%d)!", res); + return res; + } + return ERROR_OK; +} + +static int esp_xtensa_apptrace_leave_crit_section_stop(struct target *target) +{ + int res = esp_xtensa_swdbg_activate(target, 0 /*disable*/); + if (res != ERROR_OK) { + LOG_ERROR("Failed to activate SW debug (%d)!", res); + return res; + } + return ERROR_OK; +} + +static int esp_xtensa_apptrace_queue_reverse_write(struct target *target, uint32_t bufs_num, + uint32_t buf_sz[], const uint8_t *bufs[]) +{ + int res = ERROR_OK; + uint32_t cached_bytes = 0, total_sz = 0; + uint8_t cached_data8[sizeof(uint32_t)] = { 0 }; + uint32_t cached_data32 = 0; + + struct xtensa *xtensa = target_to_xtensa(target); + + for (uint32_t i = 0; i < bufs_num; i++) + total_sz += buf_sz[i]; + if (!IS_ALIGNED(total_sz, 4)) { + cached_bytes = sizeof(uint32_t) - (total_sz & 0x3UL); + total_sz = ALIGN_UP(total_sz, 4); + } + xtensa_queue_dbg_reg_write(xtensa, XDMREG_TRAXADDR, (xtensa->core_config->trace.mem_sz - total_sz) / 4); + for (uint32_t i = bufs_num; i > 0; i--) { + uint32_t bsz = buf_sz[i - 1]; + const uint8_t *cur_buf = &bufs[i - 1][bsz]; + uint32_t bytes_to_cache; + /* if there are cached bytes from the previous buffer, combine them with the last + * from the current buffer */ + if (cached_bytes) { + if ((cached_bytes + bsz) < sizeof(uint32_t)) + bytes_to_cache = bsz; + else + bytes_to_cache = sizeof(uint32_t) - cached_bytes; + memcpy(&cached_data8[sizeof(uint32_t) - cached_bytes - bytes_to_cache], + cur_buf - bytes_to_cache, + bytes_to_cache); + cached_data32 = target_buffer_get_u32(target, cached_data8); + cached_bytes += bytes_to_cache; + if (cached_bytes < sizeof(uint32_t)) + continue; + res = xtensa_queue_dbg_reg_write(xtensa, XDMREG_TRAXDATA, cached_data32); + if (res != ERROR_OK) + return res; + bsz -= bytes_to_cache; + cur_buf -= bytes_to_cache; + memset(cached_data8, 0x00, sizeof(cached_data8)); + cached_bytes = 0; + } + /* write full dwords */ + for (unsigned int k = bsz; k >= sizeof(uint32_t); k -= sizeof(uint32_t)) { + uint32_t temp = target_buffer_get_u32(target, cur_buf - sizeof(uint32_t)); + res = xtensa_queue_dbg_reg_write(xtensa, XDMREG_TRAXDATA, temp); + if (res != ERROR_OK) + return res; + cur_buf -= sizeof(uint32_t); + } + /* if there are bytes to be cached (1..3) */ + bytes_to_cache = bsz & 0x3UL; + if (bytes_to_cache > 0) { + if (bytes_to_cache + cached_bytes >= sizeof(uint32_t)) { + /* filling the cache buffer from the end to beginning */ + uint32_t to_copy = sizeof(uint32_t) - cached_bytes; + memcpy(&cached_data8[0], cur_buf - to_copy, to_copy); + cached_data32 = target_buffer_get_u32(target, cached_data8); + /* write full word of cached bytes */ + res = xtensa_queue_dbg_reg_write(xtensa, XDMREG_TRAXDATA, cached_data32); + if (res != ERROR_OK) + return res; + /* cache remaining bytes */ + memset(cached_data8, 0x00, sizeof(cached_data8)); + cur_buf -= to_copy; + to_copy = bytes_to_cache + cached_bytes - sizeof(uint32_t); + memcpy(&cached_data8[sizeof(uint32_t) - to_copy], cur_buf - to_copy, to_copy); + cached_bytes = to_copy; + } else { + /* filling the cache buffer from the end to beginning */ + memcpy(&cached_data8[sizeof(uint32_t) - cached_bytes - bytes_to_cache], + cur_buf - bytes_to_cache, + bytes_to_cache); + cached_bytes += bytes_to_cache; + } + } + } + return ERROR_OK; +} + +static int esp_xtensa_apptrace_queue_normal_write(struct target *target, uint32_t bufs_num, + uint32_t buf_sz[], const uint8_t *bufs[]) +{ + int res = ERROR_OK; + uint32_t cached_bytes = 0; + uint8_t cached_data8[4] = { 0 }; + uint32_t cached_data32 = 0; + + struct xtensa *xtensa = target_to_xtensa(target); + + /* | 1 | 2 | 1 | 2 | 4 |.......| + * | 4 | 4 | 4 | */ + xtensa_queue_dbg_reg_write(xtensa, XDMREG_TRAXADDR, 0); + for (unsigned int i = 0; i < bufs_num; i++) { + uint32_t bsz = buf_sz[i]; + const uint8_t *cur_buf = bufs[i]; + uint32_t bytes_to_cache; + /* if there are cached bytes from the previous buffer, combine them with the last + * from the current buffer */ + if (cached_bytes) { + if ((cached_bytes + bsz) < sizeof(uint32_t)) + bytes_to_cache = bsz; + else + bytes_to_cache = sizeof(uint32_t) - cached_bytes; + memcpy(&cached_data8[cached_bytes], cur_buf, bytes_to_cache); + cached_bytes += bytes_to_cache; + if (cached_bytes < sizeof(uint32_t)) + continue; + cached_data32 = target_buffer_get_u32(target, cached_data8); + res = xtensa_queue_dbg_reg_write(xtensa, XDMREG_TRAXDATA, cached_data32); + if (res != ERROR_OK) + return res; + bsz -= bytes_to_cache; + cur_buf += bytes_to_cache; + memset(cached_data8, 0x00, sizeof(cached_data8)); + cached_bytes = 0; + } + /* write full dwords */ + for (unsigned int k = 0; (k + sizeof(uint32_t)) <= bsz; k += sizeof(uint32_t)) { + uint32_t temp = target_buffer_get_u32(target, cur_buf); + res = xtensa_queue_dbg_reg_write(xtensa, XDMREG_TRAXDATA, temp); + if (res != ERROR_OK) + return res; + cur_buf += sizeof(uint32_t); + } + /* if there are bytes to be cached (1..3) */ + bytes_to_cache = bsz & 0x3UL; + if (bytes_to_cache > 0) { + if (bytes_to_cache + cached_bytes >= sizeof(uint32_t)) { + memcpy(&cached_data8[0], cur_buf, sizeof(uint32_t) - cached_bytes); + cached_data32 = target_buffer_get_u32(target, cached_data8); + /* write full word of cached bytes */ + res = xtensa_queue_dbg_reg_write(xtensa, XDMREG_TRAXDATA, cached_data32); + if (res != ERROR_OK) + return res; + /* cache remaining bytes */ + memset(cached_data8, 0x00, sizeof(cached_data8)); + cur_buf += sizeof(uint32_t) - cached_bytes; + cached_bytes = bytes_to_cache + cached_bytes - sizeof(uint32_t); + memcpy(&cached_data8[0], cur_buf, cached_bytes); + } else { + memcpy(&cached_data8[cached_bytes], cur_buf, bytes_to_cache); + cached_bytes += bytes_to_cache; + } + } + } + if (cached_bytes) { + /* write remaining cached bytes */ + cached_data32 = target_buffer_get_u32(target, cached_data8); + res = xtensa_queue_dbg_reg_write(xtensa, XDMREG_TRAXDATA, cached_data32); + if (res != ERROR_OK) + return res; + } + return ERROR_OK; +} + +static int esp_xtensa_apptrace_buffs_write(struct target *target, + uint32_t bufs_num, + uint32_t buf_sz[], + const uint8_t *bufs[], + uint32_t block_id, + bool ack, + bool data) +{ + struct xtensa *xtensa = target_to_xtensa(target); + int res = ERROR_OK; + uint32_t tmp = XTENSA_APPTRACE_HOST_CONNECT | + (data ? XTENSA_APPTRACE_HOST_DATA : 0) | XTENSA_APPTRACE_BLOCK_ID(block_id) | + XTENSA_APPTRACE_BLOCK_LEN(0); + + if (xtensa->core_config->trace.reversed_mem_access) + res = esp_xtensa_apptrace_queue_reverse_write(target, bufs_num, buf_sz, bufs); + else + res = esp_xtensa_apptrace_queue_normal_write(target, bufs_num, buf_sz, bufs); + if (res != ERROR_OK) + return res; + if (ack) { + LOG_DEBUG("Ack block %" PRId32 " on target (%s)!", block_id, target_name(target)); + res = xtensa_queue_dbg_reg_write(xtensa, XTENSA_APPTRACE_CTRL_REG, tmp); + if (res != ERROR_OK) + return res; + } + xtensa_dm_queue_tdi_idle(&xtensa->dbg_mod); + res = xtensa_dm_queue_execute(&xtensa->dbg_mod); + if (res != ERROR_OK) { + LOG_ERROR("Failed to exec JTAG queue!"); + return res; + } + return ERROR_OK; +} diff --git a/src/target/espressif/esp_xtensa_apptrace.h b/src/target/espressif/esp_xtensa_apptrace.h new file mode 100644 index 000000000..0a9be731f --- /dev/null +++ b/src/target/espressif/esp_xtensa_apptrace.h @@ -0,0 +1,37 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/*************************************************************************** + * Xtensa application tracing module for OpenOCD * + * Copyright (C) 2017 Espressif Systems Ltd. * + ***************************************************************************/ + +#ifndef OPENOCD_TARGET_ESP_XTENSA_APPTRACE_H +#define OPENOCD_TARGET_ESP_XTENSA_APPTRACE_H + +#include "esp32_apptrace.h" + +struct esp_xtensa_apptrace_info { + const struct esp32_apptrace_hw *hw; +}; + +extern struct esp32_apptrace_hw esp_xtensa_apptrace_hw; + +int esp_xtensa_apptrace_data_len_read(struct target *target, uint32_t *block_id, uint32_t *len); +int esp_xtensa_apptrace_data_read(struct target *target, + uint32_t size, + uint8_t *buffer, + uint32_t block_id, + bool ack); +int esp_xtensa_apptrace_ctrl_reg_read(struct target *target, uint32_t *block_id, uint32_t *len, bool *conn); +int esp_xtensa_apptrace_ctrl_reg_write(struct target *target, + uint32_t block_id, + uint32_t len, + bool conn, + bool data); +int esp_xtensa_apptrace_status_reg_write(struct target *target, uint32_t stat); +int esp_xtensa_apptrace_status_reg_read(struct target *target, uint32_t *stat); +uint32_t esp_xtensa_apptrace_block_max_size_get(struct target *target); +uint32_t esp_xtensa_apptrace_usr_block_max_size_get(struct target *target); +int esp_xtensa_apptrace_usr_block_write(struct target *target, uint32_t block_id, const uint8_t *data, uint32_t size); + +#endif /* OPENOCD_TARGET_ESP_XTENSA_APPTRACE_H */ From 1c31f6225f41dd2bd371571e829fbf6855788d24 Mon Sep 17 00:00:00 2001 From: panciyan Date: Fri, 31 Mar 2023 15:12:08 +0000 Subject: [PATCH 02/49] src/server: Fix memory leak of reg_list memory leak of reg_list when local_list realloc fail. Signed-off-by: panciyan Change-Id: I6b09137ecd132ab326205f5a575a38bcc82e8469 Reviewed-on: https://review.openocd.org/c/openocd/+/7566 Tested-by: jenkins Reviewed-by: Antonio Borneo --- src/server/gdb_server.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/server/gdb_server.c b/src/server/gdb_server.c index d8dbc2c8b..b15a6c1c3 100644 --- a/src/server/gdb_server.c +++ b/src/server/gdb_server.c @@ -2348,6 +2348,7 @@ static int smp_reg_list_noread(struct target *target, local_list = realloc(local_list, combined_allocated * sizeof(struct reg *)); if (!local_list) { LOG_ERROR("realloc(%zu) failed", combined_allocated * sizeof(struct reg *)); + free(reg_list); return ERROR_FAIL; } } From 1e6df1675ccea95d99d767e6d2b9a735c8ee2a36 Mon Sep 17 00:00:00 2001 From: panciyan Date: Sun, 2 Apr 2023 05:17:17 +0000 Subject: [PATCH 03/49] rtos/linux.c: Fix Linux user space border check Linux kernel and user space border is 0xc0000000 not 0xc000000 Signed-off-by: panciyan Change-Id: I6b487cce62ac31737deca97d5f5f7bbc081280f4 Reviewed-on: https://review.openocd.org/c/openocd/+/7570 Tested-by: jenkins Reviewed-by: Antonio Borneo --- src/rtos/linux.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rtos/linux.c b/src/rtos/linux.c index f9edabc2b..7517ec7a9 100644 --- a/src/rtos/linux.c +++ b/src/rtos/linux.c @@ -123,7 +123,7 @@ static int linux_read_memory(struct target *target, target->rtos->rtos_specific_params; uint32_t pa = (address & linux_os->phys_mask) + linux_os->phys_base; #endif - if (address < 0xc000000) { + if (address < 0xc0000000) { LOG_ERROR("linux awareness : address in user space"); return ERROR_FAIL; } From 95c27731d4f76c0554147030075ab476d68f9f83 Mon Sep 17 00:00:00 2001 From: Mark Zhuang Date: Mon, 10 Apr 2023 10:57:55 +0800 Subject: [PATCH 04/49] flash/rsl10: fix typo Change-Id: I11af37309fe4684fcb340a00fcc7b2096b8dad76 Signed-off-by: Mark Zhuang Reviewed-on: https://review.openocd.org/c/openocd/+/7584 Tested-by: jenkins Reviewed-by: Antonio Borneo --- contrib/loaders/flash/rsl10/rom_launcher.S | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/loaders/flash/rsl10/rom_launcher.S b/contrib/loaders/flash/rsl10/rom_launcher.S index 70f000e72..aafedfb46 100644 --- a/contrib/loaders/flash/rsl10/rom_launcher.S +++ b/contrib/loaders/flash/rsl10/rom_launcher.S @@ -21,7 +21,7 @@ .global _start _start: launch_program_in_rom: - // variables are already set, addres to jump is in r3 + // variables are already set, address to jump is in r3 blx r3 exit: // Wait for OpenOCD From 91bd4313444c5a949ce49d88ab487608df7d6c37 Mon Sep 17 00:00:00 2001 From: Daniel Anselmi Date: Wed, 14 Dec 2022 09:27:38 +0100 Subject: [PATCH 05/49] pld: move file sanity checks to pld.c Change-Id: Id64b1165b25a03634949ac22b8af16eb0e24c1fa Signed-off-by: Daniel Anselmi Reviewed-on: https://review.openocd.org/c/openocd/+/7388 Tested-by: jenkins Reviewed-by: Antonio Borneo --- src/pld/pld.c | 17 +++++++++++++++++ src/pld/xilinx_bit.c | 17 ----------------- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/pld/pld.c b/src/pld/pld.c index e2e0ef413..af1836907 100644 --- a/src/pld/pld.c +++ b/src/pld/pld.c @@ -10,6 +10,7 @@ #endif #include "pld.h" +#include #include #include #include @@ -134,6 +135,22 @@ COMMAND_HANDLER(handle_pld_load_command) return ERROR_OK; } + struct stat input_stat; + if (stat(CMD_ARGV[1], &input_stat) == -1) { + LOG_ERROR("couldn't stat() %s: %s", CMD_ARGV[1], strerror(errno)); + return ERROR_PLD_FILE_LOAD_FAILED; + } + + if (S_ISDIR(input_stat.st_mode)) { + LOG_ERROR("%s is a directory", CMD_ARGV[1]); + return ERROR_PLD_FILE_LOAD_FAILED; + } + + if (input_stat.st_size == 0) { + LOG_ERROR("Empty file %s", CMD_ARGV[1]); + return ERROR_PLD_FILE_LOAD_FAILED; + } + retval = p->driver->load(p, CMD_ARGV[1]); if (retval != ERROR_OK) { command_print(CMD, "failed loading file %s to pld device %u", diff --git a/src/pld/xilinx_bit.c b/src/pld/xilinx_bit.c index 792b3375b..e4cc52ef9 100644 --- a/src/pld/xilinx_bit.c +++ b/src/pld/xilinx_bit.c @@ -13,7 +13,6 @@ #include "pld.h" #include -#include #include static int read_section(FILE *input_file, int length_size, char section, @@ -60,27 +59,11 @@ static int read_section(FILE *input_file, int length_size, char section, int xilinx_read_bit_file(struct xilinx_bit_file *bit_file, const char *filename) { FILE *input_file; - struct stat input_stat; int read_count; if (!filename || !bit_file) return ERROR_COMMAND_SYNTAX_ERROR; - if (stat(filename, &input_stat) == -1) { - LOG_ERROR("couldn't stat() %s: %s", filename, strerror(errno)); - return ERROR_PLD_FILE_LOAD_FAILED; - } - - if (S_ISDIR(input_stat.st_mode)) { - LOG_ERROR("%s is a directory", filename); - return ERROR_PLD_FILE_LOAD_FAILED; - } - - if (input_stat.st_size == 0) { - LOG_ERROR("Empty file %s", filename); - return ERROR_PLD_FILE_LOAD_FAILED; - } - input_file = fopen(filename, "rb"); if (!input_file) { LOG_ERROR("couldn't open %s: %s", filename, strerror(errno)); From 0bb0056abc269ed14b04cbb1d768fb0281e64225 Mon Sep 17 00:00:00 2001 From: Julien Massot Date: Wed, 12 Jan 2022 14:10:36 +0100 Subject: [PATCH 06/49] target:armv8: aarch32 do not try to restore same EL While debugging a Cortex-R52 OpenOCD fail to restore context on line retval = dpm->instr_write_data_r0(dpm, ARMV8_MSR_GP_xPSR_T1(1, 0, 15), cpsr); which trigger this exception: aarch64.c:1206 aarch64_restore_context(): r8a779a0.r52 armv8_dpm.c:560 armv8_dpm_modeswitch(): restoring mode, cpsr = 0x0000011f 1262753 armv8_dpm.c:598 armv8_dpm_modeswitch(): target_el = 1, last_el = 1 armv8_dpm.c:611 armv8_dpm_modeswitch(): SPSR = 0x0000011f armv8_dpm.c:260 dpmv8_exec_opcode(): Opcode 0x8f00f390, DSCR.ERR=1, DSCR.EL=1 and finally OpenOCD doesn't succeed to restore the processor. This check 'dpm->last_el != target_el' exist for aarch64, so might be correct for aarch32 too. Signed-off-by: Julien Massot Change-Id: I41d1006233251dcaf6d69bda580488b204b7eb63 Reviewed-on: https://review.openocd.org/c/openocd/+/6807 Tested-by: jenkins Reviewed-by: Antonio Borneo --- src/target/armv8_dpm.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/target/armv8_dpm.c b/src/target/armv8_dpm.c index f40beb847..fcd4d5971 100644 --- a/src/target/armv8_dpm.c +++ b/src/target/armv8_dpm.c @@ -587,6 +587,9 @@ int armv8_dpm_modeswitch(struct arm_dpm *dpm, enum arm_mode mode) } LOG_DEBUG("target_el = %i, last_el = %i", target_el, dpm->last_el); + if (dpm->last_el == target_el) + return ERROR_OK; /* nothing to do */ + if (target_el > dpm->last_el) { retval = dpm->instr_execute(dpm, armv8_opcode(armv8, ARMV8_OPC_DCPS) | target_el); From 2096afc1b031280107ada81fb729d5e7c9075626 Mon Sep 17 00:00:00 2001 From: Julien Massot Date: Tue, 1 Feb 2022 13:44:05 +0100 Subject: [PATCH 07/49] aarch64: Add support for ARMv8-R ARMv8-R platforms are similar to ARMv8-A regarding JTAG and most cpu registers. ARMv8-R doesn't has MMU but has MPU instead. ARMv8-R platforms can be AArch32 only such as Cortex-R52, or AArch64 capable like Cortex-R82. Signed-off-by: Julien Massot Change-Id: Ib086f71685d1e3704b396d478ae9399dd8a391e1 Reviewed-on: https://review.openocd.org/c/openocd/+/6843 Tested-by: jenkins Reviewed-by: Antonio Borneo --- src/target/aarch64.c | 72 +++++++++++++++++++++++++++++++++++++++++--- src/target/armv8.h | 1 + src/target/target.c | 2 ++ 3 files changed, 71 insertions(+), 4 deletions(-) diff --git a/src/target/aarch64.c b/src/target/aarch64.c index 3c33032e9..6c9673fa2 100644 --- a/src/target/aarch64.c +++ b/src/target/aarch64.c @@ -1066,9 +1066,12 @@ static int aarch64_post_debug_entry(struct target *target) armv8_identify_cache(armv8); armv8_read_mpidr(armv8); } - - armv8->armv8_mmu.mmu_enabled = + if (armv8->is_armv8r) { + armv8->armv8_mmu.mmu_enabled = 0; + } else { + armv8->armv8_mmu.mmu_enabled = (aarch64->system_control_reg & 0x1U) ? 1 : 0; + } armv8->armv8_mmu.armv8_cache.d_u_cache_enabled = (aarch64->system_control_reg & 0x4U) ? 1 : 0; armv8->armv8_mmu.armv8_cache.i_cache_enabled = @@ -2726,6 +2729,25 @@ static int aarch64_init_arch_info(struct target *target, return ERROR_OK; } +static int armv8r_target_create(struct target *target, Jim_Interp *interp) +{ + struct aarch64_private_config *pc = target->private_config; + struct aarch64_common *aarch64; + + if (adiv5_verify_config(&pc->adiv5_config) != ERROR_OK) + return ERROR_FAIL; + + aarch64 = calloc(1, sizeof(struct aarch64_common)); + if (!aarch64) { + LOG_ERROR("Out of memory"); + return ERROR_FAIL; + } + + aarch64->armv8_common.is_armv8r = true; + + return aarch64_init_arch_info(target, aarch64, pc->adiv5_config.dap); +} + static int aarch64_target_create(struct target *target, Jim_Interp *interp) { struct aarch64_private_config *pc = target->private_config; @@ -2740,6 +2762,8 @@ static int aarch64_target_create(struct target *target, Jim_Interp *interp) return ERROR_FAIL; } + aarch64->armv8_common.is_armv8r = false; + return aarch64_init_arch_info(target, aarch64, pc->adiv5_config.dap); } @@ -2762,12 +2786,16 @@ static void aarch64_deinit_target(struct target *target) static int aarch64_mmu(struct target *target, int *enabled) { + struct aarch64_common *aarch64 = target_to_aarch64(target); + struct armv8_common *armv8 = &aarch64->armv8_common; if (target->state != TARGET_HALTED) { LOG_ERROR("%s: target %s not halted", __func__, target_name(target)); return ERROR_TARGET_INVALID; } - - *enabled = target_to_aarch64(target)->armv8_common.armv8_mmu.mmu_enabled; + if (armv8->is_armv8r) + *enabled = 0; + else + *enabled = target_to_aarch64(target)->armv8_common.armv8_mmu.mmu_enabled; return ERROR_OK; } @@ -3165,3 +3193,39 @@ struct target_type aarch64_target = { .mmu = aarch64_mmu, .virt2phys = aarch64_virt2phys, }; + +struct target_type armv8r_target = { + .name = "armv8r", + + .poll = aarch64_poll, + .arch_state = armv8_arch_state, + + .halt = aarch64_halt, + .resume = aarch64_resume, + .step = aarch64_step, + + .assert_reset = aarch64_assert_reset, + .deassert_reset = aarch64_deassert_reset, + + /* REVISIT allow exporting VFP3 registers ... */ + .get_gdb_arch = armv8_get_gdb_arch, + .get_gdb_reg_list = armv8_get_gdb_reg_list, + + .read_memory = aarch64_read_phys_memory, + .write_memory = aarch64_write_phys_memory, + + .add_breakpoint = aarch64_add_breakpoint, + .add_context_breakpoint = aarch64_add_context_breakpoint, + .add_hybrid_breakpoint = aarch64_add_hybrid_breakpoint, + .remove_breakpoint = aarch64_remove_breakpoint, + .add_watchpoint = aarch64_add_watchpoint, + .remove_watchpoint = aarch64_remove_watchpoint, + .hit_watchpoint = aarch64_hit_watchpoint, + + .commands = aarch64_command_handlers, + .target_create = armv8r_target_create, + .target_jim_configure = aarch64_jim_configure, + .init_target = aarch64_init_target, + .deinit_target = aarch64_deinit_target, + .examine = aarch64_examine, +}; diff --git a/src/target/armv8.h b/src/target/armv8.h index 54aa08634..f5aa21109 100644 --- a/src/target/armv8.h +++ b/src/target/armv8.h @@ -204,6 +204,7 @@ struct armv8_common { uint8_t pa_size; uint32_t page_size; uint64_t ttbr_base; + bool is_armv8r; struct armv8_mmu_common armv8_mmu; diff --git a/src/target/target.c b/src/target/target.c index 47abd2823..6c0f4afb1 100644 --- a/src/target/target.c +++ b/src/target/target.c @@ -82,6 +82,7 @@ extern struct target_type cortexm_target; extern struct target_type cortexa_target; extern struct target_type aarch64_target; extern struct target_type cortexr4_target; +extern struct target_type armv8r_target; extern struct target_type arm11_target; extern struct target_type ls1_sap_target; extern struct target_type mips_m4k_target; @@ -141,6 +142,7 @@ static struct target_type *target_types[] = { &esirisc_target, &arcv2_target, &aarch64_target, + &armv8r_target, &mips_mips64_target, NULL, }; From 3dfc0339fc85d467bed5cd435bb953bc7d3b9343 Mon Sep 17 00:00:00 2001 From: Julien Massot Date: Wed, 12 Jan 2022 09:53:06 +0100 Subject: [PATCH 08/49] tcl/target: renesas gen3 Set target to armv8r for Cortex-R52 Cortex-R52 is an ARMv8-R processor supporting only AArch32 Profile. Signed-off-by: Julien Massot Change-Id: I663ae4bf1d3026d7c9e4c5950a79e7ddf1bd6564 Reviewed-on: https://review.openocd.org/c/openocd/+/6805 Tested-by: jenkins Reviewed-by: Antonio Borneo --- tcl/target/renesas_rcar_gen3.cfg | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/tcl/target/renesas_rcar_gen3.cfg b/tcl/target/renesas_rcar_gen3.cfg index 3e449832f..8dc0e7a0d 100644 --- a/tcl/target/renesas_rcar_gen3.cfg +++ b/tcl/target/renesas_rcar_gen3.cfg @@ -156,15 +156,20 @@ proc setup_a5x {core_name dbgbase ctibase num boot} { } } -proc setup_cr7 {core_name dbgbase ctibase num boot} { +proc setup_crx {core_name dbgbase ctibase num boot} { global _CHIPNAME global _DAPNAME for { set _core 0 } { $_core < $num } { incr _core } { set _TARGETNAME $_CHIPNAME.$core_name set _CTINAME $_TARGETNAME.cti cti create $_CTINAME -dap $_DAPNAME -ap-num 1 -baseaddr $ctibase - set _command "target create $_TARGETNAME cortex_r4 -dap $_DAPNAME \ - -ap-num 1 -dbgbase $dbgbase" + if { $core_name == "r52" } { + set _command "target create $_TARGETNAME armv8r -dap $_DAPNAME \ + -ap-num 1 -dbgbase $dbgbase -cti $_CTINAME" + } else { + set _command "target create $_TARGETNAME cortex_r4 -dap $_DAPNAME \ + -ap-num 1 -dbgbase $dbgbase" + } if { $boot == 1 } { set _targets "$_TARGETNAME" } else { @@ -177,20 +182,20 @@ proc setup_cr7 {core_name dbgbase ctibase num boot} { # Organize target list based on the boot core if { [string equal $_boot_core CA76] } { setup_a5x a76 $CA76_DBGBASE $CA76_CTIBASE $_num_ca76 1 - setup_cr7 r52 $CR52_DBGBASE $CR52_CTIBASE $_num_cr52 0 + setup_crx r52 $CR52_DBGBASE $CR52_CTIBASE $_num_cr52 0 } elseif { [string equal $_boot_core CA57] } { setup_a5x a57 $CA57_DBGBASE $CA57_CTIBASE $_num_ca57 1 setup_a5x a53 $CA53_DBGBASE $CA53_CTIBASE $_num_ca53 0 - setup_cr7 r7 $CR7_DBGBASE $CR7_CTIBASE $_num_cr7 0 + setup_crx r7 $CR7_DBGBASE $CR7_CTIBASE $_num_cr7 0 } elseif { [string equal $_boot_core CA53] } { setup_a5x a53 $CA53_DBGBASE $CA53_CTIBASE $_num_ca53 1 setup_a5x a57 $CA57_DBGBASE $CA57_CTIBASE $_num_ca57 0 - setup_cr7 r7 $CR7_DBGBASE $CR7_CTIBASE $_num_cr7 0 + setup_crx r7 $CR7_DBGBASE $CR7_CTIBASE $_num_cr7 0 } elseif { [string equal $_boot_core CR52] } { - setup_cr7 r52 $CR52_DBGBASE $CR52_CTIBASE $_num_cr52 1 + setup_crx r52 $CR52_DBGBASE $CR52_CTIBASE $_num_cr52 1 setup_a5x a76 $CA76_DBGBASE $CA76_CTIBASE $_num_ca76 0 } else { - setup_cr7 r7 $CR7_DBGBASE $CR7_CTIBASE $_num_cr7 1 + setup_crx r7 $CR7_DBGBASE $CR7_CTIBASE $_num_cr7 1 setup_a5x a57 $CA57_DBGBASE $CA57_CTIBASE $_num_ca57 0 setup_a5x a53 $CA53_DBGBASE $CA53_CTIBASE $_num_ca53 0 } From babec0fafa7141515c606790947f66bde46396b8 Mon Sep 17 00:00:00 2001 From: Daniel Anselmi Date: Tue, 11 Apr 2023 10:18:33 +0200 Subject: [PATCH 09/49] server/ipdbg: add error checks after allocating memory Change-Id: Icf18a855eb66d2b09789a9ee27f5fbc4cd9afc89 Signed-off-by: Daniel Anselmi Reviewed-on: https://review.openocd.org/c/openocd/+/7605 Tested-by: jenkins Reviewed-by: Antonio Borneo --- src/server/ipdbg.c | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/src/server/ipdbg.c b/src/server/ipdbg.c index 755d0510e..69d0f5755 100644 --- a/src/server/ipdbg.c +++ b/src/server/ipdbg.c @@ -315,6 +315,10 @@ static int ipdbg_shift_instr(struct ipdbg_hub *hub, uint32_t instr) } uint8_t *ir_out_val = calloc(DIV_ROUND_UP(tap->ir_length, 8), 1); + if (!ir_out_val) { + LOG_ERROR("Out of memory"); + return ERROR_FAIL; + } buf_set_u32(ir_out_val, 0, tap->ir_length, instr); struct scan_field fields; @@ -344,6 +348,10 @@ static int ipdbg_shift_vir(struct ipdbg_hub *hub) return ERROR_FAIL; uint8_t *dr_out_val = calloc(DIV_ROUND_UP(hub->virtual_ir->length, 8), 1); + if (!dr_out_val) { + LOG_ERROR("Out of memory"); + return ERROR_FAIL; + } buf_set_u32(dr_out_val, 0, hub->virtual_ir->length, hub->virtual_ir->value); struct scan_field fields; @@ -366,8 +374,21 @@ static int ipdbg_shift_data(struct ipdbg_hub *hub, uint32_t dn_data, uint32_t *u return ERROR_FAIL; uint8_t *dr_out_val = calloc(DIV_ROUND_UP(hub->data_register_length, 8), 1); + if (!dr_out_val) { + LOG_ERROR("Out of memory"); + return ERROR_FAIL; + } buf_set_u32(dr_out_val, 0, hub->data_register_length, dn_data); - uint8_t *dr_in_val = up_data ? calloc(DIV_ROUND_UP(hub->data_register_length, 8), 1) : NULL; + + uint8_t *dr_in_val = NULL; + if (up_data) { + dr_in_val = calloc(DIV_ROUND_UP(hub->data_register_length, 8), 1); + if (!dr_in_val) { + LOG_ERROR("Out of memory"); + free(dr_out_val); + return ERROR_FAIL; + } + } struct scan_field fields; ipdbg_init_scan_field(&fields, dr_in_val, hub->data_register_length, dr_out_val); From bb073f897cd37a6253e49c5628a98a59fccf2ea5 Mon Sep 17 00:00:00 2001 From: Erhan Kurubas Date: Sun, 2 Apr 2023 00:26:51 +0200 Subject: [PATCH 10/49] src: fix clang15 compiler warnings Below warnings are fixed. 1- A function declaration without a prototype is deprecated in all versions of C [-Werror,-Wstrict-prototypes] 2- error: variable set but not used [-Werror,-Wunused-but-set-variable] Signed-off-by: Erhan Kurubas Change-Id: I1cf14b8e5e3e732ebc9cacc4b1cb9009276a8ea9 Reviewed-on: https://review.openocd.org/c/openocd/+/7569 Reviewed-by: Antonio Borneo Tested-by: jenkins --- src/server/gdb_server.c | 8 ++------ src/target/arm7_9_common.c | 2 -- src/target/riscv/riscv.c | 2 -- src/target/target.c | 4 ++-- 4 files changed, 4 insertions(+), 12 deletions(-) diff --git a/src/server/gdb_server.c b/src/server/gdb_server.c index b15a6c1c3..4fdbc9fbb 100644 --- a/src/server/gdb_server.c +++ b/src/server/gdb_server.c @@ -2977,7 +2977,8 @@ static int gdb_query_packet(struct connection *connection, return ERROR_OK; } -static bool gdb_handle_vcont_packet(struct connection *connection, const char *packet, int packet_size) +static bool gdb_handle_vcont_packet(struct connection *connection, const char *packet, + __attribute__((unused)) int packet_size) { struct gdb_connection *gdb_connection = connection->priv; struct target *target = get_target_from_connection(connection); @@ -2996,7 +2997,6 @@ static bool gdb_handle_vcont_packet(struct connection *connection, const char *p if (parse[0] == ';') { ++parse; - --packet_size; } /* simple case, a continue packet */ @@ -3035,14 +3035,11 @@ static bool gdb_handle_vcont_packet(struct connection *connection, const char *p int current_pc = 1; int64_t thread_id; parse++; - packet_size--; if (parse[0] == ':') { char *endp; parse++; - packet_size--; thread_id = strtoll(parse, &endp, 16); if (endp) { - packet_size -= endp - parse; parse = endp; } } else { @@ -3065,7 +3062,6 @@ static bool gdb_handle_vcont_packet(struct connection *connection, const char *p if (parse[0] == ';') { ++parse; - --packet_size; if (parse[0] == 'c') { parse += 1; diff --git a/src/target/arm7_9_common.c b/src/target/arm7_9_common.c index 8f87d9cda..0632290d9 100644 --- a/src/target/arm7_9_common.c +++ b/src/target/arm7_9_common.c @@ -1553,7 +1553,6 @@ static int arm7_9_restore_context(struct target *target) if (dirty) { uint32_t mask = 0x0; - int num_regs = 0; uint32_t regs[16]; if (mode_change) { @@ -1576,7 +1575,6 @@ static int arm7_9_restore_context(struct target *target) if (reg->dirty) { regs[j] = buf_get_u32(reg->value, 0, 32); mask |= 1 << j; - num_regs++; reg->dirty = false; reg->valid = true; LOG_DEBUG("writing register %i mode %s " diff --git a/src/target/riscv/riscv.c b/src/target/riscv/riscv.c index 8dafa02b4..865abd080 100644 --- a/src/target/riscv/riscv.c +++ b/src/target/riscv/riscv.c @@ -2187,7 +2187,6 @@ int riscv_openocd_poll(struct target *target) int halted_hart = -1; if (target->smp) { - unsigned halts_discovered = 0; unsigned should_remain_halted = 0; unsigned should_resume = 0; struct target_list *list; @@ -2203,7 +2202,6 @@ int riscv_openocd_poll(struct target *target) t->debug_reason = DBG_REASON_NOTHALTED; break; case RPH_DISCOVERED_HALTED: - halts_discovered++; t->state = TARGET_HALTED; enum riscv_halt_reason halt_reason = riscv_halt_reason(t, r->current_hartid); diff --git a/src/target/target.c b/src/target/target.c index 6c0f4afb1..c55b67cc9 100644 --- a/src/target/target.c +++ b/src/target/target.c @@ -1940,13 +1940,13 @@ static int target_call_timer_callbacks_check_time(int checktime) return ERROR_OK; } -int target_call_timer_callbacks() +int target_call_timer_callbacks(void) { return target_call_timer_callbacks_check_time(1); } /* invoke periodic callbacks immediately */ -int target_call_timer_callbacks_now() +int target_call_timer_callbacks_now(void) { return target_call_timer_callbacks_check_time(0); } From c1dc7935f78973e89dfe10e5b93238ae3f4eacd3 Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Sat, 15 Apr 2023 00:21:42 +0200 Subject: [PATCH 11/49] target/espressif: fix clang report on use of garbage value When the function xtensa_queue_dbg_reg_read() returns error, the array 'tmp' remains not initialized and scan-build complains while computing buf_get_u32() that: Result of operation is garbage or undefined Check the returned value of xtensa_queue_dbg_reg_read() and propagate it. Change-Id: If0aaad068b97ef0a76560e262d16429afd469585 Signed-off-by: Antonio Borneo Fixes: 8d1dcf293a0c ("target/espressif: add application tracing functionality over JTAG") Reviewed-on: https://review.openocd.org/c/openocd/+/7607 Tested-by: jenkins Reviewed-by: Erhan Kurubas --- src/target/espressif/esp_xtensa_apptrace.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/target/espressif/esp_xtensa_apptrace.c b/src/target/espressif/esp_xtensa_apptrace.c index dfb846da0..5741ab030 100644 --- a/src/target/espressif/esp_xtensa_apptrace.c +++ b/src/target/espressif/esp_xtensa_apptrace.c @@ -242,9 +242,11 @@ int esp_xtensa_apptrace_status_reg_read(struct target *target, uint32_t *stat) struct xtensa *xtensa = target_to_xtensa(target); uint8_t tmp[4]; - xtensa_queue_dbg_reg_read(xtensa, XTENSA_APPTRACE_STAT_REG, tmp); + int res = xtensa_queue_dbg_reg_read(xtensa, XTENSA_APPTRACE_STAT_REG, tmp); + if (res != ERROR_OK) + return res; xtensa_dm_queue_tdi_idle(&xtensa->dbg_mod); - int res = xtensa_dm_queue_execute(&xtensa->dbg_mod); + res = xtensa_dm_queue_execute(&xtensa->dbg_mod); if (res != ERROR_OK) { LOG_ERROR("Failed to exec JTAG queue!"); return res; From 8670ad4caa705c460972badbd0fc28aa98c41866 Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Sat, 15 Apr 2023 00:25:54 +0200 Subject: [PATCH 12/49] target/espressif: fix clang report on list use It looks like a false positive. Scan-build considers as possible to: - have list_empty() return false; - list_for_each_safe() to not execute any loop, thus not assigning a non-NULL value to 'block'; - the NULL pointer 'block' is passed to list_del(). This is not possible because with list_empty(), the loop runs at least once. Rewrite the function to simplify the code and making it easier for scan-build to check it. This also drops an incorrect use of list_for_each_safe(), where the 'safe' version was not required. Change-Id: Ia8b1d221cf9df73db1196e3f51986023dcaf78eb Signed-off-by: Antonio Borneo Fixes: 8d1dcf293a0c ("target/espressif: add application tracing functionality over JTAG") Reviewed-on: https://review.openocd.org/c/openocd/+/7608 Reviewed-by: Erhan Kurubas Tested-by: jenkins --- src/target/espressif/esp32_apptrace.c | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/src/target/espressif/esp32_apptrace.c b/src/target/espressif/esp32_apptrace.c index dfeb79401..291503e53 100644 --- a/src/target/espressif/esp32_apptrace.c +++ b/src/target/espressif/esp32_apptrace.c @@ -356,18 +356,14 @@ static int esp32_apptrace_ready_block_put(struct esp32_apptrace_cmd_ctx *ctx, st static struct esp32_apptrace_block *esp32_apptrace_ready_block_get(struct esp32_apptrace_cmd_ctx *ctx) { - struct esp32_apptrace_block *block = NULL; + if (list_empty(&ctx->ready_trace_blocks)) + return NULL; - if (!list_empty(&ctx->ready_trace_blocks)) { - struct list_head *head = &ctx->ready_trace_blocks; - struct list_head *tmp, *pos; + struct esp32_apptrace_block *block = + list_last_entry(&ctx->ready_trace_blocks, struct esp32_apptrace_block, node); - list_for_each_safe(pos, tmp, head) { - block = list_entry(pos, struct esp32_apptrace_block, node); - } - /* remove it from ready list */ - list_del(&block->node); - } + /* remove it from ready list */ + list_del(&block->node); return block; } From d35faaa35cd5d56fa946d194d7cf780127a3f8c8 Mon Sep 17 00:00:00 2001 From: Daniel Anselmi Date: Mon, 12 Dec 2022 09:49:51 +0100 Subject: [PATCH 13/49] pld: add support for lattice ecp2 and ecp3 devices Change-Id: I29c227c37be464f7ecc97a30d9cf3da1442e2b7f Signed-off-by: Daniel Anselmi Reviewed-on: https://review.openocd.org/c/openocd/+/7396 Reviewed-by: Antonio Borneo Tested-by: jenkins --- doc/openocd.texi | 32 ++- src/pld/Makefile.am | 8 + src/pld/ecp2_3.c | 250 ++++++++++++++++++++++ src/pld/ecp2_3.h | 19 ++ src/pld/lattice.c | 435 ++++++++++++++++++++++++++++++++++++++ src/pld/lattice.h | 32 +++ src/pld/lattice_bit.c | 105 +++++++++ src/pld/lattice_bit.h | 33 +++ src/pld/pld.c | 2 + src/pld/raw_bit.c | 55 +++++ src/pld/raw_bit.h | 21 ++ tcl/fpga/lattice_ecp2.cfg | 31 +++ tcl/fpga/lattice_ecp3.cfg | 22 ++ 13 files changed, 1044 insertions(+), 1 deletion(-) create mode 100644 src/pld/ecp2_3.c create mode 100644 src/pld/ecp2_3.h create mode 100644 src/pld/lattice.c create mode 100644 src/pld/lattice.h create mode 100644 src/pld/lattice_bit.c create mode 100644 src/pld/lattice_bit.h create mode 100644 src/pld/raw_bit.c create mode 100644 src/pld/raw_bit.h create mode 100644 tcl/fpga/lattice_ecp2.cfg create mode 100644 tcl/fpga/lattice_ecp3.cfg diff --git a/doc/openocd.texi b/doc/openocd.texi index 4154e56b5..2d94de840 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -8488,13 +8488,43 @@ openocd -f board/digilent_zedboard.cfg -c "init" \ @end example - @deffn {Command} {virtex2 read_stat} num Reads and displays the Virtex-II status register (STAT) for FPGA @var{num}. @end deffn @end deffn + + +@deffn {FPGA Driver} {lattice} [family] +The FGPA families ECP2 and ECP3 by Lattice are supported. +This driver can be used to load the bitstream into the FPGA or read the status register and read/write the usercode register. + +The option @option{family} is one of @var{ecp2 ecp3}. This is needed when the JTAG ID of the device is not known by openocd (newer NX devices). + +@deffn {Command} {lattice read_status} num +Reads and displays the status register +for FPGA @var{num}. +@end deffn + +@deffn {Command} {lattice read_user} num +Reads and displays the user register +for FPGA @var{num}. +@end deffn + +@deffn {Command} {lattice write_user} num val +Writes the user register. +for FPGA @var{num} with value @var{val}. +@end deffn + +@deffn {Command} {lattice set_preload} num length +Set the length of the register for the preload. This is needed when the JTAG ID of the device is not known by openocd (newer NX devices). +The load command for the FPGA @var{num} will use a length for the preload of @var{length}. +@end deffn +@end deffn + + + @node General Commands @chapter General Commands @cindex commands diff --git a/src/pld/Makefile.am b/src/pld/Makefile.am index 14786afbf..7cff09e15 100644 --- a/src/pld/Makefile.am +++ b/src/pld/Makefile.am @@ -2,9 +2,17 @@ noinst_LTLIBRARIES += %D%/libpld.la %C%_libpld_la_SOURCES = \ + %D%/ecp2_3.c \ + %D%/lattice.c \ + %D%/lattice_bit.c \ %D%/pld.c \ + %D%/raw_bit.c \ %D%/xilinx_bit.c \ %D%/virtex2.c \ + %D%/ecp2_3.h \ + %D%/lattice.h \ + %D%/lattice_bit.h \ %D%/pld.h \ + %D%/raw_bit.h \ %D%/xilinx_bit.h \ %D%/virtex2.h diff --git a/src/pld/ecp2_3.c b/src/pld/ecp2_3.c new file mode 100644 index 000000000..6826d0b4a --- /dev/null +++ b/src/pld/ecp2_3.c @@ -0,0 +1,250 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/*************************************************************************** + * Copyright (C) 2022 by Daniel Anselmi * + * danselmi@gmx.ch * + ***************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "lattice.h" + +#define LSCC_REFRESH 0x23 +#define ISC_ENABLE 0x15 +#define LSCC_RESET_ADDRESS 0x21 +#define ISC_PROGRAM_USERCODE 0x1A +#define ISC_ERASE 0x03 +#define READ_USERCODE 0x17 +#define ISC_DISABLE 0x1E +#define LSCC_READ_STATUS 0x53 +#define LSCC_BITSTREAM_BURST 0x02 + +#define STATUS_DONE_BIT 0x00020000 +#define STATUS_ERROR_BITS_ECP2 0x00040003 +#define STATUS_ERROR_BITS_ECP3 0x00040007 +#define REGISTER_ALL_BITS_1 0xffffffff +#define REGISTER_ALL_BITS_0 0x00000000 + +int lattice_ecp2_3_read_status(struct jtag_tap *tap, uint32_t *status, uint32_t out, bool do_idle) +{ + return lattice_read_u32_register(tap, LSCC_READ_STATUS, status, out, do_idle); +} + +int lattice_ecp2_3_read_usercode(struct jtag_tap *tap, uint32_t *usercode, uint32_t out) +{ + return lattice_read_u32_register(tap, READ_USERCODE, usercode, out, false); +} + +int lattice_ecp2_3_write_usercode(struct lattice_pld_device *lattice_device, uint32_t usercode) +{ + struct jtag_tap *tap = lattice_device->tap; + if (!tap) + return ERROR_FAIL; + + int retval = lattice_set_instr(tap, ISC_ENABLE, TAP_IDLE); + if (retval != ERROR_OK) + return retval; + jtag_add_runtest(5, TAP_IDLE); + jtag_add_sleep(20000); + + retval = lattice_set_instr(tap, ISC_PROGRAM_USERCODE, TAP_IDLE); + if (retval != ERROR_OK) + return retval; + + struct scan_field field; + uint8_t buffer[4]; + h_u32_to_le(buffer, usercode); + field.num_bits = 32; + field.out_value = buffer; + field.in_value = NULL; + jtag_add_dr_scan(tap, 1, &field, TAP_IDLE); + jtag_add_runtest(5, TAP_IDLE); + jtag_add_sleep(2000); + + retval = lattice_set_instr(tap, ISC_DISABLE, TAP_IDLE); + if (retval != ERROR_OK) + return retval; + jtag_add_runtest(5, TAP_IDLE); + jtag_add_sleep(200000); + + retval = jtag_execute_queue(); + if (retval != ERROR_OK) + return retval; + return lattice_verify_usercode(lattice_device, 0x0, usercode, REGISTER_ALL_BITS_1); +} + +static int lattice_ecp2_3_erase_device(struct lattice_pld_device *lattice_device) +{ + struct jtag_tap *tap = lattice_device->tap; + if (!tap) + return ERROR_FAIL; + + /* program user code with all bits set */ + int retval = lattice_set_instr(tap, ISC_PROGRAM_USERCODE, TAP_IRPAUSE); + if (retval != ERROR_OK) + return retval; + struct scan_field field; + uint8_t buffer[4] = {0xff, 0xff, 0xff, 0xff}; + field.num_bits = 32; + field.out_value = buffer; + field.in_value = NULL; + jtag_add_dr_scan(tap, 1, &field, TAP_IDLE); + jtag_add_runtest(5, TAP_IDLE); + jtag_add_sleep(2000); + + /* verify every bit is set */ + const uint32_t out = REGISTER_ALL_BITS_1; + const uint32_t mask = REGISTER_ALL_BITS_1; + const uint32_t expected_pre = REGISTER_ALL_BITS_1; + retval = lattice_verify_usercode(lattice_device, out, expected_pre, mask); + if (retval != ERROR_OK) + return retval; + + retval = lattice_set_instr(tap, ISC_ERASE, TAP_IDLE); + if (retval != ERROR_OK) + return retval; + jtag_add_runtest(5, TAP_IDLE); + if (lattice_device->family == LATTICE_ECP2) + jtag_add_sleep(100000); + else + jtag_add_sleep(2000000); + + retval = lattice_set_instr(tap, LSCC_RESET_ADDRESS, TAP_IDLE); + if (retval != ERROR_OK) + return retval; + jtag_add_runtest(5, TAP_IDLE); + jtag_add_sleep(2000); + + /* after erasing check all bits in user register are cleared */ + const uint32_t expected_post = REGISTER_ALL_BITS_0; + return lattice_verify_usercode(lattice_device, out, expected_post, mask); +} + +static int lattice_ecp2_3_program_config_map(struct lattice_pld_device *lattice_device, + struct lattice_bit_file *bit_file) +{ + struct jtag_tap *tap = lattice_device->tap; + if (!tap) + return ERROR_FAIL; + + int retval = lattice_set_instr(tap, LSCC_RESET_ADDRESS, TAP_IDLE); + if (retval != ERROR_OK) + return retval; + jtag_add_runtest(5, TAP_IDLE); + jtag_add_sleep(2000); + + struct scan_field field; + retval = lattice_set_instr(tap, LSCC_BITSTREAM_BURST, TAP_IDLE); + if (retval != ERROR_OK) + return retval; + field.num_bits = (bit_file->raw_bit.length - bit_file->offset) * 8; + field.out_value = bit_file->raw_bit.data + bit_file->offset; + field.in_value = NULL; + jtag_add_dr_scan(tap, 1, &field, TAP_IDLE); + jtag_add_runtest(256, TAP_IDLE); + jtag_add_sleep(2000); + return jtag_execute_queue(); +} + +static int lattice_ecp2_3_exit_programming_mode(struct lattice_pld_device *lattice_device) +{ + struct jtag_tap *tap = lattice_device->tap; + if (!tap) + return ERROR_FAIL; + + int retval = lattice_set_instr(tap, ISC_DISABLE, TAP_IDLE); + if (retval != ERROR_OK) + return retval; + jtag_add_runtest(5, TAP_IDLE); + jtag_add_sleep(200000); + retval = lattice_set_instr(tap, BYPASS, TAP_IDLE); + if (retval != ERROR_OK) + return retval; + jtag_add_runtest(100, TAP_IDLE); + jtag_add_sleep(1000); + return jtag_execute_queue(); +} + +int lattice_ecp2_load(struct lattice_pld_device *lattice_device, struct lattice_bit_file *bit_file) +{ + struct jtag_tap *tap = lattice_device->tap; + if (!tap) + return ERROR_FAIL; + + int retval = lattice_preload(lattice_device); + if (retval != ERROR_OK) + return retval; + + /* Enable the programming mode */ + retval = lattice_set_instr(tap, LSCC_REFRESH, TAP_IDLE); + if (retval != ERROR_OK) + return retval; + retval = lattice_set_instr(tap, ISC_ENABLE, TAP_IDLE); + if (retval != ERROR_OK) + return retval; + jtag_add_runtest(5, TAP_IDLE); + jtag_add_sleep(20000); + + /* Erase the device */ + retval = lattice_ecp2_3_erase_device(lattice_device); + if (retval != ERROR_OK) + return retval; + + /* Program Fuse Map */ + retval = lattice_ecp2_3_program_config_map(lattice_device, bit_file); + if (retval != ERROR_OK) + return retval; + + retval = lattice_ecp2_3_exit_programming_mode(lattice_device); + if (retval != ERROR_OK) + return retval; + + const uint32_t out = REGISTER_ALL_BITS_1; + const uint32_t mask = STATUS_DONE_BIT | STATUS_ERROR_BITS_ECP2; + const uint32_t expected = STATUS_DONE_BIT; + return lattice_verify_status_register_u32(lattice_device, out, expected, mask, false); +} + +int lattice_ecp3_load(struct lattice_pld_device *lattice_device, struct lattice_bit_file *bit_file) +{ + struct jtag_tap *tap = lattice_device->tap; + if (!tap) + return ERROR_FAIL; + + /* Program Bscan register */ + int retval = lattice_preload(lattice_device); + if (retval != ERROR_OK) + return retval; + + /* Enable the programming mode */ + retval = lattice_set_instr(tap, LSCC_REFRESH, TAP_IDLE); + if (retval != ERROR_OK) + return retval; + jtag_add_runtest(5, TAP_IDLE); + jtag_add_sleep(500000); + retval = lattice_set_instr(tap, ISC_ENABLE, TAP_IDLE); + if (retval != ERROR_OK) + return retval; + jtag_add_runtest(5, TAP_IDLE); + jtag_add_sleep(20000); + + retval = lattice_ecp2_3_erase_device(lattice_device); + if (retval != ERROR_OK) + return retval; + + /* Program Fuse Map */ + retval = lattice_ecp2_3_program_config_map(lattice_device, bit_file); + if (retval != ERROR_OK) + return retval; + + retval = lattice_ecp2_3_exit_programming_mode(lattice_device); + if (retval != ERROR_OK) + return retval; + + const uint32_t out = REGISTER_ALL_BITS_1; + const uint32_t mask = STATUS_DONE_BIT | STATUS_ERROR_BITS_ECP3; + const uint32_t expected = STATUS_DONE_BIT; + return lattice_verify_status_register_u32(lattice_device, out, expected, mask, false); +} diff --git a/src/pld/ecp2_3.h b/src/pld/ecp2_3.h new file mode 100644 index 000000000..5f3e9e97b --- /dev/null +++ b/src/pld/ecp2_3.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/*************************************************************************** + * Copyright (C) 2022 by Daniel Anselmi * + * danselmi@gmx.ch * + ***************************************************************************/ + +#ifndef OPENOCD_PLD_ECP2_3_H +#define OPENOCD_PLD_ECP2_3_H + +#include "lattice.h" + +int lattice_ecp2_3_read_status(struct jtag_tap *tap, uint32_t *status, uint32_t out, bool do_idle); +int lattice_ecp2_3_read_usercode(struct jtag_tap *tap, uint32_t *usercode, uint32_t out); +int lattice_ecp2_3_write_usercode(struct lattice_pld_device *lattice_device, uint32_t usercode); +int lattice_ecp2_load(struct lattice_pld_device *lattice_device, struct lattice_bit_file *bit_file); +int lattice_ecp3_load(struct lattice_pld_device *lattice_device, struct lattice_bit_file *bit_file); + +#endif /* OPENOCD_PLD_ECP2_3_H */ diff --git a/src/pld/lattice.c b/src/pld/lattice.c new file mode 100644 index 000000000..489b1895f --- /dev/null +++ b/src/pld/lattice.c @@ -0,0 +1,435 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/*************************************************************************** + * Copyright (C) 2022 by Daniel Anselmi * + * danselmi@gmx.ch * + ***************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "lattice.h" +#include +#include "pld.h" +#include "lattice_bit.h" +#include "ecp2_3.h" + +#define PRELOAD 0x1C + +struct lattice_devices_elem { + uint32_t id; + size_t preload_length; + enum lattice_family_e family; +}; + +static const struct lattice_devices_elem lattice_devices[] = { + {0x01270043, 654, LATTICE_ECP2 /* ecp2-6e */}, + {0x01271043, 643, LATTICE_ECP2 /* ecp2-12e */}, + {0x01272043, 827, LATTICE_ECP2 /* ecp2-20e */}, + {0x01274043, 1011, LATTICE_ECP2 /* ecp2-35e */}, + {0x01273043, 1219, LATTICE_ECP2 /* ecp2-50e */}, + {0x01275043, 654, LATTICE_ECP2 /* ecp2-70e */}, + {0x01279043, 680, LATTICE_ECP2 /* ecp2m20e */}, + {0x0127A043, 936, LATTICE_ECP2 /* ecp2m35e */}, + {0x0127B043, 1056, LATTICE_ECP2 /* ecp2m50e */}, + {0x0127C043, 1039, LATTICE_ECP2 /* ecp2m70e */}, + {0x0127D043, 1311, LATTICE_ECP2 /* ecp2m100e */}, + {0x01010043, 467, LATTICE_ECP3 /* ecp3 lae3-17ea & lfe3-17ea*/}, + {0x01012043, 675, LATTICE_ECP3 /* ecp3 lae3-35ea & lfe3-35ea*/}, + {0x01014043, 1077, LATTICE_ECP3 /* ecp3 lfe3-70ea & lfe3-70e & lfe3-95ea && lfe3-95e*/}, + {0x01015043, 1326, LATTICE_ECP3 /* ecp3 lfe3-150e*/}, +}; + +int lattice_set_instr(struct jtag_tap *tap, uint8_t new_instr, tap_state_t endstate) +{ + struct scan_field field; + field.num_bits = tap->ir_length; + void *t = calloc(DIV_ROUND_UP(field.num_bits, 8), 1); + if (!t) { + LOG_ERROR("Out of memory"); + return ERROR_FAIL; + } + field.out_value = t; + buf_set_u32(t, 0, field.num_bits, new_instr); + field.in_value = NULL; + jtag_add_ir_scan(tap, &field, endstate); + free(t); + return ERROR_OK; +} + +static int lattice_check_device_family(struct lattice_pld_device *lattice_device) +{ + if (lattice_device->family != LATTICE_UNKNOWN && lattice_device->preload_length != 0) + return ERROR_OK; + + if (!lattice_device->tap || !lattice_device->tap->hasidcode) + return ERROR_FAIL; + + for (size_t i = 0; i < ARRAY_SIZE(lattice_devices); ++i) { + if (lattice_devices[i].id == lattice_device->tap->idcode) { + if (lattice_device->family == LATTICE_UNKNOWN) + lattice_device->family = lattice_devices[i].family; + if (lattice_device->preload_length == 0) + lattice_device->preload_length = lattice_devices[i].preload_length; + return ERROR_OK; + } + } + LOG_ERROR("Unknown id! Specify family and preload-length manually."); + return ERROR_FAIL; +} + +int lattice_read_u32_register(struct jtag_tap *tap, uint8_t cmd, uint32_t *in_val, + uint32_t out_val, bool do_idle) +{ + struct scan_field field; + uint8_t buffer[4]; + + int retval = lattice_set_instr(tap, cmd, TAP_IDLE); + if (retval != ERROR_OK) + return retval; + if (do_idle) { + jtag_add_runtest(2, TAP_IDLE); + jtag_add_sleep(1000); + } + + h_u32_to_le(buffer, out_val); + field.num_bits = 32; + field.out_value = buffer; + field.in_value = buffer; + jtag_add_dr_scan(tap, 1, &field, TAP_IDLE); + retval = jtag_execute_queue(); + if (retval == ERROR_OK) + *in_val = le_to_h_u32(buffer); + + return retval; +} + +int lattice_preload(struct lattice_pld_device *lattice_device) +{ + struct scan_field field; + size_t sz_bytes = DIV_ROUND_UP(lattice_device->preload_length, 8); + + int retval = lattice_set_instr(lattice_device->tap, PRELOAD, TAP_IDLE); + if (retval != ERROR_OK) + return retval; + uint8_t *buffer = malloc(sz_bytes); + if (!buffer) { + LOG_ERROR("Out of memory"); + return ERROR_FAIL; + } + memset(buffer, 0xff, sz_bytes); + + field.num_bits = lattice_device->preload_length; + field.out_value = buffer; + field.in_value = NULL; + jtag_add_dr_scan(lattice_device->tap, 1, &field, TAP_IDLE); + retval = jtag_execute_queue(); + free(buffer); + return retval; +} + +static int lattice_read_usercode(struct lattice_pld_device *lattice_device, uint32_t *usercode, uint32_t out) +{ + struct jtag_tap *tap = lattice_device->tap; + if (!tap) + return ERROR_FAIL; + + if (lattice_device->family == LATTICE_ECP2 || lattice_device->family == LATTICE_ECP3) + return lattice_ecp2_3_read_usercode(tap, usercode, out); + + return ERROR_FAIL; +} + +int lattice_verify_usercode(struct lattice_pld_device *lattice_device, uint32_t out, + uint32_t expected, uint32_t mask) +{ + uint32_t usercode; + + int retval = lattice_read_usercode(lattice_device, &usercode, out); + if (retval != ERROR_OK) + return retval; + + if ((usercode & mask) != expected) { + LOG_ERROR("verifying user code register failed got: 0x%08" PRIx32 " expected: 0x%08" PRIx32, + usercode & mask, expected); + return ERROR_FAIL; + } + return ERROR_OK; +} + +static int lattice_write_usercode(struct lattice_pld_device *lattice_device, uint32_t usercode) +{ + if (lattice_device->family == LATTICE_ECP2 || lattice_device->family == LATTICE_ECP3) + return lattice_ecp2_3_write_usercode(lattice_device, usercode); + + return ERROR_FAIL; +} + +static int lattice_read_status_u32(struct lattice_pld_device *lattice_device, uint32_t *status, + uint32_t out, bool do_idle) +{ + if (!lattice_device->tap) + return ERROR_FAIL; + + if (lattice_device->family == LATTICE_ECP2 || lattice_device->family == LATTICE_ECP3) + return lattice_ecp2_3_read_status(lattice_device->tap, status, out, do_idle); + + return ERROR_FAIL; +} + +int lattice_verify_status_register_u32(struct lattice_pld_device *lattice_device, uint32_t out, + uint32_t expected, uint32_t mask, bool do_idle) +{ + uint32_t status; + + int retval = lattice_read_status_u32(lattice_device, &status, out, do_idle); + if (retval != ERROR_OK) + return retval; + + if ((status & mask) != expected) { + LOG_ERROR("verifying status register failed got: 0x%08" PRIx32 " expected: 0x%08" PRIx32, + status & mask, expected); + return ERROR_FAIL; + } + return ERROR_OK; +} + +static int lattice_load_command(struct pld_device *pld_device, const char *filename) +{ + if (!pld_device) + return ERROR_FAIL; + + struct lattice_pld_device *lattice_device = pld_device->driver_priv; + + if (!lattice_device || !lattice_device->tap) + return ERROR_FAIL; + struct jtag_tap *tap = lattice_device->tap; + + if (!tap || !tap->hasidcode) + return ERROR_FAIL; + + int retval = lattice_check_device_family(lattice_device); + if (retval != ERROR_OK) + return retval; + + struct lattice_bit_file bit_file; + retval = lattice_read_file(&bit_file, filename, lattice_device->family); + if (retval != ERROR_OK) + return retval; + + retval = ERROR_FAIL; + switch (lattice_device->family) { + case LATTICE_ECP2: + retval = lattice_ecp2_load(lattice_device, &bit_file); + break; + case LATTICE_ECP3: + retval = lattice_ecp3_load(lattice_device, &bit_file); + break; + default: + LOG_ERROR("loading unknown device family"); + break; + } + free(bit_file.raw_bit.data); + return retval; +} + +PLD_DEVICE_COMMAND_HANDLER(lattice_pld_device_command) +{ + if (CMD_ARGC < 2 || CMD_ARGC > 3) + return ERROR_COMMAND_SYNTAX_ERROR; + + struct jtag_tap *tap = jtag_tap_by_string(CMD_ARGV[1]); + if (!tap) { + command_print(CMD, "Tap: %s does not exist", CMD_ARGV[1]); + return ERROR_FAIL; + } + + struct lattice_pld_device *lattice_device = malloc(sizeof(struct lattice_pld_device)); + if (!lattice_device) { + LOG_ERROR("Out of memory"); + return ERROR_FAIL; + } + /* id is not known yet -> postpone lattice_check_device_family() */ + enum lattice_family_e family = LATTICE_UNKNOWN; + if (CMD_ARGC == 3) { + if (strcasecmp(CMD_ARGV[2], "ecp2") == 0) { + family = LATTICE_ECP2; + } else if (strcasecmp(CMD_ARGV[2], "ecp3") == 0) { + family = LATTICE_ECP3; + } else { + command_print(CMD, "unknown family"); + free(lattice_device); + return ERROR_FAIL; + } + } + lattice_device->tap = tap; + lattice_device->family = family; + lattice_device->preload_length = 0; + + pld->driver_priv = lattice_device; + + return ERROR_OK; +} + +COMMAND_HANDLER(lattice_read_usercode_register_command_handler) +{ + int dev_id; + uint32_t usercode; + + if (CMD_ARGC != 1) + return ERROR_COMMAND_SYNTAX_ERROR; + + COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], dev_id); + struct pld_device *device = get_pld_device_by_num(dev_id); + if (!device) { + command_print(CMD, "pld device '#%s' is out of bounds", CMD_ARGV[0]); + return ERROR_FAIL; + } + + struct lattice_pld_device *lattice_device = device->driver_priv; + if (!lattice_device) + return ERROR_FAIL; + + int retval = lattice_check_device_family(lattice_device); + if (retval != ERROR_OK) + return retval; + + retval = lattice_read_usercode(lattice_device, &usercode, 0x0); + if (retval == ERROR_OK) + command_print(CMD, "0x%8.8" PRIx32, usercode); + + return retval; +} + +COMMAND_HANDLER(lattice_set_preload_command_handler) +{ + int dev_id; + unsigned int preload_length; + + if (CMD_ARGC != 2) + return ERROR_COMMAND_SYNTAX_ERROR; + + COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], dev_id); + struct pld_device *device = get_pld_device_by_num(dev_id); + if (!device) { + command_print(CMD, "pld device '#%s' is out of bounds", CMD_ARGV[0]); + return ERROR_FAIL; + } + + COMMAND_PARSE_NUMBER(uint, CMD_ARGV[1], preload_length); + + struct lattice_pld_device *lattice_device = device->driver_priv; + + if (!lattice_device) + return ERROR_FAIL; + + lattice_device->preload_length = preload_length; + + return ERROR_OK; +} + +COMMAND_HANDLER(lattice_write_usercode_register_command_handler) +{ + int dev_id; + uint32_t usercode; + + if (CMD_ARGC != 2) + return ERROR_COMMAND_SYNTAX_ERROR; + + COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], dev_id); + struct pld_device *device = get_pld_device_by_num(dev_id); + if (!device) { + command_print(CMD, "pld device '#%s' is out of bounds", CMD_ARGV[0]); + return ERROR_FAIL; + } + + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], usercode); + + struct lattice_pld_device *lattice_device = device->driver_priv; + if (!lattice_device) + return ERROR_FAIL; + + int retval = lattice_check_device_family(lattice_device); + if (retval != ERROR_OK) + return retval; + + return lattice_write_usercode(lattice_device, usercode); +} + +COMMAND_HANDLER(lattice_read_status_command_handler) +{ + int dev_id; + + if (CMD_ARGC != 1) + return ERROR_COMMAND_SYNTAX_ERROR; + + COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], dev_id); + struct pld_device *device = get_pld_device_by_num(dev_id); + if (!device) { + command_print(CMD, "pld device '#%s' is out of bounds", CMD_ARGV[0]); + return ERROR_FAIL; + } + + struct lattice_pld_device *lattice_device = device->driver_priv; + if (!lattice_device) + return ERROR_FAIL; + + int retval = lattice_check_device_family(lattice_device); + if (retval != ERROR_OK) + return retval; + + uint32_t status; + retval = lattice_read_status_u32(lattice_device, &status, 0x0, false); + if (retval == ERROR_OK) + command_print(CMD, "0x%8.8" PRIx32, status); + + return retval; +} + +static const struct command_registration lattice_exec_command_handlers[] = { + { + .name = "read_status", + .mode = COMMAND_EXEC, + .handler = lattice_read_status_command_handler, + .help = "reading status register from FPGA", + .usage = "num_pld", + }, { + .name = "read_user", + .mode = COMMAND_EXEC, + .handler = lattice_read_usercode_register_command_handler, + .help = "reading usercode register from FPGA", + .usage = "num_pld", + }, { + .name = "write_user", + .mode = COMMAND_EXEC, + .handler = lattice_write_usercode_register_command_handler, + .help = "writing usercode register to FPGA", + .usage = "num_pld value", + }, { + .name = "set_preload", + .mode = COMMAND_EXEC, + .handler = lattice_set_preload_command_handler, + .help = "set length for preload (device specific)", + .usage = "num_pld value", + }, + COMMAND_REGISTRATION_DONE +}; + +static const struct command_registration lattice_command_handler[] = { + { + .name = "lattice", + .mode = COMMAND_ANY, + .help = "lattice specific commands", + .usage = "", + .chain = lattice_exec_command_handlers, + }, + COMMAND_REGISTRATION_DONE +}; + +struct pld_driver lattice_pld = { + .name = "lattice", + .commands = lattice_command_handler, + .pld_device_command = &lattice_pld_device_command, + .load = &lattice_load_command, +}; diff --git a/src/pld/lattice.h b/src/pld/lattice.h new file mode 100644 index 000000000..6d692cbe4 --- /dev/null +++ b/src/pld/lattice.h @@ -0,0 +1,32 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/*************************************************************************** + * Copyright (C) 2022 by Daniel Anselmi * + * danselmi@gmx.ch * + ***************************************************************************/ + +#ifndef OPENOCD_PLD_LATTICE_H +#define OPENOCD_PLD_LATTICE_H + +#include +#include "pld.h" +#include "lattice_bit.h" + +#define BYPASS 0xFF + +struct lattice_pld_device { + struct jtag_tap *tap; + size_t preload_length; + enum lattice_family_e family; +}; + +int lattice_set_instr(struct jtag_tap *tap, uint8_t new_instr, tap_state_t endstate); +int lattice_read_u32_register(struct jtag_tap *tap, uint8_t cmd, uint32_t *in_val, + uint32_t out_val, bool do_idle); +int lattice_verify_usercode(struct lattice_pld_device *lattice_device, uint32_t out, + uint32_t expected, uint32_t mask); +int lattice_verify_status_register_u32(struct lattice_pld_device *lattice_device, uint32_t out, + uint32_t expected, uint32_t mask, bool do_idle); +int lattice_preload(struct lattice_pld_device *lattice_device); + +#endif /* OPENOCD_PLD_LATTICE_H */ diff --git a/src/pld/lattice_bit.c b/src/pld/lattice_bit.c new file mode 100644 index 000000000..562b17d0a --- /dev/null +++ b/src/pld/lattice_bit.c @@ -0,0 +1,105 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/*************************************************************************** + * Copyright (C) 2022 by Daniel Anselmi * + * danselmi@gmx.ch * + ***************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include "lattice_bit.h" +#include "raw_bit.h" +#include "pld.h" +#include +#include +#include + +enum read_bit_state { + SEEK_HEADER_START, + SEEK_HEADER_END, + SEEK_PREAMBLE, + SEEK_ID, + DONE, +}; + +static int lattice_read_bit_file(struct lattice_bit_file *bit_file, const char *filename, enum lattice_family_e family) +{ + int retval = cpld_read_raw_bit_file(&bit_file->raw_bit, filename); + if (retval != ERROR_OK) + return retval; + + bit_file->part = 0; + bit_file->has_id = false; + enum read_bit_state state = SEEK_HEADER_START; + for (size_t pos = 1; pos < bit_file->raw_bit.length && state != DONE; ++pos) { + switch (state) { + case SEEK_HEADER_START: + if (bit_file->raw_bit.data[pos] == 0 && bit_file->raw_bit.data[pos - 1] == 0xff) + state = SEEK_HEADER_END; + break; + case SEEK_HEADER_END: + if (pos + 6 < bit_file->raw_bit.length && + strncmp((const char *)(bit_file->raw_bit.data + pos), "Part: ", 6) == 0) { + bit_file->part = (const char *)bit_file->raw_bit.data + pos + 6; + LOG_INFO("part found: %s\n", bit_file->part); + } else if (bit_file->raw_bit.data[pos] == 0xff && bit_file->raw_bit.data[pos - 1] == 0) { + bit_file->offset = pos; + state = (family != LATTICE_ECP2 && family != LATTICE_ECP3) ? SEEK_PREAMBLE : DONE; + } + break; + case SEEK_PREAMBLE: + if (pos >= 4) { + uint32_t preamble = be_to_h_u32(bit_file->raw_bit.data + pos - 3); + switch (preamble) { + case 0xffffbdb3: + state = SEEK_ID; + break; + case 0xffffbfb3: + case 0xffffbeb3: + state = DONE; + break; + } + } + break; + case SEEK_ID: + if (pos + 7 < bit_file->raw_bit.length && bit_file->raw_bit.data[pos] == 0xe2) { + bit_file->idcode = be_to_h_u32(&bit_file->raw_bit.data[pos + 4]); + bit_file->has_id = true; + state = DONE; + } + break; + default: + break; + } + } + + if (state != DONE) { + LOG_ERROR("parsing bitstream failed"); + return ERROR_PLD_FILE_LOAD_FAILED; + } + + for (size_t i = bit_file->offset; i < bit_file->raw_bit.length; i++) + bit_file->raw_bit.data[i] = flip_u32(bit_file->raw_bit.data[i], 8); + + return ERROR_OK; +} + +int lattice_read_file(struct lattice_bit_file *bit_file, const char *filename, enum lattice_family_e family) +{ + if (!filename || !bit_file) + return ERROR_COMMAND_SYNTAX_ERROR; + + /* check if binary .bin or ascii .bit/.hex */ + const char *file_suffix_pos = strrchr(filename, '.'); + if (!file_suffix_pos) { + LOG_ERROR("Unable to detect filename suffix"); + return ERROR_PLD_FILE_LOAD_FAILED; + } + + if (strcasecmp(file_suffix_pos, ".bit") == 0) + return lattice_read_bit_file(bit_file, filename, family); + + LOG_ERROR("Filetype not supported"); + return ERROR_PLD_FILE_LOAD_FAILED; +} diff --git a/src/pld/lattice_bit.h b/src/pld/lattice_bit.h new file mode 100644 index 000000000..33f1b347f --- /dev/null +++ b/src/pld/lattice_bit.h @@ -0,0 +1,33 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/*************************************************************************** + * Copyright (C) 2022 by Daniel Anselmi * + * danselmi@gmx.ch * + ***************************************************************************/ + +#ifndef OPENOCD_PLD_LATTICE_BIT_H +#define OPENOCD_PLD_LATTICE_BIT_H + +#include "helper/types.h" +#include "raw_bit.h" + + +struct lattice_bit_file { + struct raw_bit_file raw_bit; + size_t offset; + uint32_t idcode; + const char *part; /* reuses memory in raw_bit_file */ + bool has_id; +}; + +enum lattice_family_e { + LATTICE_ECP2, + LATTICE_ECP3, + LATTICE_ECP5, + LATTICE_CERTUS, + LATTICE_UNKNOWN, +}; + +int lattice_read_file(struct lattice_bit_file *bit_file, const char *filename, enum lattice_family_e family); + +#endif /* OPENOCD_PLD_LATTICE_BIT_H */ diff --git a/src/pld/pld.c b/src/pld/pld.c index af1836907..e838888ce 100644 --- a/src/pld/pld.c +++ b/src/pld/pld.c @@ -18,9 +18,11 @@ /* pld drivers */ +extern struct pld_driver lattice_pld; extern struct pld_driver virtex2_pld; static struct pld_driver *pld_drivers[] = { + &lattice_pld, &virtex2_pld, NULL, }; diff --git a/src/pld/raw_bit.c b/src/pld/raw_bit.c new file mode 100644 index 000000000..0c3b92e7e --- /dev/null +++ b/src/pld/raw_bit.c @@ -0,0 +1,55 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/*************************************************************************** + * Copyright (C) 2022 by Daniel Anselmi * + * danselmi@gmx.ch * + ***************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "raw_bit.h" +#include "pld.h" + +#include +#include + + +int cpld_read_raw_bit_file(struct raw_bit_file *bit_file, const char *filename) +{ + FILE *input_file = fopen(filename, "rb"); + + if (!input_file) { + LOG_ERROR("Couldn't open %s: %s", filename, strerror(errno)); + return ERROR_PLD_FILE_LOAD_FAILED; + } + + fseek(input_file, 0, SEEK_END); + long length = ftell(input_file); + fseek(input_file, 0, SEEK_SET); + + if (length < 0) { + fclose(input_file); + LOG_ERROR("Failed to get length of file %s: %s", filename, strerror(errno)); + return ERROR_PLD_FILE_LOAD_FAILED; + } + bit_file->length = (size_t)length; + + bit_file->data = malloc(bit_file->length); + if (!bit_file->data) { + fclose(input_file); + LOG_ERROR("Out of memory"); + return ERROR_PLD_FILE_LOAD_FAILED; + } + + size_t read_count = fread(bit_file->data, sizeof(char), bit_file->length, input_file); + fclose(input_file); + if (read_count != bit_file->length) { + free(bit_file->data); + bit_file->data = NULL; + return ERROR_PLD_FILE_LOAD_FAILED; + } + + return ERROR_OK; +} diff --git a/src/pld/raw_bit.h b/src/pld/raw_bit.h new file mode 100644 index 000000000..583ff76e9 --- /dev/null +++ b/src/pld/raw_bit.h @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/*************************************************************************** + * Copyright (C) 2022 by Daniel Anselmi * + * danselmi@gmx.ch * + ***************************************************************************/ + +#ifndef OPENOCD_PLD_RAW_BIN_H +#define OPENOCD_PLD_RAW_BIN_H + +#include +#include + +struct raw_bit_file { + size_t length; + uint8_t *data; +}; + +int cpld_read_raw_bit_file(struct raw_bit_file *bit_file, const char *filename); + +#endif /* OPENOCD_PLD_RAW_BIN_H */ diff --git a/tcl/fpga/lattice_ecp2.cfg b/tcl/fpga/lattice_ecp2.cfg new file mode 100644 index 000000000..a1aa2eff1 --- /dev/null +++ b/tcl/fpga/lattice_ecp2.cfg @@ -0,0 +1,31 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +if { [info exists CHIPNAME] } { + set _CHIPNAME $_CHIPNAME +} else { + set _CHIPNAME ecp2 +} + +# Lattice ECP2 family +# TAP IDs are extracted from BSDL files found on this page: +# https://www.latticesemi.com/Products/FPGAandCPLD/LatticeECP2M +# +# LFE2M20E: 0x01279043 +# LFE2M35E: 0x0127A043 +# LFE2M50E: 0x0127B043 +# LFE2M70E: 0x0127C043 +# LFE2M100E: 0x0127D043 +# LFEC2_6E: 0x01270043 +# LFEC2_12E: 0x01271043 +# LFEC2_20E: 0x01272043 +# LFEC2_35E: 0x01274043 +# LFEC2_50E: 0x01273043 +# LFEC2_70E: 0x01275043 + +jtag newtap $_CHIPNAME tap -irlen 8 \ + -expected-id 0x01279043 -expected-id 0x0127A043 -expected-id 0x0127B043 \ + -expected-id 0x0127C043 -expected-id 0x0127D043 -expected-id 0x01270043 \ + -expected-id 0x01271043 -expected-id 0x01272043 -expected-id 0x01274043 \ + -expected-id 0x01273043 -expected-id 0x01275043 + +pld device lattice $_CHIPNAME.tap diff --git a/tcl/fpga/lattice_ecp3.cfg b/tcl/fpga/lattice_ecp3.cfg new file mode 100644 index 000000000..7cd570649 --- /dev/null +++ b/tcl/fpga/lattice_ecp3.cfg @@ -0,0 +1,22 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +if { [info exists CHIPNAME] } { + set _CHIPNAME $_CHIPNAME +} else { + set _CHIPNAME ecp3 +} + +# Lattice ECP3 family +# TAP IDs are extracted from BSDL files found on this page: +# https://www.latticesemi.com/Products/FPGAandCPLD/LatticeECP3 +# +# LFE3_17: 0x01010043 +# LFE3_35: 0x01012043 +# LFE3_95: 0x01014043 and LFE3_70 +# LFE3_150: 0x01015043 + +jtag newtap $_CHIPNAME tap -irlen 8 \ + -expected-id 0x01010043 -expected-id 0x01012043 \ + -expected-id 0x01014043 -expected-id 0x01015043 + +pld device lattice $_CHIPNAME.tap From cf596a61db7ebace9cf097ffcb332e4de0679398 Mon Sep 17 00:00:00 2001 From: Daniel Anselmi Date: Mon, 12 Dec 2022 09:49:51 +0100 Subject: [PATCH 14/49] pld: add support for lattice ecp5 devices Change-Id: Ib2f0933da3abe7429abca86d6aaa50ad85ce72c7 Signed-off-by: Daniel Anselmi Reviewed-on: https://review.openocd.org/c/openocd/+/7397 Reviewed-by: Antonio Borneo Tested-by: jenkins --- doc/openocd.texi | 4 +- src/pld/Makefile.am | 3 + src/pld/ecp5.c | 206 ++++++++++++++++++++++++++++++++++ src/pld/ecp5.h | 18 +++ src/pld/lattice.c | 29 ++++- src/pld/lattice_cmd.h | 19 ++++ tcl/board/ecp5_evaluation.cfg | 19 ++++ tcl/fpga/lattice_ecp5.cfg | 2 + 8 files changed, 297 insertions(+), 3 deletions(-) create mode 100644 src/pld/ecp5.c create mode 100644 src/pld/ecp5.h create mode 100644 src/pld/lattice_cmd.h create mode 100644 tcl/board/ecp5_evaluation.cfg diff --git a/doc/openocd.texi b/doc/openocd.texi index 2d94de840..2d3ccfebe 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -8497,10 +8497,10 @@ for FPGA @var{num}. @deffn {FPGA Driver} {lattice} [family] -The FGPA families ECP2 and ECP3 by Lattice are supported. +The FGPA families ECP2, ECP3 and ECP5 by Lattice are supported. This driver can be used to load the bitstream into the FPGA or read the status register and read/write the usercode register. -The option @option{family} is one of @var{ecp2 ecp3}. This is needed when the JTAG ID of the device is not known by openocd (newer NX devices). +The option @option{family} is one of @var{ecp2 ecp3 ecp5}. This is needed when the JTAG ID of the device is not known by openocd (newer NX devices). @deffn {Command} {lattice read_status} num Reads and displays the status register diff --git a/src/pld/Makefile.am b/src/pld/Makefile.am index 7cff09e15..459792f64 100644 --- a/src/pld/Makefile.am +++ b/src/pld/Makefile.am @@ -3,6 +3,7 @@ noinst_LTLIBRARIES += %D%/libpld.la %C%_libpld_la_SOURCES = \ %D%/ecp2_3.c \ + %D%/ecp5.c \ %D%/lattice.c \ %D%/lattice_bit.c \ %D%/pld.c \ @@ -10,8 +11,10 @@ noinst_LTLIBRARIES += %D%/libpld.la %D%/xilinx_bit.c \ %D%/virtex2.c \ %D%/ecp2_3.h \ + %D%/ecp5.h \ %D%/lattice.h \ %D%/lattice_bit.h \ + %D%/lattice_cmd.h \ %D%/pld.h \ %D%/raw_bit.h \ %D%/xilinx_bit.h \ diff --git a/src/pld/ecp5.c b/src/pld/ecp5.c new file mode 100644 index 000000000..298b55f4e --- /dev/null +++ b/src/pld/ecp5.c @@ -0,0 +1,206 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/*************************************************************************** + * Copyright (C) 2022 by Daniel Anselmi * + * danselmi@gmx.ch * + ***************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "lattice.h" +#include "lattice_cmd.h" + +#define ISC_PROGRAM_USERCODE 0xC2 + +#define STATUS_DONE_BIT 0x00000100 +#define STATUS_ERROR_BITS 0x00020040 +#define STATUS_FEA_OTP 0x00004000 +#define STATUS_FAIL_FLAG 0x00002000 +#define STATUS_BUSY_FLAG 0x00001000 +#define REGISTER_ALL_BITS_1 0xffffffff + +int lattice_ecp5_read_status(struct jtag_tap *tap, uint32_t *status, uint32_t out, bool do_idle) +{ + return lattice_read_u32_register(tap, LSC_READ_STATUS, status, out, do_idle); +} + +int lattice_ecp5_read_usercode(struct jtag_tap *tap, uint32_t *usercode, uint32_t out) +{ + return lattice_read_u32_register(tap, READ_USERCODE, usercode, out, true); +} + +int lattice_ecp5_write_usercode(struct lattice_pld_device *lattice_device, uint32_t usercode) +{ + struct jtag_tap *tap = lattice_device->tap; + if (!tap) + return ERROR_FAIL; + + int retval = lattice_set_instr(tap, ISC_ENABLE, TAP_IDLE); + if (retval != ERROR_OK) + return retval; + jtag_add_runtest(5, TAP_IDLE); + jtag_add_sleep(20000); + + retval = lattice_set_instr(tap, ISC_PROGRAM_USERCODE, TAP_IDLE); + if (retval != ERROR_OK) + return retval; + + uint8_t buffer[4]; + struct scan_field field; + h_u32_to_le(buffer, usercode); + field.num_bits = 32; + field.out_value = buffer; + field.in_value = NULL; + jtag_add_dr_scan(tap, 1, &field, TAP_IDLE); + jtag_add_runtest(5, TAP_IDLE); + jtag_add_sleep(2000); + + retval = lattice_set_instr(tap, ISC_DISABLE, TAP_IDLE); + if (retval != ERROR_OK) + return retval; + jtag_add_runtest(5, TAP_IDLE); + jtag_add_sleep(200000); + + retval = jtag_execute_queue(); + if (retval != ERROR_OK) + return retval; + return lattice_verify_usercode(lattice_device, 0x0, usercode, REGISTER_ALL_BITS_1); +} + +static int lattice_ecp5_enable_sram_programming(struct jtag_tap *tap) +{ + int retval = lattice_set_instr(tap, ISC_ENABLE, TAP_IDLE); + if (retval != ERROR_OK) + return retval; + + struct scan_field field; + uint8_t buffer = 0x0; + field.num_bits = 8; + field.out_value = &buffer; + field.in_value = NULL; + jtag_add_dr_scan(tap, 1, &field, TAP_IDLE); + jtag_add_runtest(2, TAP_IDLE); + jtag_add_sleep(10000); + + return jtag_execute_queue(); +} + +static int lattice_ecp5_erase_sram(struct jtag_tap *tap) +{ + int retval = lattice_set_instr(tap, ISC_ERASE, TAP_IRPAUSE); + if (retval != ERROR_OK) + return retval; + + struct scan_field field; + uint8_t buffer = 1; + field.num_bits = 8; + field.out_value = &buffer; + field.in_value = NULL; + jtag_add_dr_scan(tap, 1, &field, TAP_IDLE); + jtag_add_runtest(2, TAP_IDLE); + jtag_add_sleep(200000); + return jtag_execute_queue(); +} + +static int lattice_ecp5_init_address(struct jtag_tap *tap) +{ + int retval = lattice_set_instr(tap, LSC_INIT_ADDRESS, TAP_IDLE); + if (retval != ERROR_OK) + return retval; + + struct scan_field field; + uint8_t buffer = 1; + field.num_bits = 8; + field.out_value = &buffer; + field.in_value = NULL; + jtag_add_dr_scan(tap, 1, &field, TAP_IDLE); + jtag_add_runtest(2, TAP_IDLE); + jtag_add_sleep(10000); + return jtag_execute_queue(); +} + +static int lattice_ecp5_program_config_map(struct jtag_tap *tap, struct lattice_bit_file *bit_file) +{ + int retval = lattice_set_instr(tap, LSC_BITSTREAM_BURST, TAP_IDLE); + if (retval != ERROR_OK) + return retval; + jtag_add_runtest(2, TAP_IDLE); + jtag_add_sleep(10000); + + struct scan_field field; + field.num_bits = (bit_file->raw_bit.length - bit_file->offset) * 8; + field.out_value = bit_file->raw_bit.data + bit_file->offset; + field.in_value = NULL; + jtag_add_dr_scan(tap, 1, &field, TAP_IDLE); + retval = lattice_set_instr(tap, BYPASS, TAP_IDLE); + if (retval != ERROR_OK) + return retval; + jtag_add_runtest(100, TAP_IDLE); + jtag_add_sleep(10000); + + return jtag_execute_queue(); +} + +static int lattice_ecp5_exit_programming_mode(struct jtag_tap *tap) +{ + int retval = lattice_set_instr(tap, ISC_DISABLE, TAP_IDLE); + if (retval != ERROR_OK) + return retval; + jtag_add_runtest(2, TAP_IDLE); + jtag_add_sleep(200000); + retval = lattice_set_instr(tap, BYPASS, TAP_IDLE); + if (retval != ERROR_OK) + return retval; + jtag_add_runtest(2, TAP_IDLE); + jtag_add_sleep(1000); + return jtag_execute_queue(); +} + +int lattice_ecp5_load(struct lattice_pld_device *lattice_device, struct lattice_bit_file *bit_file) +{ + struct jtag_tap *tap = lattice_device->tap; + if (!tap) + return ERROR_FAIL; + + int retval = lattice_preload(lattice_device); + if (retval != ERROR_OK) + return retval; + + retval = lattice_ecp5_enable_sram_programming(tap); + if (retval != ERROR_OK) + return retval; + + const uint32_t out = 0x0; + const uint32_t expected1 = 0x0; + const uint32_t mask1 = STATUS_ERROR_BITS | STATUS_FEA_OTP; + retval = lattice_verify_status_register_u32(lattice_device, out, expected1, mask1, true); + if (retval != ERROR_OK) + return retval; + + retval = lattice_ecp5_erase_sram(tap); + if (retval != ERROR_OK) + return retval; + + const uint32_t mask2 = STATUS_FAIL_FLAG | STATUS_BUSY_FLAG; + retval = lattice_verify_status_register_u32(lattice_device, out, expected1, mask2, false); + if (retval != ERROR_OK) + return retval; + + retval = lattice_ecp5_init_address(tap); + if (retval != ERROR_OK) + return retval; + + retval = lattice_ecp5_program_config_map(tap, bit_file); + if (retval != ERROR_OK) + return retval; + + retval = lattice_ecp5_exit_programming_mode(tap); + if (retval != ERROR_OK) + return retval; + + const uint32_t expected2 = STATUS_DONE_BIT; + const uint32_t mask3 = STATUS_DONE_BIT | STATUS_FAIL_FLAG; + return lattice_verify_status_register_u32(lattice_device, out, expected2, mask3, false); +} diff --git a/src/pld/ecp5.h b/src/pld/ecp5.h new file mode 100644 index 000000000..7b0c86b4a --- /dev/null +++ b/src/pld/ecp5.h @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/*************************************************************************** + * Copyright (C) 2022 by Daniel Anselmi * + * danselmi@gmx.ch * + ***************************************************************************/ + +#ifndef OPENOCD_PLD_ECP5_H +#define OPENOCD_PLD_ECP5_H + +#include "lattice.h" + +int lattice_ecp5_read_status(struct jtag_tap *tap, uint32_t *status, uint32_t out, bool do_idle); +int lattice_ecp5_read_usercode(struct jtag_tap *tap, uint32_t *usercode, uint32_t out); +int lattice_ecp5_write_usercode(struct lattice_pld_device *lattice_device, uint32_t usercode); +int lattice_ecp5_load(struct lattice_pld_device *lattice_device, struct lattice_bit_file *bit_file); + +#endif /* OPENOCD_PLD_ECP5_H */ diff --git a/src/pld/lattice.c b/src/pld/lattice.c index 489b1895f..f3d9c0da7 100644 --- a/src/pld/lattice.c +++ b/src/pld/lattice.c @@ -14,6 +14,7 @@ #include "pld.h" #include "lattice_bit.h" #include "ecp2_3.h" +#include "ecp5.h" #define PRELOAD 0x1C @@ -39,6 +40,16 @@ static const struct lattice_devices_elem lattice_devices[] = { {0x01012043, 675, LATTICE_ECP3 /* ecp3 lae3-35ea & lfe3-35ea*/}, {0x01014043, 1077, LATTICE_ECP3 /* ecp3 lfe3-70ea & lfe3-70e & lfe3-95ea && lfe3-95e*/}, {0x01015043, 1326, LATTICE_ECP3 /* ecp3 lfe3-150e*/}, + {0x21111043, 409, LATTICE_ECP5 /* "LAE5U-12F & LFE5U-12F" */}, + {0x41111043, 409, LATTICE_ECP5 /* "LFE5U-25F" */}, + {0x41112043, 510, LATTICE_ECP5 /* "LFE5U-45F" */}, + {0x41113043, 750, LATTICE_ECP5 /* "LFE5U-85F" */}, + {0x81111043, 409, LATTICE_ECP5 /* "LFE5UM5G-25F" */}, + {0x81112043, 510, LATTICE_ECP5 /* "LFE5UM5G-45F" */}, + {0x81113043, 750, LATTICE_ECP5 /* "LFE5UM5G-85F" */}, + {0x01111043, 409, LATTICE_ECP5 /* "LAE5UM-25F" */}, + {0x01112043, 510, LATTICE_ECP5 /* "LAE5UM-45F" */}, + {0x01113043, 750, LATTICE_ECP5 /* "LAE5UM-85F" */}, }; int lattice_set_instr(struct jtag_tap *tap, uint8_t new_instr, tap_state_t endstate) @@ -137,6 +148,8 @@ static int lattice_read_usercode(struct lattice_pld_device *lattice_device, uint if (lattice_device->family == LATTICE_ECP2 || lattice_device->family == LATTICE_ECP3) return lattice_ecp2_3_read_usercode(tap, usercode, out); + else if (lattice_device->family == LATTICE_ECP5) + return lattice_ecp5_read_usercode(tap, usercode, out); return ERROR_FAIL; } @@ -162,6 +175,8 @@ static int lattice_write_usercode(struct lattice_pld_device *lattice_device, uin { if (lattice_device->family == LATTICE_ECP2 || lattice_device->family == LATTICE_ECP3) return lattice_ecp2_3_write_usercode(lattice_device, usercode); + else if (lattice_device->family == LATTICE_ECP5) + return lattice_ecp5_write_usercode(lattice_device, usercode); return ERROR_FAIL; } @@ -174,6 +189,8 @@ static int lattice_read_status_u32(struct lattice_pld_device *lattice_device, ui if (lattice_device->family == LATTICE_ECP2 || lattice_device->family == LATTICE_ECP3) return lattice_ecp2_3_read_status(lattice_device->tap, status, out, do_idle); + else if (lattice_device->family == LATTICE_ECP5) + return lattice_ecp5_read_status(lattice_device->tap, status, out, do_idle); return ERROR_FAIL; } @@ -218,6 +235,7 @@ static int lattice_load_command(struct pld_device *pld_device, const char *filen if (retval != ERROR_OK) return retval; + uint32_t id = tap->idcode; retval = ERROR_FAIL; switch (lattice_device->family) { case LATTICE_ECP2: @@ -226,6 +244,12 @@ static int lattice_load_command(struct pld_device *pld_device, const char *filen case LATTICE_ECP3: retval = lattice_ecp3_load(lattice_device, &bit_file); break; + case LATTICE_ECP5: + if (bit_file.has_id && id != bit_file.idcode) + LOG_WARNING("Id on device (0x%8.8" PRIx32 ") and id in bit-stream (0x%8.8" PRIx32 ") don't match.", + id, bit_file.idcode); + retval = lattice_ecp5_load(lattice_device, &bit_file); + break; default: LOG_ERROR("loading unknown device family"); break; @@ -257,6 +281,8 @@ PLD_DEVICE_COMMAND_HANDLER(lattice_pld_device_command) family = LATTICE_ECP2; } else if (strcasecmp(CMD_ARGV[2], "ecp3") == 0) { family = LATTICE_ECP3; + } else if (strcasecmp(CMD_ARGV[2], "ecp5") == 0) { + family = LATTICE_ECP5; } else { command_print(CMD, "unknown family"); free(lattice_device); @@ -380,7 +406,8 @@ COMMAND_HANDLER(lattice_read_status_command_handler) return retval; uint32_t status; - retval = lattice_read_status_u32(lattice_device, &status, 0x0, false); + const bool do_idle = lattice_device->family == LATTICE_ECP5; + retval = lattice_read_status_u32(lattice_device, &status, 0x0, do_idle); if (retval == ERROR_OK) command_print(CMD, "0x%8.8" PRIx32, status); diff --git a/src/pld/lattice_cmd.h b/src/pld/lattice_cmd.h new file mode 100644 index 000000000..8d66ac4c4 --- /dev/null +++ b/src/pld/lattice_cmd.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/*************************************************************************** + * Copyright (C) 2022 by Daniel Anselmi * + * danselmi@gmx.ch * + ***************************************************************************/ + +#ifndef OPENOCD_PLD_LATTICE_CMD_H +#define OPENOCD_PLD_LATTICE_CMD_H + +#define ISC_ERASE 0x0E +#define ISC_DISABLE 0x26 +#define LSC_READ_STATUS 0x3C +#define LSC_INIT_ADDRESS 0x46 +#define LSC_BITSTREAM_BURST 0x7A +#define READ_USERCODE 0xC0 +#define ISC_ENABLE 0xC6 + +#endif /* OPENOCD_PLD_LATTICE_CMD_H */ diff --git a/tcl/board/ecp5_evaluation.cfg b/tcl/board/ecp5_evaluation.cfg new file mode 100644 index 000000000..427037b71 --- /dev/null +++ b/tcl/board/ecp5_evaluation.cfg @@ -0,0 +1,19 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# Lattice ECP5 evaluation Kit +# https://www.latticesemi.com/view_document?document_id=52479 +# + +adapter driver ftdi +ftdi vid_pid 0x0403 0x6010 + +ftdi channel 0 +ftdi layout_init 0x0008 0x008b +reset_config none +transport select jtag +adapter speed 6000 + +source [find fpga/lattice_ecp5.cfg] + +#openocd -f board/ecp5_evaluation.cfg -c "init" -c "pld load 0 shared_folder/ecp5_blinker_impl1.bit" +#ipdbg -start -tap ecp5.tap -hub 0x32 -port 5555 -tool 0 diff --git a/tcl/fpga/lattice_ecp5.cfg b/tcl/fpga/lattice_ecp5.cfg index a94ada740..41442492e 100644 --- a/tcl/fpga/lattice_ecp5.cfg +++ b/tcl/fpga/lattice_ecp5.cfg @@ -26,3 +26,5 @@ jtag newtap $_CHIPNAME tap -irlen 8 -irmask 0x83 -ircapture 0x1 \ -expected-id 0x21111043 -expected-id 0x41111043 -expected-id 0x41112043 \ -expected-id 0x41113043 -expected-id 0x81111043 -expected-id 0x81112043 \ -expected-id 0x81113043 + +pld device lattice $_CHIPNAME.tap From e33eae340d3502ffab8c172c246bc392a093c2ea Mon Sep 17 00:00:00 2001 From: Daniel Anselmi Date: Mon, 12 Dec 2022 09:49:51 +0100 Subject: [PATCH 15/49] pld: add support for lattice certus devices Change-Id: Ic50a724e5793000fca11f35ba848c2d317c3cbab Signed-off-by: Daniel Anselmi Reviewed-on: https://review.openocd.org/c/openocd/+/7398 Tested-by: jenkins Reviewed-by: Antonio Borneo --- doc/openocd.texi | 4 +- src/pld/Makefile.am | 2 + src/pld/certus.c | 232 +++++++++++++++++++++++++++++ src/pld/certus.h | 18 +++ src/pld/lattice.c | 83 ++++++++++- src/pld/lattice.h | 4 + tcl/board/certuspro_evaluation.cfg | 14 ++ tcl/fpga/lattice_certus.cfg | 18 +++ tcl/fpga/lattice_certuspro.cfg | 18 +++ 9 files changed, 383 insertions(+), 10 deletions(-) create mode 100644 src/pld/certus.c create mode 100644 src/pld/certus.h create mode 100644 tcl/board/certuspro_evaluation.cfg create mode 100644 tcl/fpga/lattice_certus.cfg create mode 100644 tcl/fpga/lattice_certuspro.cfg diff --git a/doc/openocd.texi b/doc/openocd.texi index 2d3ccfebe..24de2ce94 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -8497,10 +8497,10 @@ for FPGA @var{num}. @deffn {FPGA Driver} {lattice} [family] -The FGPA families ECP2, ECP3 and ECP5 by Lattice are supported. +The FGPA families ECP2, ECP3, ECP5, Certus and CertusPro by Lattice are supported. This driver can be used to load the bitstream into the FPGA or read the status register and read/write the usercode register. -The option @option{family} is one of @var{ecp2 ecp3 ecp5}. This is needed when the JTAG ID of the device is not known by openocd (newer NX devices). +The option @option{family} is one of @var{ecp2 ecp3 ecp5 certus}. This is needed when the JTAG ID of the device is not known by openocd (newer NX devices). @deffn {Command} {lattice read_status} num Reads and displays the status register diff --git a/src/pld/Makefile.am b/src/pld/Makefile.am index 459792f64..8ad4296f3 100644 --- a/src/pld/Makefile.am +++ b/src/pld/Makefile.am @@ -2,6 +2,7 @@ noinst_LTLIBRARIES += %D%/libpld.la %C%_libpld_la_SOURCES = \ + %D%/certus.c \ %D%/ecp2_3.c \ %D%/ecp5.c \ %D%/lattice.c \ @@ -10,6 +11,7 @@ noinst_LTLIBRARIES += %D%/libpld.la %D%/raw_bit.c \ %D%/xilinx_bit.c \ %D%/virtex2.c \ + %D%/certus.h \ %D%/ecp2_3.h \ %D%/ecp5.h \ %D%/lattice.h \ diff --git a/src/pld/certus.c b/src/pld/certus.c new file mode 100644 index 000000000..692ea1907 --- /dev/null +++ b/src/pld/certus.c @@ -0,0 +1,232 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/*************************************************************************** + * Copyright (C) 2022 by Daniel Anselmi * + * danselmi@gmx.ch * + ***************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "lattice.h" +#include "lattice_cmd.h" + +#define LSC_ENABLE_X 0x74 +#define LSC_REFRESH 0x79 +#define LSC_DEVICE_CTRL 0x7D + +int lattice_certus_read_status(struct jtag_tap *tap, uint64_t *status, uint64_t out) +{ + return lattice_read_u64_register(tap, LSC_READ_STATUS, status, out); +} + +int lattice_certus_read_usercode(struct jtag_tap *tap, uint32_t *usercode, uint32_t out) +{ + return lattice_read_u32_register(tap, READ_USERCODE, usercode, out, false); +} + +int lattice_certus_write_usercode(struct lattice_pld_device *lattice_device, uint32_t usercode) +{ + LOG_ERROR("Not supported to write usercode on certus devices"); + return ERROR_FAIL; +} + +static int lattice_certus_enable_transparent_mode(struct jtag_tap *tap) +{ + struct scan_field field; + + int retval = lattice_set_instr(tap, LSC_ENABLE_X, TAP_IDLE); + if (retval != ERROR_OK) + return retval; + + uint8_t buffer = 0x0; + field.num_bits = 8; + field.out_value = &buffer; + field.in_value = NULL; + jtag_add_dr_scan(tap, 1, &field, TAP_IDLE); + jtag_add_runtest(2, TAP_IDLE); + + return jtag_execute_queue(); +} + +static int lattice_certus_erase_device(struct lattice_pld_device *lattice_device) +{ + struct jtag_tap *tap = lattice_device->tap; + if (!tap) + return ERROR_FAIL; + + int retval = lattice_set_instr(tap, LSC_DEVICE_CTRL, TAP_IRPAUSE); + if (retval != ERROR_OK) + return retval; + + struct scan_field field; + uint8_t buffer = 8; + field.num_bits = 8; + field.out_value = &buffer; + field.in_value = NULL; + jtag_add_dr_scan(tap, 1, &field, TAP_IDLE); + jtag_add_runtest(2, TAP_IDLE); + retval = jtag_execute_queue(); + if (retval != ERROR_OK) + return retval; + + retval = lattice_set_instr(tap, LSC_DEVICE_CTRL, TAP_IDLE); + if (retval != ERROR_OK) + return retval; + buffer = 0; + field.num_bits = 8; + field.out_value = &buffer; + jtag_add_dr_scan(tap, 1, &field, TAP_IDLE); + jtag_add_runtest(2, TAP_IDLE); + retval = jtag_execute_queue(); + if (retval != ERROR_OK) + return retval; + + retval = lattice_set_instr(tap, ISC_ERASE, TAP_IDLE); + if (retval != ERROR_OK) + return retval; + buffer = 0; + field.num_bits = 8; + field.out_value = &buffer; + jtag_add_dr_scan(tap, 1, &field, TAP_IDLE); + jtag_add_runtest(100, TAP_IDLE); + jtag_add_sleep(5000); + retval = jtag_execute_queue(); + if (retval != ERROR_OK) + return retval; + + /* check done is cleared and fail is cleared */ + const uint64_t status_done_flag = 0x100; + const uint64_t status_fail_flag = 0x2000; + return lattice_verify_status_register_u64(lattice_device, 0x0, 0x0, status_done_flag | status_fail_flag); +} + +static int lattice_certus_enable_programming(struct jtag_tap *tap) +{ + struct scan_field field; + + int retval = lattice_set_instr(tap, LSC_REFRESH, TAP_IDLE); + if (retval != ERROR_OK) + return retval; + jtag_add_runtest(2, TAP_IDLE); + retval = jtag_execute_queue(); + if (retval != ERROR_OK) + return retval; + + retval = lattice_set_instr(tap, ISC_ENABLE, TAP_IDLE); + if (retval != ERROR_OK) + return retval; + uint8_t buffer = 0; + field.num_bits = 8; + field.out_value = &buffer; + jtag_add_dr_scan(tap, 1, &field, TAP_IDLE); + jtag_add_runtest(2, TAP_IDLE); + return jtag_execute_queue(); +} + +static int lattice_certus_init_address(struct jtag_tap *tap) +{ + int retval = lattice_set_instr(tap, LSC_INIT_ADDRESS, TAP_IDLE); + if (retval != ERROR_OK) + return retval; + jtag_add_runtest(2, TAP_IDLE); + return jtag_execute_queue(); +} + +static int lattice_certus_exit_programming_mode(struct jtag_tap *tap) +{ + int retval = lattice_set_instr(tap, ISC_DISABLE, TAP_IDLE); + if (retval != ERROR_OK) + return retval; + jtag_add_runtest(2, TAP_IDLE); + retval = lattice_set_instr(tap, BYPASS, TAP_IDLE); + if (retval != ERROR_OK) + return retval; + jtag_add_runtest(100, TAP_IDLE); + return jtag_execute_queue(); +} + +static int lattice_certus_program_config_map(struct jtag_tap *tap, struct lattice_bit_file *bit_file) +{ + struct scan_field field; + + int retval = lattice_set_instr(tap, LSC_BITSTREAM_BURST, TAP_IDLE); + if (retval != ERROR_OK) + return retval; + + field.num_bits = (bit_file->raw_bit.length - bit_file->offset) * 8; + field.out_value = bit_file->raw_bit.data + bit_file->offset; + field.in_value = NULL; + jtag_add_dr_scan(tap, 1, &field, TAP_IDLE); + + return jtag_execute_queue(); +} + +int lattice_certus_load(struct lattice_pld_device *lattice_device, struct lattice_bit_file *bit_file) +{ + struct jtag_tap *tap = lattice_device->tap; + if (!tap) + return ERROR_FAIL; + + int retval = lattice_preload(lattice_device); + if (retval != ERROR_OK) + return retval; + + /* check password protection is disabled */ + const uint64_t status_pwd_protection = 0x20000; + retval = lattice_verify_status_register_u64(lattice_device, 0x0, 0x0, status_pwd_protection); + if (retval != ERROR_OK) { + LOG_ERROR("Password protection is set"); + return retval; + } + + retval = lattice_certus_enable_transparent_mode(tap); + if (retval != ERROR_OK) + return retval; + + /* Check the SRAM Erase Lock */ + const uint64_t status_otp = 0x40; + retval = lattice_verify_status_register_u64(lattice_device, 0x0, status_otp, status_otp); + if (retval != ERROR_OK) { + LOG_ERROR("NV User Feature Sector OTP is Set"); + return retval; + } + + /* Check the SRAM Lock */ + const uint64_t status_write_protected = 0x400; + retval = lattice_verify_status_register_u64(lattice_device, 0x0, 0x0, status_write_protected); + if (retval != ERROR_OK) { + LOG_ERROR("NV User Feature Sector OTP is Set"); + return retval; + } + + retval = lattice_certus_enable_programming(tap); + if (retval != ERROR_OK) { + LOG_ERROR("failed to enable programming mode"); + return retval; + } + + retval = lattice_certus_erase_device(lattice_device); + if (retval != ERROR_OK) { + LOG_ERROR("erasing device failed"); + return retval; + } + + retval = lattice_certus_init_address(tap); + if (retval != ERROR_OK) + return retval; + + retval = lattice_certus_program_config_map(tap, bit_file); + if (retval != ERROR_OK) + return retval; + const uint32_t expected = 0x100; // done + const uint32_t mask = expected | + 0x3000 | // Busy Flag and Fail Flag + 0xf000000; // BSE Error + retval = lattice_verify_status_register_u64(lattice_device, 0x0, 0x100, mask); + if (retval != ERROR_OK) + return retval; + + return lattice_certus_exit_programming_mode(tap); +} diff --git a/src/pld/certus.h b/src/pld/certus.h new file mode 100644 index 000000000..51defc5ca --- /dev/null +++ b/src/pld/certus.h @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/*************************************************************************** + * Copyright (C) 2022 by Daniel Anselmi * + * danselmi@gmx.ch * + ***************************************************************************/ + +#ifndef OPENOCD_PLD_CERTUS_H +#define OPENOCD_PLD_CERTUS_H + +#include "lattice.h" + +int lattice_certus_read_status(struct jtag_tap *tap, uint64_t *status, uint64_t out); +int lattice_certus_read_usercode(struct jtag_tap *tap, uint32_t *usercode, uint32_t out); +int lattice_certus_write_usercode(struct lattice_pld_device *lattice_device, uint32_t usercode); +int lattice_certus_load(struct lattice_pld_device *lattice_device, struct lattice_bit_file *bit_file); + +#endif /* OPENOCD_PLD_CERTUS_H */ diff --git a/src/pld/lattice.c b/src/pld/lattice.c index f3d9c0da7..4ab5f63c0 100644 --- a/src/pld/lattice.c +++ b/src/pld/lattice.c @@ -15,6 +15,7 @@ #include "lattice_bit.h" #include "ecp2_3.h" #include "ecp5.h" +#include "certus.h" #define PRELOAD 0x1C @@ -50,6 +51,9 @@ static const struct lattice_devices_elem lattice_devices[] = { {0x01111043, 409, LATTICE_ECP5 /* "LAE5UM-25F" */}, {0x01112043, 510, LATTICE_ECP5 /* "LAE5UM-45F" */}, {0x01113043, 750, LATTICE_ECP5 /* "LAE5UM-85F" */}, + {0x310f0043, 362, LATTICE_CERTUS /* LFD2NX-17 */}, + {0x310f1043, 362, LATTICE_CERTUS /* LFD2NX-40 */}, + {0x010f4043, 362, LATTICE_CERTUS /* LFCPNX-100 */}, }; int lattice_set_instr(struct jtag_tap *tap, uint8_t new_instr, tap_state_t endstate) @@ -116,6 +120,27 @@ int lattice_read_u32_register(struct jtag_tap *tap, uint8_t cmd, uint32_t *in_va return retval; } +int lattice_read_u64_register(struct jtag_tap *tap, uint8_t cmd, uint64_t *in_val, + uint64_t out_val) +{ + struct scan_field field; + uint8_t buffer[8]; + + int retval = lattice_set_instr(tap, cmd, TAP_IDLE); + if (retval != ERROR_OK) + return retval; + h_u64_to_le(buffer, out_val); + field.num_bits = 64; + field.out_value = buffer; + field.in_value = buffer; + jtag_add_dr_scan(tap, 1, &field, TAP_IDLE); + retval = jtag_execute_queue(); + if (retval == ERROR_OK) + *in_val = le_to_h_u64(buffer); + + return retval; +} + int lattice_preload(struct lattice_pld_device *lattice_device) { struct scan_field field; @@ -150,6 +175,8 @@ static int lattice_read_usercode(struct lattice_pld_device *lattice_device, uint return lattice_ecp2_3_read_usercode(tap, usercode, out); else if (lattice_device->family == LATTICE_ECP5) return lattice_ecp5_read_usercode(tap, usercode, out); + else if (lattice_device->family == LATTICE_CERTUS) + return lattice_certus_read_usercode(tap, usercode, out); return ERROR_FAIL; } @@ -177,6 +204,8 @@ static int lattice_write_usercode(struct lattice_pld_device *lattice_device, uin return lattice_ecp2_3_write_usercode(lattice_device, usercode); else if (lattice_device->family == LATTICE_ECP5) return lattice_ecp5_write_usercode(lattice_device, usercode); + else if (lattice_device->family == LATTICE_CERTUS) + return lattice_certus_write_usercode(lattice_device, usercode); return ERROR_FAIL; } @@ -194,12 +223,22 @@ static int lattice_read_status_u32(struct lattice_pld_device *lattice_device, ui return ERROR_FAIL; } +static int lattice_read_status_u64(struct lattice_pld_device *lattice_device, uint64_t *status, + uint64_t out) +{ + if (!lattice_device->tap) + return ERROR_FAIL; + + if (lattice_device->family == LATTICE_CERTUS) + return lattice_certus_read_status(lattice_device->tap, status, out); + + return ERROR_FAIL; +} int lattice_verify_status_register_u32(struct lattice_pld_device *lattice_device, uint32_t out, uint32_t expected, uint32_t mask, bool do_idle) { uint32_t status; - int retval = lattice_read_status_u32(lattice_device, &status, out, do_idle); if (retval != ERROR_OK) return retval; @@ -212,13 +251,28 @@ int lattice_verify_status_register_u32(struct lattice_pld_device *lattice_device return ERROR_OK; } +int lattice_verify_status_register_u64(struct lattice_pld_device *lattice_device, uint64_t out, + uint64_t expected, uint64_t mask) +{ + uint64_t status; + int retval = lattice_read_status_u64(lattice_device, &status, out); + if (retval != ERROR_OK) + return retval; + + if ((status & mask) != expected) { + LOG_ERROR("verifying status register failed got: 0x%08" PRIx64 " expected: 0x%08" PRIx64, + status & mask, expected); + return ERROR_FAIL; + } + return ERROR_OK; +} + static int lattice_load_command(struct pld_device *pld_device, const char *filename) { if (!pld_device) return ERROR_FAIL; struct lattice_pld_device *lattice_device = pld_device->driver_priv; - if (!lattice_device || !lattice_device->tap) return ERROR_FAIL; struct jtag_tap *tap = lattice_device->tap; @@ -245,10 +299,14 @@ static int lattice_load_command(struct pld_device *pld_device, const char *filen retval = lattice_ecp3_load(lattice_device, &bit_file); break; case LATTICE_ECP5: + case LATTICE_CERTUS: if (bit_file.has_id && id != bit_file.idcode) LOG_WARNING("Id on device (0x%8.8" PRIx32 ") and id in bit-stream (0x%8.8" PRIx32 ") don't match.", id, bit_file.idcode); - retval = lattice_ecp5_load(lattice_device, &bit_file); + if (lattice_device->family == LATTICE_ECP5) + retval = lattice_ecp5_load(lattice_device, &bit_file); + else + retval = lattice_certus_load(lattice_device, &bit_file); break; default: LOG_ERROR("loading unknown device family"); @@ -283,6 +341,8 @@ PLD_DEVICE_COMMAND_HANDLER(lattice_pld_device_command) family = LATTICE_ECP3; } else if (strcasecmp(CMD_ARGV[2], "ecp5") == 0) { family = LATTICE_ECP5; + } else if (strcasecmp(CMD_ARGV[2], "certus") == 0) { + family = LATTICE_CERTUS; } else { command_print(CMD, "unknown family"); free(lattice_device); @@ -405,11 +465,18 @@ COMMAND_HANDLER(lattice_read_status_command_handler) if (retval != ERROR_OK) return retval; - uint32_t status; - const bool do_idle = lattice_device->family == LATTICE_ECP5; - retval = lattice_read_status_u32(lattice_device, &status, 0x0, do_idle); - if (retval == ERROR_OK) - command_print(CMD, "0x%8.8" PRIx32, status); + if (lattice_device->family == LATTICE_CERTUS) { + uint64_t status; + retval = lattice_read_status_u64(lattice_device, &status, 0x0); + if (retval == ERROR_OK) + command_print(CMD, "0x%016" PRIx64, status); + } else { + uint32_t status; + const bool do_idle = lattice_device->family == LATTICE_ECP5; + retval = lattice_read_status_u32(lattice_device, &status, 0x0, do_idle); + if (retval == ERROR_OK) + command_print(CMD, "0x%8.8" PRIx32, status); + } return retval; } diff --git a/src/pld/lattice.h b/src/pld/lattice.h index 6d692cbe4..9a76a4ec3 100644 --- a/src/pld/lattice.h +++ b/src/pld/lattice.h @@ -23,10 +23,14 @@ struct lattice_pld_device { int lattice_set_instr(struct jtag_tap *tap, uint8_t new_instr, tap_state_t endstate); int lattice_read_u32_register(struct jtag_tap *tap, uint8_t cmd, uint32_t *in_val, uint32_t out_val, bool do_idle); +int lattice_read_u64_register(struct jtag_tap *tap, uint8_t cmd, uint64_t *in_val, + uint64_t out_val); int lattice_verify_usercode(struct lattice_pld_device *lattice_device, uint32_t out, uint32_t expected, uint32_t mask); int lattice_verify_status_register_u32(struct lattice_pld_device *lattice_device, uint32_t out, uint32_t expected, uint32_t mask, bool do_idle); +int lattice_verify_status_register_u64(struct lattice_pld_device *lattice_device, uint64_t out, + uint64_t expected, uint64_t mask); int lattice_preload(struct lattice_pld_device *lattice_device); #endif /* OPENOCD_PLD_LATTICE_H */ diff --git a/tcl/board/certuspro_evaluation.cfg b/tcl/board/certuspro_evaluation.cfg new file mode 100644 index 000000000..5ff2a1e32 --- /dev/null +++ b/tcl/board/certuspro_evaluation.cfg @@ -0,0 +1,14 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# https://www.latticesemi.com/products/developmentboardsandkits/certuspro-nx-versa-board + +adapter driver ftdi +ftdi vid_pid 0x0403 0x6010 + +ftdi channel 0 +ftdi layout_init 0x0008 0x008b +reset_config none +transport select jtag +adapter speed 10000 + +source [find fpga/lattice_certuspro.cfg] diff --git a/tcl/fpga/lattice_certus.cfg b/tcl/fpga/lattice_certus.cfg new file mode 100644 index 000000000..95b6e59d8 --- /dev/null +++ b/tcl/fpga/lattice_certus.cfg @@ -0,0 +1,18 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +if { [info exists CHIPNAME] } { + set _CHIPNAME $_CHIPNAME +} else { + set _CHIPNAME certus +} + +# Lattice Certus +# +# Certus NX LFD2NX-17 0x310f0043 +# Certus NX LFD2NX-40 0x310f1043 + + +jtag newtap $_CHIPNAME tap -irlen 8 -irmask 0x83 -ircapture 0x1 \ + -expected-id 0x310F1043 -expected-id 0x310F0043 + +pld device lattice $_CHIPNAME.tap diff --git a/tcl/fpga/lattice_certuspro.cfg b/tcl/fpga/lattice_certuspro.cfg new file mode 100644 index 000000000..c15a379ae --- /dev/null +++ b/tcl/fpga/lattice_certuspro.cfg @@ -0,0 +1,18 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +if { [info exists CHIPNAME] } { + set _CHIPNAME $_CHIPNAME +} else { + set _CHIPNAME certuspro +} + +# Lattice CertusPro +# +# 0x010f4043 - LFCPNX-100 +# 0x 043 - LFCPNX-50 + +jtag newtap $_CHIPNAME tap -irlen 8 -irmask 0x83 -ircapture 0x1 \ + -expected-id 0x010f4043 +# -expected-id 0x01112043 + +pld device lattice $_CHIPNAME.tap From 7c6d44644082eb33d91af62091c37ba1384555ad Mon Sep 17 00:00:00 2001 From: Daniel Anselmi Date: Mon, 12 Dec 2022 09:49:51 +0100 Subject: [PATCH 16/49] pld: add support for efinix devices Change-Id: Ie520e761c255ba1335d5aab9c6825f160a6151d9 Signed-off-by: Daniel Anselmi Reviewed-on: https://review.openocd.org/c/openocd/+/7288 Reviewed-by: Antonio Borneo Tested-by: jenkins --- doc/openocd.texi | 6 + src/pld/Makefile.am | 1 + src/pld/efinix.c | 218 +++++++++++++++++++++++++++++++++ src/pld/pld.c | 2 + tcl/board/trion_t20_bga256.cfg | 24 ++++ tcl/fpga/efinix_titanium.cfg | 23 ++++ tcl/fpga/efinix_trion.cfg | 17 +++ 7 files changed, 291 insertions(+) create mode 100644 src/pld/efinix.c create mode 100644 tcl/board/trion_t20_bga256.cfg create mode 100644 tcl/fpga/efinix_titanium.cfg create mode 100644 tcl/fpga/efinix_trion.cfg diff --git a/doc/openocd.texi b/doc/openocd.texi index 24de2ce94..6037b8bb2 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -8524,6 +8524,12 @@ The load command for the FPGA @var{num} will use a length for the preload of @va @end deffn +@deffn {FPGA Driver} {efinix} +Both families (Trion and Titanium) sold by Efinix are supported as both use the same protocol for In-System Configuration. +This driver can be used to load the bitstream into the FPGA. +@end deffn + + @node General Commands @chapter General Commands diff --git a/src/pld/Makefile.am b/src/pld/Makefile.am index 8ad4296f3..be33bcd09 100644 --- a/src/pld/Makefile.am +++ b/src/pld/Makefile.am @@ -5,6 +5,7 @@ noinst_LTLIBRARIES += %D%/libpld.la %D%/certus.c \ %D%/ecp2_3.c \ %D%/ecp5.c \ + %D%/efinix.c \ %D%/lattice.c \ %D%/lattice_bit.c \ %D%/pld.c \ diff --git a/src/pld/efinix.c b/src/pld/efinix.c new file mode 100644 index 000000000..f08439476 --- /dev/null +++ b/src/pld/efinix.c @@ -0,0 +1,218 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/*************************************************************************** + * Copyright (C) 2022 by Daniel Anselmi * + * danselmi@gmx.ch * + ***************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#include "pld.h" +#include "raw_bit.h" + +#define PROGRAM 0x4 +#define ENTERUSER 0x7 + +#define TRAILING_ZEROS 4000 +#define RUNTEST_START_CYCLES 100 +#define RUNTEST_FINISH_CYCLES 100 + +struct efinix_pld_device { + struct jtag_tap *tap; +}; + +static int efinix_read_bit_file(struct raw_bit_file *bit_file, const char *filename) +{ + FILE *input_file = fopen(filename, "r"); + if (!input_file) { + LOG_ERROR("couldn't open %s: %s", filename, strerror(errno)); + return ERROR_PLD_FILE_LOAD_FAILED; + } + + fseek(input_file, 0, SEEK_END); + long length = ftell(input_file); + fseek(input_file, 0, SEEK_SET); + + if (length < 0 || ((length % 3))) { + fclose(input_file); + LOG_ERROR("Failed to get length from file %s: %s", filename, strerror(errno)); + return ERROR_PLD_FILE_LOAD_FAILED; + } + bit_file->length = DIV_ROUND_UP(length, 3); + + bit_file->data = malloc(bit_file->length); + if (!bit_file->data) { + fclose(input_file); + LOG_ERROR("Out of memory"); + return ERROR_PLD_FILE_LOAD_FAILED; + } + + bool end_detected = false; + char buffer[3]; + for (size_t idx = 0; !end_detected && idx < bit_file->length; ++idx) { + size_t read_count = fread(buffer, sizeof(char), 3, input_file); + end_detected = feof(input_file); + if ((read_count == 3 && buffer[2] != '\n') || + (read_count != 3 && !end_detected) || + (read_count != 2 && end_detected)) { + fclose(input_file); + free(bit_file->data); + bit_file->data = NULL; + LOG_ERROR("unexpected line length"); + return ERROR_PLD_FILE_LOAD_FAILED; + } + + if (!isxdigit(buffer[0]) || !isxdigit(buffer[1])) { + fclose(input_file); + free(bit_file->data); + bit_file->data = NULL; + LOG_ERROR("unexpected char in hex string"); + return ERROR_PLD_FILE_LOAD_FAILED; + } + unhexify(&bit_file->data[idx], buffer, 2); + } + + fclose(input_file); + + return ERROR_OK; +} + +static int efinix_read_file(struct raw_bit_file *bit_file, const char *filename) +{ + if (!filename || !bit_file) + return ERROR_COMMAND_SYNTAX_ERROR; + + /* check if binary .bin or ascii .bit/.hex */ + const char *file_ending_pos = strrchr(filename, '.'); + if (!file_ending_pos) { + LOG_ERROR("Unable to detect filename suffix"); + return ERROR_PLD_FILE_LOAD_FAILED; + } + + if (strcasecmp(file_ending_pos, ".bin") == 0) { + return cpld_read_raw_bit_file(bit_file, filename); + } else if ((strcasecmp(file_ending_pos, ".bit") == 0) || + (strcasecmp(file_ending_pos, ".hex") == 0)) { + return efinix_read_bit_file(bit_file, filename); + } + + LOG_ERROR("Unable to detect filetype"); + return ERROR_PLD_FILE_LOAD_FAILED; +} + +static int efinix_set_instr(struct jtag_tap *tap, uint8_t new_instr) +{ + struct scan_field field; + field.num_bits = tap->ir_length; + void *t = calloc(DIV_ROUND_UP(field.num_bits, 8), 1); + if (!t) { + LOG_ERROR("Out of memory"); + return ERROR_FAIL; + } + field.out_value = t; + buf_set_u32(t, 0, field.num_bits, new_instr); + field.in_value = NULL; + jtag_add_ir_scan(tap, &field, TAP_IDLE); + free(t); + return ERROR_OK; +} + +static int efinix_load(struct pld_device *pld_device, const char *filename) +{ + struct raw_bit_file bit_file; + struct scan_field field[2]; + + if (!pld_device || !pld_device->driver_priv) + return ERROR_FAIL; + + struct efinix_pld_device *efinix_info = pld_device->driver_priv; + if (!efinix_info || !efinix_info->tap) + return ERROR_FAIL; + struct jtag_tap *tap = efinix_info->tap; + + jtag_add_tlr(); + + int retval = efinix_set_instr(tap, PROGRAM); + if (retval != ERROR_OK) + return retval; + jtag_add_runtest(RUNTEST_START_CYCLES, TAP_IDLE); + retval = efinix_set_instr(tap, PROGRAM); /* fix for T20 */ + if (retval != ERROR_OK) + return retval; + retval = jtag_execute_queue(); + if (retval != ERROR_OK) + return retval; + + retval = efinix_read_file(&bit_file, filename); + if (retval != ERROR_OK) + return retval; + + for (size_t i = 0; i < bit_file.length; i++) + bit_file.data[i] = flip_u32(bit_file.data[i], 8); + + /* shift in the bitstream */ + field[0].num_bits = bit_file.length * 8; + field[0].out_value = bit_file.data; + field[0].in_value = NULL; + + /* followed by zeros */ + field[1].num_bits = TRAILING_ZEROS; + uint8_t *buf = calloc(TRAILING_ZEROS / 8, 1); + if (!buf) { + free(bit_file.data); + LOG_ERROR("Out of memory"); + return ERROR_FAIL; + } + field[1].out_value = buf; + field[1].in_value = NULL; + + jtag_add_dr_scan(tap, 2, field, TAP_DRPAUSE); + retval = jtag_execute_queue(); + free(bit_file.data); + free(buf); + if (retval != ERROR_OK) + return retval; + + retval = efinix_set_instr(tap, ENTERUSER); + if (retval != ERROR_OK) + return retval; + + /* entering RUN/TEST for 100 cycles */ + jtag_add_runtest(RUNTEST_FINISH_CYCLES, TAP_IDLE); + retval = jtag_execute_queue(); + + return retval; +} + +PLD_DEVICE_COMMAND_HANDLER(efinix_pld_device_command) +{ + if (CMD_ARGC != 2) + return ERROR_COMMAND_SYNTAX_ERROR; + + struct jtag_tap *tap = jtag_tap_by_string(CMD_ARGV[1]); + if (!tap) { + command_print(CMD, "Tap: %s does not exist", CMD_ARGV[1]); + return ERROR_FAIL; + } + + struct efinix_pld_device *efinix_info = malloc(sizeof(struct efinix_pld_device)); + if (!efinix_info) { + LOG_ERROR("Out of memory"); + return ERROR_FAIL; + } + efinix_info->tap = tap; + + pld->driver_priv = efinix_info; + + return ERROR_OK; +} + +struct pld_driver efinix_pld = { + .name = "efinix", + .pld_device_command = &efinix_pld_device_command, + .load = &efinix_load, +}; diff --git a/src/pld/pld.c b/src/pld/pld.c index e838888ce..a92486ab1 100644 --- a/src/pld/pld.c +++ b/src/pld/pld.c @@ -18,10 +18,12 @@ /* pld drivers */ +extern struct pld_driver efinix_pld; extern struct pld_driver lattice_pld; extern struct pld_driver virtex2_pld; static struct pld_driver *pld_drivers[] = { + &efinix_pld, &lattice_pld, &virtex2_pld, NULL, diff --git a/tcl/board/trion_t20_bga256.cfg b/tcl/board/trion_t20_bga256.cfg new file mode 100644 index 000000000..045d63de3 --- /dev/null +++ b/tcl/board/trion_t20_bga256.cfg @@ -0,0 +1,24 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# Trion® T20 BGA256 Development Kit +# https://www.efinixinc.com/docs/trion20-devkit-ug-v1.5.pdf +# +# works after power cycle or pushing sw1. +# it is because we cannot control CDONE which is connected to ftdi channel 0 +# note from an006: For JTAG programming, T4, T8, T13, and T20 FPGAs use the +# CRESET_N and SS_N pins in addition to the standard JTAG pins. + +adapter driver ftdi +ftdi vid_pid 0x0403 0x6010 + +ftdi channel 1 +ftdi layout_init 0x0008 0x008b +reset_config none +transport select jtag +adapter speed 6000 + +source [find fpga/efinix_trion.cfg] + +#openocd -f board/trion_t20_bga256.cfg -c "init" -c "pld load 0 outflow/trion_blinker.bit" +#ipdbg -start -tap trion.tap -hub 0x8 -port 5555 -tool 0 + diff --git a/tcl/fpga/efinix_titanium.cfg b/tcl/fpga/efinix_titanium.cfg new file mode 100644 index 000000000..681b58fc8 --- /dev/null +++ b/tcl/fpga/efinix_titanium.cfg @@ -0,0 +1,23 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# efinix titanium +# https://www.efinixinc.com/docs/an048-jtag-bst-titanium-v1.0.pdf + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME titanium +} + +jtag newtap $_CHIPNAME tap -irlen 5 -ignore-version \ + -expected-id 0x10661A79 \ + -expected-id 0x00360A79 \ + -expected-id 0x10660A79 \ + -expected-id 0x00681A79 \ + -expected-id 0x00688A79 \ + -expected-id 0x00682A79 \ + -expected-id 0x0068CA79 \ + -expected-id 0x00680A79 \ + -expected-id 0x00684A79 + +pld device efinix $_CHIPNAME.tap diff --git a/tcl/fpga/efinix_trion.cfg b/tcl/fpga/efinix_trion.cfg new file mode 100644 index 000000000..ecd2edad4 --- /dev/null +++ b/tcl/fpga/efinix_trion.cfg @@ -0,0 +1,17 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# efinix trion +# https://www.efinixinc.com/docs/an021-jtag-bst-trion-v1.0.pdf + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME trion +} + +jtag newtap $_CHIPNAME tap -irlen 4 -ignore-version \ + -expected-id 0x00210A79 \ + -expected-id 0x00240A79 \ + -expected-id 0x00220A79 + +pld device efinix $_CHIPNAME.tap From db0609aeb4d5c8dec607afb1e07f5083d3b242c3 Mon Sep 17 00:00:00 2001 From: Daniel Anselmi Date: Mon, 12 Dec 2022 09:49:51 +0100 Subject: [PATCH 17/49] pld: add support for altera/intel devices Change-Id: I7977d39c9037ae71139f78c8d381f5f925dc3489 Signed-off-by: Daniel Anselmi Reviewed-on: https://review.openocd.org/c/openocd/+/7355 Tested-by: jenkins Reviewed-by: Antonio Borneo --- doc/openocd.texi | 28 ++ src/pld/Makefile.am | 1 + src/pld/intel.c | 474 +++++++++++++++++++++++++++++++ src/pld/pld.c | 2 + tcl/board/bemicro_cycloneiii.cfg | 20 ++ tcl/cpld/altera-5m570z-cpld.cfg | 13 +- tcl/cpld/altera-epm240.cfg | 24 +- tcl/cpld/altera-max10.cfg | 30 ++ tcl/cpld/altera-maxii.cfg | 21 ++ tcl/cpld/altera-maxv.cfg | 19 ++ tcl/fpga/altera-10m50.cfg | 27 +- tcl/fpga/altera-arriaii.cfg | 31 ++ tcl/fpga/altera-cyclone10.cfg | 34 +++ tcl/fpga/altera-cycloneiii.cfg | 35 +++ tcl/fpga/altera-cycloneiv.cfg | 41 +++ tcl/fpga/altera-cyclonev.cfg | 47 +++ tcl/fpga/altera-ep3c10.cfg | 11 +- 17 files changed, 809 insertions(+), 49 deletions(-) create mode 100644 src/pld/intel.c create mode 100644 tcl/board/bemicro_cycloneiii.cfg create mode 100644 tcl/cpld/altera-max10.cfg create mode 100644 tcl/cpld/altera-maxii.cfg create mode 100644 tcl/cpld/altera-maxv.cfg create mode 100644 tcl/fpga/altera-arriaii.cfg create mode 100644 tcl/fpga/altera-cyclone10.cfg create mode 100644 tcl/fpga/altera-cycloneiii.cfg create mode 100644 tcl/fpga/altera-cycloneiv.cfg create mode 100644 tcl/fpga/altera-cyclonev.cfg diff --git a/doc/openocd.texi b/doc/openocd.texi index 6037b8bb2..8099455ac 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -8530,6 +8530,34 @@ This driver can be used to load the bitstream into the FPGA. @end deffn +@deffn {FPGA Driver} {intel} [@option{family}] +This driver can be used to load the bitstream into Intel (former Altera) FPGAs. +The families Cyclone III, Cyclone IV, Cyclone V, Cyclone 10, Arria II are supported. +@c Arria V and Arria 10, MAX II, MAX V, MAX10) + +The option @option{family} is one of @var{cycloneiii cycloneiv cyclonev cyclone10 arriaii}. +This is needed when the JTAG ID of the device is ambiguous (same ID is used for chips in different families). + +As input file format the driver supports a '.rbf' (raw bitstream file) file. The '.rbf' file can be generated +from a '.sof' file with @verb{|quartus_cpf -c blinker.sof blinker.rbf|} + +Defines a new PLD device, an FPGA of the Cyclone III family, using the TAP named @verb{|cycloneiii.tap|}: +@example +pld device intel cycloneiii.tap cycloneiii +@end example + +@deffn {Command} {intel set_bscan} num len +Set boundary scan register length of FPGA @var{num} to @var{len}. This is needed because the +length can vary between chips with the same JTAG ID. +@end deffn + +@deffn {Command} {intel set_check_pos} num pos +Selects the position @var{pos} in the boundary-scan register. The bit at this +position is checked after loading the bitstream and must be '1', which is the case when no error occurred. +With a value of -1 for @var{pos} the check will be omitted. +@end deffn +@end deffn + @node General Commands @chapter General Commands diff --git a/src/pld/Makefile.am b/src/pld/Makefile.am index be33bcd09..a13f738ea 100644 --- a/src/pld/Makefile.am +++ b/src/pld/Makefile.am @@ -6,6 +6,7 @@ noinst_LTLIBRARIES += %D%/libpld.la %D%/ecp2_3.c \ %D%/ecp5.c \ %D%/efinix.c \ + %D%/intel.c \ %D%/lattice.c \ %D%/lattice_bit.c \ %D%/pld.c \ diff --git a/src/pld/intel.c b/src/pld/intel.c new file mode 100644 index 000000000..119a5695d --- /dev/null +++ b/src/pld/intel.c @@ -0,0 +1,474 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/*************************************************************************** + * Copyright (C) 2022 by Daniel Anselmi * + * danselmi@gmx.ch * + ***************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include + +#include "pld.h" +#include "raw_bit.h" + +#define BYPASS 0x3FF + +enum intel_family_e { + INTEL_CYCLONEIII, + INTEL_CYCLONEIV, + INTEL_CYCLONEV, + INTEL_CYCLONE10, + INTEL_ARRIAII, + INTEL_UNKNOWN +}; + +struct intel_pld_device { + struct jtag_tap *tap; + unsigned int boundary_scan_length; + int checkpos; + enum intel_family_e family; +}; + +struct intel_device_parameters_elem { + uint32_t id; + unsigned int boundary_scan_length; + int checkpos; + enum intel_family_e family; +}; + +static const struct intel_device_parameters_elem intel_device_parameters[] = { + {0x020f10dd, 603, 226, INTEL_CYCLONEIII}, /* EP3C5 EP3C10 */ + {0x020f20dd, 1080, 409, INTEL_CYCLONEIII}, /* EP3C16 */ + {0x020f30dd, 732, 286, INTEL_CYCLONEIII}, /* EP3C25 */ + {0x020f40dd, 1632, 604, INTEL_CYCLONEIII}, /* EP3C40 */ + {0x020f50dd, 1164, 442, INTEL_CYCLONEIII}, /* EP3C55 */ + {0x020f60dd, 1314, 502, INTEL_CYCLONEIII}, /* EP3C80 */ + {0x020f70dd, 1620, 613, INTEL_CYCLONEIII}, /* EP3C120*/ + {0x027010dd, 1314, 226, INTEL_CYCLONEIII}, /* EP3CLS70 */ + {0x027000dd, 1314, 226, INTEL_CYCLONEIII}, /* EP3CLS100 */ + {0x027030dd, 1314, 409, INTEL_CYCLONEIII}, /* EP3CLS150 */ + {0x027020dd, 1314, 409, INTEL_CYCLONEIII}, /* EP3CLS200 */ + + {0x020f10dd, 603, 226, INTEL_CYCLONEIV}, /* EP4CE6 EP4CE10 */ + {0x020f20dd, 1080, 409, INTEL_CYCLONEIV}, /* EP4CE15 */ + {0x020f30dd, 732, 286, INTEL_CYCLONEIV}, /* EP4CE22 */ + {0x020f40dd, 1632, 604, INTEL_CYCLONEIV}, /* EP4CE30 EP4CE40 */ + {0x020f50dd, 1164, 442, INTEL_CYCLONEIV}, /* EP4CE55 */ + {0x020f60dd, 1314, 502, INTEL_CYCLONEIV}, /* EP4CE75 */ + {0x020f70dd, 1620, 613, INTEL_CYCLONEIV}, /* EP4CE115 */ + {0x028010dd, 260, 229, INTEL_CYCLONEIV}, /* EP4CGX15 */ + {0x028120dd, 494, 463, INTEL_CYCLONEIV}, /* EP4CGX22 */ + {0x028020dd, 494, 463, INTEL_CYCLONEIV}, /* EP4CGX30 */ + {0x028230dd, 1006, 943, INTEL_CYCLONEIV}, /* EP4CGX30 */ + {0x028130dd, 1006, 943, INTEL_CYCLONEIV}, /* EP4CGX50 */ + {0x028030dd, 1006, 943, INTEL_CYCLONEIV}, /* EP4CGX75 */ + {0x028140dd, 1495, 1438, INTEL_CYCLONEIV}, /* EP4CGX110 */ + {0x028040dd, 1495, 1438, INTEL_CYCLONEIV}, /* EP4CGX150 */ + + {0x02b150dd, 864, 163, INTEL_CYCLONEV}, /* 5CEBA2F23 5CEBA2F17 5CEFA2M13 5CEFA2F23 5CEBA2U15 5CEFA2U19 5CEBA2U19 */ + {0x02d020dd, 1485, 19, INTEL_CYCLONEV}, /* 5CSXFC6D6F31 5CSTFD6D5F31 5CSEBA6U23 5CSEMA6U23 5CSEBA6U19 5CSEBA6U23 + 5CSEBA6U19 5CSEMA6F31 5CSXFC6C6U23 */ + {0x02b040dd, 1728, -1, INTEL_CYCLONEV}, /* 5CGXFC9EF35 5CGXBC9AU19 5CGXBC9CF23 5CGTFD9CF23 5CGXFC9AU19 5CGXFC9CF23 + 5CGXFC9EF31 5CGXFC9DF27 5CGXBC9DF27 5CGXBC9EF31 5CGTFD9EF31 5CGTFD9EF35 + 5CGTFD9AU19 5CGXBC9EF35 5CGTFD9DF27 */ + {0x02b050dd, 864, 163, INTEL_CYCLONEV}, /* 5CEFA4U19 5CEFA4F23 5CEFA4M13 5CEBA4F17 5CEBA4U15 5CEBA4U19 5CEBA4F23 */ + {0x02b030dd, 1488, 19, INTEL_CYCLONEV}, /* 5CGXBC7CU19 5CGTFD7CU19 5CGTFD7DF27 5CGXFC7BM15 5CGXFC7DF27 5CGXFC7DF31 + 5CGTFD7CF23 5CGXBC7CF23 5CGXBC7DF31 5CGTFD7BM15 5CGXFC7CU19 5CGTFD7DF31 + 5CGXBC7BM15 5CGXFC7CF23 5CGXBC7DF27 */ + {0x02d120dd, 1485, -1, INTEL_CYCLONEV}, /* 5CSEBA5U23 5CSEBA5U23 5CSTFD5D5F31 5CSEBA5U19 5CSXFC5D6F31 5CSEMA5U23 + 5CSEMA5F31 5CSXFC5C6U23 5CSEBA5U19 */ + {0x02b220dd, 1104, 19, INTEL_CYCLONEV}, /* 5CEBA5U19 5CEFA5U19 5CEFA5M13 5CEBA5F23 5CEFA5F23 */ + {0x02b020dd, 1104, 19, INTEL_CYCLONEV}, /* 5CGXBC5CU19 5CGXFC5F6M11 5CGXFC5CM13 5CGTFD5CF23 5CGXBC5CF23 5CGTFD5CF27 + 5CGTFD5F5M11 5CGXFC5CF27 5CGXFC5CU19 5CGTFD5CM13 5CGXFC5CF23 5CGXBC5CF27 + 5CGTFD5CU19 */ + {0x02d010dd, 1197, -1, INTEL_CYCLONEV}, /* 5CSEBA4U23 5CSXFC4C6U23 5CSEMA4U23 5CSEBA4U23 5CSEBA4U19 5CSEBA4U19 + 5CSXFC2C6U23 */ + {0x02b120dd, 1104, 19, INTEL_CYCLONEV}, /* 5CGXFC4CM13 5CGXFC4CU19 5CGXFC4F6M11 5CGXBC4CU19 5CGXFC4CF27 5CGXBC4CF23 + 5CGXBC4CF27 5CGXFC4CF23 */ + {0x02b140dd, 1728, -1, INTEL_CYCLONEV}, /* 5CEFA9F31 5CEBA9F31 5CEFA9F27 5CEBA9U19 5CEBA9F27 5CEFA9U19 5CEBA9F23 + 5CEFA9F23 */ + {0x02b010dd, 720, 19, INTEL_CYCLONEV}, /* 5CGXFC3U15 5CGXBC3U15 5CGXFC3F23 5CGXFC3U19 5CGXBC3U19 5CGXBC3F23 */ + {0x02b130dd, 1488, 19, INTEL_CYCLONEV}, /* 5CEFA7F31 5CEBA7F27 5CEBA7M15 5CEFA7U19 5CEBA7F23 5CEFA7F23 5CEFA7F27 + 5CEFA7M15 5CEBA7U19 5CEBA7F31 */ + {0x02d110dd, 1197, -1, INTEL_CYCLONEV}, /* 5CSEBA2U23 5CSEMA2U23 5CSEBA2U23 5CSEBA2U19 5CSEBA2U19 */ + + {0x020f10dd, 603, 226, INTEL_CYCLONE10}, /* 10CL006E144 10CL006U256 10CL010M164 10CL010U256 10CL010E144 */ + {0x020f20dd, 1080, 409, INTEL_CYCLONE10}, /* 10CL016U256 10CL016E144 10CL016U484 10CL016F484 10CL016M164 */ + {0x020f30dd, 732, 286, INTEL_CYCLONE10}, /* 10CL025U256 10CL025E144 */ + {0x020f40dd, 1632, 604, INTEL_CYCLONE10}, /* 10CL040F484 10CL040U484 */ + {0x020f50dd, 1164, 442, INTEL_CYCLONE10}, /* 10CL055F484 10CL055U484 */ + {0x020f60dd, 1314, 502, INTEL_CYCLONE10}, /* 10CL080F484 10CL080F780 10CL080U484 */ + {0x020f70dd, 1620, 613, INTEL_CYCLONE10}, /* 10CL120F484 10CL120F780 */ + + {0x02e120dd, 1339, -1, INTEL_CYCLONE10}, /* 10CX085U484 10CX085F672 */ + {0x02e320dd, 1339, -1, INTEL_CYCLONE10}, /* 10CX105F780 10CX105U484 10CX105F672 */ + {0x02e720dd, 1339, -1, INTEL_CYCLONE10}, /* 10CX150F672 10CX150F780 10CX150U484 */ + {0x02ef20dd, 1339, -1, INTEL_CYCLONE10}, /* 10CX220F672 10CX220F780 10CX220U484 */ + + {0x025120dd, 1227, 1174, INTEL_ARRIAII}, /* EP2AGX45 */ + {0x025020dd, 1227, -1, INTEL_ARRIAII}, /* EP2AGX65 */ + {0x025130dd, 1467, -1, INTEL_ARRIAII}, /* EP2AGX95 */ + {0x025030dd, 1467, -1, INTEL_ARRIAII}, /* EP2AGX125 */ + {0x025140dd, 1971, -1, INTEL_ARRIAII}, /* EP2AGX190 */ + {0x025040dd, 1971, -1, INTEL_ARRIAII}, /* EP2AGX260 */ + {0x024810dd, 2274, -1, INTEL_ARRIAII}, /* EP2AGZ225 */ + {0x0240a0dd, 2682, -1, INTEL_ARRIAII}, /* EP2AGZ300 */ + {0x024820dd, 2682, -1, INTEL_ARRIAII}, /* EP2AGZ350 */ +}; + +static int intel_fill_device_parameters(struct intel_pld_device *intel_info) +{ + for (size_t i = 0; i < ARRAY_SIZE(intel_device_parameters); ++i) { + if (intel_device_parameters[i].id == intel_info->tap->idcode && + intel_info->family == intel_device_parameters[i].family) { + if (intel_info->boundary_scan_length == 0) + intel_info->boundary_scan_length = intel_device_parameters[i].boundary_scan_length; + + if (intel_info->checkpos == -1) + intel_info->checkpos = intel_device_parameters[i].checkpos; + + return ERROR_OK; + } + } + + return ERROR_FAIL; +} + +static int intel_check_for_unique_id(struct intel_pld_device *intel_info) +{ + int found = 0; + for (size_t i = 0; i < ARRAY_SIZE(intel_device_parameters); ++i) { + if (intel_device_parameters[i].id == intel_info->tap->idcode) { + ++found; + intel_info->family = intel_device_parameters[i].family; + } + } + + return (found == 1) ? ERROR_OK : ERROR_FAIL; +} + +static int intel_check_config(struct intel_pld_device *intel_info) +{ + if (!intel_info->tap->hasidcode) { + LOG_ERROR("no IDCODE"); + return ERROR_FAIL; + } + + if (intel_info->family == INTEL_UNKNOWN) { + if (intel_check_for_unique_id(intel_info) != ERROR_OK) { + LOG_ERROR("id is ambiguous, please specify family"); + return ERROR_FAIL; + } + } + + if (intel_info->boundary_scan_length == 0 || intel_info->checkpos == -1) { + int ret = intel_fill_device_parameters(intel_info); + if (ret != ERROR_OK) + return ret; + } + + if (intel_info->checkpos >= 0 && (unsigned int)intel_info->checkpos >= intel_info->boundary_scan_length) { + LOG_ERROR("checkpos has to be smaller than scan length %d < %u", + intel_info->checkpos, intel_info->boundary_scan_length); + return ERROR_FAIL; + } + + return ERROR_OK; +} + +static int intel_read_file(struct raw_bit_file *bit_file, const char *filename) +{ + if (!filename || !bit_file) + return ERROR_COMMAND_SYNTAX_ERROR; + + /* check if binary .bin or ascii .bit/.hex */ + const char *file_ending_pos = strrchr(filename, '.'); + if (!file_ending_pos) { + LOG_ERROR("Unable to detect filename suffix"); + return ERROR_PLD_FILE_LOAD_FAILED; + } + + if (strcasecmp(file_ending_pos, ".rbf") == 0) + return cpld_read_raw_bit_file(bit_file, filename); + + LOG_ERROR("Unable to detect filetype"); + return ERROR_PLD_FILE_LOAD_FAILED; +} + +static int intel_set_instr(struct jtag_tap *tap, uint16_t new_instr) +{ + struct scan_field field; + field.num_bits = tap->ir_length; + void *t = calloc(DIV_ROUND_UP(field.num_bits, 8), 1); + if (!t) { + LOG_ERROR("Out of memory"); + return ERROR_FAIL; + } + field.out_value = t; + buf_set_u32(t, 0, field.num_bits, new_instr); + field.in_value = NULL; + jtag_add_ir_scan(tap, &field, TAP_IDLE); + free(t); + return ERROR_OK; +} + + +static int intel_load(struct pld_device *pld_device, const char *filename) +{ + unsigned int speed = adapter_get_speed_khz(); + if (speed < 1) + speed = 1; + + unsigned int cycles = DIV_ROUND_UP(speed, 200); + if (cycles < 1) + cycles = 1; + + if (!pld_device || !pld_device->driver_priv) + return ERROR_FAIL; + + struct intel_pld_device *intel_info = pld_device->driver_priv; + if (!intel_info || !intel_info->tap) + return ERROR_FAIL; + struct jtag_tap *tap = intel_info->tap; + + int retval = intel_check_config(intel_info); + if (retval != ERROR_OK) + return retval; + + struct raw_bit_file bit_file; + retval = intel_read_file(&bit_file, filename); + if (retval != ERROR_OK) + return retval; + + if (retval != ERROR_OK) + return retval; + + retval = intel_set_instr(tap, 0x002); + if (retval != ERROR_OK) { + free(bit_file.data); + return retval; + } + jtag_add_runtest(speed, TAP_IDLE); + retval = jtag_execute_queue(); + if (retval != ERROR_OK) { + free(bit_file.data); + return retval; + } + + /* shift in the bitstream */ + struct scan_field field; + field.num_bits = bit_file.length * 8; + field.out_value = bit_file.data; + field.in_value = NULL; + + jtag_add_dr_scan(tap, 1, &field, TAP_DRPAUSE); + retval = jtag_execute_queue(); + free(bit_file.data); + if (retval != ERROR_OK) + return retval; + + retval = intel_set_instr(tap, 0x004); + if (retval != ERROR_OK) + return retval; + jtag_add_runtest(cycles, TAP_IDLE); + retval = jtag_execute_queue(); + if (retval != ERROR_OK) + return retval; + + if (intel_info->boundary_scan_length != 0) { + uint8_t *buf = calloc(DIV_ROUND_UP(intel_info->boundary_scan_length, 8), 1); + if (!buf) { + LOG_ERROR("Out of memory"); + return ERROR_FAIL; + } + + field.num_bits = intel_info->boundary_scan_length; + field.out_value = buf; + field.in_value = buf; + jtag_add_dr_scan(tap, 1, &field, TAP_DRPAUSE); + retval = jtag_execute_queue(); + if (retval != ERROR_OK) { + free(buf); + return retval; + } + + if (intel_info->checkpos != -1) + retval = ((buf[intel_info->checkpos / 8] & (1 << (intel_info->checkpos % 8)))) ? + ERROR_OK : ERROR_FAIL; + free(buf); + if (retval != ERROR_OK) { + LOG_ERROR("Check failed"); + return ERROR_FAIL; + } + } + + retval = intel_set_instr(tap, 0x003); + if (retval != ERROR_OK) + return retval; + switch (intel_info->family) { + case INTEL_CYCLONEIII: + case INTEL_CYCLONEIV: + jtag_add_runtest(5 * speed + 512, TAP_IDLE); + break; + case INTEL_CYCLONEV: + jtag_add_runtest(5 * speed + 512, TAP_IDLE); + break; + case INTEL_CYCLONE10: + jtag_add_runtest(DIV_ROUND_UP(512ul * speed, 125ul) + 512, TAP_IDLE); + break; + case INTEL_ARRIAII: + jtag_add_runtest(DIV_ROUND_UP(64ul * speed, 125ul) + 512, TAP_IDLE); + break; + case INTEL_UNKNOWN: + LOG_ERROR("unknown family"); + return ERROR_FAIL; + } + + retval = intel_set_instr(tap, BYPASS); + if (retval != ERROR_OK) + return retval; + jtag_add_runtest(speed, TAP_IDLE); + return jtag_execute_queue(); +} + +COMMAND_HANDLER(intel_set_bscan_command_handler) +{ + int dev_id; + unsigned int boundary_scan_length; + + if (CMD_ARGC != 2) + return ERROR_COMMAND_SYNTAX_ERROR; + + COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], dev_id); + struct pld_device *pld_device = get_pld_device_by_num(dev_id); + if (!pld_device) { + command_print(CMD, "pld device '#%s' is out of bounds", CMD_ARGV[0]); + return ERROR_FAIL; + } + + COMMAND_PARSE_NUMBER(uint, CMD_ARGV[1], boundary_scan_length); + + struct intel_pld_device *intel_info = pld_device->driver_priv; + + if (!intel_info) + return ERROR_FAIL; + + intel_info->boundary_scan_length = boundary_scan_length; + + return ERROR_OK; +} + +COMMAND_HANDLER(intel_set_check_pos_command_handler) +{ + int dev_id; + int checkpos; + + if (CMD_ARGC != 2) + return ERROR_COMMAND_SYNTAX_ERROR; + + COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], dev_id); + struct pld_device *pld_device = get_pld_device_by_num(dev_id); + if (!pld_device) { + command_print(CMD, "pld device '#%s' is out of bounds", CMD_ARGV[0]); + return ERROR_FAIL; + } + + COMMAND_PARSE_NUMBER(int, CMD_ARGV[1], checkpos); + + struct intel_pld_device *intel_info = pld_device->driver_priv; + + if (!intel_info) + return ERROR_FAIL; + + intel_info->checkpos = checkpos; + + return ERROR_OK; +} + + +PLD_DEVICE_COMMAND_HANDLER(intel_pld_device_command) +{ + if (CMD_ARGC < 2 || CMD_ARGC > 3) + return ERROR_COMMAND_SYNTAX_ERROR; + + struct jtag_tap *tap = jtag_tap_by_string(CMD_ARGV[1]); + if (!tap) { + command_print(CMD, "Tap: %s does not exist", CMD_ARGV[1]); + return ERROR_FAIL; + } + + struct intel_pld_device *intel_info = malloc(sizeof(struct intel_pld_device)); + if (!intel_info) { + LOG_ERROR("Out of memory"); + return ERROR_FAIL; + } + + enum intel_family_e family = INTEL_UNKNOWN; + + if (CMD_ARGC == 3) { + if (strcmp(CMD_ARGV[2], "cycloneiii") == 0) { + family = INTEL_CYCLONEIII; + } else if (strcmp(CMD_ARGV[2], "cycloneiv") == 0) { + family = INTEL_CYCLONEIV; + } else if (strcmp(CMD_ARGV[2], "cyclonev") == 0) { + family = INTEL_CYCLONEV; + } else if (strcmp(CMD_ARGV[2], "cyclone10") == 0) { + family = INTEL_CYCLONE10; + } else if (strcmp(CMD_ARGV[2], "arriaii") == 0) { + family = INTEL_ARRIAII; + } else { + command_print(CMD, "unknown family"); + free(intel_info); + return ERROR_FAIL; + } + } + intel_info->tap = tap; + intel_info->boundary_scan_length = 0; + intel_info->checkpos = -1; + intel_info->family = family; + + pld->driver_priv = intel_info; + + return ERROR_OK; +} + +static const struct command_registration intel_exec_command_handlers[] = { + { + .name = "set_bscan", + .mode = COMMAND_EXEC, + .handler = intel_set_bscan_command_handler, + .help = "set boundary scan register length of FPGA", + .usage = "num_pld len", + }, { + .name = "set_check_pos", + .mode = COMMAND_EXEC, + .handler = intel_set_check_pos_command_handler, + .help = "set check_pos of FPGA", + .usage = "num_pld pos", + }, + COMMAND_REGISTRATION_DONE +}; + +static const struct command_registration intel_command_handler[] = { + { + .name = "intel", + .mode = COMMAND_ANY, + .help = "intel specific commands", + .usage = "", + .chain = intel_exec_command_handlers, + }, + COMMAND_REGISTRATION_DONE +}; + +struct pld_driver intel_pld = { + .name = "intel", + .commands = intel_command_handler, + .pld_device_command = &intel_pld_device_command, + .load = &intel_load, +}; diff --git a/src/pld/pld.c b/src/pld/pld.c index a92486ab1..f4f79bacb 100644 --- a/src/pld/pld.c +++ b/src/pld/pld.c @@ -19,11 +19,13 @@ /* pld drivers */ extern struct pld_driver efinix_pld; +extern struct pld_driver intel_pld; extern struct pld_driver lattice_pld; extern struct pld_driver virtex2_pld; static struct pld_driver *pld_drivers[] = { &efinix_pld, + &intel_pld, &lattice_pld, &virtex2_pld, NULL, diff --git a/tcl/board/bemicro_cycloneiii.cfg b/tcl/board/bemicro_cycloneiii.cfg new file mode 100644 index 000000000..7781bd5c7 --- /dev/null +++ b/tcl/board/bemicro_cycloneiii.cfg @@ -0,0 +1,20 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# BeMicro Cyclone III + + +adapter driver ftdi +ftdi channel 0 +ftdi layout_init 0x0008 0x008b +ftdi vid_pid 0x0403 0xa4a0 +reset_config none +transport select jtag + +adapter speed 10000 + +source [find cpld/altera-cycloneiii.cfg] + +#quartus_cpf --option=bitstream_compression=off -c output_files\cycloneiii_blinker.sof cycloneiii_blinker.rbf + +#openocd -f board/bemicro_cycloneiii.cfg -c "init" -c "pld load 0 cycloneiii_blinker.rbf" +# "ipdbg -start -tap cycloneiii.tap -hub 0x00e -tool 0 -port 5555" diff --git a/tcl/cpld/altera-5m570z-cpld.cfg b/tcl/cpld/altera-5m570z-cpld.cfg index 5dbd0deee..4504a8064 100644 --- a/tcl/cpld/altera-5m570z-cpld.cfg +++ b/tcl/cpld/altera-5m570z-cpld.cfg @@ -1,8 +1,9 @@ # SPDX-License-Identifier: GPL-2.0-or-later -# Altera MAXV 5M24OZ/5M570Z CPLD -# see MAX V Device Handbook -# Table 6-3: 32-Bit MAX V Device IDCODE -# Version Part Number Manuf. ID LSB -# 0000 0010 0000 1010 0111 000 0110 1110 1 -jtag newtap 5m570z tap -expected-id 0x020a60dd -irlen 10 +# file altera-5m570z-cpld.cfg replaced by altera-maxv.cfg +echo "DEPRECATED: use altera-maxv.cfg instead of deprecated altera-5m570z-cpld.cfg" + +#just to be backward compatible: +#tap will be 5m570z.tap instead of maxv.tap: +set CHIPNAME 5m570z +source [find cpld/altera-maxv.cfg] diff --git a/tcl/cpld/altera-epm240.cfg b/tcl/cpld/altera-epm240.cfg index 39c409bc3..185925a16 100644 --- a/tcl/cpld/altera-epm240.cfg +++ b/tcl/cpld/altera-epm240.cfg @@ -1,24 +1,12 @@ # SPDX-License-Identifier: GPL-2.0-or-later -# Altera MAXII EPM240T100C CPLD +# file altera-epm240.cfg replaced by altera-maxii.cfg +echo "DEPRECATED: use altera-maxii.cfg instead of deprecated altera-epm240.cfg" -if { [info exists CHIPNAME] } { - set _CHIPNAME $CHIPNAME -} else { - set _CHIPNAME epm240 -} - -# see MAX II Device Handbook -# Table 3-3: 32-Bit MAX II Device IDCODE -# Version Part Number Manuf. ID LSB -# 0000 0010 0000 1010 0001 000 0110 1110 1 -jtag newtap $_CHIPNAME tap -irlen 10 \ - -expected-id 0x020a10dd \ - -expected-id 0x020a20dd \ - -expected-id 0x020a30dd \ - -expected-id 0x020a40dd \ - -expected-id 0x020a50dd \ - -expected-id 0x020a60dd +#just to be backward compatible: +#tap will be epm240.tap instead of maxii.tap: +set CHIPNAME epm240 +source [find cpld/altera-maxii.cfg] # 200ns seems like a good speed # c.f. Table 5-34: MAX II JTAG Timing Parameters diff --git a/tcl/cpld/altera-max10.cfg b/tcl/cpld/altera-max10.cfg new file mode 100644 index 000000000..a2ed00ac8 --- /dev/null +++ b/tcl/cpld/altera-max10.cfg @@ -0,0 +1,30 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# see MAX 10 FPGA Device Architecture +# Table 3-1: IDCODE Information for MAX 10 Devices +# Intel MAX 10M02 0x31810dd +# Intel MAX 10M04 0x318a0dd +# Intel MAX 10M08 0x31820dd +# Intel MAX 10M16 0x31830dd +# Intel MAX 10M25 0x31840dd +# Intel MAX 10M40 0x318d0dd +# Intel MAX 10M50 0x31850dd +# Intel MAX 10M02 0x31010dd +# Intel MAX 10M04 0x310a0dd +# Intel MAX 10M08 0x31020dd +# Intel MAX 10M16 0x31030dd +# Intel MAX 10M25 0x31040dd +# Intel MAX 10M40 0x310d0dd +# Intel MAX 10M50 0x31050dd + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME max10 +} + +jtag newtap $_CHIPNAME tap -irlen 10 -expected-id 0x31810dd -expected-id 0x318a0dd \ + -expected-id 0x31820dd -expected-id 0x31830dd -expected-id 0x31840dd \ + -expected-id 0x318d0dd -expected-id 0x31850dd -expected-id 0x31010dd \ + -expected-id 0x310a0dd -expected-id 0x31020dd -expected-id 0x31030dd \ + -expected-id 0x31040dd -expected-id 0x310d0dd -expected-id 0x31050dd diff --git a/tcl/cpld/altera-maxii.cfg b/tcl/cpld/altera-maxii.cfg new file mode 100644 index 000000000..2dee37f41 --- /dev/null +++ b/tcl/cpld/altera-maxii.cfg @@ -0,0 +1,21 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# Altera MAXII CPLD + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME maxii +} + +# see MAX II Device Handbook +# Table 3-3: 32-Bit MAX II Device IDCODE +# Version Part Number Manuf. ID LSB +# 0000 0010 0000 1010 0001 000 0110 1110 1 +jtag newtap $_CHIPNAME tap -irlen 10 \ + -expected-id 0x020a10dd \ + -expected-id 0x020a20dd \ + -expected-id 0x020a30dd \ + -expected-id 0x020a40dd \ + -expected-id 0x020a50dd \ + -expected-id 0x020a60dd diff --git a/tcl/cpld/altera-maxv.cfg b/tcl/cpld/altera-maxv.cfg new file mode 100644 index 000000000..03fad076f --- /dev/null +++ b/tcl/cpld/altera-maxv.cfg @@ -0,0 +1,19 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# Altera MAXV 5M24OZ/5M570Z CPLD +# see MAX V Device Handbook +# Table 6-3: 32-Bit MAX V Device IDCODE +# 5M40Z 5M80Z 5M160Z 5M240Z: 0x020A50DD +# 5M570Z: 0x020A60DD +# 5M1270Z: 0x020A30DD +# 5M1270Z 5M2210Z: 0x020A40DD + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME maxv +} + +jtag newtap $_CHIPNAME tap -irlen 10 \ + -expected-id 0x020A50DD -expected-id 0x020A60DD \ + -expected-id 0x020A30DD -expected-id 0x020A40DD diff --git a/tcl/fpga/altera-10m50.cfg b/tcl/fpga/altera-10m50.cfg index 1937cb4b6..94228d26f 100644 --- a/tcl/fpga/altera-10m50.cfg +++ b/tcl/fpga/altera-10m50.cfg @@ -1,24 +1,9 @@ # SPDX-License-Identifier: GPL-2.0-or-later -# see MAX 10 FPGA Device Architecture -# Table 3-1: IDCODE Information for MAX 10 Devices -# Intel MAX 10M02 0x31810dd -# Intel MAX 10M04 0x318a0dd -# Intel MAX 10M08 0x31820dd -# Intel MAX 10M16 0x31830dd -# Intel MAX 10M25 0x31840dd -# Intel MAX 10M40 0x318d0dd -# Intel MAX 10M50 0x31850dd -# Intel MAX 10M02 0x31010dd -# Intel MAX 10M04 0x310a0dd -# Intel MAX 10M08 0x31020dd -# Intel MAX 10M16 0x31030dd -# Intel MAX 10M25 0x31040dd -# Intel MAX 10M40 0x310d0dd -# Intel MAX 10M50 0x31050dd +# file altera-10m50.cfg replaced by altera-max10.cfg +echo "DEPRECATED: use altera-max10.cfg instead of deprecated altera-10m50.cfg" -jtag newtap 10m50 tap -irlen 10 -expected-id 0x31810dd -expected-id 0x318a0dd \ - -expected-id 0x31820dd -expected-id 0x31830dd -expected-id 0x31840dd \ - -expected-id 0x318d0dd -expected-id 0x31850dd -expected-id 0x31010dd \ - -expected-id 0x310a0dd -expected-id 0x31020dd -expected-id 0x31030dd \ - -expected-id 0x31040dd -expected-id 0x310d0dd -expected-id 0x31050dd +#just to be backward compatible: +#tap will be 10m50.tap instead of max10.tap: +set CHIPNAME 10m50 +source [find cpld/altera-max10.cfg] diff --git a/tcl/fpga/altera-arriaii.cfg b/tcl/fpga/altera-arriaii.cfg new file mode 100644 index 000000000..ae752dfb1 --- /dev/null +++ b/tcl/fpga/altera-arriaii.cfg @@ -0,0 +1,31 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# Intel Arria II FPGA +# Arria II Device Handbook +# Table 11–2. 32-Bit IDCODE for Arria II Devices + +#GX: +#EP2AGX45: 0x025120dd +#EP2AGX65: 0x025020dd +#EP2AGX95: 0x025130dd +#EP2AGX125: 0x025030dd +#EP2AGX190: 0x025140dd +#EP2AGX260: 0x025040dd +#EP2AGZ225: 0x024810dd +#EP2AGZ300: 0x0240a0dd +#EP2AGZ350: 0x024820dd + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME arriaii +} + +jtag newtap $_CHIPNAME tap -irlen 10 \ + -expected-id 0x025120dd -expected-id 0x025040dd \ + -expected-id 0x025020dd -expected-id 0x024810dd \ + -expected-id 0x025130dd -expected-id 0x0240a0dd \ + -expected-id 0x025030dd -expected-id 0x024820dd \ + -expected-id 0x025140dd + +pld device intel $_CHIPNAME.tap arriaii diff --git a/tcl/fpga/altera-cyclone10.cfg b/tcl/fpga/altera-cyclone10.cfg new file mode 100644 index 000000000..3a1bc1f65 --- /dev/null +++ b/tcl/fpga/altera-cyclone10.cfg @@ -0,0 +1,34 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# Intel Cyclone 10 FPGA +# see: https://www.intel.com/content/www/us/en/docs/programmable/683777/current/bst-operation-control.html +# and: https://www.intel.cn/content/dam/support/us/en/programmable/kdb/pdfs/literature/hb/cyclone-10/c10gx-51003.pdf + +# GX085: 0x02e120dd +# GX105: 0x02e320dd +# GX150: 0x02e720dd +# GX220: 0x02ef20dd +# 10cl006: 0x020f10dd +# 10cl010: 0x020f10dd +# 10cl016: 0x020f20dd +# 10cl025: 0x020f30dd +# 10cl040: 0x020f40dd +# 10cl055: 0x020f50dd +# 10cl080: 0x020f60dd +# 10cl120: 0x020f70dd + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME cyclone10 +} + +jtag newtap $_CHIPNAME tap -irlen 10 \ + -expected-id 0x02e720dd -expected-id 0x02e120dd \ + -expected-id 0x02ef20dd -expected-id 0x02e320dd \ + -expected-id 0x020f10dd -expected-id 0x020f20dd \ + -expected-id 0x020f30dd -expected-id 0x020f40dd \ + -expected-id 0x020f50dd -expected-id 0x020f60dd \ + -expected-id 0x020f70dd + +pld device intel $_CHIPNAME.tap cyclone10 diff --git a/tcl/fpga/altera-cycloneiii.cfg b/tcl/fpga/altera-cycloneiii.cfg new file mode 100644 index 000000000..e14357245 --- /dev/null +++ b/tcl/fpga/altera-cycloneiii.cfg @@ -0,0 +1,35 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# Intel Cyclone III FPGA +# see Cyclone III Device Handbook +# Table 12-2: Device IDCODE for Cyclone III Device Family + +#EP3C5 0x020f10dd +#EP3C10 0x020f10dd +#EP3C16 0x020f20dd +#EP3C25 0x020f30dd +#EP3C40 0x020f40dd +#EP3C55 0x020f50dd +#EP3C80 0x020f60dd +#EP3C120 0x020f70dd +#Cyclone III LS +#EP3CLS70 0x027010dd +#EP3CLS100 0x027000dd +#EP3CLS150 0x027030dd +#EP3CLS200 0x027020dd + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME cycloneiii +} + +jtag newtap $_CHIPNAME tap -irlen 10 \ + -expected-id 0x020f10dd -expected-id 0x020f20dd \ + -expected-id 0x020f30dd -expected-id 0x020f40dd \ + -expected-id 0x020f50dd -expected-id 0x020f60dd \ + -expected-id 0x020f70dd -expected-id 0x027010dd \ + -expected-id 0x027000dd -expected-id 0x027030dd \ + -expected-id 0x027020dd + +pld device intel $_CHIPNAME.tap cycloneiii diff --git a/tcl/fpga/altera-cycloneiv.cfg b/tcl/fpga/altera-cycloneiv.cfg new file mode 100644 index 000000000..59243cfd0 --- /dev/null +++ b/tcl/fpga/altera-cycloneiv.cfg @@ -0,0 +1,41 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# Intel Cyclone IV FPGA +# see Cyclone IV Device Handbook +# Table 10-2: IDCODE Information for 32-Bit Cyclone IV Devices + +#EP4CE6 0x020f10dd +#EP4CE10 0x020f10dd +#EP4CE15 0x020f20dd +#EP4CE22 0x020f30dd +#EP4CE30 0x020f40dd +#EP4CE40 0x020f40dd +#EP4CE55 0x020f50dd +#EP4CE75 0x020f60dd +#EP4CE115 0x020f70dd +#EP4CGX15 0x028010dd +#EP4CGX22 0x028120dd +#EP4CGX30 (3) 0x028020dd +#EP4CGX30 (4) 0x028230dd +#EP4CGX50 0x028130dd +#EP4CGX75 0x028030dd +#EP4CGX110 0x028140dd +#EP4CGX150 0x028040dd + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME cycloneiv +} + +jtag newtap $_CHIPNAME tap -irlen 10 \ + -expected-id 0x020f10dd -expected-id 0x020f20dd \ + -expected-id 0x020f30dd -expected-id 0x020f40dd \ + -expected-id 0x020f50dd -expected-id 0x020f60dd \ + -expected-id 0x020f70dd -expected-id 0x028010dd \ + -expected-id 0x028120dd -expected-id 0x028020dd \ + -expected-id 0x028230dd -expected-id 0x028130dd \ + -expected-id 0x028030dd -expected-id 0x028140dd \ + -expected-id 0x028040dd + +pld device intel $_CHIPNAME.tap cycloneiv diff --git a/tcl/fpga/altera-cyclonev.cfg b/tcl/fpga/altera-cyclonev.cfg new file mode 100644 index 000000000..1e9c9c405 --- /dev/null +++ b/tcl/fpga/altera-cyclonev.cfg @@ -0,0 +1,47 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# Intel Cyclone 5 FPGA +# see Cyclone V Device Handbook +# Table 9-1: IDCODE Information for Cyclone V Devices + +#5CEA2 0x02b150dd +#5CEA4 0x02b050dd +#5CEA5 0x02b220dd +#5CEA7 0x02b130dd +#5CEA9 0x02b140dd +#5CGXC3 0x02b010dd +#5CGXC4 0x02b120dd +#5CGXC5 0x02b020dd +#5CGXC7 0x02b030dd +#5CGXC9 0x02b040dd +#5CGTD5 0x02b020dd +#5CGTD7 0x02b030dd +#5CGTD9 0x02b040dd +#5CSEA2 0x02d110dd +#5CSEA4 0x02d010dd +#5CSEA5 0x02d120dd +#5CSEA6 0x02d020dd +#5CSXC2 0x02d110dd +#5CSXC4 0x02d010dd +#5CSXC5 0x02d120dd +#5CSXC6 0x02d020dd +#5CSTD5 0x02d120dd +#5CSTD6 0x02d020dd + + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME cyclonev +} + +jtag newtap $_CHIPNAME tap -irlen 10 \ + -expected-id 0x02b150dd -expected-id 0x02b050dd \ + -expected-id 0x02b220dd -expected-id 0x02b130dd \ + -expected-id 0x02b140dd -expected-id 0x02b010dd \ + -expected-id 0x02b120dd -expected-id 0x02b020dd \ + -expected-id 0x02b030dd -expected-id 0x02b040dd \ + -expected-id 0x02d110dd -expected-id 0x02d010dd \ + -expected-id 0x02d120dd -expected-id 0x02d020dd + +pld device intel $_CHIPNAME.tap cyclonev diff --git a/tcl/fpga/altera-ep3c10.cfg b/tcl/fpga/altera-ep3c10.cfg index 7c231f942..d7a92d748 100644 --- a/tcl/fpga/altera-ep3c10.cfg +++ b/tcl/fpga/altera-ep3c10.cfg @@ -1,6 +1,9 @@ # SPDX-License-Identifier: GPL-2.0-or-later -# Altera Cyclone III EP3C10 -# see Cyclone III Device Handbook, Volume 1; -# Table 14–5. 32-Bit Cyclone III Device IDCODE -jtag newtap ep3c10 tap -expected-id 0x020f10dd -irlen 10 +# file altera-ep3c10.cfg replaced by altera-cycloneiii.cfg +echo "DEPRECATED: use altera-cycloneiii.cfg instead of deprecated altera-ep3c10.cfg" + +#just to be backward compatible: +#tap will be ep3c10.tap instead of cycloneiii.tap: +set CHIPNAME ep3c10 +source [find fpga/altera-cycloneiii.cfg] From 4b56c73ef3781c3232056b57be6d0d2ae3486a4a Mon Sep 17 00:00:00 2001 From: Daniel Anselmi Date: Mon, 12 Dec 2022 09:49:51 +0100 Subject: [PATCH 18/49] pld: add support for gowin devices Change-Id: Idd1a09514bbbbe0a7b54d69010f6c2f91215fd1d Signed-off-by: Daniel Anselmi Reviewed-on: https://review.openocd.org/c/openocd/+/7368 Tested-by: jenkins Reviewed-by: Antonio Borneo --- doc/openocd.texi | 7 + src/pld/Makefile.am | 1 + src/pld/gowin.c | 581 +++++++++++++++++++++++++++++++++++++ src/pld/pld.c | 2 + tcl/board/gowin_runber.cfg | 19 ++ tcl/fpga/gowin_gw1n.cfg | 29 ++ 6 files changed, 639 insertions(+) create mode 100644 src/pld/gowin.c create mode 100644 tcl/board/gowin_runber.cfg create mode 100644 tcl/fpga/gowin_gw1n.cfg diff --git a/doc/openocd.texi b/doc/openocd.texi index 8099455ac..cea02bd54 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -8559,6 +8559,13 @@ With a value of -1 for @var{pos} the check will be omitted. @end deffn +@deffn {FPGA Driver} {gowin} +This driver can be used to load the bitstream into FPGAs from Gowin. +It is possible to program the SRAM. Programming the flash is not supported. +The files @verb{|.fs|} and @verb{|.bin|} generated by Gowin FPGA Designer are supported. +@end deffn + + @node General Commands @chapter General Commands @cindex commands diff --git a/src/pld/Makefile.am b/src/pld/Makefile.am index a13f738ea..22ae9fd20 100644 --- a/src/pld/Makefile.am +++ b/src/pld/Makefile.am @@ -6,6 +6,7 @@ noinst_LTLIBRARIES += %D%/libpld.la %D%/ecp2_3.c \ %D%/ecp5.c \ %D%/efinix.c \ + %D%/gowin.c \ %D%/intel.c \ %D%/lattice.c \ %D%/lattice_bit.c \ diff --git a/src/pld/gowin.c b/src/pld/gowin.c new file mode 100644 index 000000000..467b79937 --- /dev/null +++ b/src/pld/gowin.c @@ -0,0 +1,581 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/*************************************************************************** + * Copyright (C) 2022 by Daniel Anselmi * + * danselmi@gmx.ch * + ***************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include "pld.h" +#include "raw_bit.h" + +#define NO_OP 0x02 +#define ERASE_SRAM 0x05 +#define SRAM_ERASE_DONE 0x09 +#define IDCODE 0x11 +#define ADDRESS_INITIALIZATION 0x12 +#define READ_USERCODE 0x13 +#define CONFIG_ENABLE 0x15 +#define TRANSFER_CONFIGURATION_DATA 0x17 +#define CONFIG_DISABLE 0x3A +#define RELOAD 0x3C +#define STATUS_REGISTER 0x41 +#define ERASE_FLASH 0x75 +#define ENABLE_2ND_FLASH 0x78 + +#define STAUS_MASK_MEMORY_ERASE BIT(5) +#define STAUS_MASK_SYSTEM_EDIT_MODE BIT(7) + +struct gowin_pld_device { + struct jtag_tap *tap; +}; + +struct gowin_bit_file { + struct raw_bit_file raw_file; + size_t capacity; + uint32_t id; + uint16_t stored_checksum; + int compressed; + int crc_en; + uint16_t checksum; + uint8_t replace8x; + uint8_t replace4x; + uint8_t replace2x; +}; + +static uint64_t gowin_read_fs_file_bitsequence(const char *bits, int length) +{ + uint64_t res = 0; + for (int i = 0; i < length; i++) + res = (res << 1) | (*bits++ == '1' ? 1 : 0); + return res; +} + +static int gowin_add_byte_to_bit_file(struct gowin_bit_file *bit_file, uint8_t byte) +{ + if (bit_file->raw_file.length + 1 > bit_file->capacity) { + uint8_t *buffer; + if (bit_file->raw_file.data) + buffer = realloc(bit_file->raw_file.data, bit_file->capacity + 8192); + else + buffer = malloc(8192); + if (!buffer) { + LOG_ERROR("Out of memory"); + return ERROR_FAIL; + } + bit_file->raw_file.data = buffer; + bit_file->capacity += 8192; + } + + bit_file->raw_file.data[bit_file->raw_file.length++] = byte; + + return ERROR_OK; +} + +static int gowin_read_fs_file_header(struct gowin_bit_file *bit_file, FILE *stream) +{ + if (!bit_file) + return ERROR_FAIL; + + int end_of_header = 0; + while (!end_of_header) { + char buffer[256]; + char *line = fgets(buffer, 256, stream); + if (!line || feof(stream) || ferror(stream)) + return ERROR_FAIL; + + if (line[0] == '/') + continue; + + size_t line_length = strlen(line); + if (line[line_length - 1] != '\n') + return ERROR_FAIL; + line_length--; + + for (unsigned int i = 0; i < line_length; i += 8) { + uint8_t byte = gowin_read_fs_file_bitsequence(line + i, 8); + int retval = gowin_add_byte_to_bit_file(bit_file, byte); + if (retval != ERROR_OK) + return retval; + } + + uint8_t key = gowin_read_fs_file_bitsequence(line, 8); + line += 8; + uint64_t value = gowin_read_fs_file_bitsequence(line, line_length - 8); + + if (key == 0x06) { + bit_file->id = value & 0xffffffff; + } else if (key == 0x3B) { + end_of_header = 1; + bit_file->crc_en = (value & BIT(23)) ? 1 : 0; + } + } + + return ERROR_OK; +} + +static int gowin_read_fs_file(struct gowin_bit_file *bit_file, const char *filename) +{ + FILE *input_file = fopen(filename, "r"); + + if (!input_file) { + LOG_ERROR("Couldn't open %s: %s", filename, strerror(errno)); + return ERROR_PLD_FILE_LOAD_FAILED; + } + + int retval = gowin_read_fs_file_header(bit_file, input_file); + if (retval != ERROR_OK) { + free(bit_file->raw_file.data); + fclose(input_file); + return retval; + } + + char digits_buffer[9]; /* 8 + 1 trailing zero */ + do { + char *digits = fgets(digits_buffer, 9, input_file); + if (feof(input_file)) + break; + if (!digits || ferror(input_file)) { + free(bit_file->raw_file.data); + fclose(input_file); + return ERROR_FAIL; + } + if (digits[0] == '\n') + continue; + + if (strlen(digits) != 8) { + free(bit_file->raw_file.data); + fclose(input_file); + return ERROR_FAIL; + } + uint8_t byte = gowin_read_fs_file_bitsequence(digits, 8); + retval = gowin_add_byte_to_bit_file(bit_file, byte); + if (retval != ERROR_OK) { + free(bit_file->raw_file.data); + fclose(input_file); + return ERROR_FAIL; + } + } while (1); + + fclose(input_file); + return ERROR_OK; +} + +static int gowin_read_file(struct gowin_bit_file *bit_file, const char *filename, bool *is_fs) +{ + memset(bit_file, 0, sizeof(struct gowin_bit_file)); + + if (!filename || !bit_file) + return ERROR_COMMAND_SYNTAX_ERROR; + + const char *file_suffix_pos = strrchr(filename, '.'); + if (!file_suffix_pos) { + LOG_ERROR("Unable to detect filename suffix"); + return ERROR_PLD_FILE_LOAD_FAILED; + } + + /* check if binary .bin or ascii .fs */ + if (strcasecmp(file_suffix_pos, ".bin") == 0) { + *is_fs = false; + return cpld_read_raw_bit_file(&bit_file->raw_file, filename); + } else if (strcasecmp(file_suffix_pos, ".fs") == 0) { + *is_fs = true; + return gowin_read_fs_file(bit_file, filename); + } + + LOG_ERROR("Filetype not supported, expecting .fs or .bin file"); + return ERROR_PLD_FILE_LOAD_FAILED; +} + +static int gowin_set_instr(struct jtag_tap *tap, uint8_t new_instr) +{ + struct scan_field field; + field.num_bits = tap->ir_length; + void *t = calloc(DIV_ROUND_UP(field.num_bits, 8), 1); + if (!t) { + LOG_ERROR("Out of memory"); + return ERROR_FAIL; + } + field.out_value = t; + buf_set_u32(t, 0, field.num_bits, new_instr); + field.in_value = NULL; + jtag_add_ir_scan(tap, &field, TAP_IDLE); + jtag_add_runtest(3, TAP_IDLE); + free(t); + return ERROR_OK; +} + +static int gowin_read_register(struct jtag_tap *tap, uint32_t reg, uint32_t *result) +{ + struct scan_field field; + + int retval = gowin_set_instr(tap, reg); + if (retval != ERROR_OK) + return retval; + retval = jtag_execute_queue(); + if (retval != ERROR_OK) + return retval; + + uint8_t buf[4] = {0}; + field.check_mask = NULL; + field.check_value = NULL; + field.num_bits = 32; + field.out_value = buf; + field.in_value = buf; + + jtag_add_dr_scan(tap, 1, &field, TAP_IDLE); + retval = jtag_execute_queue(); + *result = le_to_h_u32(buf); + return retval; +} + +static int gowin_check_status_flag(struct jtag_tap *tap, uint32_t mask, uint32_t flag) +{ + uint32_t status = 0; + + int retries = 0; + do { + int retval = gowin_read_register(tap, STATUS_REGISTER, &status); + if (retval != ERROR_OK) + return retval; + if (retries++ == 100000) + return ERROR_FAIL; + } while ((status & mask) != flag); + + return ERROR_OK; +} + +static int gowin_enable_config(struct jtag_tap *tap) +{ + int retval = gowin_set_instr(tap, CONFIG_ENABLE); + if (retval != ERROR_OK) + return retval; + retval = jtag_execute_queue(); + if (retval != ERROR_OK) + return retval; + + return gowin_check_status_flag(tap, STAUS_MASK_SYSTEM_EDIT_MODE, STAUS_MASK_SYSTEM_EDIT_MODE); +} + +static int gowin_disable_config(struct jtag_tap *tap) +{ + int retval = gowin_set_instr(tap, CONFIG_DISABLE); + if (retval != ERROR_OK) + return retval; + retval = jtag_execute_queue(); + if (retval != ERROR_OK) + return retval; + + return gowin_check_status_flag(tap, STAUS_MASK_SYSTEM_EDIT_MODE, 0); +} + +static int gowin_reload(struct jtag_tap *tap) +{ + int retval = gowin_set_instr(tap, RELOAD); + if (retval != ERROR_OK) + return retval; + retval = gowin_set_instr(tap, NO_OP); + if (retval != ERROR_OK) + return retval; + return jtag_execute_queue(); +} + +static int gowin_runtest_idle(struct jtag_tap *tap, unsigned int frac_sec) +{ + int speed = adapter_get_speed_khz() * 1000; + int cycles = DIV_ROUND_UP(speed, frac_sec); + jtag_add_runtest(cycles, TAP_IDLE); + return jtag_execute_queue(); +} + +static int gowin_erase_sram(struct jtag_tap *tap, bool tx_erase_done) +{ + /* config is already enabled */ + int retval = gowin_set_instr(tap, ERASE_SRAM); + if (retval != ERROR_OK) + return retval; + retval = gowin_set_instr(tap, NO_OP); + if (retval != ERROR_OK) + return retval; + + /* Delay or Run Test 2~10ms */ + /* 10 ms is worst case for GW2A-55 */ + jtag_add_sleep(10000); + retval = jtag_execute_queue(); + if (retval != ERROR_OK) + return retval; + + retval = gowin_check_status_flag(tap, STAUS_MASK_MEMORY_ERASE, + STAUS_MASK_MEMORY_ERASE); + if (retval != ERROR_OK) + return retval; + + if (tx_erase_done) { + retval = gowin_set_instr(tap, SRAM_ERASE_DONE); + if (retval != ERROR_OK) + return retval; + retval = gowin_set_instr(tap, NO_OP); + if (retval != ERROR_OK) + return retval; + retval = jtag_execute_queue(); + if (retval != ERROR_OK) + return retval; + /* gen clock cycles in RUN/IDLE for 500us -> 1/500us = 2000/s */ + retval = gowin_runtest_idle(tap, 2000); + if (retval != ERROR_OK) + return retval; + } + + retval = gowin_set_instr(tap, NO_OP); + if (retval != ERROR_OK) + return retval; + return jtag_execute_queue(); +} + +static int gowin_load_to_sram(struct pld_device *pld_device, const char *filename) +{ + if (!pld_device) + return ERROR_FAIL; + + struct gowin_pld_device *gowin_info = pld_device->driver_priv; + + if (!gowin_info || !gowin_info->tap) + return ERROR_FAIL; + struct jtag_tap *tap = gowin_info->tap; + + bool is_fs = false; + struct gowin_bit_file bit_file; + int retval = gowin_read_file(&bit_file, filename, &is_fs); + if (retval != ERROR_OK) + return retval; + + for (unsigned int i = 0; i < bit_file.raw_file.length; i++) + bit_file.raw_file.data[i] = flip_u32(bit_file.raw_file.data[i], 8); + + uint32_t id; + retval = gowin_read_register(tap, IDCODE, &id); + if (retval != ERROR_OK) { + free(bit_file.raw_file.data); + return retval; + } + + if (is_fs && id != bit_file.id) { + free(bit_file.raw_file.data); + LOG_ERROR("Id on device (0x%8.8" PRIx32 ") and id in bit-stream (0x%8.8" PRIx32 ") don't match.", + id, bit_file.id); + return ERROR_FAIL; + } + + retval = gowin_enable_config(tap); + if (retval != ERROR_OK) { + free(bit_file.raw_file.data); + return retval; + } + + retval = gowin_erase_sram(tap, false); + if (retval != ERROR_OK) { + free(bit_file.raw_file.data); + return retval; + } + + retval = gowin_set_instr(tap, ADDRESS_INITIALIZATION); + if (retval != ERROR_OK) { + free(bit_file.raw_file.data); + return retval; + } + retval = gowin_set_instr(tap, TRANSFER_CONFIGURATION_DATA); + if (retval != ERROR_OK) { + free(bit_file.raw_file.data); + return retval; + } + + /* scan out the bitstream */ + struct scan_field field; + field.num_bits = bit_file.raw_file.length * 8; + field.out_value = bit_file.raw_file.data; + field.in_value = bit_file.raw_file.data; + jtag_add_dr_scan(gowin_info->tap, 1, &field, TAP_IDLE); + jtag_add_runtest(3, TAP_IDLE); + + retval = jtag_execute_queue(); + if (retval != ERROR_OK) { + free(bit_file.raw_file.data); + return retval; + } + + retval = gowin_disable_config(tap); + free(bit_file.raw_file.data); + if (retval != ERROR_OK) + return retval; + + retval = gowin_set_instr(gowin_info->tap, NO_OP); + if (retval != ERROR_OK) + return retval; + + retval = jtag_execute_queue(); + + return retval; +} + +static int gowin_read_register_command(struct pld_device *pld_device, uint32_t cmd, uint32_t *value) +{ + if (!pld_device) + return ERROR_FAIL; + + struct gowin_pld_device *gowin_info = pld_device->driver_priv; + + if (!gowin_info || !gowin_info->tap) + return ERROR_FAIL; + + return gowin_read_register(gowin_info->tap, cmd, value); +} + +static int gowin_reload_command(struct pld_device *pld_device) +{ + if (!pld_device) + return ERROR_FAIL; + + struct gowin_pld_device *gowin_info = pld_device->driver_priv; + + if (!gowin_info || !gowin_info->tap) + return ERROR_FAIL; + + return gowin_reload(gowin_info->tap); +} + +COMMAND_HANDLER(gowin_read_status_command_handler) +{ + int dev_id; + + if (CMD_ARGC != 1) + return ERROR_COMMAND_SYNTAX_ERROR; + + COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], dev_id); + struct pld_device *device = get_pld_device_by_num(dev_id); + if (!device) { + command_print(CMD, "pld device '#%s' is out of bounds", CMD_ARGV[0]); + return ERROR_FAIL; + } + + uint32_t status = 0; + int retval = gowin_read_register_command(device, STATUS_REGISTER, &status); + + if (retval == ERROR_OK) + command_print(CMD, "0x%8.8" PRIx32, status); + + return retval; +} + +COMMAND_HANDLER(gowin_read_user_register_command_handler) +{ + int dev_id; + + if (CMD_ARGC != 1) + return ERROR_COMMAND_SYNTAX_ERROR; + + COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], dev_id); + struct pld_device *device = get_pld_device_by_num(dev_id); + if (!device) { + command_print(CMD, "pld device '#%s' is out of bounds", CMD_ARGV[0]); + return ERROR_FAIL; + } + + uint32_t user_reg = 0; + int retval = gowin_read_register_command(device, READ_USERCODE, &user_reg); + + if (retval == ERROR_OK) + command_print(CMD, "0x%8.8" PRIx32, user_reg); + + return retval; +} + +COMMAND_HANDLER(gowin_reload_command_handler) +{ + int dev_id; + + if (CMD_ARGC != 1) + return ERROR_COMMAND_SYNTAX_ERROR; + + COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], dev_id); + struct pld_device *device = get_pld_device_by_num(dev_id); + if (!device) { + command_print(CMD, "pld device '#%s' is out of bounds", CMD_ARGV[0]); + return ERROR_FAIL; + } + + return gowin_reload_command(device); +} + +static const struct command_registration gowin_exec_command_handlers[] = { + { + .name = "read_status", + .mode = COMMAND_EXEC, + .handler = gowin_read_status_command_handler, + .help = "reading status register from FPGA", + .usage = "num_pld", + }, { + .name = "read_user", + .mode = COMMAND_EXEC, + .handler = gowin_read_user_register_command_handler, + .help = "reading user register from FPGA", + .usage = "num_pld", + }, { + .name = "reload", + .mode = COMMAND_EXEC, + .handler = gowin_reload_command_handler, + .help = "reloading bitstream from flash to SRAM", + .usage = "num_pld", + }, + COMMAND_REGISTRATION_DONE +}; + +static const struct command_registration gowin_command_handler[] = { + { + .name = "gowin", + .mode = COMMAND_ANY, + .help = "gowin specific commands", + .usage = "", + .chain = gowin_exec_command_handlers + }, + COMMAND_REGISTRATION_DONE +}; + +PLD_DEVICE_COMMAND_HANDLER(gowin_pld_device_command) +{ + struct jtag_tap *tap; + + struct gowin_pld_device *gowin_info; + + if (CMD_ARGC != 2) + return ERROR_COMMAND_SYNTAX_ERROR; + + tap = jtag_tap_by_string(CMD_ARGV[1]); + if (!tap) { + command_print(CMD, "Tap: %s does not exist", CMD_ARGV[1]); + return ERROR_FAIL; + } + + gowin_info = malloc(sizeof(struct gowin_pld_device)); + if (!gowin_info) { + LOG_ERROR("Out of memory"); + return ERROR_FAIL; + } + gowin_info->tap = tap; + + pld->driver_priv = gowin_info; + + return ERROR_OK; +} + +struct pld_driver gowin_pld = { + .name = "gowin", + .commands = gowin_command_handler, + .pld_device_command = &gowin_pld_device_command, + .load = &gowin_load_to_sram, +}; diff --git a/src/pld/pld.c b/src/pld/pld.c index f4f79bacb..d9e01f16c 100644 --- a/src/pld/pld.c +++ b/src/pld/pld.c @@ -19,12 +19,14 @@ /* pld drivers */ extern struct pld_driver efinix_pld; +extern struct pld_driver gowin_pld; extern struct pld_driver intel_pld; extern struct pld_driver lattice_pld; extern struct pld_driver virtex2_pld; static struct pld_driver *pld_drivers[] = { &efinix_pld, + &gowin_pld, &intel_pld, &lattice_pld, &virtex2_pld, diff --git a/tcl/board/gowin_runber.cfg b/tcl/board/gowin_runber.cfg new file mode 100644 index 000000000..9496c6f00 --- /dev/null +++ b/tcl/board/gowin_runber.cfg @@ -0,0 +1,19 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# Gowin RUNBER FPGA Development Board +# https://www.seeedstudio.com/Gowin-RUNBER-Development-Board-p-4779.html + +adapter driver ftdi +ftdi vid_pid 0x0403 0x6010 + +ftdi channel 0 +ftdi layout_init 0x0008 0x008b +reset_config none +transport select jtag +adapter speed 6000 + +source [find fpga/gowin_gw1n.cfg] + + +#openocd -f board/gowin_runber.cfg -c "init" -c "pld load 0 impl/pnr/gw1n_blinker.fs" +#ipdbg -start -tap gw1n.tap -hub 0x42 -port 5555 -tool 0 diff --git a/tcl/fpga/gowin_gw1n.cfg b/tcl/fpga/gowin_gw1n.cfg new file mode 100644 index 000000000..43d66b70e --- /dev/null +++ b/tcl/fpga/gowin_gw1n.cfg @@ -0,0 +1,29 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# Gowin FPGA IDCODEs +# from JTAG Programming and Configuration Guide +# http://cdn.gowinsemi.com.cn/TN653E.pdf + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME gw1n +} + +jtag newtap $_CHIPNAME tap -irlen 8 -ignore-version \ + -expected-id 0x0900281B \ + -expected-id 0x0900381B \ + -expected-id 0x0100681B \ + -expected-id 0x0300081B \ + -expected-id 0x0300181B \ + -expected-id 0x0120681B \ + -expected-id 0x0100381B \ + -expected-id 0x1100381B \ + -expected-id 0x0100981B \ + -expected-id 0x1100581B \ + -expected-id 0x1100481B \ + -expected-id 0x0100181B \ + -expected-id 0x1100181B \ + -expected-id 0x0100481B + +pld device gowin $_CHIPNAME.tap From 682f927f8e4e6c6216c6d0b259b3c24b9f3f6342 Mon Sep 17 00:00:00 2001 From: Daniel Anselmi Date: Fri, 24 Feb 2023 15:57:30 +0100 Subject: [PATCH 19/49] pld: add support for cologne chip gatemate fpgas Change-Id: I0bf5a52ee6a7f0287524619114eba0cfccf6ac81 Signed-off-by: Daniel Anselmi Reviewed-on: https://review.openocd.org/c/openocd/+/7565 Tested-by: jenkins Reviewed-by: Antonio Borneo --- doc/openocd.texi | 6 + src/pld/Makefile.am | 1 + src/pld/gatemate.c | 241 ++++++++++++++++++++++++++++++++++++ src/pld/pld.c | 2 + tcl/board/gatemate_eval.cfg | 16 +++ tcl/fpga/gatemate.cfg | 16 +++ 6 files changed, 282 insertions(+) create mode 100644 src/pld/gatemate.c create mode 100644 tcl/board/gatemate_eval.cfg create mode 100644 tcl/fpga/gatemate.cfg diff --git a/doc/openocd.texi b/doc/openocd.texi index cea02bd54..f32ef3475 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -8566,6 +8566,12 @@ The files @verb{|.fs|} and @verb{|.bin|} generated by Gowin FPGA Designer are su @end deffn +@deffn {FPGA Driver} {gatemate} +This driver can be used to load the bitstream into GateMate FPGAs form CologneChip. +The files @verb{|.bit|} and @verb{|.cfg|} both generated by p_r tool from CologneChip are supported. +@end deffn + + @node General Commands @chapter General Commands @cindex commands diff --git a/src/pld/Makefile.am b/src/pld/Makefile.am index 22ae9fd20..69e457c96 100644 --- a/src/pld/Makefile.am +++ b/src/pld/Makefile.am @@ -6,6 +6,7 @@ noinst_LTLIBRARIES += %D%/libpld.la %D%/ecp2_3.c \ %D%/ecp5.c \ %D%/efinix.c \ + %D%/gatemate.c \ %D%/gowin.c \ %D%/intel.c \ %D%/lattice.c \ diff --git a/src/pld/gatemate.c b/src/pld/gatemate.c new file mode 100644 index 000000000..afd27efca --- /dev/null +++ b/src/pld/gatemate.c @@ -0,0 +1,241 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/*************************************************************************** + * Copyright (C) 2022 by Daniel Anselmi * + * danselmi@gmx.ch * + ***************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include "pld.h" +#include "raw_bit.h" + +#define JTAG_CONFIGURE 0x06 + +struct gatemate_pld_device { + struct jtag_tap *tap; +}; + +struct gatemate_bit_file { + struct raw_bit_file raw_file; + size_t capacity; +}; + +static int gatemate_add_byte_to_bitfile(struct gatemate_bit_file *bit_file, uint8_t byte) +{ + const size_t chunk_size = 8192; + if (bit_file->raw_file.length + 1 > bit_file->capacity) { + uint8_t *buffer; + if (bit_file->raw_file.data) + buffer = realloc(bit_file->raw_file.data, bit_file->capacity + chunk_size); + else + buffer = malloc(chunk_size); + if (!buffer) { + LOG_ERROR("Out of memory"); + return ERROR_FAIL; + } + bit_file->raw_file.data = buffer; + bit_file->capacity += chunk_size; + } + + bit_file->raw_file.data[bit_file->raw_file.length++] = byte; + + return ERROR_OK; +} + +static int gatemate_read_cfg_line(struct gatemate_bit_file *bit_file, const char *line_buffer, size_t nread) +{ + for (size_t idx = 0; idx < nread; ++idx) { + if (line_buffer[idx] == ' ') { + continue; + } else if (line_buffer[idx] == 0) { + break; + } else if (idx + 1 < nread) { + if (isxdigit(line_buffer[idx]) && isxdigit(line_buffer[idx + 1])) { + uint8_t byte; + unhexify(&byte, line_buffer + idx, 2); + int retval = gatemate_add_byte_to_bitfile(bit_file, byte); + if (retval != ERROR_OK) + return retval; + } else if (line_buffer[idx] == '/' && line_buffer[idx + 1] == '/') { + break; + } + ++idx; + } else { + LOG_ERROR("parsing failed"); + return ERROR_FAIL; + } + } + return ERROR_OK; +} + +static int gatemate_getline(char **buffer, size_t *buf_size, FILE *input_file) +{ + const size_t chunk_size = 32; + if (!*buffer) + *buf_size = 0; + + size_t read = 0; + do { + if (read + 1 > *buf_size) { + char *new_buffer; + if (*buffer) + new_buffer = realloc(*buffer, *buf_size + chunk_size); + else + new_buffer = malloc(chunk_size); + if (!new_buffer) { + LOG_ERROR("Out of memory"); + return -1; + } + *buffer = new_buffer; + *buf_size += chunk_size; + } + + int c = fgetc(input_file); + if ((c == EOF && read) || (char)c == '\n') { + (*buffer)[read++] = 0; + return read; + } else if (c == EOF) { + return -1; + } + + (*buffer)[read++] = (char)c; + } while (1); + + return -1; +} + +static int gatemate_read_cfg_file(struct gatemate_bit_file *bit_file, const char *filename) +{ + FILE *input_file = fopen(filename, "r"); + + if (!input_file) { + LOG_ERROR("Couldn't open %s: %s", filename, strerror(errno)); + return ERROR_PLD_FILE_LOAD_FAILED; + } + + int retval = ERROR_OK; + char *line_buffer = NULL; + size_t buffer_length = 0; + int nread; + while (((nread = gatemate_getline(&line_buffer, &buffer_length, input_file)) != -1) && (retval == ERROR_OK)) + retval = gatemate_read_cfg_line(bit_file, line_buffer, (size_t)nread); + + if (line_buffer) + free(line_buffer); + + fclose(input_file); + if (retval != ERROR_OK) + free(bit_file->raw_file.data); + return retval; +} + +static int gatemate_read_file(struct gatemate_bit_file *bit_file, const char *filename) +{ + memset(bit_file, 0, sizeof(struct gatemate_bit_file)); + + if (!filename || !bit_file) + return ERROR_COMMAND_SYNTAX_ERROR; + + /* check if binary .bit or ascii .cfg */ + const char *file_suffix_pos = strrchr(filename, '.'); + if (!file_suffix_pos) { + LOG_ERROR("Unable to detect filename suffix"); + return ERROR_PLD_FILE_LOAD_FAILED; + } + + if (strcasecmp(file_suffix_pos, ".bit") == 0) + return cpld_read_raw_bit_file(&bit_file->raw_file, filename); + else if (strcasecmp(file_suffix_pos, ".cfg") == 0) + return gatemate_read_cfg_file(bit_file, filename); + + LOG_ERROR("Filetype not supported, expecting .bit or .cfg file"); + return ERROR_PLD_FILE_LOAD_FAILED; +} + +static int gatemate_set_instr(struct jtag_tap *tap, uint8_t new_instr) +{ + struct scan_field field; + field.num_bits = tap->ir_length; + void *t = calloc(DIV_ROUND_UP(field.num_bits, 8), 1); + if (!t) { + LOG_ERROR("Out of memory"); + return ERROR_FAIL; + } + field.out_value = t; + buf_set_u32(t, 0, field.num_bits, new_instr); + field.in_value = NULL; + jtag_add_ir_scan(tap, &field, TAP_IDLE); + jtag_add_runtest(3, TAP_IDLE); + free(t); + return ERROR_OK; +} + +static int gatemate_load(struct pld_device *pld_device, const char *filename) +{ + if (!pld_device) + return ERROR_FAIL; + + struct gatemate_pld_device *gatemate_info = pld_device->driver_priv; + + if (!gatemate_info || !gatemate_info->tap) + return ERROR_FAIL; + struct jtag_tap *tap = gatemate_info->tap; + + struct gatemate_bit_file bit_file; + int retval = gatemate_read_file(&bit_file, filename); + if (retval != ERROR_OK) + return retval; + + retval = gatemate_set_instr(tap, JTAG_CONFIGURE); + if (retval != ERROR_OK) + return retval; + + struct scan_field field; + field.num_bits = bit_file.raw_file.length * 8; + field.out_value = bit_file.raw_file.data; + field.in_value = NULL; + jtag_add_dr_scan(tap, 1, &field, TAP_IDLE); + + retval = jtag_execute_queue(); + free(bit_file.raw_file.data); + + return retval; +} + +PLD_DEVICE_COMMAND_HANDLER(gatemate_pld_device_command) +{ + struct jtag_tap *tap; + + struct gatemate_pld_device *gatemate_info; + + if (CMD_ARGC != 2) + return ERROR_COMMAND_SYNTAX_ERROR; + + tap = jtag_tap_by_string(CMD_ARGV[1]); + if (!tap) { + command_print(CMD, "Tap: %s does not exist", CMD_ARGV[1]); + return ERROR_FAIL; + } + + gatemate_info = malloc(sizeof(struct gatemate_pld_device)); + if (!gatemate_info) { + LOG_ERROR("Out of memory"); + return ERROR_FAIL; + } + gatemate_info->tap = tap; + + pld->driver_priv = gatemate_info; + + return ERROR_OK; +} + +struct pld_driver gatemate_pld = { + .name = "gatemate", + .pld_device_command = &gatemate_pld_device_command, + .load = &gatemate_load, +}; diff --git a/src/pld/pld.c b/src/pld/pld.c index d9e01f16c..dd8f8263f 100644 --- a/src/pld/pld.c +++ b/src/pld/pld.c @@ -19,6 +19,7 @@ /* pld drivers */ extern struct pld_driver efinix_pld; +extern struct pld_driver gatemate_pld; extern struct pld_driver gowin_pld; extern struct pld_driver intel_pld; extern struct pld_driver lattice_pld; @@ -26,6 +27,7 @@ extern struct pld_driver virtex2_pld; static struct pld_driver *pld_drivers[] = { &efinix_pld, + &gatemate_pld, &gowin_pld, &intel_pld, &lattice_pld, diff --git a/tcl/board/gatemate_eval.cfg b/tcl/board/gatemate_eval.cfg new file mode 100644 index 000000000..cc078a0e3 --- /dev/null +++ b/tcl/board/gatemate_eval.cfg @@ -0,0 +1,16 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# GateMateTM FPGA Evaluation Board +# https://www.colognechip.com/programmable-logic/gatemate-evaluation-board/ +# + +adapter driver ftdi +ftdi vid_pid 0x0403 0x6010 + +ftdi channel 0 +ftdi layout_init 0x0014 0x011b +reset_config none +transport select jtag +adapter speed 6000 + +source [find fpga/gatemate.cfg] diff --git a/tcl/fpga/gatemate.cfg b/tcl/fpga/gatemate.cfg new file mode 100644 index 000000000..cc19fd4c2 --- /dev/null +++ b/tcl/fpga/gatemate.cfg @@ -0,0 +1,16 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# GateMateTM FPGA +# https://www.colognechip.com/programmable-logic/gatemate/ +# https://colognechip.com/docs/ds1001-gatemate1-datasheet-latest.pdf + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME gatemate +} + +jtag newtap $_CHIPNAME tap -irlen 6 -ignore-version \ + -expected-id 0x20000001 + +pld device gatemate $_CHIPNAME.tap From 411dfa2409221259108b7cec99ac7824e53e3867 Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Sat, 8 Apr 2023 23:19:50 +0200 Subject: [PATCH 20/49] jtag: drivers: add static to local symbols Add static type to symbols that are not used elsewhere. Detected through 'sparse' tool. Change-Id: I00e151d2466868a5dce028444d326defb80d4826 Signed-off-by: Antonio Borneo Reviewed-on: https://review.openocd.org/c/openocd/+/7591 Tested-by: jenkins --- src/jtag/drivers/bcm2835gpio.c | 2 +- src/jtag/drivers/ep93xx.c | 2 +- src/jtag/drivers/vdebug.c | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/jtag/drivers/bcm2835gpio.c b/src/jtag/drivers/bcm2835gpio.c index 635d9a5ff..879ca3c84 100644 --- a/src/jtag/drivers/bcm2835gpio.c +++ b/src/jtag/drivers/bcm2835gpio.c @@ -19,7 +19,7 @@ #include -uint32_t bcm2835_peri_base = 0x20000000; +static uint32_t bcm2835_peri_base = 0x20000000; #define BCM2835_GPIO_BASE (bcm2835_peri_base + 0x200000) /* GPIO controller */ #define BCM2835_PADS_GPIO_0_27 (bcm2835_peri_base + 0x100000) diff --git a/src/jtag/drivers/ep93xx.c b/src/jtag/drivers/ep93xx.c index 393fc7e85..5cb6dff24 100644 --- a/src/jtag/drivers/ep93xx.c +++ b/src/jtag/drivers/ep93xx.c @@ -37,7 +37,7 @@ static int ep93xx_reset(int trst, int srst); static int ep93xx_init(void); static int ep93xx_quit(void); -struct timespec ep93xx_zzzz; +static struct timespec ep93xx_zzzz; static struct jtag_interface ep93xx_interface = { .supported = DEBUG_CAP_TMS_SEQ, diff --git a/src/jtag/drivers/vdebug.c b/src/jtag/drivers/vdebug.c index 7898e9d9b..9223be23f 100644 --- a/src/jtag/drivers/vdebug.c +++ b/src/jtag/drivers/vdebug.c @@ -344,7 +344,7 @@ static uint32_t vdebug_wait_server(int hsock, struct vd_shm *pmem) return rc; } -int vdebug_run_jtag_queue(int hsock, struct vd_shm *pm, unsigned int count) +static int vdebug_run_jtag_queue(int hsock, struct vd_shm *pm, unsigned int count) { uint8_t num_pre, num_post, tdi, tms; unsigned int num, anum, bytes, hwords, words; @@ -420,7 +420,7 @@ int vdebug_run_jtag_queue(int hsock, struct vd_shm *pm, unsigned int count) return rc; } -int vdebug_run_reg_queue(int hsock, struct vd_shm *pm, unsigned int count) +static int vdebug_run_reg_queue(int hsock, struct vd_shm *pm, unsigned int count) { unsigned int num, awidth, wwidth; unsigned int req, waddr, rwords; From 07e1ebcc12cdc7e6aba4db2e33aba79d0461f994 Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Sat, 8 Apr 2023 23:21:33 +0200 Subject: [PATCH 21/49] jtag: drivers: with pointers, use NULL instead of 0 Don't compare pointers with 0, use NULL when needed. Don't assign pointer to 0, use NULL. Don't pass 0 ad pointer argument, pass NULL. While there, check for return value from malloc(), replace an assert() with a LOG_ERROR(), drop a useless cast. Detected through 'sparse' tool. Change-Id: Ia7cf52221b12198aba1a07ebdfaf57ce341d5699 Signed-off-by: Antonio Borneo Reviewed-on: https://review.openocd.org/c/openocd/+/7592 Tested-by: jenkins --- src/jtag/drivers/arm-jtag-ew.c | 2 +- src/jtag/drivers/at91rm9200.c | 8 ++++++-- src/jtag/drivers/ep93xx.c | 2 +- src/jtag/drivers/ft232r.c | 12 ++++++------ src/jtag/drivers/ftdi.c | 2 +- src/jtag/drivers/mpsse.c | 14 +++++++------- src/jtag/drivers/opendous.c | 2 +- src/jtag/drivers/parport.c | 6 +++++- src/jtag/drivers/rlink.c | 2 +- src/jtag/drivers/stlink_usb.c | 2 +- src/jtag/drivers/sysfsgpio.c | 2 +- src/jtag/drivers/ti_icdi_usb.c | 6 +++--- src/jtag/drivers/usbprog.c | 2 +- src/jtag/drivers/xds110.c | 10 +++++----- 14 files changed, 40 insertions(+), 32 deletions(-) diff --git a/src/jtag/drivers/arm-jtag-ew.c b/src/jtag/drivers/arm-jtag-ew.c index 7db3c7b15..a37272084 100644 --- a/src/jtag/drivers/arm-jtag-ew.c +++ b/src/jtag/drivers/arm-jtag-ew.c @@ -213,7 +213,7 @@ static int armjtagew_init(void) armjtagew_handle = armjtagew_usb_open(); - if (armjtagew_handle == 0) { + if (!armjtagew_handle) { LOG_ERROR( "Cannot find ARM-JTAG-EW Interface! Please check connection and permissions."); return ERROR_JTAG_INIT_FAILED; diff --git a/src/jtag/drivers/at91rm9200.c b/src/jtag/drivers/at91rm9200.c index 08daa004b..ba9ee5e34 100644 --- a/src/jtag/drivers/at91rm9200.c +++ b/src/jtag/drivers/at91rm9200.c @@ -107,7 +107,7 @@ static int at91rm9200_quit(void); static struct bitbang_interface at91rm9200_bitbang = { .read = at91rm9200_read, .write = at91rm9200_write, - .blink = 0 + .blink = NULL, }; static bb_value_t at91rm9200_read(void) @@ -157,8 +157,12 @@ COMMAND_HANDLER(at91rm9200_handle_device_command) return ERROR_COMMAND_SYNTAX_ERROR; /* only if the device name wasn't overwritten by cmdline */ - if (at91rm9200_device == 0) { + if (!at91rm9200_device) { at91rm9200_device = malloc(strlen(CMD_ARGV[0]) + sizeof(char)); + if (!at91rm9200_device) { + LOG_ERROR("Out of memory"); + return ERROR_FAIL; + } strcpy(at91rm9200_device, CMD_ARGV[0]); } diff --git a/src/jtag/drivers/ep93xx.c b/src/jtag/drivers/ep93xx.c index 5cb6dff24..c3e841d37 100644 --- a/src/jtag/drivers/ep93xx.c +++ b/src/jtag/drivers/ep93xx.c @@ -58,7 +58,7 @@ struct adapter_driver ep93xx_adapter_driver = { static struct bitbang_interface ep93xx_bitbang = { .read = ep93xx_read, .write = ep93xx_write, - .blink = 0, + .blink = NULL, }; static bb_value_t ep93xx_read(void) diff --git a/src/jtag/drivers/ft232r.c b/src/jtag/drivers/ft232r.c index 816b2d05e..1d73af4e5 100644 --- a/src/jtag/drivers/ft232r.c +++ b/src/jtag/drivers/ft232r.c @@ -235,7 +235,7 @@ static int ft232r_speed(int divisor) if (jtag_libusb_control_transfer(adapter, LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE | LIBUSB_ENDPOINT_OUT, - SIO_SET_BAUD_RATE, divisor, 0, 0, 0, 1000) != 0) { + SIO_SET_BAUD_RATE, divisor, 0, NULL, 0, 1000) != 0) { LOG_ERROR("cannot set baud rate"); return ERROR_JTAG_DEVICE_ERROR; } @@ -266,7 +266,7 @@ static int ft232r_init(void) /* Reset the device. */ if (jtag_libusb_control_transfer(adapter, LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE | LIBUSB_ENDPOINT_OUT, - SIO_RESET, 0, 0, 0, 0, 1000) != 0) { + SIO_RESET, 0, 0, NULL, 0, 1000) != 0) { LOG_ERROR("unable to reset device"); return ERROR_JTAG_INIT_FAILED; } @@ -275,7 +275,7 @@ static int ft232r_init(void) if (jtag_libusb_control_transfer(adapter, LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE | LIBUSB_ENDPOINT_OUT, SIO_SET_BITMODE, (1<invert_oe; break; default: - assert(0 && "invalid signal level specifier"); + LOG_ERROR("invalid signal level specifier \'%c\'(0x%02x)", value, value); return ERROR_FAIL; } diff --git a/src/jtag/drivers/mpsse.c b/src/jtag/drivers/mpsse.c index 9f2fdde9f..fad91dde2 100644 --- a/src/jtag/drivers/mpsse.c +++ b/src/jtag/drivers/mpsse.c @@ -313,7 +313,7 @@ struct mpsse_ctx *mpsse_open(const uint16_t vids[], const uint16_t pids[], const int err; if (!ctx) - return 0; + return NULL; bit_copy_queue_init(&ctx->read_queue); ctx->read_chunk_size = 16384; @@ -348,7 +348,7 @@ struct mpsse_ctx *mpsse_open(const uint16_t vids[], const uint16_t pids[], const description ? description : "*", serial ? serial : "*", location ? location : "*"); - ctx->usb_dev = 0; + ctx->usb_dev = NULL; goto error; } @@ -378,7 +378,7 @@ struct mpsse_ctx *mpsse_open(const uint16_t vids[], const uint16_t pids[], const return ctx; error: mpsse_close(ctx); - return 0; + return NULL; } void mpsse_close(struct mpsse_ctx *ctx) @@ -465,13 +465,13 @@ static unsigned buffer_add_read(struct mpsse_ctx *ctx, uint8_t *in, unsigned in_ void mpsse_clock_data_out(struct mpsse_ctx *ctx, const uint8_t *out, unsigned out_offset, unsigned length, uint8_t mode) { - mpsse_clock_data(ctx, out, out_offset, 0, 0, length, mode); + mpsse_clock_data(ctx, out, out_offset, NULL, 0, length, mode); } void mpsse_clock_data_in(struct mpsse_ctx *ctx, uint8_t *in, unsigned in_offset, unsigned length, uint8_t mode) { - mpsse_clock_data(ctx, 0, 0, in, in_offset, length, mode); + mpsse_clock_data(ctx, NULL, 0, in, in_offset, length, mode); } void mpsse_clock_data(struct mpsse_ctx *ctx, const uint8_t *out, unsigned out_offset, uint8_t *in, @@ -548,7 +548,7 @@ void mpsse_clock_data(struct mpsse_ctx *ctx, const uint8_t *out, unsigned out_of void mpsse_clock_tms_cs_out(struct mpsse_ctx *ctx, const uint8_t *out, unsigned out_offset, unsigned length, bool tdi, uint8_t mode) { - mpsse_clock_tms_cs(ctx, out, out_offset, 0, 0, length, tdi, mode); + mpsse_clock_tms_cs(ctx, out, out_offset, NULL, 0, length, tdi, mode); } void mpsse_clock_tms_cs(struct mpsse_ctx *ctx, const uint8_t *out, unsigned out_offset, uint8_t *in, @@ -842,7 +842,7 @@ int mpsse_flush(struct mpsse_ctx *ctx) if (ctx->write_count == 0) return retval; - struct libusb_transfer *read_transfer = 0; + struct libusb_transfer *read_transfer = NULL; struct transfer_result read_result = { .ctx = ctx, .done = true }; if (ctx->read_count) { buffer_write_byte(ctx, 0x87); /* SEND_IMMEDIATE */ diff --git a/src/jtag/drivers/opendous.c b/src/jtag/drivers/opendous.c index c353aef40..ad980bf23 100644 --- a/src/jtag/drivers/opendous.c +++ b/src/jtag/drivers/opendous.c @@ -347,7 +347,7 @@ static int opendous_init(void) opendous_jtag_handle = opendous_usb_open(); - if (opendous_jtag_handle == 0) { + if (!opendous_jtag_handle) { LOG_ERROR("Cannot find opendous Interface! Please check connection and permissions."); return ERROR_JTAG_INIT_FAILED; } diff --git a/src/jtag/drivers/parport.c b/src/jtag/drivers/parport.c index 4073d066e..d26a51048 100644 --- a/src/jtag/drivers/parport.c +++ b/src/jtag/drivers/parport.c @@ -411,9 +411,13 @@ COMMAND_HANDLER(parport_handle_parport_cable_command) return ERROR_OK; /* only if the cable name wasn't overwritten by cmdline */ - if (parport_cable == 0) { + if (!parport_cable) { /* REVISIT first verify that it's listed in cables[] ... */ parport_cable = malloc(strlen(CMD_ARGV[0]) + sizeof(char)); + if (!parport_cable) { + LOG_ERROR("Out of memory"); + return ERROR_FAIL; + } strcpy(parport_cable, CMD_ARGV[0]); } diff --git a/src/jtag/drivers/rlink.c b/src/jtag/drivers/rlink.c index c933b3e1c..65f7494bd 100644 --- a/src/jtag/drivers/rlink.c +++ b/src/jtag/drivers/rlink.c @@ -632,7 +632,7 @@ static int dtc_queue_run(void) uint8_t dtc_mask, tdo_mask; uint8_t reply_buffer[USB_EP2IN_SIZE]; - assert((dtc_queue.rq_head != 0) == (dtc_queue.reply_index > 0)); + assert((!!dtc_queue.rq_head) == (dtc_queue.reply_index > 0)); assert(dtc_queue.cmd_index < USB_EP2BANK_SIZE); assert(dtc_queue.reply_index <= USB_EP2IN_SIZE); diff --git a/src/jtag/drivers/stlink_usb.c b/src/jtag/drivers/stlink_usb.c index 5b051c1ff..ee629542b 100644 --- a/src/jtag/drivers/stlink_usb.c +++ b/src/jtag/drivers/stlink_usb.c @@ -3694,7 +3694,7 @@ static int stlink_open(struct hl_interface_param_s *param, enum stlink_mode mode h = calloc(1, sizeof(struct stlink_usb_handle_s)); - if (h == 0) { + if (!h) { LOG_DEBUG("malloc failed"); return ERROR_FAIL; } diff --git a/src/jtag/drivers/sysfsgpio.c b/src/jtag/drivers/sysfsgpio.c index ee254d66a..a5f5fd3ac 100644 --- a/src/jtag/drivers/sysfsgpio.c +++ b/src/jtag/drivers/sysfsgpio.c @@ -571,7 +571,7 @@ static struct bitbang_interface sysfsgpio_bitbang = { .swdio_read = sysfsgpio_swdio_read, .swdio_drive = sysfsgpio_swdio_drive, .swd_write = sysfsgpio_swd_write, - .blink = 0 + .blink = NULL, }; /* helper func to close and cleanup files only if they were valid/ used */ diff --git a/src/jtag/drivers/ti_icdi_usb.c b/src/jtag/drivers/ti_icdi_usb.c index ca52559d1..3e3621873 100644 --- a/src/jtag/drivers/ti_icdi_usb.c +++ b/src/jtag/drivers/ti_icdi_usb.c @@ -369,7 +369,7 @@ static int icdi_usb_query(void *handle) if (h->max_packet != ICDI_PACKET_SIZE) { h->read_buffer = realloc(h->read_buffer, h->max_packet); h->write_buffer = realloc(h->write_buffer, h->max_packet); - if (h->read_buffer == 0 || h->write_buffer == 0) { + if (!h->read_buffer || !h->write_buffer) { LOG_ERROR("unable to reallocate memory"); return ERROR_FAIL; } @@ -664,7 +664,7 @@ static int icdi_usb_open(struct hl_interface_param_s *param, void **fd) h = calloc(1, sizeof(struct icdi_usb_handle_s)); - if (h == 0) { + if (!h) { LOG_ERROR("unable to allocate memory"); return ERROR_FAIL; } @@ -712,7 +712,7 @@ static int icdi_usb_open(struct hl_interface_param_s *param, void **fd) h->write_buffer = malloc(ICDI_PACKET_SIZE); h->max_packet = ICDI_PACKET_SIZE; - if (h->read_buffer == 0 || h->write_buffer == 0) { + if (!h->read_buffer || !h->write_buffer) { LOG_DEBUG("malloc failed"); goto error_open; } diff --git a/src/jtag/drivers/usbprog.c b/src/jtag/drivers/usbprog.c index 0c0f24ee2..5d41656b4 100644 --- a/src/jtag/drivers/usbprog.c +++ b/src/jtag/drivers/usbprog.c @@ -148,7 +148,7 @@ static int usbprog_init(void) usbprog_jtag_handle = usbprog_jtag_open(); tms_chain_index = 0; - if (usbprog_jtag_handle == 0) { + if (!usbprog_jtag_handle) { LOG_ERROR("Can't find USB JTAG Interface! Please check connection and permissions."); return ERROR_JTAG_INIT_FAILED; } diff --git a/src/jtag/drivers/xds110.c b/src/jtag/drivers/xds110.c index 8e5d638db..3ea98ad6b 100644 --- a/src/jtag/drivers/xds110.c +++ b/src/jtag/drivers/xds110.c @@ -1300,7 +1300,7 @@ static int xds110_swd_run_queue(void) /* Transfer results into caller's buffers */ for (result = 0; result < xds110.txn_result_count; result++) - if (xds110.txn_dap_results[result] != 0) + if (xds110.txn_dap_results[result]) *xds110.txn_dap_results[result] = dap_results[result]; xds110.txn_request_size = 0; @@ -1611,7 +1611,7 @@ static void xds110_flush(void) } bits = 0; } - if (xds110.txn_scan_results[result].buffer != 0) + if (xds110.txn_scan_results[result].buffer) bit_copy(xds110.txn_scan_results[result].buffer, 0, data_pntr, bits, xds110.txn_scan_results[result].num_bits); bits += xds110.txn_scan_results[result].num_bits; @@ -1687,8 +1687,8 @@ static void xds110_execute_pathmove(struct jtag_command *cmd) if (num_states == 0) return; - path = (uint8_t *)malloc(num_states * sizeof(uint8_t)); - if (path == 0) { + path = malloc(num_states * sizeof(uint8_t)); + if (path) { LOG_ERROR("XDS110: unable to allocate memory"); return; } @@ -1766,7 +1766,7 @@ static void xds110_queue_scan(struct jtag_command *cmd) /* Clear data out buffer to default value of all zeros */ memset((void *)buffer, 0x00, total_bytes); for (i = 0; i < cmd->cmd.scan->num_fields; i++) { - if (cmd->cmd.scan->fields[i].out_value != 0) { + if (cmd->cmd.scan->fields[i].out_value) { /* Copy over data to scan out into request buffer */ bit_copy(buffer, offset, cmd->cmd.scan->fields[i].out_value, 0, cmd->cmd.scan->fields[i].num_bits); From 6e4000df9e37ea7eb857c3dcd707057d47a5d0ca Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Sat, 8 Apr 2023 23:50:00 +0200 Subject: [PATCH 22/49] flash: nor: use 'ULL' suffix for long constants On 32 bit hosts, gcc should consider constants without suffix as 32 bits values. Adding a cast to convert it to 64 bits should not be enough. Use the suffix 'ULL' to guarantee it is a 64 bit. Detected through 'sparse' tool. Change-Id: If6be35bd3cbbc7c3a83e0da1407e611f07ff6e06 Signed-off-by: Antonio Borneo Reviewed-on: https://review.openocd.org/c/openocd/+/7593 Tested-by: jenkins --- src/flash/nor/at91samd.c | 20 ++++++++++---------- src/flash/nor/atsame5.c | 2 +- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/flash/nor/at91samd.c b/src/flash/nor/at91samd.c index 416f07778..36298f19d 100644 --- a/src/flash/nor/at91samd.c +++ b/src/flash/nor/at91samd.c @@ -78,7 +78,7 @@ #define SAMD_GET_DEVSEL(id) (id & 0xFF) /* Bits to mask out lockbits in user row */ -#define NVMUSERROW_LOCKBIT_MASK ((uint64_t)0x0000FFFFFFFFFFFF) +#define NVMUSERROW_LOCKBIT_MASK 0x0000FFFFFFFFFFFFULL struct samd_part { uint8_t id; @@ -316,31 +316,31 @@ struct samd_family { static const struct samd_family samd_families[] = { { SAMD_PROCESSOR_M0, SAMD_FAMILY_D, SAMD_SERIES_20, samd20_parts, ARRAY_SIZE(samd20_parts), - (uint64_t)0xFFFF01FFFE01FF77 }, + 0xFFFF01FFFE01FF77ULL }, { SAMD_PROCESSOR_M0, SAMD_FAMILY_D, SAMD_SERIES_21, samd21_parts, ARRAY_SIZE(samd21_parts), - (uint64_t)0xFFFF01FFFE01FF77 }, + 0xFFFF01FFFE01FF77ULL }, { SAMD_PROCESSOR_M0, SAMD_FAMILY_D, SAMD_SERIES_09, samd09_parts, ARRAY_SIZE(samd09_parts), - (uint64_t)0xFFFF01FFFE01FF77 }, + 0xFFFF01FFFE01FF77ULL }, { SAMD_PROCESSOR_M0, SAMD_FAMILY_D, SAMD_SERIES_10, samd10_parts, ARRAY_SIZE(samd10_parts), - (uint64_t)0xFFFF01FFFE01FF77 }, + 0xFFFF01FFFE01FF77ULL }, { SAMD_PROCESSOR_M0, SAMD_FAMILY_D, SAMD_SERIES_11, samd11_parts, ARRAY_SIZE(samd11_parts), - (uint64_t)0xFFFF01FFFE01FF77 }, + 0xFFFF01FFFE01FF77ULL }, { SAMD_PROCESSOR_M0, SAMD_FAMILY_L, SAMD_SERIES_21, saml21_parts, ARRAY_SIZE(saml21_parts), - (uint64_t)0xFFFF03FFFC01FF77 }, + 0xFFFF03FFFC01FF77ULL }, { SAMD_PROCESSOR_M0, SAMD_FAMILY_L, SAMD_SERIES_22, saml22_parts, ARRAY_SIZE(saml22_parts), - (uint64_t)0xFFFF03FFFC01FF77 }, + 0xFFFF03FFFC01FF77ULL }, { SAMD_PROCESSOR_M0, SAMD_FAMILY_C, SAMD_SERIES_20, samc20_parts, ARRAY_SIZE(samc20_parts), - (uint64_t)0xFFFF03FFFC01FF77 }, + 0xFFFF03FFFC01FF77ULL }, { SAMD_PROCESSOR_M0, SAMD_FAMILY_C, SAMD_SERIES_21, samc21_parts, ARRAY_SIZE(samc21_parts), - (uint64_t)0xFFFF03FFFC01FF77 }, + 0xFFFF03FFFC01FF77ULL }, }; struct samd_info { diff --git a/src/flash/nor/atsame5.c b/src/flash/nor/atsame5.c index fdd610f5f..c590081fc 100644 --- a/src/flash/nor/atsame5.c +++ b/src/flash/nor/atsame5.c @@ -93,7 +93,7 @@ #define SAMD_GET_DEVSEL(id) (id & 0xFF) /* Bits to mask user row */ -#define NVMUSERROW_SAM_E5_D5_MASK ((uint64_t)0x7FFF00FF3C007FFF) +#define NVMUSERROW_SAM_E5_D5_MASK 0x7FFF00FF3C007FFFULL struct samd_part { uint8_t id; From d4fe63e36b662ad274783585ff7222befbf54268 Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Sat, 8 Apr 2023 23:59:42 +0200 Subject: [PATCH 23/49] flash: nor: add static to local symbols Add static type to symbols that are not used elsewhere. Detected through 'sparse' tool. Change-Id: I2bdac5d2b06a6dbed5c27bfdb1cf36eee90ad823 Signed-off-by: Antonio Borneo Reviewed-on: https://review.openocd.org/c/openocd/+/7594 Tested-by: jenkins --- src/flash/nor/numicro.c | 4 ++-- src/flash/nor/rsl10.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/flash/nor/numicro.c b/src/flash/nor/numicro.c index 0b04ce4b7..a0c6e0c81 100644 --- a/src/flash/nor/numicro.c +++ b/src/flash/nor/numicro.c @@ -536,8 +536,8 @@ struct numicro_flash_bank { }; /* Private variables */ -uint32_t m_page_size = NUMICRO_PAGESIZE; -uint32_t m_address_bias_offset; +static uint32_t m_page_size = NUMICRO_PAGESIZE; +static uint32_t m_address_bias_offset; /* Private methods */ static int numicro_get_arm_arch(struct target *target) diff --git a/src/flash/nor/rsl10.c b/src/flash/nor/rsl10.c index d92c4b8b1..5f0ac9b8f 100644 --- a/src/flash/nor/rsl10.c +++ b/src/flash/nor/rsl10.c @@ -107,7 +107,7 @@ static const char *const rsl10_error_list[] = { [RSL10_FLASH_ERR_PROG_FAILED] = "prog failed", }; -const char *rsl10_error(enum rsl10_flash_status x) +static const char *rsl10_error(enum rsl10_flash_status x) { if (x >= RSL10_FLASH_MAX_ERR_CODES || !rsl10_error_list[x]) return "unknown"; From aa1214280d11c32f82961da44dee863098e1ac38 Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Sun, 9 Apr 2023 00:00:37 +0200 Subject: [PATCH 24/49] flash: with pointers, use NULL instead of 0 Don't compare pointers with 0, use NULL when needed. Don't pass 0 ad pointer argument, pass NULL. Detected through 'sparse' tool. Change-Id: I118554fffde41c94cea9e1201ea941ff3c1ee762 Signed-off-by: Antonio Borneo Reviewed-on: https://review.openocd.org/c/openocd/+/7595 Tested-by: jenkins --- src/flash/nand/lpc32xx.c | 2 +- src/flash/nor/msp432.c | 2 +- src/flash/nor/stellaris.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/flash/nand/lpc32xx.c b/src/flash/nand/lpc32xx.c index 2c578d1b4..f8b59b357 100644 --- a/src/flash/nand/lpc32xx.c +++ b/src/flash/nand/lpc32xx.c @@ -1029,7 +1029,7 @@ static int lpc32xx_write_page_slc(struct nand_device *nand, LOG_DEBUG("SLC write page %" PRIx32 " data=%d, oob=%d, " "data_size=%" PRIu32 ", oob_size=%" PRIu32, - page, data != 0, oob != 0, data_size, oob_size); + page, !!data, !!oob, data_size, oob_size); target_mem_base = pworking_area->address; /* diff --git a/src/flash/nor/msp432.c b/src/flash/nor/msp432.c index d9b9695df..5e2935d02 100644 --- a/src/flash/nor/msp432.c +++ b/src/flash/nor/msp432.c @@ -375,7 +375,7 @@ static int msp432_init(struct flash_bank *bank) buf_set_u32(reg_params[0].value, 0, 32, ALGO_STACK_POINTER_ADDR); /* Begin executing the flash helper algorithm */ - retval = target_start_algorithm(target, 0, 0, 1, reg_params, + retval = target_start_algorithm(target, 0, NULL, 1, reg_params, algo_entry_addr, 0, &msp432_bank->armv7m_info); destroy_reg_param(®_params[0]); if (retval != ERROR_OK) { diff --git a/src/flash/nor/stellaris.c b/src/flash/nor/stellaris.c index 3a78952ef..972686e3f 100644 --- a/src/flash/nor/stellaris.c +++ b/src/flash/nor/stellaris.c @@ -1342,7 +1342,7 @@ COMMAND_HANDLER(stellaris_handle_recover_command) * cycle to recover. */ - Jim_Eval_Named(CMD_CTX->interp, "catch { hla_command \"debug unlock\" }", 0, 0); + Jim_Eval_Named(CMD_CTX->interp, "catch { hla_command \"debug unlock\" }", NULL, 0); if (!strcmp(Jim_GetString(Jim_GetResult(CMD_CTX->interp), NULL), "0")) { retval = ERROR_OK; goto user_action; From 9dc1d90f64168863d350694d38e5ff7f20a57a7e Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Sun, 9 Apr 2023 00:14:45 +0200 Subject: [PATCH 25/49] helper: util: include util.h Let source file to include its file .h to validate the exported prototypes. Detected through 'sparse' tool. Change-Id: I5de107b4f8a468f0e37f06171f5f0c3c0546db1a Signed-off-by: Antonio Borneo Reviewed-on: https://review.openocd.org/c/openocd/+/7596 Tested-by: jenkins --- src/helper/util.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/helper/util.c b/src/helper/util.c index 5e12021ff..2e9f6155e 100644 --- a/src/helper/util.c +++ b/src/helper/util.c @@ -12,6 +12,7 @@ #include "log.h" #include "time_support.h" +#include "util.h" COMMAND_HANDLER(handler_util_ms) { From cd44c6cf83841076b40e7a873285117b7440dd42 Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Sun, 9 Apr 2023 00:16:28 +0200 Subject: [PATCH 26/49] helper: with pointers, use NULL instead of 0 Don't compare pointers with 0, use NULL when needed. Don't assign pointer to 0, use NULL. Don't pass 0 ad pointer argument, pass NULL. Detected through 'sparse' tool. Change-Id: I3f867cb9c0903f6e396311e7b3970ee5fb3a4231 Signed-off-by: Antonio Borneo Reviewed-on: https://review.openocd.org/c/openocd/+/7597 Tested-by: jenkins --- src/helper/command.c | 2 +- src/helper/jep106.c | 2 +- src/helper/options.c | 12 ++++++------ 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/helper/command.c b/src/helper/command.c index 235bec858..945b890b3 100644 --- a/src/helper/command.c +++ b/src/helper/command.c @@ -582,7 +582,7 @@ int command_run_line(struct command_context *context, char *line) Jim_DeleteAssocData(interp, "retval"); retcode = Jim_SetAssocData(interp, "retval", NULL, &retval); if (retcode == JIM_OK) { - retcode = Jim_Eval_Named(interp, line, 0, 0); + retcode = Jim_Eval_Named(interp, line, NULL, 0); Jim_DeleteAssocData(interp, "retval"); } diff --git a/src/helper/jep106.c b/src/helper/jep106.c index d422561bc..62d24a9b2 100644 --- a/src/helper/jep106.c +++ b/src/helper/jep106.c @@ -26,7 +26,7 @@ const char *jep106_table_manufacturer(unsigned int bank, unsigned int id) /* index is zero based */ id--; - if (bank >= ARRAY_SIZE(jep106) || jep106[bank][id] == 0) + if (bank >= ARRAY_SIZE(jep106) || !jep106[bank][id]) return ""; return jep106[bank][id]; diff --git a/src/helper/options.c b/src/helper/options.c index 327c418d0..05cde6709 100644 --- a/src/helper/options.c +++ b/src/helper/options.c @@ -39,12 +39,12 @@ static int help_flag, version_flag; static const struct option long_options[] = { {"help", no_argument, &help_flag, 1}, {"version", no_argument, &version_flag, 1}, - {"debug", optional_argument, 0, 'd'}, - {"file", required_argument, 0, 'f'}, - {"search", required_argument, 0, 's'}, - {"log_output", required_argument, 0, 'l'}, - {"command", required_argument, 0, 'c'}, - {0, 0, 0, 0} + {"debug", optional_argument, NULL, 'd'}, + {"file", required_argument, NULL, 'f'}, + {"search", required_argument, NULL, 's'}, + {"log_output", required_argument, NULL, 'l'}, + {"command", required_argument, NULL, 'c'}, + {NULL, 0, NULL, 0} }; int configuration_output_handler(struct command_context *context, const char *line) From 314f4c665f746ebec3be69a8e26f0a671cfdcb46 Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Sun, 9 Apr 2023 00:33:38 +0200 Subject: [PATCH 27/49] rtos: with pointers, use NULL instead of 0 Don't compare pointers with 0, use NULL when needed. Don't assign pointer to 0, use NULL. Detected through 'sparse' tool. Change-Id: Ifa81ba961c0d490cc74880b4a46b620e6358f779 Signed-off-by: Antonio Borneo Reviewed-on: https://review.openocd.org/c/openocd/+/7598 Tested-by: jenkins --- src/rtos/chibios.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/rtos/chibios.c b/src/rtos/chibios.c index 68fe8a14c..20378274e 100644 --- a/src/rtos/chibios.c +++ b/src/rtos/chibios.c @@ -80,12 +80,12 @@ struct chibios_params { static struct chibios_params chibios_params_list[] = { { "cortex_m", /* target_name */ - 0, + NULL, NULL, /* stacking_info */ }, { "hla_target", /* target_name */ - 0, + NULL, NULL, /* stacking_info */ } }; @@ -198,7 +198,7 @@ static int chibios_update_memory_signature(struct rtos *rtos) errfree: /* Error reading the ChibiOS memory structure */ free(signature); - param->signature = 0; + param->signature = NULL; return -1; } @@ -468,7 +468,7 @@ static int chibios_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, return -1; /* Update stacking if it can only be determined from runtime information */ - if ((param->stacking_info == 0) && + if (!param->stacking_info && (chibios_update_stacking(rtos) != ERROR_OK)) { LOG_ERROR("Failed to determine exact stacking for the target type %s", rtos->target->type->name); return -1; From ea62f8e22adb0c56509dd1999a2be9cf9798b8aa Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Sun, 9 Apr 2023 01:36:04 +0200 Subject: [PATCH 28/49] target: use 'ULL' suffix for long constants On 32 bit hosts, gcc should consider constants without suffix as 32 bits values. Use the suffix 'ULL' to guarantee it is a 64 bit. Detected through 'sparse' tool. Change-Id: I205ca986968fef9a536f87492d1f6c80e41829f3 Signed-off-by: Antonio Borneo Reviewed-on: https://review.openocd.org/c/openocd/+/7601 Tested-by: jenkins --- src/target/aarch64.c | 26 +++--- src/target/armv8.c | 2 +- src/target/lakemont.c | 174 +++++++++++++++++++------------------- src/target/mips64_pracc.h | 2 +- 4 files changed, 102 insertions(+), 102 deletions(-) diff --git a/src/target/aarch64.c b/src/target/aarch64.c index 6c9673fa2..c6ebfb011 100644 --- a/src/target/aarch64.c +++ b/src/target/aarch64.c @@ -588,7 +588,7 @@ static int aarch64_restore_one(struct target *target, int current, resume_pc &= 0xFFFFFFFC; break; case ARM_STATE_AARCH64: - resume_pc &= 0xFFFFFFFFFFFFFFFC; + resume_pc &= 0xFFFFFFFFFFFFFFFCULL; break; case ARM_STATE_THUMB: case ARM_STATE_THUMB_EE: @@ -1248,7 +1248,7 @@ static int aarch64_set_breakpoint(struct target *target, | (byte_addr_select << 5) | (3 << 1) | 1; brp_list[brp_i].used = 1; - brp_list[brp_i].value = breakpoint->address & 0xFFFFFFFFFFFFFFFC; + brp_list[brp_i].value = breakpoint->address & 0xFFFFFFFFFFFFFFFCULL; brp_list[brp_i].control = control; bpt_value = brp_list[brp_i].value; @@ -1300,28 +1300,28 @@ static int aarch64_set_breakpoint(struct target *target, buf_set_u32(code, 0, 32, opcode); retval = target_read_memory(target, - breakpoint->address & 0xFFFFFFFFFFFFFFFE, + breakpoint->address & 0xFFFFFFFFFFFFFFFEULL, breakpoint->length, 1, breakpoint->orig_instr); if (retval != ERROR_OK) return retval; armv8_cache_d_inner_flush_virt(armv8, - breakpoint->address & 0xFFFFFFFFFFFFFFFE, + breakpoint->address & 0xFFFFFFFFFFFFFFFEULL, breakpoint->length); retval = target_write_memory(target, - breakpoint->address & 0xFFFFFFFFFFFFFFFE, + breakpoint->address & 0xFFFFFFFFFFFFFFFEULL, breakpoint->length, 1, code); if (retval != ERROR_OK) return retval; armv8_cache_d_inner_flush_virt(armv8, - breakpoint->address & 0xFFFFFFFFFFFFFFFE, + breakpoint->address & 0xFFFFFFFFFFFFFFFEULL, breakpoint->length); armv8_cache_i_inner_inval_virt(armv8, - breakpoint->address & 0xFFFFFFFFFFFFFFFE, + breakpoint->address & 0xFFFFFFFFFFFFFFFEULL, breakpoint->length); breakpoint->is_set = true; @@ -1453,7 +1453,7 @@ static int aarch64_set_hybrid_breakpoint(struct target *target, struct breakpoin | (iva_byte_addr_select << 5) | (3 << 1) | 1; brp_list[brp_2].used = 1; - brp_list[brp_2].value = breakpoint->address & 0xFFFFFFFFFFFFFFFC; + brp_list[brp_2].value = breakpoint->address & 0xFFFFFFFFFFFFFFFCULL; brp_list[brp_2].control = control_iva; retval = aarch64_dap_write_memap_register_u32(target, armv8->debug_base + CPUV8_DBG_BVR_BASE + 16 * brp_list[brp_2].brpn, @@ -1577,29 +1577,29 @@ static int aarch64_unset_breakpoint(struct target *target, struct breakpoint *br /* restore original instruction (kept in target endianness) */ armv8_cache_d_inner_flush_virt(armv8, - breakpoint->address & 0xFFFFFFFFFFFFFFFE, + breakpoint->address & 0xFFFFFFFFFFFFFFFEULL, breakpoint->length); if (breakpoint->length == 4) { retval = target_write_memory(target, - breakpoint->address & 0xFFFFFFFFFFFFFFFE, + breakpoint->address & 0xFFFFFFFFFFFFFFFEULL, 4, 1, breakpoint->orig_instr); if (retval != ERROR_OK) return retval; } else { retval = target_write_memory(target, - breakpoint->address & 0xFFFFFFFFFFFFFFFE, + breakpoint->address & 0xFFFFFFFFFFFFFFFEULL, 2, 1, breakpoint->orig_instr); if (retval != ERROR_OK) return retval; } armv8_cache_d_inner_flush_virt(armv8, - breakpoint->address & 0xFFFFFFFFFFFFFFFE, + breakpoint->address & 0xFFFFFFFFFFFFFFFEULL, breakpoint->length); armv8_cache_i_inner_inval_virt(armv8, - breakpoint->address & 0xFFFFFFFFFFFFFFFE, + breakpoint->address & 0xFFFFFFFFFFFFFFFEULL, breakpoint->length); } breakpoint->is_set = false; diff --git a/src/target/armv8.c b/src/target/armv8.c index ff71a8e63..b01afdbc7 100644 --- a/src/target/armv8.c +++ b/src/target/armv8.c @@ -236,7 +236,7 @@ static int armv8_read_ttbcr(struct target *target) armv8->pa_size = armv8_pa_size((ttbcr_64 >> 32) & 7); armv8->page_size = (ttbcr_64 >> 14) & 3; armv8->armv8_mmu.ttbr1_used = (((ttbcr_64 >> 16) & 0x3F) != 0) ? 1 : 0; - armv8->armv8_mmu.ttbr0_mask = 0x0000FFFFFFFFFFFF; + armv8->armv8_mmu.ttbr0_mask = 0x0000FFFFFFFFFFFFULL; retval += dpm->instr_read_data_r0_64(dpm, ARMV8_MRS(SYSTEM_TTBR0_EL1 | (armv8->armv8_mmu.ttbr1_used), 0), &armv8->ttbr_base); diff --git a/src/target/lakemont.c b/src/target/lakemont.c index 5035cdb54..6c0964bfa 100644 --- a/src/target/lakemont.c +++ b/src/target/lakemont.c @@ -73,26 +73,26 @@ static const struct { const char *feature; } regs[] = { /* general purpose registers */ - { EAX, "eax", 0x000000D01D660000, 0, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.core" }, - { ECX, "ecx", 0x000000501D660000, 1, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.core" }, - { EDX, "edx", 0x000000901D660000, 2, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.core" }, - { EBX, "ebx", 0x000000101D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.core" }, - { ESP, "esp", 0x000000E01D660000, NOT_PMREG, 32, REG_TYPE_DATA_PTR, "general", "org.gnu.gdb.i386.core" }, - { EBP, "ebp", 0x000000601D660000, NOT_PMREG, 32, REG_TYPE_DATA_PTR, "general", "org.gnu.gdb.i386.core" }, - { ESI, "esi", 0x000000A01D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.core" }, - { EDI, "edi", 0x000000201D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.core" }, + { EAX, "eax", 0x000000D01D660000ULL, 0, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.core" }, + { ECX, "ecx", 0x000000501D660000ULL, 1, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.core" }, + { EDX, "edx", 0x000000901D660000ULL, 2, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.core" }, + { EBX, "ebx", 0x000000101D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.core" }, + { ESP, "esp", 0x000000E01D660000ULL, NOT_PMREG, 32, REG_TYPE_DATA_PTR, "general", "org.gnu.gdb.i386.core" }, + { EBP, "ebp", 0x000000601D660000ULL, NOT_PMREG, 32, REG_TYPE_DATA_PTR, "general", "org.gnu.gdb.i386.core" }, + { ESI, "esi", 0x000000A01D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.core" }, + { EDI, "edi", 0x000000201D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.core" }, /* instruction pointer & flags */ - { EIP, "eip", 0x000000C01D660000, 3, 32, REG_TYPE_CODE_PTR, "general", "org.gnu.gdb.i386.core" }, - { EFLAGS, "eflags", 0x000000401D660000, 4, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.core" }, + { EIP, "eip", 0x000000C01D660000ULL, 3, 32, REG_TYPE_CODE_PTR, "general", "org.gnu.gdb.i386.core" }, + { EFLAGS, "eflags", 0x000000401D660000ULL, 4, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.core" }, /* segment registers */ - { CS, "cs", 0x000000281D660000, 5, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.core" }, - { SS, "ss", 0x000000C81D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.core" }, - { DS, "ds", 0x000000481D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.core" }, - { ES, "es", 0x000000A81D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.core" }, - { FS, "fs", 0x000000881D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.core" }, - { GS, "gs", 0x000000081D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.core" }, + { CS, "cs", 0x000000281D660000ULL, 5, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.core" }, + { SS, "ss", 0x000000C81D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.core" }, + { DS, "ds", 0x000000481D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.core" }, + { ES, "es", 0x000000A81D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.core" }, + { FS, "fs", 0x000000881D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.core" }, + { GS, "gs", 0x000000081D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.core" }, /* floating point unit registers - not accessible via JTAG - here to satisfy GDB */ { ST0, "st0", 0x0, NOT_AVAIL_REG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.core" }, @@ -113,56 +113,56 @@ static const struct { { FOP, "fop", 0x0, NOT_AVAIL_REG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.core" }, /* control registers */ - { CR0, "cr0", 0x000000001D660000, 6, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, - { CR2, "cr2", 0x000000BC1D660000, 7, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, - { CR3, "cr3", 0x000000801D660000, 8, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, - { CR4, "cr4", 0x0000002C1D660000, 9, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, + { CR0, "cr0", 0x000000001D660000ULL, 6, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, + { CR2, "cr2", 0x000000BC1D660000ULL, 7, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, + { CR3, "cr3", 0x000000801D660000ULL, 8, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, + { CR4, "cr4", 0x0000002C1D660000ULL, 9, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, /* debug registers */ - { DR0, "dr0", 0x0000007C1D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, - { DR1, "dr1", 0x000000FC1D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, - { DR2, "dr2", 0x000000021D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, - { DR3, "dr3", 0x000000821D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, - { DR6, "dr6", 0x000000301D660000, 10, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, - { DR7, "dr7", 0x000000B01D660000, 11, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, + { DR0, "dr0", 0x0000007C1D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, + { DR1, "dr1", 0x000000FC1D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, + { DR2, "dr2", 0x000000021D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, + { DR3, "dr3", 0x000000821D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, + { DR6, "dr6", 0x000000301D660000ULL, 10, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, + { DR7, "dr7", 0x000000B01D660000ULL, 11, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, /* descriptor tables */ - { IDTB, "idtbase", 0x000000581D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, - { IDTL, "idtlimit", 0x000000D81D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, - { IDTAR, "idtar", 0x000000981D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, - { GDTB, "gdtbase", 0x000000B81D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, - { GDTL, "gdtlimit", 0x000000781D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, - { GDTAR, "gdtar", 0x000000381D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, - { TR, "tr", 0x000000701D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, - { LDTR, "ldtr", 0x000000F01D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, - { LDTB, "ldbase", 0x000000041D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, - { LDTL, "ldlimit", 0x000000841D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, - { LDTAR, "ldtar", 0x000000F81D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, + { IDTB, "idtbase", 0x000000581D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, + { IDTL, "idtlimit", 0x000000D81D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, + { IDTAR, "idtar", 0x000000981D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, + { GDTB, "gdtbase", 0x000000B81D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, + { GDTL, "gdtlimit", 0x000000781D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, + { GDTAR, "gdtar", 0x000000381D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, + { TR, "tr", 0x000000701D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, + { LDTR, "ldtr", 0x000000F01D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, + { LDTB, "ldbase", 0x000000041D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, + { LDTL, "ldlimit", 0x000000841D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, + { LDTAR, "ldtar", 0x000000F81D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, /* segment registers */ - { CSB, "csbase", 0x000000F41D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, - { CSL, "cslimit", 0x0000000C1D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, - { CSAR, "csar", 0x000000741D660000, 12, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, - { DSB, "dsbase", 0x000000941D660000, 13, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, - { DSL, "dslimit", 0x000000541D660000, 14, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, - { DSAR, "dsar", 0x000000141D660000, 15, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, - { ESB, "esbase", 0x0000004C1D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, - { ESL, "eslimit", 0x000000CC1D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, - { ESAR, "esar", 0x0000008C1D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, - { FSB, "fsbase", 0x000000641D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, - { FSL, "fslimit", 0x000000E41D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, - { FSAR, "fsar", 0x000000A41D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, - { GSB, "gsbase", 0x000000C41D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, - { GSL, "gslimit", 0x000000241D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, - { GSAR, "gsar", 0x000000441D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, - { SSB, "ssbase", 0x000000341D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, - { SSL, "sslimit", 0x000000B41D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, - { SSAR, "ssar", 0x000000D41D660000, 16, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, - { TSSB, "tssbase", 0x000000E81D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, - { TSSL, "tsslimit", 0x000000181D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, - { TSSAR, "tssar", 0x000000681D660000, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, + { CSB, "csbase", 0x000000F41D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, + { CSL, "cslimit", 0x0000000C1D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, + { CSAR, "csar", 0x000000741D660000ULL, 12, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, + { DSB, "dsbase", 0x000000941D660000ULL, 13, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, + { DSL, "dslimit", 0x000000541D660000ULL, 14, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, + { DSAR, "dsar", 0x000000141D660000ULL, 15, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, + { ESB, "esbase", 0x0000004C1D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, + { ESL, "eslimit", 0x000000CC1D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, + { ESAR, "esar", 0x0000008C1D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, + { FSB, "fsbase", 0x000000641D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, + { FSL, "fslimit", 0x000000E41D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, + { FSAR, "fsar", 0x000000A41D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, + { GSB, "gsbase", 0x000000C41D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, + { GSL, "gslimit", 0x000000241D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, + { GSAR, "gsar", 0x000000441D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, + { SSB, "ssbase", 0x000000341D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, + { SSL, "sslimit", 0x000000B41D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, + { SSAR, "ssar", 0x000000D41D660000ULL, 16, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, + { TSSB, "tssbase", 0x000000E81D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, + { TSSL, "tsslimit", 0x000000181D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, + { TSSAR, "tssar", 0x000000681D660000ULL, NOT_PMREG, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, /* probemode control register */ - { PMCR, "pmcr", 0x000000421D660000, 17, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, + { PMCR, "pmcr", 0x000000421D660000ULL, 17, 32, REG_TYPE_INT32, "general", "org.gnu.gdb.i386.sys" }, }; static const struct { @@ -171,36 +171,36 @@ static const struct { uint64_t op; } instructions[] = { /* memory read/write */ - { MEMRDB32, "MEMRDB32", 0x0909090909090851 }, - { MEMRDB16, "MEMRDB16", 0x09090909090851E6 }, - { MEMRDH32, "MEMRDH32", 0x090909090908D166 }, - { MEMRDH16, "MEMRDH16", 0x090909090908D1E6 }, - { MEMRDW32, "MEMRDW32", 0x09090909090908D1 }, - { MEMRDW16, "MEMRDW16", 0x0909090908D1E666 }, - { MEMWRB32, "MEMWRB32", 0x0909090909090811 }, - { MEMWRB16, "MEMWRB16", 0x09090909090811E6 }, - { MEMWRH32, "MEMWRH32", 0x0909090909089166 }, - { MEMWRH16, "MEMWRH16", 0x09090909090891E6 }, - { MEMWRW32, "MEMWRW32", 0x0909090909090891 }, - { MEMWRW16, "MEMWRW16", 0x090909090891E666 }, + { MEMRDB32, "MEMRDB32", 0x0909090909090851ULL }, + { MEMRDB16, "MEMRDB16", 0x09090909090851E6ULL }, + { MEMRDH32, "MEMRDH32", 0x090909090908D166ULL }, + { MEMRDH16, "MEMRDH16", 0x090909090908D1E6ULL }, + { MEMRDW32, "MEMRDW32", 0x09090909090908D1ULL }, + { MEMRDW16, "MEMRDW16", 0x0909090908D1E666ULL }, + { MEMWRB32, "MEMWRB32", 0x0909090909090811ULL }, + { MEMWRB16, "MEMWRB16", 0x09090909090811E6ULL }, + { MEMWRH32, "MEMWRH32", 0x0909090909089166ULL }, + { MEMWRH16, "MEMWRH16", 0x09090909090891E6ULL }, + { MEMWRW32, "MEMWRW32", 0x0909090909090891ULL }, + { MEMWRW16, "MEMWRW16", 0x090909090891E666ULL }, /* IO read/write */ - { IORDB32, "IORDB32", 0x0909090909090937 }, - { IORDB16, "IORDB16", 0x09090909090937E6 }, - { IORDH32, "IORDH32", 0x090909090909B766 }, - { IORDH16, "IORDH16", 0x090909090909B7E6 }, - { IORDW32, "IORDW32", 0x09090909090909B7 }, - { IORDW16, "IORDW16", 0x0909090909B7E666 }, - { IOWRB32, "IOWRB32", 0x0909090909090977 }, - { IOWRB16, "IOWRB16", 0x09090909090977E6 }, - { IOWRH32, "IOWRH32", 0x090909090909F766 }, - { IOWRH16, "IOWRH16", 0x090909090909F7E6 }, - { IOWRW32, "IOWRW32", 0x09090909090909F7 }, - { IOWRW16, "IOWRW16", 0x0909090909F7E666 }, + { IORDB32, "IORDB32", 0x0909090909090937ULL }, + { IORDB16, "IORDB16", 0x09090909090937E6ULL }, + { IORDH32, "IORDH32", 0x090909090909B766ULL }, + { IORDH16, "IORDH16", 0x090909090909B7E6ULL }, + { IORDW32, "IORDW32", 0x09090909090909B7ULL }, + { IORDW16, "IORDW16", 0x0909090909B7E666ULL }, + { IOWRB32, "IOWRB32", 0x0909090909090977ULL }, + { IOWRB16, "IOWRB16", 0x09090909090977E6ULL }, + { IOWRH32, "IOWRH32", 0x090909090909F766ULL }, + { IOWRH16, "IOWRH16", 0x090909090909F7E6ULL }, + { IOWRW32, "IOWRW32", 0x09090909090909F7ULL }, + { IOWRW16, "IOWRW16", 0x0909090909F7E666ULL }, /* lakemont1 core shadow ram access opcodes */ - { SRAMACCESS, "SRAMACCESS", 0x0000000E9D660000 }, - { SRAM2PDR, "SRAM2PDR", 0x4CF0000000000000 }, - { PDR2SRAM, "PDR2SRAM", 0x0CF0000000000000 }, - { WBINVD, "WBINVD", 0x09090909090990F0 }, + { SRAMACCESS, "SRAMACCESS", 0x0000000E9D660000ULL }, + { SRAM2PDR, "SRAM2PDR", 0x4CF0000000000000ULL }, + { PDR2SRAM, "PDR2SRAM", 0x0CF0000000000000ULL }, + { WBINVD, "WBINVD", 0x09090909090990F0ULL }, }; bool check_not_halted(const struct target *t) diff --git a/src/target/mips64_pracc.h b/src/target/mips64_pracc.h index 65ff6e6ac..19d151946 100644 --- a/src/target/mips64_pracc.h +++ b/src/target/mips64_pracc.h @@ -29,7 +29,7 @@ #undef LOWER16 #define UPPER16(v) ((uint32_t)((v >> 16) & 0xFFFF)) #define LOWER16(v) ((uint32_t)(v & 0xFFFF)) -#define MIPS64_PRACC_FASTDATA_AREA 0xffffffffFF200000 +#define MIPS64_PRACC_FASTDATA_AREA 0xffffffffFF200000ull #define MIPS64_PRACC_FASTDATA_SIZE 16 #define MIPS64_FASTDATA_HANDLER_SIZE 0x80 From 4b7dc557386a7482e8d77b59f543b9a0ef7cae4f Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Sun, 9 Apr 2023 01:37:11 +0200 Subject: [PATCH 29/49] target: rtt: include rtt.h Let source file to include its file .h to validate the exported prototypes. Detected through 'sparse' tool. Change-Id: I8ae2f8f1fdaea5683e157247463533b17237e464 Signed-off-by: Antonio Borneo Reviewed-on: https://review.openocd.org/c/openocd/+/7602 Tested-by: jenkins --- src/target/rtt.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/target/rtt.c b/src/target/rtt.c index b14c42f91..5ce049ae1 100644 --- a/src/target/rtt.c +++ b/src/target/rtt.c @@ -14,6 +14,7 @@ #include #include #include +#include #include "target.h" From d771d7f1a7d0181b4670c7c3ddb83ba8b8eb7da0 Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Sun, 9 Apr 2023 01:40:51 +0200 Subject: [PATCH 30/49] target: with pointers, use NULL instead of 0 Don't assign pointer to 0, use NULL. Don't pass 0 ad pointer argument, pass NULL. Detected through 'sparse' tool. Change-Id: I806031d2ae505fa5f0accc6be1936d48cd365ca4 Signed-off-by: Antonio Borneo Reviewed-on: https://review.openocd.org/c/openocd/+/7604 Tested-by: jenkins --- src/target/arm9tdmi.c | 2 +- src/target/armv8_dpm.c | 4 ++-- src/target/dsp563xx_once.c | 10 +++++----- src/target/xtensa/xtensa.c | 4 ++-- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/target/arm9tdmi.c b/src/target/arm9tdmi.c index 805330f25..3bacfaefd 100644 --- a/src/target/arm9tdmi.c +++ b/src/target/arm9tdmi.c @@ -57,7 +57,7 @@ static const struct arm9tdmi_vector { {"dabt", ARM9TDMI_DABT_VECTOR}, {"irq", ARM9TDMI_IRQ_VECTOR}, {"fiq", ARM9TDMI_FIQ_VECTOR}, - {0, 0}, + {NULL, 0}, }; int arm9tdmi_examine_debug_reason(struct target *target) diff --git a/src/target/armv8_dpm.c b/src/target/armv8_dpm.c index fcd4d5971..d1eefe5b3 100644 --- a/src/target/armv8_dpm.c +++ b/src/target/armv8_dpm.c @@ -274,7 +274,7 @@ static int dpmv8_instr_write_data_dcc(struct arm_dpm *dpm, if (retval != ERROR_OK) return retval; - return dpmv8_exec_opcode(dpm, opcode, 0); + return dpmv8_exec_opcode(dpm, opcode, NULL); } static int dpmv8_instr_write_data_dcc_64(struct arm_dpm *dpm, @@ -287,7 +287,7 @@ static int dpmv8_instr_write_data_dcc_64(struct arm_dpm *dpm, if (retval != ERROR_OK) return retval; - return dpmv8_exec_opcode(dpm, opcode, 0); + return dpmv8_exec_opcode(dpm, opcode, NULL); } static int dpmv8_instr_write_data_r0(struct arm_dpm *dpm, diff --git a/src/target/dsp563xx_once.c b/src/target/dsp563xx_once.c index 22445067a..866f33152 100644 --- a/src/target/dsp563xx_once.c +++ b/src/target/dsp563xx_once.c @@ -60,7 +60,7 @@ static inline int dsp563xx_once_ir_exec(struct jtag_tap *tap, int flush, uint8_t { int err; - err = dsp563xx_write_dr_u8(tap, 0, instr | (ex << 5) | (go << 6) | (rw << 7), 8, 0); + err = dsp563xx_write_dr_u8(tap, NULL, instr | (ex << 5) | (go << 6) | (rw << 7), 8, 0); if (err != ERROR_OK) return err; if (flush) @@ -226,7 +226,7 @@ int dsp563xx_once_reg_write(struct jtag_tap *tap, int flush, uint8_t reg, uint32 err = dsp563xx_once_ir_exec(tap, flush, reg, 0, 0, 0); if (err != ERROR_OK) return err; - err = dsp563xx_write_dr_u32(tap, 0x00, data, 24, 0); + err = dsp563xx_write_dr_u32(tap, NULL, data, 24, 0); if (err != ERROR_OK) return err; if (flush) @@ -242,7 +242,7 @@ int dsp563xx_once_execute_sw_ir(struct jtag_tap *tap, int flush, uint32_t opcode err = dsp563xx_once_ir_exec(tap, flush, DSP563XX_ONCE_OPDBR, 0, 1, 0); if (err != ERROR_OK) return err; - err = dsp563xx_write_dr_u32(tap, 0, opcode, 24, 0); + err = dsp563xx_write_dr_u32(tap, NULL, opcode, 24, 0); if (err != ERROR_OK) return err; if (flush) @@ -258,7 +258,7 @@ int dsp563xx_once_execute_dw_ir(struct jtag_tap *tap, int flush, uint32_t opcode err = dsp563xx_once_ir_exec(tap, flush, DSP563XX_ONCE_OPDBR, 0, 0, 0); if (err != ERROR_OK) return err; - err = dsp563xx_write_dr_u32(tap, 0, opcode, 24, 0); + err = dsp563xx_write_dr_u32(tap, NULL, opcode, 24, 0); if (err != ERROR_OK) return err; if (flush) { @@ -270,7 +270,7 @@ int dsp563xx_once_execute_dw_ir(struct jtag_tap *tap, int flush, uint32_t opcode err = dsp563xx_once_ir_exec(tap, flush, DSP563XX_ONCE_OPDBR, 0, 1, 0); if (err != ERROR_OK) return err; - err = dsp563xx_write_dr_u32(tap, 0, operand, 24, 0); + err = dsp563xx_write_dr_u32(tap, NULL, operand, 24, 0); if (err != ERROR_OK) return err; if (flush) { diff --git a/src/target/xtensa/xtensa.c b/src/target/xtensa/xtensa.c index fcd00487c..63ffefce7 100644 --- a/src/target/xtensa/xtensa.c +++ b/src/target/xtensa/xtensa.c @@ -410,7 +410,7 @@ static int xtensa_core_reg_get(struct reg *reg) return ERROR_TARGET_NOT_HALTED; if (!reg->exist) { if (strncmp(reg->name, "?0x", 3) == 0) { - unsigned int regnum = strtoul(reg->name + 1, 0, 0); + unsigned int regnum = strtoul(reg->name + 1, NULL, 0); LOG_WARNING("Read unknown register 0x%04x ignored", regnum); return ERROR_OK; } @@ -430,7 +430,7 @@ static int xtensa_core_reg_set(struct reg *reg, uint8_t *buf) if (!reg->exist) { if (strncmp(reg->name, "?0x", 3) == 0) { - unsigned int regnum = strtoul(reg->name + 1, 0, 0); + unsigned int regnum = strtoul(reg->name + 1, NULL, 0); LOG_WARNING("Write unknown register 0x%04x ignored", regnum); return ERROR_OK; } From 57f7ce68a48b03bcd198a009fc9c75fe3948c0db Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Sun, 30 Apr 2023 22:57:59 +0200 Subject: [PATCH 31/49] pld: gatemate: fix memory leak When gatemate_set_instr() fails, the array pointed by bit_file.raw_file.data is not freed. Issue identified by OpenOCD Jenkins clang build. Free the array while propagating the error. Change-Id: I2f7fadee903f9c65cdc9ab9b52ccb5803b48a59d Signed-off-by: Antonio Borneo Fixes: 682f927f8e4e ("pld: add support for cologne chip gatemate fpgas") Reviewed-on: https://review.openocd.org/c/openocd/+/7632 Tested-by: jenkins Reviewed-by: Daniel Anselmi --- src/pld/gatemate.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/pld/gatemate.c b/src/pld/gatemate.c index afd27efca..43b3f02d1 100644 --- a/src/pld/gatemate.c +++ b/src/pld/gatemate.c @@ -192,8 +192,10 @@ static int gatemate_load(struct pld_device *pld_device, const char *filename) return retval; retval = gatemate_set_instr(tap, JTAG_CONFIGURE); - if (retval != ERROR_OK) + if (retval != ERROR_OK) { + free(bit_file.raw_file.data); return retval; + } struct scan_field field; field.num_bits = bit_file.raw_file.length * 8; From dd9137dc0e0c9a7dd3468ecb7adb0427b8f06715 Mon Sep 17 00:00:00 2001 From: Daniel Anselmi Date: Thu, 13 Apr 2023 01:55:10 +0200 Subject: [PATCH 32/49] pld/virtex2: add missing error checks Add error checks after allocating memory. Add error checks for calls to jtag_execute_queue(). Change-Id: I3b63b3d836170244ad3b0566d5bd9d9aabb8e238 Signed-off-by: Daniel Anselmi Reviewed-on: https://review.openocd.org/c/openocd/+/7633 Tested-by: jenkins Reviewed-by: Antonio Borneo --- src/pld/virtex2.c | 121 +++++++++++++++++++++++++++++++++++----------- 1 file changed, 94 insertions(+), 27 deletions(-) diff --git a/src/pld/virtex2.c b/src/pld/virtex2.c index 98fd58adb..3c174ae59 100644 --- a/src/pld/virtex2.c +++ b/src/pld/virtex2.c @@ -23,6 +23,10 @@ static int virtex2_set_instr(struct jtag_tap *tap, uint32_t new_instr) field.num_bits = tap->ir_length; void *t = calloc(DIV_ROUND_UP(field.num_bits, 8), 1); + if (!t) { + LOG_ERROR("Out of memory"); + return ERROR_FAIL; + } field.out_value = t; buf_set_u32(t, 0, field.num_bits, new_instr); field.in_value = NULL; @@ -44,6 +48,10 @@ static int virtex2_send_32(struct pld_device *pld_device, int i; values = malloc(num_words * 4); + if (!values) { + LOG_ERROR("Out of memory"); + return ERROR_FAIL; + } scan_field.num_bits = num_words * 32; scan_field.out_value = values; @@ -52,7 +60,11 @@ static int virtex2_send_32(struct pld_device *pld_device, for (i = 0; i < num_words; i++) buf_set_u32(values + 4 * i, 0, 32, flip_u32(*words++, 32)); - virtex2_set_instr(virtex2_info->tap, 0x5); /* CFG_IN */ + int retval = virtex2_set_instr(virtex2_info->tap, 0x5); /* CFG_IN */ + if (retval != ERROR_OK) { + free(values); + return retval; + } jtag_add_dr_scan(virtex2_info->tap, 1, &scan_field, TAP_DRPAUSE); @@ -77,7 +89,9 @@ static int virtex2_receive_32(struct pld_device *pld_device, scan_field.out_value = NULL; scan_field.in_value = NULL; - virtex2_set_instr(virtex2_info->tap, 0x4); /* CFG_OUT */ + int retval = virtex2_set_instr(virtex2_info->tap, 0x4); /* CFG_OUT */ + if (retval != ERROR_OK) + return retval; while (num_words--) { scan_field.in_value = (uint8_t *)words; @@ -103,15 +117,72 @@ static int virtex2_read_stat(struct pld_device *pld_device, uint32_t *status) data[2] = 0x20000000; /* NOOP (Type 1, read, address 0, 0 words */ data[3] = 0x20000000; /* NOOP */ data[4] = 0x20000000; /* NOOP */ - virtex2_send_32(pld_device, 5, data); + int retval = virtex2_send_32(pld_device, 5, data); + if (retval != ERROR_OK) + return retval; - virtex2_receive_32(pld_device, 1, status); + retval = virtex2_receive_32(pld_device, 1, status); + if (retval != ERROR_OK) + return retval; - jtag_execute_queue(); + retval = jtag_execute_queue(); + if (retval == ERROR_OK) + LOG_DEBUG("status: 0x%8.8" PRIx32, *status); - LOG_DEBUG("status: 0x%8.8" PRIx32 "", *status); + return retval; +} - return ERROR_OK; +static int virtex2_load_prepare(struct pld_device *pld_device) +{ + struct virtex2_pld_device *virtex2_info = pld_device->driver_priv; + int retval; + + retval = virtex2_set_instr(virtex2_info->tap, 0xb); /* JPROG_B */ + if (retval != ERROR_OK) + return retval; + + retval = jtag_execute_queue(); + if (retval != ERROR_OK) + return retval; + jtag_add_sleep(1000); + + retval = virtex2_set_instr(virtex2_info->tap, 0x5); /* CFG_IN */ + if (retval != ERROR_OK) + return retval; + + return jtag_execute_queue(); +} + +static int virtex2_load_cleanup(struct pld_device *pld_device) +{ + struct virtex2_pld_device *virtex2_info = pld_device->driver_priv; + int retval; + + jtag_add_tlr(); + + if (!(virtex2_info->no_jstart)) { + retval = virtex2_set_instr(virtex2_info->tap, 0xc); /* JSTART */ + if (retval != ERROR_OK) + return retval; + } + jtag_add_runtest(13, TAP_IDLE); + retval = virtex2_set_instr(virtex2_info->tap, 0x3f); /* BYPASS */ + if (retval != ERROR_OK) + return retval; + retval = virtex2_set_instr(virtex2_info->tap, 0x3f); /* BYPASS */ + if (retval != ERROR_OK) + return retval; + if (!(virtex2_info->no_jstart)) { + retval = virtex2_set_instr(virtex2_info->tap, 0xc); /* JSTART */ + if (retval != ERROR_OK) + return retval; + } + jtag_add_runtest(13, TAP_IDLE); + retval = virtex2_set_instr(virtex2_info->tap, 0x3f); /* BYPASS */ + if (retval != ERROR_OK) + return retval; + + return jtag_execute_queue(); } static int virtex2_load(struct pld_device *pld_device, const char *filename) @@ -128,12 +199,11 @@ static int virtex2_load(struct pld_device *pld_device, const char *filename) if (retval != ERROR_OK) return retval; - virtex2_set_instr(virtex2_info->tap, 0xb); /* JPROG_B */ - jtag_execute_queue(); - jtag_add_sleep(1000); - - virtex2_set_instr(virtex2_info->tap, 0x5); /* CFG_IN */ - jtag_execute_queue(); + retval = virtex2_load_prepare(pld_device); + if (retval != ERROR_OK) { + xilinx_free_bit_file(&bit_file); + return retval; + } for (i = 0; i < bit_file.length; i++) bit_file.data[i] = flip_u32(bit_file.data[i], 8); @@ -142,24 +212,17 @@ static int virtex2_load(struct pld_device *pld_device, const char *filename) field.out_value = bit_file.data; jtag_add_dr_scan(virtex2_info->tap, 1, &field, TAP_DRPAUSE); - jtag_execute_queue(); + retval = jtag_execute_queue(); + if (retval != ERROR_OK) { + xilinx_free_bit_file(&bit_file); + return retval; + } - jtag_add_tlr(); - - if (!(virtex2_info->no_jstart)) - virtex2_set_instr(virtex2_info->tap, 0xc); /* JSTART */ - jtag_add_runtest(13, TAP_IDLE); - virtex2_set_instr(virtex2_info->tap, 0x3f); /* BYPASS */ - virtex2_set_instr(virtex2_info->tap, 0x3f); /* BYPASS */ - if (!(virtex2_info->no_jstart)) - virtex2_set_instr(virtex2_info->tap, 0xc); /* JSTART */ - jtag_add_runtest(13, TAP_IDLE); - virtex2_set_instr(virtex2_info->tap, 0x3f); /* BYPASS */ - jtag_execute_queue(); + retval = virtex2_load_cleanup(pld_device); xilinx_free_bit_file(&bit_file); - return ERROR_OK; + return retval; } COMMAND_HANDLER(virtex2_handle_read_stat_command) @@ -201,6 +264,10 @@ PLD_DEVICE_COMMAND_HANDLER(virtex2_pld_device_command) } virtex2_info = malloc(sizeof(struct virtex2_pld_device)); + if (!virtex2_info) { + LOG_ERROR("Out of memory"); + return ERROR_FAIL; + } virtex2_info->tap = tap; virtex2_info->no_jstart = 0; From 92c1bee18c8268511de3478aabd226ce4f92322a Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Sat, 6 May 2023 10:16:08 +0200 Subject: [PATCH 33/49] jtag: xds110: fix check on malloc() returned pointer Commit 07e1ebcc12cd ("jtag: drivers: with pointers, use NULL instead of 0") incorrectly inverts the check, making the driver's pathmove operation not functional and triggering two clang errors. Fix the check on malloc() returned pointer. Change-Id: If1f220aca67452adbcd3a1c9cf691fc984b16b27 Signed-off-by: Antonio Borneo Fixes: 07e1ebcc12cd ("jtag: drivers: with pointers, use NULL instead of 0") Reviewed-on: https://review.openocd.org/c/openocd/+/7656 Tested-by: jenkins --- src/jtag/drivers/xds110.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/jtag/drivers/xds110.c b/src/jtag/drivers/xds110.c index 3ea98ad6b..371dc8803 100644 --- a/src/jtag/drivers/xds110.c +++ b/src/jtag/drivers/xds110.c @@ -1688,7 +1688,7 @@ static void xds110_execute_pathmove(struct jtag_command *cmd) return; path = malloc(num_states * sizeof(uint8_t)); - if (path) { + if (!path) { LOG_ERROR("XDS110: unable to allocate memory"); return; } From 329b10754aa2294d11717c461f356c174eba5094 Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Sun, 9 Apr 2023 01:00:15 +0200 Subject: [PATCH 34/49] target: etm: fix check trace status Current code tests a function pointer against a numeric value that is the same enum type as returned by the pointed function. Clearly the author was willing to call the function and check its returned value. Fix the check by calling the function. Detected through 'sparse' tool. Change-Id: I27d18d26c2c797160a397daa32835c199014b70b Signed-off-by: Antonio Borneo Checkpatch-ignore: GIT_COMMIT_ID Fixes: 237e894805dd ("reworked etm/etb into a generic etm part with trace capture") Reviewed-on: https://review.openocd.org/c/openocd/+/7599 Tested-by: jenkins Reviewed-by: Tomas Vanek --- src/target/etm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/target/etm.c b/src/target/etm.c index 57417c3fa..6718875ee 100644 --- a/src/target/etm.c +++ b/src/target/etm.c @@ -1706,7 +1706,7 @@ COMMAND_HANDLER(handle_etm_dump_command) return ERROR_FAIL; } - if (etm_ctx->capture_driver->status == TRACE_IDLE) { + if (etm_ctx->capture_driver->status(etm_ctx) == TRACE_IDLE) { command_print(CMD, "trace capture wasn't enabled, no trace data captured"); return ERROR_OK; } From 160288137aad7dc8825566f2221dd24db7f81110 Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Mon, 8 May 2023 10:45:25 +0200 Subject: [PATCH 35/49] xtensa: fix build with gcc 13.1.1 New gcc does not understand that the variable 'restore_ms' is set to 'true' only when the variable 'ms' is assigned in static int xtensa_write_dirty_registers(...) { xtensa_reg_val_t ms; bool restore_ms = false; ... if (...) { ms = regval; restore_ms = true; ... } ... if (restore_ms) { USE(ms); } ... } and complains about possible use of uninitialized variable 'ms'. Sadly initialize 'ms' to zero to hide this false positive. Change-Id: I1fb3949070c8abbf4aa45a740f0ca2fdb753d4fa Signed-off-by: Antonio Borneo Reviewed-on: https://review.openocd.org/c/openocd/+/7681 Reviewed-by: Erhan Kurubas Reviewed-by: Ian Thompson Tested-by: jenkins --- src/target/xtensa/xtensa.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/target/xtensa/xtensa.c b/src/target/xtensa/xtensa.c index 63ffefce7..5880637f4 100644 --- a/src/target/xtensa/xtensa.c +++ b/src/target/xtensa/xtensa.c @@ -607,7 +607,7 @@ static int xtensa_write_dirty_registers(struct target *target) xtensa_reg_val_t a3 = 0, woe; unsigned int ms_idx = (xtensa->core_config->core_type == XT_NX) ? xtensa->nx_reg_idx[XT_NX_REG_IDX_MS] : reg_list_size; - xtensa_reg_val_t ms; + xtensa_reg_val_t ms = 0; bool restore_ms = false; LOG_TARGET_DEBUG(target, "start"); From 599f1cf763448f043e97702ca8a611f0ab87b849 Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Mon, 26 Dec 2022 22:46:19 +0100 Subject: [PATCH 36/49] openocd: trivial replace of jim-nvp with new nvp For some trivial case only, replace calls to jim-nvp with calls to the new OpenOCD nvp. Change-Id: Ifd9aff32b67748af8ab808e6a6b6e64f5271b888 Signed-off-by: Antonio Borneo Reviewed-on: https://review.openocd.org/c/openocd/+/7553 Tested-by: jenkins --- src/jtag/drivers/ftdi.c | 9 +++++---- src/target/aarch64.c | 9 +++++---- src/target/armv8.c | 11 ++++++----- src/target/cortex_a.c | 17 +++++++++-------- src/target/cortex_m.c | 9 +++++---- src/target/target.c | 25 +++++++++++++------------ 6 files changed, 43 insertions(+), 37 deletions(-) diff --git a/src/jtag/drivers/ftdi.c b/src/jtag/drivers/ftdi.c index 85b451308..7175925e4 100644 --- a/src/jtag/drivers/ftdi.c +++ b/src/jtag/drivers/ftdi.c @@ -64,6 +64,7 @@ #include #include #include +#include #if IS_CYGWIN == 1 #include @@ -896,22 +897,22 @@ COMMAND_HANDLER(ftdi_handle_vid_pid_command) COMMAND_HANDLER(ftdi_handle_tdo_sample_edge_command) { - struct jim_nvp *n; - static const struct jim_nvp nvp_ftdi_jtag_modes[] = { + const struct nvp *n; + static const struct nvp nvp_ftdi_jtag_modes[] = { { .name = "rising", .value = JTAG_MODE }, { .name = "falling", .value = JTAG_MODE_ALT }, { .name = NULL, .value = -1 }, }; if (CMD_ARGC > 0) { - n = jim_nvp_name2value_simple(nvp_ftdi_jtag_modes, CMD_ARGV[0]); + n = nvp_name2value(nvp_ftdi_jtag_modes, CMD_ARGV[0]); if (!n->name) return ERROR_COMMAND_SYNTAX_ERROR; ftdi_jtag_mode = n->value; } - n = jim_nvp_value2name_simple(nvp_ftdi_jtag_modes, ftdi_jtag_mode); + n = nvp_value2name(nvp_ftdi_jtag_modes, ftdi_jtag_mode); command_print(CMD, "ftdi samples TDO on %s edge of TCK", n->name); return ERROR_OK; diff --git a/src/target/aarch64.c b/src/target/aarch64.c index c6ebfb011..5a16b3a3b 100644 --- a/src/target/aarch64.c +++ b/src/target/aarch64.c @@ -21,6 +21,7 @@ #include "arm_semihosting.h" #include "jtag/interface.h" #include "smp.h" +#include #include enum restart_mode { @@ -2957,15 +2958,15 @@ COMMAND_HANDLER(aarch64_mask_interrupts_command) struct target *target = get_current_target(CMD_CTX); struct aarch64_common *aarch64 = target_to_aarch64(target); - static const struct jim_nvp nvp_maskisr_modes[] = { + static const struct nvp nvp_maskisr_modes[] = { { .name = "off", .value = AARCH64_ISRMASK_OFF }, { .name = "on", .value = AARCH64_ISRMASK_ON }, { .name = NULL, .value = -1 }, }; - const struct jim_nvp *n; + const struct nvp *n; if (CMD_ARGC > 0) { - n = jim_nvp_name2value_simple(nvp_maskisr_modes, CMD_ARGV[0]); + n = nvp_name2value(nvp_maskisr_modes, CMD_ARGV[0]); if (!n->name) { LOG_ERROR("Unknown parameter: %s - should be off or on", CMD_ARGV[0]); return ERROR_COMMAND_SYNTAX_ERROR; @@ -2974,7 +2975,7 @@ COMMAND_HANDLER(aarch64_mask_interrupts_command) aarch64->isrmasking_mode = n->value; } - n = jim_nvp_value2name_simple(nvp_maskisr_modes, aarch64->isrmasking_mode); + n = nvp_value2name(nvp_maskisr_modes, aarch64->isrmasking_mode); command_print(CMD, "aarch64 interrupt mask %s", n->name); return ERROR_OK; diff --git a/src/target/armv8.c b/src/target/armv8.c index b01afdbc7..ffed263a9 100644 --- a/src/target/armv8.c +++ b/src/target/armv8.c @@ -19,6 +19,7 @@ #include "register.h" #include #include +#include #include #include @@ -1043,7 +1044,7 @@ COMMAND_HANDLER(armv8_handle_exception_catch_command) unsigned int argp = 0; int retval; - static const struct jim_nvp nvp_ecatch_modes[] = { + static const struct nvp nvp_ecatch_modes[] = { { .name = "off", .value = 0 }, { .name = "nsec_el1", .value = (1 << 5) }, { .name = "nsec_el2", .value = (2 << 5) }, @@ -1053,7 +1054,7 @@ COMMAND_HANDLER(armv8_handle_exception_catch_command) { .name = "sec_el13", .value = (5 << 1) }, { .name = NULL, .value = -1 }, }; - const struct jim_nvp *n; + const struct nvp *n; if (CMD_ARGC == 0) { const char *sec = NULL, *nsec = NULL; @@ -1063,11 +1064,11 @@ COMMAND_HANDLER(armv8_handle_exception_catch_command) if (retval != ERROR_OK) return retval; - n = jim_nvp_value2name_simple(nvp_ecatch_modes, edeccr & 0x0f); + n = nvp_value2name(nvp_ecatch_modes, edeccr & 0x0f); if (n->name) sec = n->name; - n = jim_nvp_value2name_simple(nvp_ecatch_modes, edeccr & 0xf0); + n = nvp_value2name(nvp_ecatch_modes, edeccr & 0xf0); if (n->name) nsec = n->name; @@ -1081,7 +1082,7 @@ COMMAND_HANDLER(armv8_handle_exception_catch_command) } while (argp < CMD_ARGC) { - n = jim_nvp_name2value_simple(nvp_ecatch_modes, CMD_ARGV[argp]); + n = nvp_name2value(nvp_ecatch_modes, CMD_ARGV[argp]); if (!n->name) { LOG_ERROR("Unknown option: %s", CMD_ARGV[argp]); return ERROR_FAIL; diff --git a/src/target/cortex_a.c b/src/target/cortex_a.c index 3db9c62a5..d9688be13 100644 --- a/src/target/cortex_a.c +++ b/src/target/cortex_a.c @@ -52,6 +52,7 @@ #include "transport/transport.h" #include "smp.h" #include +#include #include static int cortex_a_poll(struct target *target); @@ -3246,15 +3247,15 @@ COMMAND_HANDLER(handle_cortex_a_mask_interrupts_command) struct target *target = get_current_target(CMD_CTX); struct cortex_a_common *cortex_a = target_to_cortex_a(target); - static const struct jim_nvp nvp_maskisr_modes[] = { + static const struct nvp nvp_maskisr_modes[] = { { .name = "off", .value = CORTEX_A_ISRMASK_OFF }, { .name = "on", .value = CORTEX_A_ISRMASK_ON }, { .name = NULL, .value = -1 }, }; - const struct jim_nvp *n; + const struct nvp *n; if (CMD_ARGC > 0) { - n = jim_nvp_name2value_simple(nvp_maskisr_modes, CMD_ARGV[0]); + n = nvp_name2value(nvp_maskisr_modes, CMD_ARGV[0]); if (!n->name) { LOG_ERROR("Unknown parameter: %s - should be off or on", CMD_ARGV[0]); return ERROR_COMMAND_SYNTAX_ERROR; @@ -3263,7 +3264,7 @@ COMMAND_HANDLER(handle_cortex_a_mask_interrupts_command) cortex_a->isrmasking_mode = n->value; } - n = jim_nvp_value2name_simple(nvp_maskisr_modes, cortex_a->isrmasking_mode); + n = nvp_value2name(nvp_maskisr_modes, cortex_a->isrmasking_mode); command_print(CMD, "cortex_a interrupt mask %s", n->name); return ERROR_OK; @@ -3274,22 +3275,22 @@ COMMAND_HANDLER(handle_cortex_a_dacrfixup_command) struct target *target = get_current_target(CMD_CTX); struct cortex_a_common *cortex_a = target_to_cortex_a(target); - static const struct jim_nvp nvp_dacrfixup_modes[] = { + static const struct nvp nvp_dacrfixup_modes[] = { { .name = "off", .value = CORTEX_A_DACRFIXUP_OFF }, { .name = "on", .value = CORTEX_A_DACRFIXUP_ON }, { .name = NULL, .value = -1 }, }; - const struct jim_nvp *n; + const struct nvp *n; if (CMD_ARGC > 0) { - n = jim_nvp_name2value_simple(nvp_dacrfixup_modes, CMD_ARGV[0]); + n = nvp_name2value(nvp_dacrfixup_modes, CMD_ARGV[0]); if (!n->name) return ERROR_COMMAND_SYNTAX_ERROR; cortex_a->dacrfixup_mode = n->value; } - n = jim_nvp_value2name_simple(nvp_dacrfixup_modes, cortex_a->dacrfixup_mode); + n = nvp_value2name(nvp_dacrfixup_modes, cortex_a->dacrfixup_mode); command_print(CMD, "cortex_a domain access control fixup %s", n->name); return ERROR_OK; diff --git a/src/target/cortex_m.c b/src/target/cortex_m.c index 88e9bb299..8e55014f9 100644 --- a/src/target/cortex_m.c +++ b/src/target/cortex_m.c @@ -29,6 +29,7 @@ #include "arm_opcodes.h" #include "arm_semihosting.h" #include "smp.h" +#include #include #include @@ -2935,14 +2936,14 @@ COMMAND_HANDLER(handle_cortex_m_mask_interrupts_command) struct cortex_m_common *cortex_m = target_to_cm(target); int retval; - static const struct jim_nvp nvp_maskisr_modes[] = { + static const struct nvp nvp_maskisr_modes[] = { { .name = "auto", .value = CORTEX_M_ISRMASK_AUTO }, { .name = "off", .value = CORTEX_M_ISRMASK_OFF }, { .name = "on", .value = CORTEX_M_ISRMASK_ON }, { .name = "steponly", .value = CORTEX_M_ISRMASK_STEPONLY }, { .name = NULL, .value = -1 }, }; - const struct jim_nvp *n; + const struct nvp *n; retval = cortex_m_verify_pointer(CMD, cortex_m); @@ -2955,14 +2956,14 @@ COMMAND_HANDLER(handle_cortex_m_mask_interrupts_command) } if (CMD_ARGC > 0) { - n = jim_nvp_name2value_simple(nvp_maskisr_modes, CMD_ARGV[0]); + n = nvp_name2value(nvp_maskisr_modes, CMD_ARGV[0]); if (!n->name) return ERROR_COMMAND_SYNTAX_ERROR; cortex_m->isrmasking_mode = n->value; cortex_m_set_maskints_for_halt(target); } - n = jim_nvp_value2name_simple(nvp_maskisr_modes, cortex_m->isrmasking_mode); + n = nvp_value2name(nvp_maskisr_modes, cortex_m->isrmasking_mode); command_print(CMD, "cortex_m interrupt mask %s", n->name); return ERROR_OK; diff --git a/src/target/target.c b/src/target/target.c index c55b67cc9..fb5ef7219 100644 --- a/src/target/target.c +++ b/src/target/target.c @@ -31,6 +31,7 @@ #endif #include +#include #include #include #include @@ -166,7 +167,7 @@ static const struct jim_nvp nvp_assert[] = { { .name = NULL, .value = -1 } }; -static const struct jim_nvp nvp_error_target[] = { +static const struct nvp nvp_error_target[] = { { .value = ERROR_TARGET_INVALID, .name = "err-invalid" }, { .value = ERROR_TARGET_INIT_FAILED, .name = "err-init-failed" }, { .value = ERROR_TARGET_TIMEOUT, .name = "err-timeout" }, @@ -183,9 +184,9 @@ static const struct jim_nvp nvp_error_target[] = { static const char *target_strerror_safe(int err) { - const struct jim_nvp *n; + const struct nvp *n; - n = jim_nvp_value2name_simple(nvp_error_target, err); + n = nvp_value2name(nvp_error_target, err); if (!n->name) return "unknown"; else @@ -253,7 +254,7 @@ static const struct jim_nvp nvp_target_state[] = { { .name = NULL, .value = -1 }, }; -static const struct jim_nvp nvp_target_debug_reason[] = { +static const struct nvp nvp_target_debug_reason[] = { { .name = "debug-request", .value = DBG_REASON_DBGRQ }, { .name = "breakpoint", .value = DBG_REASON_BREAKPOINT }, { .name = "watchpoint", .value = DBG_REASON_WATCHPOINT }, @@ -274,7 +275,7 @@ static const struct jim_nvp nvp_target_endian[] = { { .name = NULL, .value = -1 }, }; -static const struct jim_nvp nvp_reset_modes[] = { +static const struct nvp nvp_reset_modes[] = { { .name = "unknown", .value = RESET_UNKNOWN }, { .name = "run", .value = RESET_RUN }, { .name = "halt", .value = RESET_HALT }, @@ -286,7 +287,7 @@ const char *debug_reason_name(struct target *t) { const char *cp; - cp = jim_nvp_value2name_simple(nvp_target_debug_reason, + cp = nvp_value2name(nvp_target_debug_reason, t->debug_reason)->name; if (!cp) { LOG_ERROR("Invalid debug reason: %d", (int)(t->debug_reason)); @@ -324,7 +325,7 @@ const char *target_event_name(enum target_event event) const char *target_reset_mode_name(enum target_reset_mode reset_mode) { const char *cp; - cp = jim_nvp_value2name_simple(nvp_reset_modes, reset_mode)->name; + cp = nvp_value2name(nvp_reset_modes, reset_mode)->name; if (!cp) { LOG_ERROR("Invalid target reset mode: %d", (int)(reset_mode)); cp = "(*BUG*unknown*BUG*)"; @@ -668,8 +669,8 @@ static int target_process_reset(struct command_invocation *cmd, enum target_rese { char buf[100]; int retval; - struct jim_nvp *n; - n = jim_nvp_value2name_simple(nvp_reset_modes, reset_mode); + const struct nvp *n; + n = nvp_value2name(nvp_reset_modes, reset_mode); if (!n->name) { LOG_ERROR("invalid reset mode"); return ERROR_FAIL; @@ -1856,7 +1857,7 @@ int target_call_reset_callbacks(struct target *target, enum target_reset_mode re struct target_reset_callback *callback; LOG_DEBUG("target reset %i (%s)", reset_mode, - jim_nvp_value2name_simple(nvp_reset_modes, reset_mode)->name); + nvp_value2name(nvp_reset_modes, reset_mode)->name); list_for_each_entry(callback, &target_reset_callback_list, list) callback->callback(target, reset_mode, callback->priv); @@ -3338,8 +3339,8 @@ COMMAND_HANDLER(handle_reset_command) enum target_reset_mode reset_mode = RESET_RUN; if (CMD_ARGC == 1) { - const struct jim_nvp *n; - n = jim_nvp_name2value_simple(nvp_reset_modes, CMD_ARGV[0]); + const struct nvp *n; + n = nvp_name2value(nvp_reset_modes, CMD_ARGV[0]); if ((!n->name) || (n->value == RESET_UNKNOWN)) return ERROR_COMMAND_SYNTAX_ERROR; reset_mode = n->value; From 4bf994fc9c810a996e31f9cd21ffc7d58ad3917d Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Mon, 2 Jan 2023 22:16:46 +0100 Subject: [PATCH 37/49] jtag: rewrite command 'drscan' as COMMAND_HANDLER Reorganize the code to parse the command line only once. Add check for successful memory allocation. Change-Id: Ibf6068e177c09e93150d11aecfcf079348c47c21 Signed-off-by: Antonio Borneo Reviewed-on: https://review.openocd.org/c/openocd/+/7555 Tested-by: jenkins --- src/jtag/tcl.c | 193 ++++++++++++++++++------------------------------- 1 file changed, 72 insertions(+), 121 deletions(-) diff --git a/src/jtag/tcl.c b/src/jtag/tcl.c index b3cbc48b4..ea501022b 100644 --- a/src/jtag/tcl.c +++ b/src/jtag/tcl.c @@ -72,147 +72,98 @@ static bool scan_is_safe(tap_state_t state) } } -static int jim_command_drscan(Jim_Interp *interp, int argc, Jim_Obj * const *args) +static COMMAND_HELPER(handle_jtag_command_drscan_fields, struct scan_field *fields) { - int retval; - struct scan_field *fields; - int num_fields; - int field_count = 0; - int i, e; - struct jtag_tap *tap; - tap_state_t endstate; - - /* args[1] = device - * args[2] = num_bits - * args[3] = hex string - * ... repeat num bits and hex string ... - * - * .. optionally: - * args[N-2] = "-endstate" - * args[N-1] = statename - */ - if ((argc < 4) || ((argc % 2) != 0)) { - Jim_WrongNumArgs(interp, 1, args, "wrong arguments"); - return JIM_ERR; - } - - endstate = TAP_IDLE; - - /* validate arguments as numbers */ - e = JIM_OK; - for (i = 2; i < argc; i += 2) { - long bits; - const char *cp; - - e = Jim_GetLong(interp, args[i], &bits); - /* If valid - try next arg */ - if (e == JIM_OK) - continue; - - /* Not valid.. are we at the end? */ - if (((i + 2) != argc)) { - /* nope, then error */ - return e; - } - - /* it could be: "-endstate FOO" - * e.g. DRPAUSE so we can issue more instructions - * before entering RUN/IDLE and executing them. - */ - - /* get arg as a string. */ - cp = Jim_GetString(args[i], NULL); - /* is it the magic? */ - if (strcmp("-endstate", cp) == 0) { - /* is the statename valid? */ - cp = Jim_GetString(args[i + 1], NULL); - - /* see if it is a valid state name */ - endstate = tap_state_by_name(cp); - if (endstate < 0) { - /* update the error message */ - Jim_SetResultFormatted(interp, "endstate: %s invalid", cp); - } else { - if (!scan_is_safe(endstate)) - LOG_WARNING("drscan with unsafe " - "endstate \"%s\"", cp); - - /* valid - so clear the error */ - e = JIM_OK; - /* and remove the last 2 args */ - argc -= 2; - } - } - - /* Still an error? */ - if (e != JIM_OK) - return e; /* too bad */ - } /* validate args */ - - assert(e == JIM_OK); - - tap = jtag_tap_by_jim_obj(interp, args[1]); - if (!tap) - return JIM_ERR; - - num_fields = (argc-2)/2; - if (num_fields <= 0) { - Jim_SetResultString(interp, "drscan: no scan fields supplied", -1); - return JIM_ERR; - } - fields = malloc(sizeof(struct scan_field) * num_fields); - for (i = 2; i < argc; i += 2) { - long bits; - int len; - const char *str; - - Jim_GetLong(interp, args[i], &bits); - str = Jim_GetString(args[i + 1], &len); - + unsigned int field_count = 0; + for (unsigned int i = 1; i < CMD_ARGC; i += 2) { + unsigned int bits; + COMMAND_PARSE_NUMBER(uint, CMD_ARGV[i], bits); fields[field_count].num_bits = bits; + void *t = malloc(DIV_ROUND_UP(bits, 8)); + if (!t) { + LOG_ERROR("Out of memory"); + return ERROR_FAIL; + } fields[field_count].out_value = t; - str_to_buf(str, len, t, bits, 0); + str_to_buf(CMD_ARGV[i + 1], strlen(CMD_ARGV[i + 1]), t, bits, 0); fields[field_count].in_value = t; field_count++; } + return ERROR_OK; +} + +COMMAND_HANDLER(handle_jtag_command_drscan) +{ + /* + * CMD_ARGV[0] = device + * CMD_ARGV[1] = num_bits + * CMD_ARGV[2] = hex string + * ... repeat num bits and hex string ... + * + * ... optionally: + * CMD_ARGV[CMD_ARGC-2] = "-endstate" + * CMD_ARGV[CMD_ARGC-1] = statename + */ + + if (CMD_ARGC < 3 || (CMD_ARGC % 2) != 1) + return ERROR_COMMAND_SYNTAX_ERROR; + + struct jtag_tap *tap = jtag_tap_by_string(CMD_ARGV[0]); + if (!tap) { + command_print(CMD, "Tap '%s' could not be found", CMD_ARGV[0]); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + + tap_state_t endstate = TAP_IDLE; + if (CMD_ARGC > 3 && !strcmp("-endstate", CMD_ARGV[CMD_ARGC - 2])) { + const char *state_name = CMD_ARGV[CMD_ARGC - 1]; + endstate = tap_state_by_name(state_name); + if (endstate < 0) { + command_print(CMD, "endstate: %s invalid", state_name); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + + if (!scan_is_safe(endstate)) + LOG_WARNING("drscan with unsafe endstate \"%s\"", state_name); + + CMD_ARGC -= 2; + } + + unsigned int num_fields = (CMD_ARGC - 1) / 2; + struct scan_field *fields = calloc(num_fields, sizeof(struct scan_field)); + if (!fields) { + LOG_ERROR("Out of memory"); + return ERROR_FAIL; + } + + int retval = CALL_COMMAND_HANDLER(handle_jtag_command_drscan_fields, fields); + if (retval != ERROR_OK) + goto fail; + jtag_add_dr_scan(tap, num_fields, fields, endstate); retval = jtag_execute_queue(); if (retval != ERROR_OK) { - Jim_SetResultString(interp, "drscan: jtag execute failed", -1); - - for (i = 0; i < field_count; i++) - free(fields[i].in_value); - free(fields); - - return JIM_ERR; + command_print(CMD, "drscan: jtag execute failed"); + goto fail; } - field_count = 0; - Jim_Obj *list = Jim_NewListObj(interp, NULL, 0); - for (i = 2; i < argc; i += 2) { - long bits; - char *str; - - Jim_GetLong(interp, args[i], &bits); - str = buf_to_hex_str(fields[field_count].in_value, bits); - free(fields[field_count].in_value); - - Jim_ListAppendElement(interp, list, Jim_NewStringObj(interp, str, strlen(str))); + for (unsigned int i = 0; i < num_fields; i++) { + char *str = buf_to_hex_str(fields[i].in_value, fields[i].num_bits); + command_print(CMD, "%s", str); free(str); - field_count++; } - Jim_SetResult(interp, list); - +fail: + for (unsigned int i = 0; i < num_fields; i++) + free(fields[i].in_value); free(fields); - return JIM_OK; + return retval; } - static int jim_command_pathmove(Jim_Interp *interp, int argc, Jim_Obj * const *args) { tap_state_t states[8]; @@ -274,7 +225,7 @@ static const struct command_registration jtag_command_handlers_to_move[] = { { .name = "drscan", .mode = COMMAND_EXEC, - .jim_handler = jim_command_drscan, + .handler = handle_jtag_command_drscan, .help = "Execute Data Register (DR) scan for one TAP. " "Other TAPs must be in BYPASS mode.", .usage = "tap_name [num_bits value]* ['-endstate' state_name]", From 7319eb3a25732c9d9bcaff804dac6abded99fc43 Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Mon, 2 Jan 2023 22:32:53 +0100 Subject: [PATCH 38/49] jtag: rewrite command 'pathmove' as COMMAND_HANDLER Change-Id: I1f8c6722021f392b1f065484b63a19964db69ad5 Signed-off-by: Antonio Borneo Reviewed-on: https://review.openocd.org/c/openocd/+/7556 Tested-by: jenkins --- src/jtag/tcl.c | 43 ++++++++++++++++++++----------------------- 1 file changed, 20 insertions(+), 23 deletions(-) diff --git a/src/jtag/tcl.c b/src/jtag/tcl.c index ea501022b..d792081c4 100644 --- a/src/jtag/tcl.c +++ b/src/jtag/tcl.c @@ -164,40 +164,37 @@ fail: return retval; } -static int jim_command_pathmove(Jim_Interp *interp, int argc, Jim_Obj * const *args) +COMMAND_HANDLER(handle_jtag_command_pathmove) { tap_state_t states[8]; - if ((argc < 2) || ((size_t)argc > (ARRAY_SIZE(states) + 1))) { - Jim_WrongNumArgs(interp, 1, args, "wrong arguments"); - return JIM_ERR; - } + if (CMD_ARGC < 1 || CMD_ARGC > ARRAY_SIZE(states)) + return ERROR_COMMAND_SYNTAX_ERROR; - int i; - for (i = 0; i < argc-1; i++) { - const char *cp; - cp = Jim_GetString(args[i + 1], NULL); - states[i] = tap_state_by_name(cp); + for (unsigned int i = 0; i < CMD_ARGC; i++) { + states[i] = tap_state_by_name(CMD_ARGV[i]); if (states[i] < 0) { - /* update the error message */ - Jim_SetResultFormatted(interp, "endstate: %s invalid", cp); - return JIM_ERR; + command_print(CMD, "endstate: %s invalid", CMD_ARGV[i]); + return ERROR_COMMAND_ARGUMENT_INVALID; } } - if ((jtag_add_statemove(states[0]) != ERROR_OK) || (jtag_execute_queue() != ERROR_OK)) { - Jim_SetResultString(interp, "pathmove: jtag execute failed", -1); - return JIM_ERR; + int retval = jtag_add_statemove(states[0]); + if (retval == ERROR_OK) + retval = jtag_execute_queue(); + if (retval != ERROR_OK) { + command_print(CMD, "pathmove: jtag execute failed"); + return retval; } - jtag_add_pathmove(argc - 2, states + 1); - - if (jtag_execute_queue() != ERROR_OK) { - Jim_SetResultString(interp, "pathmove: failed", -1); - return JIM_ERR; + jtag_add_pathmove(CMD_ARGC - 1, states + 1); + retval = jtag_execute_queue(); + if (retval != ERROR_OK) { + command_print(CMD, "pathmove: failed"); + return retval; } - return JIM_OK; + return ERROR_OK; } COMMAND_HANDLER(handle_jtag_flush_count) @@ -241,7 +238,7 @@ static const struct command_registration jtag_command_handlers_to_move[] = { { .name = "pathmove", .mode = COMMAND_EXEC, - .jim_handler = jim_command_pathmove, + .handler = handle_jtag_command_pathmove, .usage = "start_state state1 [state2 [state3 ...]]", .help = "Move JTAG state machine from current state " "(start_state) to state1, then state2, state3, etc.", From 219412f9d65cff4457f9b9ce339a444ad903a1df Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Mon, 27 Mar 2023 10:34:14 +0200 Subject: [PATCH 39/49] target: rewrite command 'arp_poll' as COMMAND_HANDLER While there, add the missing .usage field. Change-Id: I16e0aeacdaaada09fa77ad29552fa4025eff0c45 Signed-off-by: Antonio Borneo Reviewed-on: https://review.openocd.org/c/openocd/+/7557 Tested-by: jenkins --- src/target/target.c | 32 ++++++++++++++------------------ 1 file changed, 14 insertions(+), 18 deletions(-) diff --git a/src/target/target.c b/src/target/target.c index fb5ef7219..e995f134e 100644 --- a/src/target/target.c +++ b/src/target/target.c @@ -5753,26 +5753,21 @@ COMMAND_HANDLER(handle_target_halt_gdb) return target_call_event_callbacks(target, TARGET_EVENT_GDB_HALT); } -static int jim_target_poll(Jim_Interp *interp, int argc, Jim_Obj *const *argv) +COMMAND_HANDLER(handle_target_poll) { - if (argc != 1) { - Jim_WrongNumArgs(interp, 1, argv, "[no parameters]"); - return JIM_ERR; - } - struct command_context *cmd_ctx = current_command_context(interp); - assert(cmd_ctx); - struct target *target = get_current_target(cmd_ctx); - if (!target->tap->enabled) - return jim_target_tap_disabled(interp); + if (CMD_ARGC != 0) + return ERROR_COMMAND_SYNTAX_ERROR; + + struct target *target = get_current_target(CMD_CTX); + if (!target->tap->enabled) { + command_print(CMD, "[TAP is disabled]"); + return ERROR_FAIL; + } - int e; if (!(target_was_examined(target))) - e = ERROR_TARGET_NOT_EXAMINED; - else - e = target->type->poll(target); - if (e != ERROR_OK) - return JIM_ERR; - return JIM_OK; + return ERROR_TARGET_NOT_EXAMINED; + + return target->type->poll(target); } static int jim_target_reset(Jim_Interp *interp, int argc, Jim_Obj *const *argv) @@ -6100,8 +6095,9 @@ static const struct command_registration target_instance_command_handlers[] = { { .name = "arp_poll", .mode = COMMAND_EXEC, - .jim_handler = jim_target_poll, + .handler = handle_target_poll, .help = "used internally for reset processing", + .usage = "", }, { .name = "arp_reset", From b931286ab440f4677a9ac983a64b55055d20c438 Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Mon, 27 Mar 2023 10:43:30 +0200 Subject: [PATCH 40/49] target: rewrite command 'arp_halt' as COMMAND_HANDLER While there, add the missing .usage field. Change-Id: I748382cafe08443c458ff1d4e47819610cfbf85c Signed-off-by: Antonio Borneo Reviewed-on: https://review.openocd.org/c/openocd/+/7558 Tested-by: jenkins --- src/target/target.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/target/target.c b/src/target/target.c index e995f134e..f2e8d531a 100644 --- a/src/target/target.c +++ b/src/target/target.c @@ -5822,19 +5822,18 @@ static int jim_target_reset(Jim_Interp *interp, int argc, Jim_Obj *const *argv) return (e == ERROR_OK) ? JIM_OK : JIM_ERR; } -static int jim_target_halt(Jim_Interp *interp, int argc, Jim_Obj *const *argv) +COMMAND_HANDLER(handle_target_halt) { - if (argc != 1) { - Jim_WrongNumArgs(interp, 1, argv, "[no parameters]"); - return JIM_ERR; + if (CMD_ARGC != 0) + return ERROR_COMMAND_SYNTAX_ERROR; + + struct target *target = get_current_target(CMD_CTX); + if (!target->tap->enabled) { + command_print(CMD, "[TAP is disabled]"); + return ERROR_FAIL; } - struct command_context *cmd_ctx = current_command_context(interp); - assert(cmd_ctx); - struct target *target = get_current_target(cmd_ctx); - if (!target->tap->enabled) - return jim_target_tap_disabled(interp); - int e = target->type->halt(target); - return (e == ERROR_OK) ? JIM_OK : JIM_ERR; + + return target->type->halt(target); } static int jim_target_wait_state(Jim_Interp *interp, int argc, Jim_Obj *const *argv) @@ -6108,8 +6107,9 @@ static const struct command_registration target_instance_command_handlers[] = { { .name = "arp_halt", .mode = COMMAND_EXEC, - .jim_handler = jim_target_halt, + .handler = handle_target_halt, .help = "used internally for reset processing", + .usage = "", }, { .name = "arp_waitstate", From 85b5c518062f4d77f73cb5f00620ccebd2d7847a Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Mon, 27 Mar 2023 11:11:46 +0200 Subject: [PATCH 41/49] target: rewrite command 'arp_reset' as COMMAND_HANDLER While there, add the missing .usage field and move in target.c the enum nvp_assert. Change-Id: Ia4f2f962887b5a35faeaa4eae128fa2865569b24 Signed-off-by: Antonio Borneo Reviewed-on: https://review.openocd.org/c/openocd/+/7559 Tested-by: jenkins --- src/target/target.c | 58 ++++++++++++++++++++------------------------- src/target/target.h | 5 ---- 2 files changed, 26 insertions(+), 37 deletions(-) diff --git a/src/target/target.c b/src/target/target.c index f2e8d531a..73fba0da7 100644 --- a/src/target/target.c +++ b/src/target/target.c @@ -157,7 +157,12 @@ static LIST_HEAD(target_trace_callback_list); static const int polling_interval = TARGET_DEFAULT_POLLING_INTERVAL; static LIST_HEAD(empty_smp_targets); -static const struct jim_nvp nvp_assert[] = { +enum nvp_assert { + NVP_DEASSERT, + NVP_ASSERT, +}; + +static const struct nvp nvp_assert[] = { { .name = "assert", NVP_ASSERT }, { .name = "deassert", NVP_DEASSERT }, { .name = "T", NVP_ASSERT }, @@ -5770,40 +5775,30 @@ COMMAND_HANDLER(handle_target_poll) return target->type->poll(target); } -static int jim_target_reset(Jim_Interp *interp, int argc, Jim_Obj *const *argv) +COMMAND_HANDLER(handle_target_reset) { - struct jim_getopt_info goi; - jim_getopt_setup(&goi, interp, argc - 1, argv + 1); + if (CMD_ARGC != 2) + return ERROR_COMMAND_SYNTAX_ERROR; - if (goi.argc != 2) { - Jim_WrongNumArgs(interp, 0, argv, - "([tT]|[fF]|assert|deassert) BOOL"); - return JIM_ERR; + const struct nvp *n = nvp_name2value(nvp_assert, CMD_ARGV[0]); + if (!n->name) { + nvp_unknown_command_print(CMD, nvp_assert, NULL, CMD_ARGV[0]); + return ERROR_COMMAND_ARGUMENT_INVALID; } - struct jim_nvp *n; - int e = jim_getopt_nvp(&goi, nvp_assert, &n); - if (e != JIM_OK) { - jim_getopt_nvp_unknown(&goi, nvp_assert, 1); - return e; - } /* the halt or not param */ - jim_wide a; - e = jim_getopt_wide(&goi, &a); - if (e != JIM_OK) - return e; + int a; + COMMAND_PARSE_NUMBER(int, CMD_ARGV[1], a); - struct command_context *cmd_ctx = current_command_context(interp); - assert(cmd_ctx); - struct target *target = get_current_target(cmd_ctx); - if (!target->tap->enabled) - return jim_target_tap_disabled(interp); + struct target *target = get_current_target(CMD_CTX); + if (!target->tap->enabled) { + command_print(CMD, "[TAP is disabled]"); + return ERROR_FAIL; + } if (!target->type->assert_reset || !target->type->deassert_reset) { - Jim_SetResultFormatted(interp, - "No target-specific reset for %s", - target_name(target)); - return JIM_ERR; + command_print(CMD, "No target-specific reset for %s", target_name(target)); + return ERROR_FAIL; } if (target->defer_examine) @@ -5816,10 +5811,8 @@ static int jim_target_reset(Jim_Interp *interp, int argc, Jim_Obj *const *argv) /* do the assert */ if (n->value == NVP_ASSERT) - e = target->type->assert_reset(target); - else - e = target->type->deassert_reset(target); - return (e == ERROR_OK) ? JIM_OK : JIM_ERR; + return target->type->assert_reset(target); + return target->type->deassert_reset(target); } COMMAND_HANDLER(handle_target_halt) @@ -6101,8 +6094,9 @@ static const struct command_registration target_instance_command_handlers[] = { { .name = "arp_reset", .mode = COMMAND_EXEC, - .jim_handler = jim_target_reset, + .handler = handle_target_reset, .help = "used internally for reset processing", + .usage = "'assert'|'deassert' halt", }, { .name = "arp_halt", diff --git a/src/target/target.h b/src/target/target.h index ef9ba1062..00bf43c58 100644 --- a/src/target/target.h +++ b/src/target/target.h @@ -57,11 +57,6 @@ enum target_state { TARGET_DEBUG_RUNNING = 4, }; -enum nvp_assert { - NVP_DEASSERT, - NVP_ASSERT, -}; - enum target_reset_mode { RESET_UNKNOWN = 0, RESET_RUN = 1, /* reset and let target run */ From 8d12ae796ead267aeef48467ccd49ec4c2f863ad Mon Sep 17 00:00:00 2001 From: Paul Fertser Date: Tue, 2 May 2023 15:10:11 +0300 Subject: [PATCH 42/49] jtag: tcl: change drscan usage to show at least one value is required It's customary to use [] brackets to mean the argument is optional, but drscan requires at least one pair of "num_bits value" so change it to (). In common regular expressions * means 0 or more, and + means 1 or more, so change that too. Signed-off-by: Paul Fertser Change-Id: Ib15d833bda2aa398ad1345a042f97d91c98dbf66 Reviewed-on: https://review.openocd.org/c/openocd/+/7653 Tested-by: jenkins Reviewed-by: Antonio Borneo --- src/jtag/tcl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/jtag/tcl.c b/src/jtag/tcl.c index d792081c4..395439039 100644 --- a/src/jtag/tcl.c +++ b/src/jtag/tcl.c @@ -225,7 +225,7 @@ static const struct command_registration jtag_command_handlers_to_move[] = { .handler = handle_jtag_command_drscan, .help = "Execute Data Register (DR) scan for one TAP. " "Other TAPs must be in BYPASS mode.", - .usage = "tap_name [num_bits value]* ['-endstate' state_name]", + .usage = "tap_name (num_bits value)+ ['-endstate' state_name]", }, { .name = "flush_count", From 3a4f445bd92101d3daee3715178d3fbff3b7b029 Mon Sep 17 00:00:00 2001 From: Paul Fertser Date: Tue, 2 May 2023 15:15:21 +0300 Subject: [PATCH 43/49] jtag: tcl: show error message when attempting manual "drscan" on a bypassed tap To perform any meaningful manipulations with DR the corresponding IR should be set to a relevant instruction, not BYPASS, so warn the user accordingly. Signed-off-by: Paul Fertser Change-Id: I42580ecd75ae824a4145f6f17f0df9bcf825b50f Reviewed-on: https://review.openocd.org/c/openocd/+/7654 Reviewed-by: Antonio Borneo Tested-by: jenkins --- src/jtag/tcl.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/jtag/tcl.c b/src/jtag/tcl.c index 395439039..934b60352 100644 --- a/src/jtag/tcl.c +++ b/src/jtag/tcl.c @@ -116,6 +116,11 @@ COMMAND_HANDLER(handle_jtag_command_drscan) return ERROR_COMMAND_ARGUMENT_INVALID; } + if (tap->bypass) { + command_print(CMD, "Can't execute as the selected tap is in BYPASS"); + return ERROR_FAIL; + } + tap_state_t endstate = TAP_IDLE; if (CMD_ARGC > 3 && !strcmp("-endstate", CMD_ARGV[CMD_ARGC - 2])) { const char *state_name = CMD_ARGV[CMD_ARGC - 1]; From ed46188a72492148be3c694bfea1f6a2fb92b646 Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Mon, 1 May 2023 00:00:47 +0200 Subject: [PATCH 44/49] target: move in target_type.h the target_type's declaration The static analyser 'sparse' complains, while compiling a target's file, that the struct target_type is declared in the file as non static, but it is not exposed through an include file. The message is: warning: symbol 'XXX' was not declared. Should it be static? Move the list of target_type's declaration in target_type.h While there, fix a name clash in stm8.c Change-Id: Ia9c681e0825cfd04d509616dbc04a0cf4944f379 Signed-off-by: Antonio Borneo Reviewed-on: https://review.openocd.org/c/openocd/+/7659 Tested-by: jenkins --- src/target/stm8.c | 4 ++-- src/target/target.c | 40 ---------------------------------------- src/target/target_type.h | 39 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 41 insertions(+), 42 deletions(-) diff --git a/src/target/stm8.c b/src/target/stm8.c index aa934c9bc..9fd65091c 100644 --- a/src/target/stm8.c +++ b/src/target/stm8.c @@ -542,12 +542,12 @@ static int stm8_get_core_reg(struct reg *reg) int retval; struct stm8_core_reg *stm8_reg = reg->arch_info; struct target *target = stm8_reg->target; - struct stm8_common *stm8_target = target_to_stm8(target); + struct stm8_common *stm8 = target_to_stm8(target); if (target->state != TARGET_HALTED) return ERROR_TARGET_NOT_HALTED; - retval = stm8_target->read_core_reg(target, stm8_reg->num); + retval = stm8->read_core_reg(target, stm8_reg->num); return retval; } diff --git a/src/target/target.c b/src/target/target.c index 73fba0da7..fee9583ae 100644 --- a/src/target/target.c +++ b/src/target/target.c @@ -66,46 +66,6 @@ static int target_get_gdb_fileio_info_default(struct target *target, static int target_gdb_fileio_end_default(struct target *target, int retcode, int fileio_errno, bool ctrl_c); -/* targets */ -extern struct target_type arm7tdmi_target; -extern struct target_type arm720t_target; -extern struct target_type arm9tdmi_target; -extern struct target_type arm920t_target; -extern struct target_type arm966e_target; -extern struct target_type arm946e_target; -extern struct target_type arm926ejs_target; -extern struct target_type fa526_target; -extern struct target_type feroceon_target; -extern struct target_type dragonite_target; -extern struct target_type xscale_target; -extern struct target_type xtensa_chip_target; -extern struct target_type cortexm_target; -extern struct target_type cortexa_target; -extern struct target_type aarch64_target; -extern struct target_type cortexr4_target; -extern struct target_type armv8r_target; -extern struct target_type arm11_target; -extern struct target_type ls1_sap_target; -extern struct target_type mips_m4k_target; -extern struct target_type mips_mips64_target; -extern struct target_type avr_target; -extern struct target_type dsp563xx_target; -extern struct target_type dsp5680xx_target; -extern struct target_type testee_target; -extern struct target_type avr32_ap7k_target; -extern struct target_type hla_target; -extern struct target_type esp32_target; -extern struct target_type esp32s2_target; -extern struct target_type esp32s3_target; -extern struct target_type or1k_target; -extern struct target_type quark_x10xx_target; -extern struct target_type quark_d20xx_target; -extern struct target_type stm8_target; -extern struct target_type riscv_target; -extern struct target_type mem_ap_target; -extern struct target_type esirisc_target; -extern struct target_type arcv2_target; - static struct target_type *target_types[] = { &arm7tdmi_target, &arm9tdmi_target, diff --git a/src/target/target_type.h b/src/target/target_type.h index 947080381..5186e9c19 100644 --- a/src/target/target_type.h +++ b/src/target/target_type.h @@ -311,4 +311,43 @@ struct target_type { unsigned int (*data_bits)(struct target *target); }; +extern struct target_type aarch64_target; +extern struct target_type arcv2_target; +extern struct target_type arm11_target; +extern struct target_type arm720t_target; +extern struct target_type arm7tdmi_target; +extern struct target_type arm920t_target; +extern struct target_type arm926ejs_target; +extern struct target_type arm946e_target; +extern struct target_type arm966e_target; +extern struct target_type arm9tdmi_target; +extern struct target_type armv8r_target; +extern struct target_type avr32_ap7k_target; +extern struct target_type avr_target; +extern struct target_type cortexa_target; +extern struct target_type cortexm_target; +extern struct target_type cortexr4_target; +extern struct target_type dragonite_target; +extern struct target_type dsp563xx_target; +extern struct target_type dsp5680xx_target; +extern struct target_type esirisc_target; +extern struct target_type esp32s2_target; +extern struct target_type esp32s3_target; +extern struct target_type esp32_target; +extern struct target_type fa526_target; +extern struct target_type feroceon_target; +extern struct target_type hla_target; +extern struct target_type ls1_sap_target; +extern struct target_type mem_ap_target; +extern struct target_type mips_m4k_target; +extern struct target_type mips_mips64_target; +extern struct target_type or1k_target; +extern struct target_type quark_d20xx_target; +extern struct target_type quark_x10xx_target; +extern struct target_type riscv_target; +extern struct target_type stm8_target; +extern struct target_type testee_target; +extern struct target_type xscale_target; +extern struct target_type xtensa_chip_target; + #endif /* OPENOCD_TARGET_TARGET_TYPE_H */ From f07efff961ede4c8015624679bbfd5b54fcb25b5 Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Sun, 30 Apr 2023 23:54:44 +0200 Subject: [PATCH 45/49] rtos: move in rtos.h the rtos_type's declaration The static analyser 'sparse' complains, while compiling a rtos' file, that the struct rtos_type is declared in the file as non static, but it is not exposed through an include file. The message is: warning: symbol 'XXX' was not declared. Should it be static? Move the list of rtos_type's declaration in rtos.h Change-Id: Ia96dff077407a6653b11920519c1724e4c1167a3 Signed-off-by: Antonio Borneo Reviewed-on: https://review.openocd.org/c/openocd/+/7660 Tested-by: jenkins --- src/rtos/rtos.c | 16 ---------------- src/rtos/rtos.h | 15 +++++++++++++++ 2 files changed, 15 insertions(+), 16 deletions(-) diff --git a/src/rtos/rtos.c b/src/rtos/rtos.c index f1e8956a3..6c88de33c 100644 --- a/src/rtos/rtos.c +++ b/src/rtos/rtos.c @@ -15,22 +15,6 @@ #include "helper/binarybuffer.h" #include "server/gdb_server.h" -/* RTOSs */ -extern const struct rtos_type freertos_rtos; -extern const struct rtos_type threadx_rtos; -extern const struct rtos_type ecos_rtos; -extern const struct rtos_type linux_rtos; -extern const struct rtos_type chibios_rtos; -extern const struct rtos_type chromium_ec_rtos; -extern const struct rtos_type embkernel_rtos; -extern const struct rtos_type mqx_rtos; -extern const struct rtos_type ucos_iii_rtos; -extern const struct rtos_type nuttx_rtos; -extern const struct rtos_type hwthread_rtos; -extern const struct rtos_type riot_rtos; -extern const struct rtos_type zephyr_rtos; -extern const struct rtos_type rtkernel_rtos; - static const struct rtos_type *rtos_types[] = { &threadx_rtos, &freertos_rtos, diff --git a/src/rtos/rtos.h b/src/rtos/rtos.h index 9128c163c..e283dd21b 100644 --- a/src/rtos/rtos.h +++ b/src/rtos/rtos.h @@ -135,4 +135,19 @@ int rtos_read_buffer(struct target *target, target_addr_t address, int rtos_write_buffer(struct target *target, target_addr_t address, uint32_t size, const uint8_t *buffer); +extern const struct rtos_type chibios_rtos; +extern const struct rtos_type chromium_ec_rtos; +extern const struct rtos_type ecos_rtos; +extern const struct rtos_type embkernel_rtos; +extern const struct rtos_type freertos_rtos; +extern const struct rtos_type hwthread_rtos; +extern const struct rtos_type linux_rtos; +extern const struct rtos_type mqx_rtos; +extern const struct rtos_type nuttx_rtos; +extern const struct rtos_type riot_rtos; +extern const struct rtos_type rtkernel_rtos; +extern const struct rtos_type threadx_rtos; +extern const struct rtos_type ucos_iii_rtos; +extern const struct rtos_type zephyr_rtos; + #endif /* OPENOCD_RTOS_RTOS_H */ From 5d77897526115a59754f625b6d503459c0d73eee Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Mon, 1 May 2023 00:08:32 +0200 Subject: [PATCH 46/49] nand: move in driver.h the nand_flash_controller's declaration The static analyser 'sparse' complains, while compiling a nand driver, that the struct nand_flash_controller is declared in the file as non static, but it is not exposed through an include file. The message is: warning: symbol 'XXX' was not declared. Should it be static? Move the list of nand_flash_controller's declaration in driver.h While there, drop the unused/commented boundary scan controller. Change-Id: I7dc32cef55be13ba537abe0f4c47b135d837126c Signed-off-by: Antonio Borneo Reviewed-on: https://review.openocd.org/c/openocd/+/7661 Tested-by: jenkins --- src/flash/nand/driver.c | 20 -------------------- src/flash/nand/driver.h | 15 +++++++++++++++ 2 files changed, 15 insertions(+), 20 deletions(-) diff --git a/src/flash/nand/driver.c b/src/flash/nand/driver.c index 02e5c09a2..ce79e1382 100644 --- a/src/flash/nand/driver.c +++ b/src/flash/nand/driver.c @@ -13,25 +13,6 @@ #include "core.h" #include "driver.h" -/* NAND flash controller - */ -extern struct nand_flash_controller nonce_nand_controller; -extern struct nand_flash_controller davinci_nand_controller; -extern struct nand_flash_controller lpc3180_nand_controller; -extern struct nand_flash_controller lpc32xx_nand_controller; -extern struct nand_flash_controller orion_nand_controller; -extern struct nand_flash_controller s3c2410_nand_controller; -extern struct nand_flash_controller s3c2412_nand_controller; -extern struct nand_flash_controller s3c2440_nand_controller; -extern struct nand_flash_controller s3c2443_nand_controller; -extern struct nand_flash_controller s3c6400_nand_controller; -extern struct nand_flash_controller mxc_nand_flash_controller; -extern struct nand_flash_controller imx31_nand_flash_controller; -extern struct nand_flash_controller at91sam9_nand_controller; -extern struct nand_flash_controller nuc910_nand_controller; - -/* extern struct nand_flash_controller boundary_scan_nand_controller; */ - static struct nand_flash_controller *nand_flash_controllers[] = { &nonce_nand_controller, &davinci_nand_controller, @@ -47,7 +28,6 @@ static struct nand_flash_controller *nand_flash_controllers[] = { &imx31_nand_flash_controller, &at91sam9_nand_controller, &nuc910_nand_controller, -/* &boundary_scan_nand_controller, */ NULL }; diff --git a/src/flash/nand/driver.h b/src/flash/nand/driver.h index a874cc890..4e84f10fb 100644 --- a/src/flash/nand/driver.h +++ b/src/flash/nand/driver.h @@ -89,4 +89,19 @@ typedef int (*nand_driver_walker_t)(struct nand_flash_controller *c, void *); */ int nand_driver_walk(nand_driver_walker_t f, void *x); +extern struct nand_flash_controller at91sam9_nand_controller; +extern struct nand_flash_controller davinci_nand_controller; +extern struct nand_flash_controller imx31_nand_flash_controller; +extern struct nand_flash_controller lpc3180_nand_controller; +extern struct nand_flash_controller lpc32xx_nand_controller; +extern struct nand_flash_controller mxc_nand_flash_controller; +extern struct nand_flash_controller nonce_nand_controller; +extern struct nand_flash_controller nuc910_nand_controller; +extern struct nand_flash_controller orion_nand_controller; +extern struct nand_flash_controller s3c2410_nand_controller; +extern struct nand_flash_controller s3c2412_nand_controller; +extern struct nand_flash_controller s3c2440_nand_controller; +extern struct nand_flash_controller s3c2443_nand_controller; +extern struct nand_flash_controller s3c6400_nand_controller; + #endif /* OPENOCD_FLASH_NAND_DRIVER_H */ From 20005eb81abaa3d191d6cdf36fd6f3d4e48a1db7 Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Mon, 1 May 2023 00:17:23 +0200 Subject: [PATCH 47/49] nor: move in driver.h the flash_driver's declaration The static analyser 'sparse' complains, while compiling a nor driver, that the struct flash_driver is declared in the file as non static, but it is not exposed through an include file. The message is: warning: symbol 'XXX' was not declared. Should it be static? Move the list of flash_driver's declaration in driver.h Fix some incorrect non-const declaration and remove redundant forward declarations. Change-Id: I5e41d094307aac4a57dfa9a70496ff3cf180bd92 Signed-off-by: Antonio Borneo Reviewed-on: https://review.openocd.org/c/openocd/+/7662 Tested-by: jenkins --- src/flash/nor/at91sam3.c | 2 -- src/flash/nor/at91sam4.c | 2 -- src/flash/nor/atsamv.c | 2 -- src/flash/nor/driver.h | 71 ++++++++++++++++++++++++++++++++++++++++ src/flash/nor/drivers.c | 71 ---------------------------------------- src/flash/nor/rp2040.c | 2 +- src/flash/nor/stmqspi.c | 2 +- src/flash/nor/swm050.c | 2 +- 8 files changed, 74 insertions(+), 80 deletions(-) diff --git a/src/flash/nor/at91sam3.c b/src/flash/nor/at91sam3.c index fb6d98b56..b1cb8f110 100644 --- a/src/flash/nor/at91sam3.c +++ b/src/flash/nor/at91sam3.c @@ -67,8 +67,6 @@ #define OFFSET_EFC_FSR 8 #define OFFSET_EFC_FRR 12 -extern const struct flash_driver at91sam3_flash; - static float _tomhz(uint32_t freq_hz) { float f; diff --git a/src/flash/nor/at91sam4.c b/src/flash/nor/at91sam4.c index 6b9437390..62127530f 100644 --- a/src/flash/nor/at91sam4.c +++ b/src/flash/nor/at91sam4.c @@ -62,8 +62,6 @@ #define OFFSET_EFC_FSR 8 #define OFFSET_EFC_FRR 12 -extern const struct flash_driver at91sam4_flash; - static float _tomhz(uint32_t freq_hz) { float f; diff --git a/src/flash/nor/atsamv.c b/src/flash/nor/atsamv.c index 67533fc1e..24c432cba 100644 --- a/src/flash/nor/atsamv.c +++ b/src/flash/nor/atsamv.c @@ -53,8 +53,6 @@ #define SAMV_PAGE_SIZE 512 #define SAMV_FLASH_BASE 0x00400000 -extern const struct flash_driver atsamv_flash; - struct samv_flash_bank { bool probed; unsigned size_bytes; diff --git a/src/flash/nor/driver.h b/src/flash/nor/driver.h index 931f79421..889a811e3 100644 --- a/src/flash/nor/driver.h +++ b/src/flash/nor/driver.h @@ -237,4 +237,75 @@ struct flash_driver { */ const struct flash_driver *flash_driver_find_by_name(const char *name); +extern const struct flash_driver aduc702x_flash; +extern const struct flash_driver aducm360_flash; +extern const struct flash_driver ambiqmicro_flash; +extern const struct flash_driver at91sam3_flash; +extern const struct flash_driver at91sam4_flash; +extern const struct flash_driver at91sam4l_flash; +extern const struct flash_driver at91sam7_flash; +extern const struct flash_driver at91samd_flash; +extern const struct flash_driver ath79_flash; +extern const struct flash_driver atsame5_flash; +extern const struct flash_driver atsamv_flash; +extern const struct flash_driver avr_flash; +extern const struct flash_driver bluenrgx_flash; +extern const struct flash_driver cc26xx_flash; +extern const struct flash_driver cc3220sf_flash; +extern const struct flash_driver cfi_flash; +extern const struct flash_driver dsp5680xx_flash; +extern const struct flash_driver efm32_flash; +extern const struct flash_driver em357_flash; +extern const struct flash_driver esirisc_flash; +extern const struct flash_driver faux_flash; +extern const struct flash_driver fespi_flash; +extern const struct flash_driver fm3_flash; +extern const struct flash_driver fm4_flash; +extern const struct flash_driver jtagspi_flash; +extern const struct flash_driver kinetis_flash; +extern const struct flash_driver kinetis_ke_flash; +extern const struct flash_driver lpc2000_flash; +extern const struct flash_driver lpc288x_flash; +extern const struct flash_driver lpc2900_flash; +extern const struct flash_driver lpcspifi_flash; +extern const struct flash_driver max32xxx_flash; +extern const struct flash_driver mdr_flash; +extern const struct flash_driver mrvlqspi_flash; +extern const struct flash_driver msp432_flash; +extern const struct flash_driver niietcm4_flash; +extern const struct flash_driver npcx_flash; +extern const struct flash_driver nrf51_flash; +extern const struct flash_driver nrf5_flash; +extern const struct flash_driver numicro_flash; +extern const struct flash_driver ocl_flash; +extern const struct flash_driver pic32mx_flash; +extern const struct flash_driver psoc4_flash; +extern const struct flash_driver psoc5lp_eeprom_flash; +extern const struct flash_driver psoc5lp_flash; +extern const struct flash_driver psoc5lp_nvl_flash; +extern const struct flash_driver psoc6_flash; +extern const struct flash_driver renesas_rpchf_flash; +extern const struct flash_driver rp2040_flash; +extern const struct flash_driver rsl10_flash; +extern const struct flash_driver sh_qspi_flash; +extern const struct flash_driver sim3x_flash; +extern const struct flash_driver stellaris_flash; +extern const struct flash_driver stm32f1x_flash; +extern const struct flash_driver stm32f2x_flash; +extern const struct flash_driver stm32h7x_flash; +extern const struct flash_driver stm32l4x_flash; +extern const struct flash_driver stm32lx_flash; +extern const struct flash_driver stmqspi_flash; +extern const struct flash_driver stmsmi_flash; +extern const struct flash_driver str7x_flash; +extern const struct flash_driver str9x_flash; +extern const struct flash_driver str9xpec_flash; +extern const struct flash_driver swm050_flash; +extern const struct flash_driver tms470_flash; +extern const struct flash_driver virtual_flash; +extern const struct flash_driver w600_flash; +extern const struct flash_driver xcf_flash; +extern const struct flash_driver xmc1xxx_flash; +extern const struct flash_driver xmc4xxx_flash; + #endif /* OPENOCD_FLASH_NOR_DRIVER_H */ diff --git a/src/flash/nor/drivers.c b/src/flash/nor/drivers.c index b9353d820..92476987e 100644 --- a/src/flash/nor/drivers.c +++ b/src/flash/nor/drivers.c @@ -9,77 +9,6 @@ #endif #include "imp.h" -extern const struct flash_driver aduc702x_flash; -extern const struct flash_driver aducm360_flash; -extern const struct flash_driver ambiqmicro_flash; -extern const struct flash_driver at91sam3_flash; -extern const struct flash_driver at91sam4_flash; -extern const struct flash_driver at91sam4l_flash; -extern const struct flash_driver at91sam7_flash; -extern const struct flash_driver at91samd_flash; -extern const struct flash_driver ath79_flash; -extern const struct flash_driver atsame5_flash; -extern const struct flash_driver atsamv_flash; -extern const struct flash_driver avr_flash; -extern const struct flash_driver bluenrgx_flash; -extern const struct flash_driver cc3220sf_flash; -extern const struct flash_driver cc26xx_flash; -extern const struct flash_driver cfi_flash; -extern const struct flash_driver dsp5680xx_flash; -extern const struct flash_driver efm32_flash; -extern const struct flash_driver em357_flash; -extern const struct flash_driver esirisc_flash; -extern const struct flash_driver faux_flash; -extern const struct flash_driver fm3_flash; -extern const struct flash_driver fm4_flash; -extern const struct flash_driver fespi_flash; -extern const struct flash_driver jtagspi_flash; -extern const struct flash_driver kinetis_flash; -extern const struct flash_driver kinetis_ke_flash; -extern const struct flash_driver lpc2000_flash; -extern const struct flash_driver lpc288x_flash; -extern const struct flash_driver lpc2900_flash; -extern const struct flash_driver lpcspifi_flash; -extern const struct flash_driver max32xxx_flash; -extern const struct flash_driver mdr_flash; -extern const struct flash_driver mrvlqspi_flash; -extern const struct flash_driver msp432_flash; -extern const struct flash_driver niietcm4_flash; -extern const struct flash_driver npcx_flash; -extern const struct flash_driver nrf5_flash; -extern const struct flash_driver nrf51_flash; -extern const struct flash_driver numicro_flash; -extern const struct flash_driver ocl_flash; -extern const struct flash_driver pic32mx_flash; -extern const struct flash_driver psoc4_flash; -extern const struct flash_driver psoc5lp_flash; -extern const struct flash_driver psoc5lp_eeprom_flash; -extern const struct flash_driver psoc5lp_nvl_flash; -extern const struct flash_driver psoc6_flash; -extern const struct flash_driver renesas_rpchf_flash; -extern const struct flash_driver rp2040_flash; -extern const struct flash_driver sh_qspi_flash; -extern const struct flash_driver sim3x_flash; -extern const struct flash_driver stellaris_flash; -extern const struct flash_driver stm32f1x_flash; -extern const struct flash_driver stm32f2x_flash; -extern const struct flash_driver stm32lx_flash; -extern const struct flash_driver stm32l4x_flash; -extern const struct flash_driver stm32h7x_flash; -extern const struct flash_driver stmqspi_flash; -extern const struct flash_driver stmsmi_flash; -extern const struct flash_driver str7x_flash; -extern const struct flash_driver str9x_flash; -extern const struct flash_driver str9xpec_flash; -extern const struct flash_driver swm050_flash; -extern const struct flash_driver tms470_flash; -extern const struct flash_driver virtual_flash; -extern const struct flash_driver w600_flash; -extern const struct flash_driver xcf_flash; -extern const struct flash_driver xmc1xxx_flash; -extern const struct flash_driver xmc4xxx_flash; -extern const struct flash_driver rsl10_flash; - /** * The list of built-in flash drivers. * @todo Make this dynamically extendable with loadable modules. diff --git a/src/flash/nor/rp2040.c b/src/flash/nor/rp2040.c index b0d118bdb..6c18c7b28 100644 --- a/src/flash/nor/rp2040.c +++ b/src/flash/nor/rp2040.c @@ -520,7 +520,7 @@ FLASH_BANK_COMMAND_HANDLER(rp2040_flash_bank_command) return ERROR_OK; } -struct flash_driver rp2040_flash = { +const struct flash_driver rp2040_flash = { .name = "rp2040_flash", .flash_bank_command = rp2040_flash_bank_command, .erase = rp2040_flash_erase, diff --git a/src/flash/nor/stmqspi.c b/src/flash/nor/stmqspi.c index 77ea4c40d..c9fc1bffa 100644 --- a/src/flash/nor/stmqspi.c +++ b/src/flash/nor/stmqspi.c @@ -2447,7 +2447,7 @@ static const struct command_registration stmqspi_command_handlers[] = { COMMAND_REGISTRATION_DONE }; -struct flash_driver stmqspi_flash = { +const struct flash_driver stmqspi_flash = { .name = "stmqspi", .commands = stmqspi_command_handlers, .flash_bank_command = stmqspi_flash_bank_command, diff --git a/src/flash/nor/swm050.c b/src/flash/nor/swm050.c index 89e59ae47..dcf59d380 100644 --- a/src/flash/nor/swm050.c +++ b/src/flash/nor/swm050.c @@ -183,7 +183,7 @@ static const struct command_registration swm050_command_handlers[] = { COMMAND_REGISTRATION_DONE }; -struct flash_driver swm050_flash = { +const struct flash_driver swm050_flash = { .name = "swm050", .commands = swm050_command_handlers, .flash_bank_command = swm050_flash_bank_command, From 177bafd4cccf505df0d02ace0d235af78cac4d8a Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Mon, 1 May 2023 00:24:37 +0200 Subject: [PATCH 48/49] pld: move in pld.h the pld_driver's declaration The static analyser 'sparse' complains, while compiling a pld driver, that the struct pld_driver is declared in the file as non static, but it is not exposed through an include file. The message is: warning: symbol 'XXX' was not declared. Should it be static? Move the list of pld_driver's declaration in pld.h Change-Id: I0f917aecc7534c1b51af0afa9b32ccfd33db3511 Signed-off-by: Antonio Borneo Reviewed-on: https://review.openocd.org/c/openocd/+/7663 Tested-by: jenkins --- src/pld/pld.c | 9 --------- src/pld/pld.h | 7 +++++++ 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/src/pld/pld.c b/src/pld/pld.c index dd8f8263f..7dd2cec18 100644 --- a/src/pld/pld.c +++ b/src/pld/pld.c @@ -16,15 +16,6 @@ #include -/* pld drivers - */ -extern struct pld_driver efinix_pld; -extern struct pld_driver gatemate_pld; -extern struct pld_driver gowin_pld; -extern struct pld_driver intel_pld; -extern struct pld_driver lattice_pld; -extern struct pld_driver virtex2_pld; - static struct pld_driver *pld_drivers[] = { &efinix_pld, &gatemate_pld, diff --git a/src/pld/pld.h b/src/pld/pld.h index a7cd20f64..322b96ec6 100644 --- a/src/pld/pld.h +++ b/src/pld/pld.h @@ -38,4 +38,11 @@ struct pld_device *get_pld_device_by_num(int num); #define ERROR_PLD_DEVICE_INVALID (-1000) #define ERROR_PLD_FILE_LOAD_FAILED (-1001) +extern struct pld_driver efinix_pld; +extern struct pld_driver gatemate_pld; +extern struct pld_driver gowin_pld; +extern struct pld_driver intel_pld; +extern struct pld_driver lattice_pld; +extern struct pld_driver virtex2_pld; + #endif /* OPENOCD_PLD_PLD_H */ From e17fe4db0f256ee4fb97dcfd6b9f7f55c966b190 Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Mon, 1 May 2023 00:29:11 +0200 Subject: [PATCH 49/49] pld: validate exported functions by including its own .h Let source files to include its file .h to validate the exported prototypes. Detected through 'sparse' tool. Change-Id: I217c2903fdb19e1a2cce39d2536a903c3d72f3f7 Signed-off-by: Antonio Borneo Reviewed-on: https://review.openocd.org/c/openocd/+/7664 Tested-by: jenkins --- src/pld/certus.c | 1 + src/pld/ecp2_3.c | 1 + src/pld/ecp5.c | 1 + 3 files changed, 3 insertions(+) diff --git a/src/pld/certus.c b/src/pld/certus.c index 692ea1907..1309c1b27 100644 --- a/src/pld/certus.c +++ b/src/pld/certus.c @@ -9,6 +9,7 @@ #include "config.h" #endif +#include "certus.h" #include "lattice.h" #include "lattice_cmd.h" diff --git a/src/pld/ecp2_3.c b/src/pld/ecp2_3.c index 6826d0b4a..b1c2833d5 100644 --- a/src/pld/ecp2_3.c +++ b/src/pld/ecp2_3.c @@ -9,6 +9,7 @@ #include "config.h" #endif +#include "ecp2_3.h" #include "lattice.h" #define LSCC_REFRESH 0x23 diff --git a/src/pld/ecp5.c b/src/pld/ecp5.c index 298b55f4e..2e1009baa 100644 --- a/src/pld/ecp5.c +++ b/src/pld/ecp5.c @@ -9,6 +9,7 @@ #include "config.h" #endif +#include "ecp5.h" #include "lattice.h" #include "lattice_cmd.h"