You can subscribe to this list here.
| 2008 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
(75) |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 2009 |
Jan
(70) |
Feb
(20) |
Mar
(52) |
Apr
(149) |
May
(387) |
Jun
(466) |
Jul
(133) |
Aug
(87) |
Sep
(122) |
Oct
(140) |
Nov
(185) |
Dec
(105) |
| 2010 |
Jan
(85) |
Feb
(45) |
Mar
(75) |
Apr
(17) |
May
(41) |
Jun
(52) |
Jul
(33) |
Aug
(29) |
Sep
(36) |
Oct
(15) |
Nov
(26) |
Dec
(34) |
| 2011 |
Jan
(26) |
Feb
(25) |
Mar
(26) |
Apr
(29) |
May
(20) |
Jun
(27) |
Jul
(15) |
Aug
(32) |
Sep
(13) |
Oct
(64) |
Nov
(60) |
Dec
(10) |
| 2012 |
Jan
(64) |
Feb
(63) |
Mar
(39) |
Apr
(43) |
May
(54) |
Jun
(11) |
Jul
(30) |
Aug
(45) |
Sep
(11) |
Oct
(70) |
Nov
(24) |
Dec
(23) |
| 2013 |
Jan
(17) |
Feb
(8) |
Mar
(35) |
Apr
(40) |
May
(20) |
Jun
(24) |
Jul
(36) |
Aug
(25) |
Sep
(42) |
Oct
(40) |
Nov
(9) |
Dec
(21) |
| 2014 |
Jan
(29) |
Feb
(24) |
Mar
(60) |
Apr
(22) |
May
(22) |
Jun
(46) |
Jul
(11) |
Aug
(23) |
Sep
(26) |
Oct
(10) |
Nov
(14) |
Dec
(2) |
| 2015 |
Jan
(28) |
Feb
(47) |
Mar
(33) |
Apr
(58) |
May
(5) |
Jun
(1) |
Jul
|
Aug
(8) |
Sep
(12) |
Oct
(25) |
Nov
(58) |
Dec
(21) |
| 2016 |
Jan
(12) |
Feb
(40) |
Mar
(2) |
Apr
(1) |
May
(67) |
Jun
(2) |
Jul
(5) |
Aug
(36) |
Sep
|
Oct
(24) |
Nov
(17) |
Dec
(50) |
| 2017 |
Jan
(14) |
Feb
(16) |
Mar
(2) |
Apr
(35) |
May
(14) |
Jun
(16) |
Jul
(3) |
Aug
(3) |
Sep
|
Oct
(19) |
Nov
|
Dec
(16) |
| 2018 |
Jan
(55) |
Feb
(11) |
Mar
(34) |
Apr
(14) |
May
(4) |
Jun
(20) |
Jul
(39) |
Aug
(16) |
Sep
(17) |
Oct
(16) |
Nov
(20) |
Dec
(30) |
| 2019 |
Jan
(29) |
Feb
(24) |
Mar
(37) |
Apr
(26) |
May
(19) |
Jun
(21) |
Jul
(2) |
Aug
(3) |
Sep
(9) |
Oct
(12) |
Nov
(12) |
Dec
(12) |
| 2020 |
Jan
(47) |
Feb
(36) |
Mar
(54) |
Apr
(44) |
May
(37) |
Jun
(19) |
Jul
(32) |
Aug
(13) |
Sep
(16) |
Oct
(24) |
Nov
(32) |
Dec
(11) |
| 2021 |
Jan
(14) |
Feb
(5) |
Mar
(40) |
Apr
(32) |
May
(42) |
Jun
(31) |
Jul
(29) |
Aug
(47) |
Sep
(38) |
Oct
(17) |
Nov
(74) |
Dec
(33) |
| 2022 |
Jan
(11) |
Feb
(15) |
Mar
(40) |
Apr
(21) |
May
(39) |
Jun
(44) |
Jul
(19) |
Aug
(46) |
Sep
(79) |
Oct
(35) |
Nov
(21) |
Dec
(15) |
| 2023 |
Jan
(56) |
Feb
(13) |
Mar
(43) |
Apr
(28) |
May
(60) |
Jun
(15) |
Jul
(29) |
Aug
(28) |
Sep
(32) |
Oct
(21) |
Nov
(42) |
Dec
(39) |
| 2024 |
Jan
(35) |
Feb
(17) |
Mar
(28) |
Apr
(7) |
May
(14) |
Jun
(35) |
Jul
(30) |
Aug
(35) |
Sep
(30) |
Oct
(28) |
Nov
(38) |
Dec
(18) |
| 2025 |
Jan
(21) |
Feb
(28) |
Mar
(36) |
Apr
(35) |
May
(34) |
Jun
(58) |
Jul
(9) |
Aug
(54) |
Sep
(47) |
Oct
(15) |
Nov
(58) |
Dec
|
|
From: openocd-gerrit <ope...@us...> - 2023-05-05 22:08:06
|
This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "Main OpenOCD repository".
The branch, master has been updated
via 411dfa2409221259108b7cec99ac7824e53e3867 (commit)
from 682f927f8e4e6c6216c6d0b259b3c24b9f3f6342 (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commit 411dfa2409221259108b7cec99ac7824e53e3867
Author: Antonio Borneo <bor...@gm...>
Date: Sat Apr 8 23:19:50 2023 +0200
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 <bor...@gm...>
Reviewed-on: https://review.openocd.org/c/openocd/+/7591
Tested-by: jenkins
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 <sys/mman.h>
-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;
-----------------------------------------------------------------------
Summary of changes:
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(-)
hooks/post-receive
--
Main OpenOCD repository
|
|
From: openocd-gerrit <ope...@us...> - 2023-04-30 14:55:42
|
This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "Main OpenOCD repository".
The branch, master has been updated
via 682f927f8e4e6c6216c6d0b259b3c24b9f3f6342 (commit)
from 4b56c73ef3781c3232056b57be6d0d2ae3486a4a (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commit 682f927f8e4e6c6216c6d0b259b3c24b9f3f6342
Author: Daniel Anselmi <dan...@gm...>
Date: Fri Feb 24 15:57:30 2023 +0100
pld: add support for cologne chip gatemate fpgas
Change-Id: I0bf5a52ee6a7f0287524619114eba0cfccf6ac81
Signed-off-by: Daniel Anselmi <dan...@gm...>
Reviewed-on: https://review.openocd.org/c/openocd/+/7565
Tested-by: jenkins
Reviewed-by: Antonio Borneo <bor...@gm...>
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 *
+ * dan...@gm... *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <jtag/jtag.h>
+#include <jtag/adapter.h>
+#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
-----------------------------------------------------------------------
Summary of changes:
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
hooks/post-receive
--
Main OpenOCD repository
|
|
From: openocd-gerrit <ope...@us...> - 2023-04-30 14:55:11
|
This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "Main OpenOCD repository".
The branch, master has been updated
via 4b56c73ef3781c3232056b57be6d0d2ae3486a4a (commit)
via db0609aeb4d5c8dec607afb1e07f5083d3b242c3 (commit)
from 7c6d44644082eb33d91af62091c37ba1384555ad (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commit 4b56c73ef3781c3232056b57be6d0d2ae3486a4a
Author: Daniel Anselmi <dan...@gm...>
Date: Mon Dec 12 09:49:51 2022 +0100
pld: add support for gowin devices
Change-Id: Idd1a09514bbbbe0a7b54d69010f6c2f91215fd1d
Signed-off-by: Daniel Anselmi <dan...@gm...>
Reviewed-on: https://review.openocd.org/c/openocd/+/7368
Tested-by: jenkins
Reviewed-by: Antonio Borneo <bor...@gm...>
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 *
+ * dan...@gm... *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <jtag/jtag.h>
+#include <jtag/adapter.h>
+#include <helper/bits.h>
+#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
commit db0609aeb4d5c8dec607afb1e07f5083d3b242c3
Author: Daniel Anselmi <dan...@gm...>
Date: Mon Dec 12 09:49:51 2022 +0100
pld: add support for altera/intel devices
Change-Id: I7977d39c9037ae71139f78c8d381f5f925dc3489
Signed-off-by: Daniel Anselmi <dan...@gm...>
Reviewed-on: https://review.openocd.org/c/openocd/+/7355
Tested-by: jenkins
Reviewed-by: Antonio Borneo <bor...@gm...>
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 *
+ * dan...@gm... *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <jtag/jtag.h>
+#include <jtag/adapter.h>
+#include <helper/system.h>
+#include <helper/log.h>
+
+#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/fpga/altera-10m50.cfg b/tcl/cpld/altera-max10.cfg
similarity index 82%
copy from tcl/fpga/altera-10m50.cfg
copy to tcl/cpld/altera-max10.cfg
index 1937cb4b6..a2ed00ac8 100644
--- a/tcl/fpga/altera-10m50.cfg
+++ b/tcl/cpld/altera-max10.cfg
@@ -17,7 +17,13 @@
# Intel MAX 10M40 0x310d0dd
# Intel MAX 10M50 0x31050dd
-jtag newtap 10m50 tap -irlen 10 -expected-id 0x31810dd -expected-id 0x318a0dd \
+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 \
diff --git a/tcl/cpld/altera-epm240.cfg b/tcl/cpld/altera-maxii.cfg
similarity index 76%
copy from tcl/cpld/altera-epm240.cfg
copy to tcl/cpld/altera-maxii.cfg
index 39c409bc3..2dee37f41 100644
--- a/tcl/cpld/altera-epm240.cfg
+++ b/tcl/cpld/altera-maxii.cfg
@@ -1,11 +1,11 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# Altera MAXII EPM240T100C CPLD
+# Altera MAXII CPLD
if { [info exists CHIPNAME] } {
set _CHIPNAME $CHIPNAME
} else {
- set _CHIPNAME epm240
+ set _CHIPNAME maxii
}
# see MAX II Device Handbook
@@ -19,7 +19,3 @@ jtag newtap $_CHIPNAME tap -irlen 10 \
-expected-id 0x020a40dd \
-expected-id 0x020a50dd \
-expected-id 0x020a60dd
-
-# 200ns seems like a good speed
-# c.f. Table 5-34: MAX II JTAG Timing Parameters
-adapter speed 5000
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]
-----------------------------------------------------------------------
Summary of changes:
doc/openocd.texi | 35 ++
src/pld/Makefile.am | 2 +
src/pld/gowin.c | 581 +++++++++++++++++++++
src/pld/intel.c | 474 +++++++++++++++++
src/pld/pld.c | 4 +
tcl/board/bemicro_cycloneiii.cfg | 20 +
tcl/board/gowin_runber.cfg | 19 +
tcl/cpld/altera-5m570z-cpld.cfg | 13 +-
tcl/cpld/altera-epm240.cfg | 24 +-
.../altera-10m50.cfg => cpld/altera-max10.cfg} | 8 +-
tcl/cpld/{altera-epm240.cfg => altera-maxii.cfg} | 8 +-
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 +-
tcl/fpga/gowin_gw1n.cfg | 29 +
20 files changed, 1406 insertions(+), 56 deletions(-)
create mode 100644 src/pld/gowin.c
create mode 100644 src/pld/intel.c
create mode 100644 tcl/board/bemicro_cycloneiii.cfg
create mode 100644 tcl/board/gowin_runber.cfg
copy tcl/{fpga/altera-10m50.cfg => cpld/altera-max10.cfg} (82%)
copy tcl/cpld/{altera-epm240.cfg => altera-maxii.cfg} (76%)
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
create mode 100644 tcl/fpga/gowin_gw1n.cfg
hooks/post-receive
--
Main OpenOCD repository
|
|
From: openocd-gerrit <ope...@us...> - 2023-04-30 14:54:36
|
This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "Main OpenOCD repository".
The branch, master has been updated
via 7c6d44644082eb33d91af62091c37ba1384555ad (commit)
via e33eae340d3502ffab8c172c246bc392a093c2ea (commit)
from cf596a61db7ebace9cf097ffcb332e4de0679398 (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commit 7c6d44644082eb33d91af62091c37ba1384555ad
Author: Daniel Anselmi <dan...@gm...>
Date: Mon Dec 12 09:49:51 2022 +0100
pld: add support for efinix devices
Change-Id: Ie520e761c255ba1335d5aab9c6825f160a6151d9
Signed-off-by: Daniel Anselmi <dan...@gm...>
Reviewed-on: https://review.openocd.org/c/openocd/+/7288
Reviewed-by: Antonio Borneo <bor...@gm...>
Tested-by: jenkins
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 *
+ * dan...@gm... *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <jtag/jtag.h>
+
+#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
commit e33eae340d3502ffab8c172c246bc392a093c2ea
Author: Daniel Anselmi <dan...@gm...>
Date: Mon Dec 12 09:49:51 2022 +0100
pld: add support for lattice certus devices
Change-Id: Ic50a724e5793000fca11f35ba848c2d317c3cbab
Signed-off-by: Daniel Anselmi <dan...@gm...>
Reviewed-on: https://review.openocd.org/c/openocd/+/7398
Tested-by: jenkins
Reviewed-by: Antonio Borneo <bor...@gm...>
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 *
+ * dan...@gm... *
+ ***************************************************************************/
+
+#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 *
+ * dan...@gm... *
+ ***************************************************************************/
+
+#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
-----------------------------------------------------------------------
Summary of changes:
doc/openocd.texi | 10 +-
src/pld/Makefile.am | 3 +
src/pld/certus.c | 232 +++++++++++++++++++++++++++++++++++++
src/pld/certus.h | 18 +++
src/pld/efinix.c | 218 ++++++++++++++++++++++++++++++++++
src/pld/lattice.c | 83 +++++++++++--
src/pld/lattice.h | 4 +
src/pld/pld.c | 2 +
tcl/board/certuspro_evaluation.cfg | 14 +++
tcl/board/trion_t20_bga256.cfg | 24 ++++
tcl/fpga/efinix_titanium.cfg | 23 ++++
tcl/fpga/efinix_trion.cfg | 17 +++
tcl/fpga/lattice_certus.cfg | 18 +++
tcl/fpga/lattice_certuspro.cfg | 18 +++
14 files changed, 674 insertions(+), 10 deletions(-)
create mode 100644 src/pld/certus.c
create mode 100644 src/pld/certus.h
create mode 100644 src/pld/efinix.c
create mode 100644 tcl/board/certuspro_evaluation.cfg
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
create mode 100644 tcl/fpga/lattice_certus.cfg
create mode 100644 tcl/fpga/lattice_certuspro.cfg
hooks/post-receive
--
Main OpenOCD repository
|
|
From: openocd-gerrit <ope...@us...> - 2023-04-30 14:54:12
|
This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "Main OpenOCD repository".
The branch, master has been updated
via cf596a61db7ebace9cf097ffcb332e4de0679398 (commit)
from d35faaa35cd5d56fa946d194d7cf780127a3f8c8 (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commit cf596a61db7ebace9cf097ffcb332e4de0679398
Author: Daniel Anselmi <dan...@gm...>
Date: Mon Dec 12 09:49:51 2022 +0100
pld: add support for lattice ecp5 devices
Change-Id: Ib2f0933da3abe7429abca86d6aaa50ad85ce72c7
Signed-off-by: Daniel Anselmi <dan...@gm...>
Reviewed-on: https://review.openocd.org/c/openocd/+/7397
Reviewed-by: Antonio Borneo <bor...@gm...>
Tested-by: jenkins
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 *
+ * dan...@gm... *
+ ***************************************************************************/
+
+#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 *
+ * dan...@gm... *
+ ***************************************************************************/
+
+#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 *
+ * dan...@gm... *
+ ***************************************************************************/
+
+#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
-----------------------------------------------------------------------
Summary of changes:
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/{raw_bit.h => lattice_cmd.h} | 22 ++--
tcl/board/ecp5_evaluation.cfg | 19 ++++
tcl/fpga/lattice_ecp5.cfg | 2 +
8 files changed, 288 insertions(+), 15 deletions(-)
create mode 100644 src/pld/ecp5.c
create mode 100644 src/pld/ecp5.h
copy src/pld/{raw_bit.h => lattice_cmd.h} (51%)
create mode 100644 tcl/board/ecp5_evaluation.cfg
hooks/post-receive
--
Main OpenOCD repository
|
|
From: openocd-gerrit <ope...@us...> - 2023-04-30 14:53:55
|
This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "Main OpenOCD repository".
The branch, master has been updated
via d35faaa35cd5d56fa946d194d7cf780127a3f8c8 (commit)
from 8670ad4caa705c460972badbd0fc28aa98c41866 (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commit d35faaa35cd5d56fa946d194d7cf780127a3f8c8
Author: Daniel Anselmi <dan...@gm...>
Date: Mon Dec 12 09:49:51 2022 +0100
pld: add support for lattice ecp2 and ecp3 devices
Change-Id: I29c227c37be464f7ecc97a30d9cf3da1442e2b7f
Signed-off-by: Daniel Anselmi <dan...@gm...>
Reviewed-on: https://review.openocd.org/c/openocd/+/7396
Reviewed-by: Antonio Borneo <bor...@gm...>
Tested-by: jenkins
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 *
+ * dan...@gm... *
+ ***************************************************************************/
+
+#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 *
+ * dan...@gm... *
+ ***************************************************************************/
+
+#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 *
+ * dan...@gm... *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "lattice.h"
+#include <jtag/jtag.h>
+#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 *
+ * dan...@gm... *
+ ***************************************************************************/
+
+#ifndef OPENOCD_PLD_LATTICE_H
+#define OPENOCD_PLD_LATTICE_H
+
+#include <jtag/jtag.h>
+#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 *
+ * dan...@gm... *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "lattice_bit.h"
+#include "raw_bit.h"
+#include "pld.h"
+#include <helper/system.h>
+#include <helper/log.h>
+#include <helper/binarybuffer.h>
+
+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 *
+ * dan...@gm... *
+ ***************************************************************************/
+
+#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 *
+ * dan...@gm... *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "raw_bit.h"
+#include "pld.h"
+
+#include <helper/system.h>
+#include <helper/log.h>
+
+
+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 *
+ * dan...@gm... *
+ ***************************************************************************/
+
+#ifndef OPENOCD_PLD_RAW_BIN_H
+#define OPENOCD_PLD_RAW_BIN_H
+
+#include <stddef.h>
+#include <stdint.h>
+
+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
-----------------------------------------------------------------------
Summary of changes:
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
hooks/post-receive
--
Main OpenOCD repository
|
|
From: openocd-gerrit <ope...@us...> - 2023-04-30 14:53:22
|
This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "Main OpenOCD repository".
The branch, master has been updated
via 8670ad4caa705c460972badbd0fc28aa98c41866 (commit)
via c1dc7935f78973e89dfe10e5b93238ae3f4eacd3 (commit)
from bb073f897cd37a6253e49c5628a98a59fccf2ea5 (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commit 8670ad4caa705c460972badbd0fc28aa98c41866
Author: Antonio Borneo <bor...@gm...>
Date: Sat Apr 15 00:25:54 2023 +0200
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 <bor...@gm...>
Fixes: 8d1dcf293a0c ("target/espressif: add application tracing functionality over JTAG")
Reviewed-on: https://review.openocd.org/c/openocd/+/7608
Reviewed-by: Erhan Kurubas <erh...@es...>
Tested-by: jenkins
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;
}
commit c1dc7935f78973e89dfe10e5b93238ae3f4eacd3
Author: Antonio Borneo <bor...@gm...>
Date: Sat Apr 15 00:21:42 2023 +0200
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 <bor...@gm...>
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 <erh...@es...>
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;
-----------------------------------------------------------------------
Summary of changes:
src/target/espressif/esp32_apptrace.c | 16 ++++++----------
src/target/espressif/esp_xtensa_apptrace.c | 6 ++++--
2 files changed, 10 insertions(+), 12 deletions(-)
hooks/post-receive
--
Main OpenOCD repository
|
|
From: openocd-gerrit <ope...@us...> - 2023-04-30 14:52:07
|
This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "Main OpenOCD repository".
The branch, master has been updated
via bb073f897cd37a6253e49c5628a98a59fccf2ea5 (commit)
from babec0fafa7141515c606790947f66bde46396b8 (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commit bb073f897cd37a6253e49c5628a98a59fccf2ea5
Author: Erhan Kurubas <erh...@es...>
Date: Sun Apr 2 00:26:51 2023 +0200
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 <erh...@es...>
Change-Id: I1cf14b8e5e3e732ebc9cacc4b1cb9009276a8ea9
Reviewed-on: https://review.openocd.org/c/openocd/+/7569
Reviewed-by: Antonio Borneo <bor...@gm...>
Tested-by: jenkins
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);
}
-----------------------------------------------------------------------
Summary of changes:
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(-)
hooks/post-receive
--
Main OpenOCD repository
|
|
From: openocd-gerrit <ope...@us...> - 2023-04-30 14:51:39
|
This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "Main OpenOCD repository".
The branch, master has been updated
via babec0fafa7141515c606790947f66bde46396b8 (commit)
from 3dfc0339fc85d467bed5cd435bb953bc7d3b9343 (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commit babec0fafa7141515c606790947f66bde46396b8
Author: Daniel Anselmi <dan...@gm...>
Date: Tue Apr 11 10:18:33 2023 +0200
server/ipdbg: add error checks after allocating memory
Change-Id: Icf18a855eb66d2b09789a9ee27f5fbc4cd9afc89
Signed-off-by: Daniel Anselmi <dan...@gm...>
Reviewed-on: https://review.openocd.org/c/openocd/+/7605
Tested-by: jenkins
Reviewed-by: Antonio Borneo <bor...@gm...>
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);
-----------------------------------------------------------------------
Summary of changes:
src/server/ipdbg.c | 23 ++++++++++++++++++++++-
1 file changed, 22 insertions(+), 1 deletion(-)
hooks/post-receive
--
Main OpenOCD repository
|
|
From: openocd-gerrit <ope...@us...> - 2023-04-30 14:51:00
|
This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "Main OpenOCD repository".
The branch, master has been updated
via 3dfc0339fc85d467bed5cd435bb953bc7d3b9343 (commit)
from 2096afc1b031280107ada81fb729d5e7c9075626 (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commit 3dfc0339fc85d467bed5cd435bb953bc7d3b9343
Author: Julien Massot <jul...@io...>
Date: Wed Jan 12 09:53:06 2022 +0100
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 <jul...@io...>
Change-Id: I663ae4bf1d3026d7c9e4c5950a79e7ddf1bd6564
Reviewed-on: https://review.openocd.org/c/openocd/+/6805
Tested-by: jenkins
Reviewed-by: Antonio Borneo <bor...@gm...>
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
}
-----------------------------------------------------------------------
Summary of changes:
tcl/target/renesas_rcar_gen3.cfg | 21 +++++++++++++--------
1 file changed, 13 insertions(+), 8 deletions(-)
hooks/post-receive
--
Main OpenOCD repository
|
|
From: openocd-gerrit <ope...@us...> - 2023-04-30 14:50:27
|
This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "Main OpenOCD repository".
The branch, master has been updated
via 2096afc1b031280107ada81fb729d5e7c9075626 (commit)
from 0bb0056abc269ed14b04cbb1d768fb0281e64225 (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commit 2096afc1b031280107ada81fb729d5e7c9075626
Author: Julien Massot <jul...@io...>
Date: Tue Feb 1 13:44:05 2022 +0100
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 <jul...@io...>
Change-Id: Ib086f71685d1e3704b396d478ae9399dd8a391e1
Reviewed-on: https://review.openocd.org/c/openocd/+/6843
Tested-by: jenkins
Reviewed-by: Antonio Borneo <bor...@gm...>
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,
};
-----------------------------------------------------------------------
Summary of changes:
src/target/aarch64.c | 72 +++++++++++++++++++++++++++++++++++++++++++++++++---
src/target/armv8.h | 1 +
src/target/target.c | 2 ++
3 files changed, 71 insertions(+), 4 deletions(-)
hooks/post-receive
--
Main OpenOCD repository
|
|
From: openocd-gerrit <ope...@us...> - 2023-04-30 14:46:56
|
This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "Main OpenOCD repository".
The branch, master has been updated
via 0bb0056abc269ed14b04cbb1d768fb0281e64225 (commit)
from 91bd4313444c5a949ce49d88ab487608df7d6c37 (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commit 0bb0056abc269ed14b04cbb1d768fb0281e64225
Author: Julien Massot <jul...@io...>
Date: Wed Jan 12 14:10:36 2022 +0100
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 <jul...@io...>
Change-Id: I41d1006233251dcaf6d69bda580488b204b7eb63
Reviewed-on: https://review.openocd.org/c/openocd/+/6807
Tested-by: jenkins
Reviewed-by: Antonio Borneo <bor...@gm...>
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);
-----------------------------------------------------------------------
Summary of changes:
src/target/armv8_dpm.c | 3 +++
1 file changed, 3 insertions(+)
hooks/post-receive
--
Main OpenOCD repository
|
|
From: openocd-gerrit <ope...@us...> - 2023-04-14 15:19:15
|
This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "Main OpenOCD repository".
The branch, master has been updated
via 91bd4313444c5a949ce49d88ab487608df7d6c37 (commit)
from 95c27731d4f76c0554147030075ab476d68f9f83 (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commit 91bd4313444c5a949ce49d88ab487608df7d6c37
Author: Daniel Anselmi <dan...@gm...>
Date: Wed Dec 14 09:27:38 2022 +0100
pld: move file sanity checks to pld.c
Change-Id: Id64b1165b25a03634949ac22b8af16eb0e24c1fa
Signed-off-by: Daniel Anselmi <dan...@gm...>
Reviewed-on: https://review.openocd.org/c/openocd/+/7388
Tested-by: jenkins
Reviewed-by: Antonio Borneo <bor...@gm...>
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 <sys/stat.h>
#include <helper/log.h>
#include <helper/replacements.h>
#include <helper/time_support.h>
@@ -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 <helper/log.h>
-#include <sys/stat.h>
#include <helper/system.h>
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));
-----------------------------------------------------------------------
Summary of changes:
src/pld/pld.c | 17 +++++++++++++++++
src/pld/xilinx_bit.c | 17 -----------------
2 files changed, 17 insertions(+), 17 deletions(-)
hooks/post-receive
--
Main OpenOCD repository
|
|
From: openocd-gerrit <ope...@us...> - 2023-04-14 15:17:42
|
This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "Main OpenOCD repository".
The branch, master has been updated
via 95c27731d4f76c0554147030075ab476d68f9f83 (commit)
from 1e6df1675ccea95d99d767e6d2b9a735c8ee2a36 (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commit 95c27731d4f76c0554147030075ab476d68f9f83
Author: Mark Zhuang <mar...@sp...>
Date: Mon Apr 10 10:57:55 2023 +0800
flash/rsl10: fix typo
Change-Id: I11af37309fe4684fcb340a00fcc7b2096b8dad76
Signed-off-by: Mark Zhuang <mar...@sp...>
Reviewed-on: https://review.openocd.org/c/openocd/+/7584
Tested-by: jenkins
Reviewed-by: Antonio Borneo <bor...@gm...>
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
-----------------------------------------------------------------------
Summary of changes:
contrib/loaders/flash/rsl10/rom_launcher.S | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
hooks/post-receive
--
Main OpenOCD repository
|
|
From: openocd-gerrit <ope...@us...> - 2023-04-14 15:17:07
|
This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "Main OpenOCD repository".
The branch, master has been updated
via 1e6df1675ccea95d99d767e6d2b9a735c8ee2a36 (commit)
from 1c31f6225f41dd2bd371571e829fbf6855788d24 (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commit 1e6df1675ccea95d99d767e6d2b9a735c8ee2a36
Author: panciyan <pan...@es...>
Date: Sun Apr 2 05:17:17 2023 +0000
rtos/linux.c: Fix Linux user space border check
Linux kernel and user space border is 0xc0000000 not 0xc000000
Signed-off-by: panciyan <pan...@es...>
Change-Id: I6b487cce62ac31737deca97d5f5f7bbc081280f4
Reviewed-on: https://review.openocd.org/c/openocd/+/7570
Tested-by: jenkins
Reviewed-by: Antonio Borneo <bor...@gm...>
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;
}
-----------------------------------------------------------------------
Summary of changes:
src/rtos/linux.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
hooks/post-receive
--
Main OpenOCD repository
|
|
From: openocd-gerrit <ope...@us...> - 2023-04-14 15:16:49
|
This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "Main OpenOCD repository".
The branch, master has been updated
via 1c31f6225f41dd2bd371571e829fbf6855788d24 (commit)
from 8d1dcf293a0cee71b264787c65749de3f6c4d8bc (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commit 1c31f6225f41dd2bd371571e829fbf6855788d24
Author: panciyan <pan...@es...>
Date: Fri Mar 31 15:12:08 2023 +0000
src/server: Fix memory leak of reg_list
memory leak of reg_list when local_list realloc fail.
Signed-off-by: panciyan <pan...@es...>
Change-Id: I6b09137ecd132ab326205f5a575a38bcc82e8469
Reviewed-on: https://review.openocd.org/c/openocd/+/7566
Tested-by: jenkins
Reviewed-by: Antonio Borneo <bor...@gm...>
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;
}
}
-----------------------------------------------------------------------
Summary of changes:
src/server/gdb_server.c | 1 +
1 file changed, 1 insertion(+)
hooks/post-receive
--
Main OpenOCD repository
|
|
From: openocd-gerrit <ope...@us...> - 2023-04-14 15:16:22
|
This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "Main OpenOCD repository".
The branch, master has been updated
via 8d1dcf293a0cee71b264787c65749de3f6c4d8bc (commit)
from 0384fe5d596f42388f8b84d42959d899f29388ab (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commit 8d1dcf293a0cee71b264787c65749de3f6c4d8bc
Author: Erhan Kurubas <erh...@es...>
Date: Thu Aug 25 15:38:34 2022 +0300
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 <erh...@es...>
Change-Id: I95dee00ac22891fa326915a3fcac3c088cbb2afc
Reviewed-on: https://review.openocd.org/c/openocd/+/7163
Tested-by: jenkins
Reviewed-by: Antonio Borneo <bor...@gm...>
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 <destination> [<poll_period> [<trace_size> [<stop_tmo> [<wait4halt> [<skip_size>]]]]])
+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://<outfile>} - Save trace logs into file.
+@item @code{tcp://<host>:<port>} - 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://<outfile>)
+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 <arpa/inet.h>
+#endif
+
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+
+#ifndef _WIN32
+#include <netinet/tcp.h>
+#include <sys/ioctl.h>
+#endif
+
+#include <helper/list.h>
+#include <helper/time_support.h>
+#include <target/target.h>
+#include <target/target_type.h>
+#include <target/smp.h>
+#include <server/server.h>
+#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 <destination> [poll_period [trace_size [stop_tmo [wait4halt [skip_size]]]]] | [stop] | [status] | [dump <destination>]",
+ },
+ 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 <helper/command.h>
+#include <helper/time_support.h>
+#include <target/target.h>
+
+#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 <stdbool.h>
#include <stdint.h>
#include <target/smp.h>
+#include "esp_xtensa_apptrace.h"
#include <target/register.h>
#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 <target/xtensa/xtensa.h>
#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 <helper/align.h>
+#include <target/xtensa/xtensa.h>
+#include <target/xtensa/xtensa_debug_module.h>
+#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_...
[truncated message content] |
|
From: openocd-gerrit <ope...@us...> - 2023-04-14 15:15:37
|
This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "Main OpenOCD repository".
The branch, master has been updated
via 0384fe5d596f42388f8b84d42959d899f29388ab (commit)
from ffd9638bdb04fb3021a20f78330c4692a2ebab6a (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commit 0384fe5d596f42388f8b84d42959d899f29388ab
Author: Tomas Vanek <va...@fb...>
Date: Tue Apr 4 13:03:59 2023 +0200
doc: drop "resume will wait 5 seconds"
Checkpatch-ignore: GIT_COMMIT_ID
Waiting for running state was removed from handle_resume_command()
in commit a92d27afb073 ("very long and bad structured commit msg
without anything relevant to resume") around year 2008.
Update the doc accordingly.
Silent checkpatch or we have to copy 10 or more lines
of the old commit msg.
Signed-off-by: Tomas Vanek <va...@fb...>
Change-Id: I3296cb2c29cf80aeed63eddd8fbf352edec778c1
Reviewed-on: https://review.openocd.org/c/openocd/+/7579
Tested-by: jenkins
Reviewed-by: Antonio Borneo <bor...@gm...>
diff --git a/doc/openocd.texi b/doc/openocd.texi
index 67661845d..fe72cf5fa 100644
--- a/doc/openocd.texi
+++ b/doc/openocd.texi
@@ -8780,7 +8780,6 @@ power consumption (because the CPU is needlessly clocked).
@deffn {Command} {resume} [address]
Resume the target at its current code position,
or the optional @var{address} if it is provided.
-OpenOCD will wait 5 seconds for the target to resume.
@end deffn
@deffn {Command} {step} [address]
-----------------------------------------------------------------------
Summary of changes:
doc/openocd.texi | 1 -
1 file changed, 1 deletion(-)
hooks/post-receive
--
Main OpenOCD repository
|
|
From: openocd-gerrit <ope...@us...> - 2023-04-14 15:12:00
|
This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "Main OpenOCD repository".
The branch, master has been updated
via ffd9638bdb04fb3021a20f78330c4692a2ebab6a (commit)
from e87fa5e3ab424d3ccd66eeddccfbe1e0181e20d0 (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commit ffd9638bdb04fb3021a20f78330c4692a2ebab6a
Author: Daniel Anselmi <dan...@gm...>
Date: Wed Nov 30 04:05:44 2022 +0100
tcl: cpld/xilinx-xc7: remove virtex-7 devices with ir-length > 6
They have an ir length of 22, 24 or 38 bit and different command codes.
Change-Id: I488e8613f1c4d017e1590111f60b2725ec62964b
Signed-off-by: Daniel Anselmi <dan...@gm...>
Reviewed-on: https://review.openocd.org/c/openocd/+/7387
Tested-by: jenkins
Reviewed-by: Antonio Borneo <bor...@gm...>
diff --git a/tcl/cpld/xilinx-xc7.cfg b/tcl/cpld/xilinx-xc7.cfg
index 22e0aea7f..91a07f9eb 100644
--- a/tcl/cpld/xilinx-xc7.cfg
+++ b/tcl/cpld/xilinx-xc7.cfg
@@ -33,19 +33,21 @@ jtag newtap $_CHIPNAME tap -irlen 6 -ignore-version \
-expected-id 0x03752093 \
-expected-id 0x03751093 \
-expected-id 0x03671093 \
- -expected-id 0x036B3093 \
- -expected-id 0x036B7093 \
- -expected-id 0x036BB093 \
- -expected-id 0x036BF093 \
-expected-id 0x03667093 \
-expected-id 0x03682093 \
-expected-id 0x03687093 \
-expected-id 0x03692093 \
-expected-id 0x03691093 \
- -expected-id 0x03696093 \
- -expected-id 0x036D5093 \
- -expected-id 0x036D9093 \
- -expected-id 0x036DB093
+ -expected-id 0x03696093
+
+#jtag newtap $_CHIPNAME tap -irlen 24 -ignore-version \
+# -expected-id 0x036B3093 -expected-id 0x036B7093 \
+# -expected-id 0x036BB093 -expected-id 0x036BF093 \
+# -expected-id 0x036D5093
+
+#jtag newtap $_CHIPNAME tap -irlen 22 -ignore-version -expected-id 0x036D9093
+
+#jtag newtap $_CHIPNAME tap -irlen 38 -ignore-version -expected-id 0x036DB093
pld device virtex2 $_CHIPNAME.tap 1
-----------------------------------------------------------------------
Summary of changes:
tcl/cpld/xilinx-xc7.cfg | 18 ++++++++++--------
1 file changed, 10 insertions(+), 8 deletions(-)
hooks/post-receive
--
Main OpenOCD repository
|
|
From: openocd-gerrit <ope...@us...> - 2023-04-14 15:10:17
|
This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "Main OpenOCD repository".
The branch, master has been updated
via e87fa5e3ab424d3ccd66eeddccfbe1e0181e20d0 (commit)
from 561f27fde9dc51f014b672c227dc7c8ca2530fcf (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commit e87fa5e3ab424d3ccd66eeddccfbe1e0181e20d0
Author: Daniel Anselmi <dan...@gm...>
Date: Wed Nov 30 03:42:18 2022 +0100
tcl: zynq_7000: add missing id codes
Add missing ID codes and ignore the version in the ID.
Change-Id: Idd2d3a5eddb6995f3af1c45afd2adf76ce3442bf
Signed-off-by: Daniel Anselmi <dan...@gm...>
Reviewed-on: https://review.openocd.org/c/openocd/+/7386
Tested-by: jenkins
Reviewed-by: Tomas Vanek <va...@fb...>
diff --git a/tcl/target/zynq_7000.cfg b/tcl/target/zynq_7000.cfg
index 0272587c1..a6f899541 100644
--- a/tcl/target/zynq_7000.cfg
+++ b/tcl/target/zynq_7000.cfg
@@ -1,18 +1,34 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-#
# Xilinx Zynq-7000 All Programmable SoC
#
# http://www.xilinx.com/products/silicon-devices/soc/zynq-7000/index.htm
+# https://www.xilinx.com/member/forms/download/sim-model-eval-license-xef.html?filename=bsdl_zynq_2.zip
#
+# 0x03736093 XQ7Z100 XC7Z100I XC7Z100
+# 0x03731093 XQ7Z045 XC7Z045I XC7Z045
+# 0x0372c093 XQ7Z030 XC7Z030I XC7Z030 XA7Z030
+# 0x03727093 XQ7Z020 XC7Z020I XC7Z020 XA7Z020
+# 0x03732093 XC7Z035I XC7Z035
+# 0x0373b093 XC7Z015I XC7Z015
+# 0x03728093 XC7Z014S
+# 0x0373c093 XC7Z012S
+# 0x03722093 XC7Z010I XC7Z010 XA7Z010
+# 0x03723093 XC7Z007S
set _CHIPNAME zynq
set _TARGETNAME $_CHIPNAME.cpu
-jtag newtap zynq_pl bs -irlen 6 -ircapture 0x1 -irmask 0x03 \
- -expected-id 0x23727093 \
- -expected-id 0x13722093 \
+jtag newtap zynq_pl bs -irlen 6 -ignore-version -ircapture 0x1 -irmask 0x03 \
+ -expected-id 0x03723093 \
+ -expected-id 0x03722093 \
+ -expected-id 0x0373c093 \
+ -expected-id 0x03728093 \
+ -expected-id 0x0373B093 \
+ -expected-id 0x03732093 \
-expected-id 0x03727093 \
+ -expected-id 0x0372C093 \
+ -expected-id 0x03731093 \
-expected-id 0x03736093
jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id 0x4ba00477
-----------------------------------------------------------------------
Summary of changes:
tcl/target/zynq_7000.cfg | 24 ++++++++++++++++++++----
1 file changed, 20 insertions(+), 4 deletions(-)
hooks/post-receive
--
Main OpenOCD repository
|
|
From: openocd-gerrit <ope...@us...> - 2023-04-07 23:02:20
|
This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "Main OpenOCD repository".
The branch, master has been updated
via 561f27fde9dc51f014b672c227dc7c8ca2530fcf (commit)
from 7e0797d19ac1837e3001df9d45030b5eb97ca36d (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commit 561f27fde9dc51f014b672c227dc7c8ca2530fcf
Author: Antonio Borneo <bor...@gm...>
Date: Sun Apr 2 14:24:23 2023 +0200
helper/compiler fix build with gcc on MacOS
On MacOS libc includes files from MacOSX.sdk that define the macro
#define __nonnull
without arguments, causing compile error.
Extend the existing check for clang on MacOS and undefine the
macro for gcc too.
Change-Id: Ic99de78348c6aa86561212a3aded9342e5d32e02
Signed-off-by: Antonio Borneo <bor...@gm...>
Reported-by: Erhan Kurubas <erh...@es...>
Reviewed-on: https://review.openocd.org/c/openocd/+/7571
Reviewed-by: Erhan Kurubas <erh...@es...>
Tested-by: jenkins
diff --git a/src/helper/compiler.h b/src/helper/compiler.h
index 33a075d64..312d261fc 100644
--- a/src/helper/compiler.h
+++ b/src/helper/compiler.h
@@ -36,9 +36,11 @@
* clang for Apple defines
* #define __nonnull _Nonnull
* that is a per argument attribute, incompatible with the gcc per function attribute __nonnull__.
- * Undefine it to keep compatibility among compilers.
+ * gcc for Apple includes sys/cdefs.h from MacOSX.sdk that defines
+ * #define __nonnull
+ * In both cases, undefine __nonnull to keep compatibility among compilers and platforms.
*/
-#if defined(__clang__) && defined(__APPLE__)
+#if defined(__APPLE__)
# undef __nonnull
#endif
#ifndef __nonnull
-----------------------------------------------------------------------
Summary of changes:
src/helper/compiler.h | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
hooks/post-receive
--
Main OpenOCD repository
|
|
From: openocd-gerrit <ope...@us...> - 2023-04-07 21:50:21
|
This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "Main OpenOCD repository".
The branch, master has been updated
via 7e0797d19ac1837e3001df9d45030b5eb97ca36d (commit)
from c8de1b82ec7f74c0717bfa0094f5fb6b79fbbfaf (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commit 7e0797d19ac1837e3001df9d45030b5eb97ca36d
Author: Daniel Anselmi <dan...@gm...>
Date: Wed Dec 14 12:51:48 2022 +0100
ipdbg: whitespaces
Change-Id: I9294c551cf2e795ad5e3e92dc3926c564424e067
Signed-off-by: Daniel Anselmi <dan...@gm...>
Reviewed-on: https://review.openocd.org/c/openocd/+/7399
Tested-by: jenkins
Reviewed-by: Jonathan McDowell <noo...@ea...>
Reviewed-by: Antonio Borneo <bor...@gm...>
diff --git a/src/server/ipdbg.c b/src/server/ipdbg.c
index f4a6f6cdc..755d0510e 100644
--- a/src/server/ipdbg.c
+++ b/src/server/ipdbg.c
@@ -90,7 +90,7 @@ static void ipdbg_zero_rd_idx(struct ipdbg_fifo *fifo)
return;
size_t ri = fifo->rd_idx;
- for (size_t idx = 0 ; idx < fifo->count ; ++idx)
+ for (size_t idx = 0; idx < fifo->count; ++idx)
fifo->buffer[idx] = fifo->buffer[ri++];
fifo->rd_idx = 0;
}
@@ -149,7 +149,7 @@ static int ipdbg_max_tools_from_data_register_length(uint8_t data_register_lengt
static struct ipdbg_service *ipdbg_find_service(struct ipdbg_hub *hub, uint8_t tool)
{
struct ipdbg_service *service;
- for (service = ipdbg_first_service ; service ; service = service->next) {
+ for (service = ipdbg_first_service; service; service = service->next) {
if (service->hub == hub && service->tool == tool)
break;
}
@@ -160,7 +160,7 @@ static void ipdbg_add_service(struct ipdbg_service *service)
{
struct ipdbg_service *iservice;
if (ipdbg_first_service) {
- for (iservice = ipdbg_first_service ; iservice->next; iservice = iservice->next)
+ for (iservice = ipdbg_first_service; iservice->next; iservice = iservice->next)
;
iservice->next = service;
} else
@@ -192,7 +192,7 @@ static int ipdbg_remove_service(struct ipdbg_service *service)
return ERROR_OK;
}
- for (struct ipdbg_service *iservice = ipdbg_first_service ; iservice->next ; iservice = iservice->next) {
+ for (struct ipdbg_service *iservice = ipdbg_first_service; iservice->next; iservice = iservice->next) {
if (service == iservice->next) {
iservice->next = service->next;
return ERROR_OK;
@@ -205,7 +205,7 @@ static struct ipdbg_hub *ipdbg_find_hub(struct jtag_tap *tap,
uint32_t user_instruction, struct ipdbg_virtual_ir_info *virtual_ir)
{
struct ipdbg_hub *hub = NULL;
- for (hub = ipdbg_first_hub ; hub ; hub = hub->next) {
+ for (hub = ipdbg_first_hub; hub; hub = hub->next) {
if (hub->tap == tap && hub->user_instruction == user_instruction) {
if ((!virtual_ir && !hub->virtual_ir) ||
(virtual_ir && hub->virtual_ir &&
@@ -223,7 +223,7 @@ static void ipdbg_add_hub(struct ipdbg_hub *hub)
{
struct ipdbg_hub *ihub;
if (ipdbg_first_hub) {
- for (ihub = ipdbg_first_hub ; ihub->next; ihub = ihub->next)
+ for (ihub = ipdbg_first_hub; ihub->next; ihub = ihub->next)
;
ihub->next = hub;
} else
@@ -281,7 +281,7 @@ static int ipdbg_remove_hub(struct ipdbg_hub *hub)
return ERROR_OK;
}
- for (struct ipdbg_hub *ihub = ipdbg_first_hub ; ihub->next ; ihub = ihub->next) {
+ for (struct ipdbg_hub *ihub = ipdbg_first_hub; ihub->next; ihub = ihub->next) {
if (hub == ihub->next) {
ihub->next = hub->next;
return ERROR_OK;
@@ -447,7 +447,7 @@ static int ipdbg_polling_callback(void *priv)
/* transfer dn buffers to jtag-hub */
unsigned int num_transfers = 0;
- for (size_t tool = 0 ; tool < hub->max_tools ; ++tool) {
+ for (size_t tool = 0; tool < hub->max_tools; ++tool) {
struct connection *conn = hub->connections[tool];
if (conn && conn->priv) {
struct ipdbg_connection *connection = conn->priv;
@@ -475,7 +475,7 @@ static int ipdbg_polling_callback(void *priv)
}
/* write from up fifos to sockets */
- for (size_t tool = 0 ; tool < hub->max_tools ; ++tool) {
+ for (size_t tool = 0; tool < hub->max_tools; ++tool) {
struct connection *conn = hub->connections[tool];
if (conn && conn->priv) {
struct ipdbg_connection *connection = conn->priv;
-----------------------------------------------------------------------
Summary of changes:
src/server/ipdbg.c | 18 +++++++++---------
1 file changed, 9 insertions(+), 9 deletions(-)
hooks/post-receive
--
Main OpenOCD repository
|
|
From: openocd-gerrit <ope...@us...> - 2023-04-07 21:47:59
|
This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "Main OpenOCD repository".
The branch, master has been updated
via c8de1b82ec7f74c0717bfa0094f5fb6b79fbbfaf (commit)
from 90ce9da644d751466d8dc451d7d2a043cdbf7d72 (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commit c8de1b82ec7f74c0717bfa0094f5fb6b79fbbfaf
Author: Antonio Borneo <bor...@gm...>
Date: Tue Mar 14 15:20:14 2023 +0100
helper/list: re-align with Linux kernel 6.3-rc1
Minor changes due to kernel switch to 100 char/line.
Added four new functions.
Silent checkpatch; we don't want to diverge from Linux reference
code.
Checkpatch-ignore: MACRO_ARG_REUSE, UNNECESSARY_PARENTHESES
Checkpatch-ignore: MACRO_ARG_PRECEDENCE
Change-Id: I1d2ff25bf3bab8cd0f5c9be55c7501795490ea75
Signed-off-by: Antonio Borneo <bor...@gm...>
Reviewed-on: https://review.openocd.org/c/openocd/+/7568
Tested-by: jenkins
Reviewed-by: Tomas Vanek <va...@fb...>
diff --git a/src/helper/list.h b/src/helper/list.h
index 396ff06c9..c9de0569b 100644
--- a/src/helper/list.h
+++ b/src/helper/list.h
@@ -265,8 +265,7 @@ static inline void list_bulk_move_tail(struct list_head *head,
* @param list the entry to test
* @param head the head of the list
*/
-static inline int list_is_first(const struct list_head *list,
- const struct list_head *head)
+static inline int list_is_first(const struct list_head *list, const struct list_head *head)
{
return list->prev == head;
}
@@ -276,12 +275,21 @@ static inline int list_is_first(const struct list_head *list,
* @param list the entry to test
* @param head the head of the list
*/
-static inline int list_is_last(const struct list_head *list,
- const struct list_head *head)
+static inline int list_is_last(const struct list_head *list, const struct list_head *head)
{
return list->next == head;
}
+/**
+ * list_is_head - tests whether @a list is the list @a head
+ * @param list the entry to test
+ * @param head the head of the list
+ */
+static inline int list_is_head(const struct list_head *list, const struct list_head *head)
+{
+ return list == head;
+}
+
/**
* list_empty - tests whether a list is empty
* @param head the list to test.
@@ -400,10 +408,9 @@ static inline void list_cut_position(struct list_head *list,
{
if (list_empty(head))
return;
- if (list_is_singular(head) &&
- (head->next != entry && head != entry))
+ if (list_is_singular(head) && !list_is_head(entry, head) && (entry != head->next))
return;
- if (entry == head)
+ if (list_is_head(entry, head))
INIT_LIST_HEAD(list);
else
__list_cut_position(list, head, entry);
@@ -563,6 +570,19 @@ static inline void list_splice_tail_init(struct list_head *list,
#define list_next_entry(pos, member) \
list_entry((pos)->member.next, typeof(*(pos)), member)
+/**
+ * list_next_entry_circular - get the next element in list
+ * @param pos the type * to cursor.
+ * @param head the list head to take the element from.
+ * @param member the name of the list_head within the struct.
+ *
+ * Wraparound if pos is the last element (return the first element).
+ * Note, that list is expected to be not empty.
+ */
+#define list_next_entry_circular(pos, head, member) \
+ (list_is_last(&(pos)->member, head) ? \
+ list_first_entry(head, typeof(*(pos)), member) : list_next_entry(pos, member))
+
/**
* list_prev_entry - get the prev element in list
* @param pos the type * to cursor
@@ -571,13 +591,28 @@ static inline void list_splice_tail_init(struct list_head *list,
#define list_prev_entry(pos, member) \
list_entry((pos)->member.prev, typeof(*(pos)), member)
+/**
+ * list_prev_entry_circular - get the prev element in list
+ * @param pos the type * to cursor.
+ * @param head the list head to take the element from.
+ * @param member the name of the list_head within the struct.
+ *
+ * Wraparound if pos is the first element (return the last element).
+ * Note, that list is expected to be not empty.
+ */
+#define list_prev_entry_circular(pos, head, member) \
+ (list_is_first(&(pos)->member, head) ? \
+ list_last_entry(head, typeof(*(pos)), member) : list_prev_entry(pos, member))
+
/**
* list_for_each - iterate over a list
* @param pos the &struct list_head to use as a loop cursor.
* @param head the head for your list.
*/
#define list_for_each(pos, head) \
- for (pos = (head)->next; pos != (head); pos = pos->next)
+ for (pos = (head)->next; !list_is_head(pos, (head)); pos = pos->next)
+
+/* Ignore kernel list_for_each_rcu() */
/**
* list_for_each_continue - continue iteration over a list
@@ -618,6 +653,21 @@ static inline void list_splice_tail_init(struct list_head *list,
pos != (head); \
pos = n, n = pos->prev)
+/**
+ * list_count_nodes - count nodes in the list
+ * @param head the head for your list.
+ */
+static inline size_t list_count_nodes(struct list_head *head)
+{
+ struct list_head *pos;
+ size_t count = 0;
+
+ list_for_each(pos, head)
+ count++;
+
+ return count;
+}
+
/**
* list_entry_is_head - test if the entry points to the head of the list
* @param pos the type * to cursor
-----------------------------------------------------------------------
Summary of changes:
src/helper/list.h | 66 ++++++++++++++++++++++++++++++++++++++++++++++++-------
1 file changed, 58 insertions(+), 8 deletions(-)
hooks/post-receive
--
Main OpenOCD repository
|
|
From: openocd-gerrit <ope...@us...> - 2023-04-07 21:47:39
|
This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "Main OpenOCD repository".
The branch, master has been updated
via 90ce9da644d751466d8dc451d7d2a043cdbf7d72 (commit)
from 55e04e3157cd4d817cfd39c6f1384f96d61a0951 (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commit 90ce9da644d751466d8dc451d7d2a043cdbf7d72
Author: Antonio Borneo <bor...@gm...>
Date: Tue Mar 14 15:01:18 2023 +0100
helper/list: remove unused hlist_*
The file list.h is taken from Linux and includes two similar
implementation of double linked lists:
- with single linked list's head (hlist_*), and
- with double linked list's head (list_*).
While the former offers a minor memory footprint improvement,
keeping two implementations makes harder for newbie developers
to approach them.
So far only the latter implementation has been used and no new
patches in gerrit is going to change that.
Drop the support for lists with single linked head.
It can be easily taken back from git history, if needed.
Change-Id: I420e5de38ab755fdfbeb2115538c61818308ec2b
Signed-off-by: Antonio Borneo <bor...@gm...>
Reviewed-on: https://review.openocd.org/c/openocd/+/7567
Tested-by: jenkins
Reviewed-by: Tomas Vanek <va...@fb...>
diff --git a/src/helper/list.h b/src/helper/list.h
index 552a3202a..396ff06c9 100644
--- a/src/helper/list.h
+++ b/src/helper/list.h
@@ -27,13 +27,6 @@ struct list_head {
struct list_head *next, *prev;
};
-struct hlist_head {
- struct hlist_node *first;
-};
-
-struct hlist_node {
- struct hlist_node *next, **pprev;
-};
/* end local changes */
/*
@@ -811,237 +804,7 @@ static inline void list_splice_tail_init(struct list_head *list,
/*
* Double linked lists with a single pointer list head.
- * Mostly useful for hash tables where the two pointer list head is
- * too wasteful.
- * You lose the ability to access the tail in O(1).
- */
-
-#define HLIST_HEAD_INIT { .first = NULL }
-#define HLIST_HEAD(name) struct hlist_head name = { .first = NULL }
-#define INIT_HLIST_HEAD(ptr) ((ptr)->first = NULL)
-static inline void INIT_HLIST_NODE(struct hlist_node *h)
-{
- h->next = NULL;
- h->pprev = NULL;
-}
-
-/**
- * hlist_unhashed - Has node been removed from list and reinitialized?
- * @param h Node to be checked
- *
- * Not that not all removal functions will leave a node in unhashed
- * state. For example, hlist_nulls_del_init_rcu() does leave the
- * node in unhashed state, but hlist_nulls_del() does not.
- */
-static inline int hlist_unhashed(const struct hlist_node *h)
-{
- return !h->pprev;
-}
-
-/* Ignore kernel hlist_unhashed_lockless() */
-
-/**
- * hlist_empty - Is the specified hlist_head structure an empty hlist?
- * @param h Structure to check.
- */
-static inline int hlist_empty(const struct hlist_head *h)
-{
- return !h->first;
-}
-
-static inline void __hlist_del(struct hlist_node *n)
-{
- struct hlist_node *next = n->next;
- struct hlist_node **pprev = n->pprev;
-
- *pprev = next;
- if (next)
- next->pprev = pprev;
-}
-
-/**
- * hlist_del - Delete the specified hlist_node from its list
- * @param n Node to delete.
- *
- * Note that this function leaves the node in hashed state. Use
- * hlist_del_init() or similar instead to unhash @a n.
- */
-static inline void hlist_del(struct hlist_node *n)
-{
- __hlist_del(n);
- n->next = LIST_POISON1;
- n->pprev = LIST_POISON2;
-}
-
-/**
- * hlist_del_init - Delete the specified hlist_node from its list and initialize
- * @param n Node to delete.
- *
- * Note that this function leaves the node in unhashed state.
- */
-static inline void hlist_del_init(struct hlist_node *n)
-{
- if (!hlist_unhashed(n)) {
- __hlist_del(n);
- INIT_HLIST_NODE(n);
- }
-}
-
-/**
- * hlist_add_head - add a new entry at the beginning of the hlist
- * @param n new entry to be added
- * @param h hlist head to add it after
- *
- * Insert a new entry after the specified head.
- * This is good for implementing stacks.
- */
-static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h)
-{
- struct hlist_node *first = h->first;
- n->next = first;
- if (first)
- first->pprev = &n->next;
- h->first = n;
- n->pprev = &h->first;
-}
-
-/**
- * hlist_add_before - add a new entry before the one specified
- * @param n new entry to be added
- * @param next hlist node to add it before, which must be non-NULL
- */
-static inline void hlist_add_before(struct hlist_node *n,
- struct hlist_node *next)
-{
- n->pprev = next->pprev;
- n->next = next;
- next->pprev = &n->next;
- *(n->pprev) = n;
-}
-
-/**
- * hlist_add_behind - add a new entry after the one specified
- * @param n new entry to be added
- * @param prev hlist node to add it after, which must be non-NULL
- */
-static inline void hlist_add_behind(struct hlist_node *n,
- struct hlist_node *prev)
-{
- n->next = prev->next;
- prev->next = n;
- n->pprev = &prev->next;
-
- if (n->next)
- n->next->pprev = &n->next;
-}
-
-/**
- * hlist_add_fake - create a fake hlist consisting of a single headless node
- * @param n Node to make a fake list out of
- *
- * This makes @a n appear to be its own predecessor on a headless hlist.
- * The point of this is to allow things like hlist_del() to work correctly
- * in cases where there is no list.
- */
-static inline void hlist_add_fake(struct hlist_node *n)
-{
- n->pprev = &n->next;
-}
-
-/**
- * hlist_fake: Is this node a fake hlist?
- * @param h Node to check for being a self-referential fake hlist.
- */
-static inline bool hlist_fake(struct hlist_node *h)
-{
- return h->pprev == &h->next;
-}
-
-/**
- * hlist_is_singular_node - is node the only element of the specified hlist?
- * @param n Node to check for singularity.
- * @param h Header for potentially singular list.
- *
- * Check whether the node is the only node of the head without
- * accessing head, thus avoiding unnecessary cache misses.
- */
-static inline bool
-hlist_is_singular_node(struct hlist_node *n, struct hlist_head *h)
-{
- return !n->next && n->pprev == &h->first;
-}
-
-/**
- * hlist_move_list - Move an hlist
- * @param old hlist_head for old list.
- * @param new hlist_head for new list.
- *
- * Move a list from one list head to another. Fixup the pprev
- * reference of the first entry if it exists.
- */
-static inline void hlist_move_list(struct hlist_head *old,
- struct hlist_head *new)
-{
- new->first = old->first;
- if (new->first)
- new->first->pprev = &new->first;
- old->first = NULL;
-}
-
-#define hlist_entry(ptr, type, member) container_of(ptr, type, member)
-
-#define hlist_for_each(pos, head) \
- for (pos = (head)->first; pos ; pos = pos->next)
-
-#define hlist_for_each_safe(pos, n, head) \
- for (pos = (head)->first; pos && ({ n = pos->next; 1; }); \
- pos = n)
-
-#define hlist_entry_safe(ptr, type, member) \
- ({ typeof(ptr) ____ptr = (ptr); \
- ____ptr ? hlist_entry(____ptr, type, member) : NULL; \
- })
-
-/**
- * hlist_for_each_entry - iterate over list of given type
- * @param pos the type * to use as a loop cursor.
- * @param head the head for your list.
- * @param member the name of the hlist_node within the struct.
- */
-#define hlist_for_each_entry(pos, head, member) \
- for (pos = hlist_entry_safe((head)->first, typeof(*(pos)), member);\
- pos; \
- pos = hlist_entry_safe((pos)->member.next, typeof(*(pos)), member))
-
-/**
- * hlist_for_each_entry_continue - iterate over a hlist continuing after current point
- * @param pos the type * to use as a loop cursor.
- * @param member the name of the hlist_node within the struct.
- */
-#define hlist_for_each_entry_continue(pos, member) \
- for (pos = hlist_entry_safe((pos)->member.next, typeof(*(pos)), member);\
- pos; \
- pos = hlist_entry_safe((pos)->member.next, typeof(*(pos)), member))
-
-/**
- * hlist_for_each_entry_from - iterate over a hlist continuing from current point
- * @param pos the type * to use as a loop cursor.
- * @param member the name of the hlist_node within the struct.
- */
-#define hlist_for_each_entry_from(pos, member) \
- for (; pos; \
- pos = hlist_entry_safe((pos)->member.next, typeof(*(pos)), member))
-
-/**
- * hlist_for_each_entry_safe - iterate over list of given type safe against removal of list entry
- * @param pos the type * to use as a loop cursor.
- * @param n a &struct hlist_node to use as temporary storage
- * @param head the head for your list.
- * @param member the name of the hlist_node within the struct.
+ * IGNORED
*/
-#define hlist_for_each_entry_safe(pos, n, head, member) \
- for (pos = hlist_entry_safe((head)->first, typeof(*pos), member);\
- pos && ({ n = pos->member.next; 1; }); \
- pos = hlist_entry_safe(n, typeof(*pos), member))
#endif /* OPENOCD_HELPER_LIST_H */
-----------------------------------------------------------------------
Summary of changes:
src/helper/list.h | 239 +-----------------------------------------------------
1 file changed, 1 insertion(+), 238 deletions(-)
hooks/post-receive
--
Main OpenOCD repository
|
|
From: openocd-gerrit <ope...@us...> - 2023-04-07 21:47:00
|
This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "Main OpenOCD repository".
The branch, master has been updated
via 55e04e3157cd4d817cfd39c6f1384f96d61a0951 (commit)
from 18aacc8bf3ff7c7481673cbbfe82f0104e4dccf9 (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commit 55e04e3157cd4d817cfd39c6f1384f96d61a0951
Author: François LEGAL <de...@th...>
Date: Wed Mar 29 17:46:38 2023 +0200
src/target/mips_m4k : add fast read method
Add the fast read method to speed up flash verification
after programming. Works the same as fast write already
implemented.
Signed-off-by: François LEGAL <de...@th...>
Change-Id: I74611a3542a88212f0483ec8ee368aba3d1f03c7
Reviewed-on: https://review.openocd.org/c/openocd/+/7564
Tested-by: jenkins
Reviewed-by: Antonio Borneo <bor...@gm...>
diff --git a/src/target/mips_m4k.c b/src/target/mips_m4k.c
index d3b07585d..14e3f3b27 100644
--- a/src/target/mips_m4k.c
+++ b/src/target/mips_m4k.c
@@ -36,6 +36,8 @@ static int mips_m4k_internal_restore(struct target *target, int current,
static int mips_m4k_halt(struct target *target);
static int mips_m4k_bulk_write_memory(struct target *target, target_addr_t address,
uint32_t count, const uint8_t *buffer);
+static int mips_m4k_bulk_read_memory(struct target *target, target_addr_t address,
+ uint32_t count, uint8_t *buffer);
static int mips_m4k_examine_debug_reason(struct target *target)
{
@@ -1021,6 +1023,12 @@ static int mips_m4k_read_memory(struct target *target, target_addr_t address,
if (((size == 4) && (address & 0x3u)) || ((size == 2) && (address & 0x1u)))
return ERROR_TARGET_UNALIGNED_ACCESS;
+ if (size == 4 && count > 32) {
+ int retval = mips_m4k_bulk_read_memory(target, address, count, buffer);
+ if (retval == ERROR_OK)
+ return ERROR_OK;
+ LOG_WARNING("Falling back to non-bulk read");
+ }
/* since we don't know if buffer is aligned, we allocate new mem that is always aligned */
void *t = NULL;
@@ -1249,6 +1257,71 @@ static int mips_m4k_bulk_write_memory(struct target *target, target_addr_t addre
return retval;
}
+static int mips_m4k_bulk_read_memory(struct target *target, target_addr_t address,
+ uint32_t count, uint8_t *buffer)
+{
+ struct mips32_common *mips32 = target_to_mips32(target);
+ struct mips_ejtag *ejtag_info = &mips32->ejtag_info;
+ struct working_area *fast_data_area;
+ int retval;
+ int write_t = 0;
+
+ LOG_DEBUG("address: " TARGET_ADDR_FMT ", count: 0x%8.8" PRIx32 "",
+ address, count);
+
+ /* check alignment */
+ if (address & 0x3u)
+ return ERROR_TARGET_UNALIGNED_ACCESS;
+
+ if (!mips32->fast_data_area) {
+ /* Get memory for block read handler
+ * we preserve this area between calls and gain a speed increase
+ * of about 3kb/sec when reading flash
+ * this will be released/nulled by the system when the target is resumed or reset */
+ retval = target_alloc_working_area(target,
+ MIPS32_FASTDATA_HANDLER_SIZE,
+ &mips32->fast_data_area);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("No working area available");
+ return retval;
+ }
+
+ /* reset fastadata state so the algo get reloaded */
+ ejtag_info->fast_access_save = -1;
+ }
+
+ fast_data_area = mips32->fast_data_area;
+
+ if (address < (fast_data_area->address + fast_data_area->size) &&
+ fast_data_area->address < (address + count)) {
+ LOG_ERROR("fast_data (" TARGET_ADDR_FMT ") is within read area "
+ "(" TARGET_ADDR_FMT "-" TARGET_ADDR_FMT ").",
+ fast_data_area->address, address, address + count);
+ LOG_ERROR("Change work-area-phys or load_image address!");
+ return ERROR_FAIL;
+ }
+
+ /* mips32_pracc_fastdata_xfer requires uint32_t in host endianness, */
+ /* but byte array represents target endianness */
+ uint32_t *t = malloc(count * sizeof(uint32_t));
+ if (!t) {
+ LOG_ERROR("Out of memory");
+ return ERROR_FAIL;
+ }
+
+ retval = mips32_pracc_fastdata_xfer(ejtag_info, mips32->fast_data_area, write_t, address,
+ count, t);
+
+ target_buffer_set_u32_array(target, buffer, count, t);
+
+ free(t);
+
+ if (retval != ERROR_OK)
+ LOG_ERROR("Fastdata access Failed");
+
+ return retval;
+}
+
static int mips_m4k_verify_pointer(struct command_invocation *cmd,
struct mips_m4k_common *mips_m4k)
{
-----------------------------------------------------------------------
Summary of changes:
src/target/mips_m4k.c | 73 +++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 73 insertions(+)
hooks/post-receive
--
Main OpenOCD repository
|